1 /* Copyright 2022-2025 Thales Alenia Space
2 * Licensed to CS GROUP (CS) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * CS licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.orekit.frames;
18
19 import org.hipparchus.CalculusFieldElement;
20 import org.orekit.time.FieldAbsoluteDate;
21
22 import java.util.LinkedHashMap;
23 import java.util.Map;
24 import java.util.concurrent.locks.ReentrantLock;
25 import java.util.function.Function;
26
27 /** Thread-safe cached provider for frame transforms.
28 * <p>
29 * This provider is based on a thread-safe Least Recently Used cache
30 * using date as it access key, hence saving computation time on
31 * transform building.
32 * </p>
33 * <p>
34 * This class is thread-safe.
35 * </p>
36 * @param <T> type of the field elements
37 * @author Luc Maisonobe
38 * @since 13.0.3
39 */
40 public class FieldCachedTransformProvider<T extends CalculusFieldElement<T>> {
41
42 /** Origin frame. */
43 private final Frame origin;
44
45 /** Destination frame. */
46 private final Frame destination;
47
48 /** Number of transforms kept in the date-based cache. */
49 private final int cacheSize;
50
51 /** Generator for full transforms. */
52 private final Function<FieldAbsoluteDate<T>, FieldTransform<T>> fullGenerator;
53
54 /** Generator for kinematic transforms. */
55 private final Function<FieldAbsoluteDate<T>, FieldKinematicTransform<T>> kinematicGenerator;
56
57 /** Generator for static transforms. */
58 private final Function<FieldAbsoluteDate<T>, FieldStaticTransform<T>> staticGenerator;
59
60 /** Lock for concurrent access. */
61 private final ReentrantLock lock;
62
63 /** Transforms LRU cache. */
64 private final Map<FieldAbsoluteDate<T>, FieldTransform<T>> fullCache;
65
66 /** Transforms LRU cache. */
67 private final Map<FieldAbsoluteDate<T>, FieldKinematicTransform<T>> kinematicCache;
68
69 /** Transforms LRU cache. */
70 private final Map<FieldAbsoluteDate<T>, FieldStaticTransform<T>> staticCache;
71
72 /**
73 * Simple constructor.
74 * @param origin origin frame
75 * @param destination destination frame
76 * @param fullGenerator generator for full transforms
77 * @param kinematicGenerator generator for kinematic transforms
78 * @param staticGenerator generator for static transforms
79 * @param cacheSize number of transforms kept in the date-based cache
80 */
81 public FieldCachedTransformProvider(final Frame origin, final Frame destination,
82 final Function<FieldAbsoluteDate<T>, FieldTransform<T>> fullGenerator,
83 final Function<FieldAbsoluteDate<T>, FieldKinematicTransform<T>> kinematicGenerator,
84 final Function<FieldAbsoluteDate<T>, FieldStaticTransform<T>> staticGenerator,
85 final int cacheSize) {
86
87 this.origin = origin;
88 this.destination = destination;
89 this.cacheSize = cacheSize;
90 this.fullGenerator = fullGenerator;
91 this.kinematicGenerator = kinematicGenerator;
92 this.staticGenerator = staticGenerator;
93 this.lock = new ReentrantLock();
94
95 // cache for full transforms
96 this.fullCache = new LinkedHashMap<FieldAbsoluteDate<T>, FieldTransform<T>>(cacheSize, 0.75f, true) {
97 /** {@inheritDoc} */
98 @Override
99 protected boolean removeEldestEntry(final Map.Entry<FieldAbsoluteDate<T>, FieldTransform<T>> eldest) {
100 return size() > cacheSize;
101 }
102 };
103
104 // cache for kinematic transforms
105 this.kinematicCache = new LinkedHashMap<FieldAbsoluteDate<T>, FieldKinematicTransform<T>>(cacheSize, 0.75f, true) {
106 /** {@inheritDoc} */
107 @Override
108 protected boolean removeEldestEntry(final Map.Entry<FieldAbsoluteDate<T>, FieldKinematicTransform<T>> eldest) {
109 return size() > cacheSize;
110 }
111 };
112
113 // cache for static transforms
114 this.staticCache = new LinkedHashMap<FieldAbsoluteDate<T>, FieldStaticTransform<T>>(cacheSize, 0.75f, true) {
115 /** {@inheritDoc} */
116 @Override
117 protected boolean removeEldestEntry(final Map.Entry<FieldAbsoluteDate<T>, FieldStaticTransform<T>> eldest) {
118 return size() > cacheSize;
119 }
120 };
121
122 }
123
124 /** Get origin frame.
125 * @return origin frame
126 */
127 public Frame getOrigin() {
128 return origin;
129 }
130
131 /** Get destination frame.
132 * @return destination frame
133 */
134 public Frame getDestination() {
135 return destination;
136 }
137
138 /** Get the nmber of transforms kept in the date-based cache.
139 * @return nmber of transforms kept in the date-based cache
140 */
141 public int getCacheSize() {
142 return cacheSize;
143 }
144
145 /** Get the {@link Transform} corresponding to specified date.
146 * @param date current date
147 * @return transform at specified date
148 */
149 public FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
150 lock.lock();
151 try {
152 return fullCache.computeIfAbsent(date, fullGenerator);
153 } finally {
154 lock.unlock();
155 }
156 }
157
158 /** Get the {@link Transform} corresponding to specified date.
159 * @param date current date
160 * @return transform at specified date
161 */
162 public FieldKinematicTransform<T> getKinematicTransform(final FieldAbsoluteDate<T> date) {
163 lock.lock();
164 try {
165 return kinematicCache.computeIfAbsent(date, kinematicGenerator);
166 } finally {
167 lock.unlock();
168 }
169 }
170
171 /** Get the {@link Transform} corresponding to specified date.
172 * @param date current date
173 * @return transform at specified date
174 */
175 public FieldStaticTransform<T> getStaticTransform(final FieldAbsoluteDate<T> date) {
176 lock.lock();
177 try {
178 return staticCache.computeIfAbsent(date, staticGenerator);
179 } finally {
180 lock.unlock();
181 }
182 }
183
184 }