1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.frames;
18
19 import org.hipparchus.CalculusFieldElement;
20 import org.hipparchus.Field;
21 import org.hipparchus.random.RandomGenerator;
22 import org.hipparchus.random.Well19937a;
23 import org.hipparchus.util.Binary64Field;
24 import org.junit.jupiter.api.AfterEach;
25 import org.junit.jupiter.api.Assertions;
26 import org.junit.jupiter.api.BeforeEach;
27 import org.junit.jupiter.api.Test;
28 import org.orekit.Utils;
29 import org.orekit.time.FieldAbsoluteDate;
30 import org.orekit.utils.Constants;
31 import org.orekit.utils.IERSConventions;
32
33 import java.util.ArrayList;
34 import java.util.List;
35 import java.util.concurrent.Callable;
36 import java.util.concurrent.ExecutionException;
37 import java.util.concurrent.ExecutorService;
38 import java.util.concurrent.Executors;
39 import java.util.concurrent.Future;
40 import java.util.function.Function;
41
42 public class FieldCachedTransformProviderTest {
43
44 private Frame inertialFrame;
45 private CountingFrame earth1;
46 private CountingFrame earth2;
47
48 @Test
49 public void testSingleThread() {
50 doTestSingleThread(Binary64Field.getInstance());
51 }
52
53 private <T extends CalculusFieldElement<T>> void doTestSingleThread(final Field<T> field) {
54 final FieldCachedTransformProvider<T> cachedTransformProvider = buildCache(20);
55 Assertions.assertSame(earth1, cachedTransformProvider.getOrigin());
56 Assertions.assertSame(inertialFrame, cachedTransformProvider.getDestination());
57 Assertions.assertEquals(20, cachedTransformProvider.getCacheSize());
58 final List<FieldAbsoluteDate<T>> dates = generateDates(field, new Well19937a(0x03fb4b0832dadcbe2L), 50, 5);
59 for (final FieldAbsoluteDate<T> date : dates) {
60 final FieldTransform<T> transform1 = cachedTransformProvider.getTransform(date);
61 final FieldTransform<T> transform2 = earth2.getTransformTo(inertialFrame, date);
62 final FieldTransform<T> backAndForth = new FieldTransform<>(date, transform1, transform2.getInverse());
63 Assertions.assertEquals(0.0, backAndForth.getRotation().getAngle().getReal(), 3.0e-15);
64 }
65 Assertions.assertEquals(10, earth1.count);
66 Assertions.assertEquals(dates.size(), earth2.count);
67 }
68
69 @Test
70 public void testSingleThreadKinematic() {
71 doTestSingleThreadKinematic(Binary64Field.getInstance());
72 }
73
74 private <T extends CalculusFieldElement<T>> void doTestSingleThreadKinematic(final Field<T> field) {
75 final FieldCachedTransformProvider<T> cachedTransformProvider = buildCache(20);
76 Assertions.assertSame(earth1, cachedTransformProvider.getOrigin());
77 Assertions.assertSame(inertialFrame, cachedTransformProvider.getDestination());
78 Assertions.assertEquals(20, cachedTransformProvider.getCacheSize());
79 final List<FieldAbsoluteDate<T>> dates = generateDates(field, new Well19937a(0x03fb4b0832dadcbe2L), 50, 5);
80 for (final FieldAbsoluteDate<T> date : dates) {
81 final FieldKinematicTransform<T> transform1 = cachedTransformProvider.getKinematicTransform(date);
82 final FieldKinematicTransform<T> transform2 = earth2.getKinematicTransformTo(inertialFrame, date);
83 final FieldKinematicTransform<T> backAndForth = FieldKinematicTransform.compose(date, transform1, transform2.getInverse());
84 Assertions.assertEquals(0.0, backAndForth.getRotation().getAngle().getReal(), 3.0e-15);
85 }
86 Assertions.assertEquals(10, earth1.count);
87 Assertions.assertEquals(dates.size(), earth2.count);
88 }
89
90 @Test
91 public void testSingleThreadStatic() {
92 doTestSingleThreadStatic(Binary64Field.getInstance());
93 }
94
95 private <T extends CalculusFieldElement<T>> void doTestSingleThreadStatic(final Field<T> field) {
96 final FieldCachedTransformProvider<T> cachedTransformProvider = buildCache(20);
97 Assertions.assertSame(earth1, cachedTransformProvider.getOrigin());
98 Assertions.assertSame(inertialFrame, cachedTransformProvider.getDestination());
99 Assertions.assertEquals(20, cachedTransformProvider.getCacheSize());
100 final List<FieldAbsoluteDate<T>> dates = generateDates(field, new Well19937a(0x03fb4b0832dadcbe2L), 50, 5);
101 for (final FieldAbsoluteDate<T> date : dates) {
102 final FieldStaticTransform<T> transform1 = cachedTransformProvider.getStaticTransform(date);
103 final FieldStaticTransform<T> transform2 = earth2.getStaticTransformTo(inertialFrame, date);
104 final FieldStaticTransform<T> backAndForth = FieldStaticTransform.compose(date, transform1, transform2.getInverse());
105 Assertions.assertEquals(0.0, backAndForth.getRotation().getAngle().getReal(), 3.0e-15);
106 }
107 Assertions.assertEquals(10, earth1.count);
108 Assertions.assertEquals(dates.size(), earth2.count);
109 }
110
111 @Test
112 public void testMultiThread() throws InterruptedException, ExecutionException {
113 doTestMultiThread(Binary64Field.getInstance());
114 }
115
116 private <T extends CalculusFieldElement<T>> void doTestMultiThread(final Field<T> field)
117 throws InterruptedException, ExecutionException {
118 final FieldCachedTransformProvider<T> cachedTransformProvider = buildCache(30);
119 Assertions.assertEquals(30, cachedTransformProvider.getCacheSize());
120 final List<FieldAbsoluteDate<T>> dates = generateDates(field, new Well19937a(0x7d63ba984c6ae29eL), 300, 10);
121 final List<Callable<FieldTransform<T>>> tasks = new ArrayList<>();
122 for (final FieldAbsoluteDate<T> date : dates) {
123 tasks.add(() -> cachedTransformProvider.getTransform(date));
124 }
125 ExecutorService executorService = Executors.newFixedThreadPool(8);
126 final List<Future<FieldTransform<T>>> futures = executorService.invokeAll(tasks);
127 for (int i = 0; i < dates.size(); i++) {
128 final FieldTransform<T> transform1 = futures.get(i).get();
129 final FieldTransform<T> transform2 = earth2.getTransformTo(inertialFrame, dates.get(i));
130 final FieldTransform<T> backAndForth = new FieldTransform<>(dates.get(i), transform1, transform2.getInverse());
131 Assertions.assertEquals(0.0, backAndForth.getRotation().getAngle().getReal(), 1.0e-14);
132 }
133 Assertions.assertTrue(earth1.count < 50, "this test may randomly fail due to multi-threading non-determinism");
134 Assertions.assertEquals(dates.size(), earth2.count);
135 }
136
137 @Test
138 public void testExhaust() {
139 doTestExhaust(Binary64Field.getInstance());
140 }
141
142 private <T extends CalculusFieldElement<T>> void doTestExhaust(final Field<T> field) {
143 final RandomGenerator random = new Well19937a(0x3b18a628c1a8b5e9L);
144 final FieldCachedTransformProvider<T> cachedTransformProvider = buildCache(20);
145 final List<FieldAbsoluteDate<T>> dates = generateDates(field,
146 random,
147 10 * cachedTransformProvider.getCacheSize(),
148 50 * cachedTransformProvider.getCacheSize());
149
150
151 final List<FieldTransform<T>> firstBatch = new ArrayList<>();
152 for (int i = 0; i < cachedTransformProvider.getCacheSize(); i++) {
153 firstBatch.add(cachedTransformProvider.getTransform(dates.get(i)));
154 }
155 for (int i = 0; i < 1000; i++) {
156
157 final int k = random.nextInt(firstBatch.size());
158 Assertions.assertSame(firstBatch.get(k), cachedTransformProvider.getTransform(dates.get(k)));
159 }
160 final FieldTransform<T> t14 = cachedTransformProvider.getTransform(dates.get(14));
161
162
163 for (int i = 0; i < dates.size(); i++) {
164 Assertions.assertNotNull(cachedTransformProvider.getTransform(dates.get(dates.size() - 1 - i)));
165 Assertions.assertNotNull(cachedTransformProvider.getTransform(dates.get(14)));
166 }
167
168 for (int i = 0; i < 100; i++) {
169
170
171 final int k = random.nextInt(firstBatch.size());
172 final FieldTransform<T> t = cachedTransformProvider.getTransform(dates.get(k));
173 final FieldTransform<T> backAndForth = new FieldTransform<>(dates.get(k), firstBatch.get(k), t.getInverse());
174 if (k != 14) {
175 Assertions.assertNotSame(firstBatch.get(k), t);
176 }
177 Assertions.assertEquals(0.0, backAndForth.getRotation().getAngle().getReal(), 1.0e-20);
178 Assertions.assertEquals(0.0, backAndForth.getCartesian().getPosition().getNorm().getReal(), 1.0e-20);
179 }
180
181
182 Assertions.assertSame(t14, cachedTransformProvider.getTransform(dates.get(14)));
183
184 }
185
186 @Test
187 public void testExhaustKinematic() {
188 doTestExhaustKinematic(Binary64Field.getInstance());
189 }
190
191 private <T extends CalculusFieldElement<T>> void doTestExhaustKinematic(final Field<T> field) {
192 final RandomGenerator random = new Well19937a(0x3b18a628c1a8b5e9L);
193 final FieldCachedTransformProvider<T> cachedTransformProvider = buildCache(20);
194 final List<FieldAbsoluteDate<T>> dates = generateDates(field,
195 random,
196 10 * cachedTransformProvider.getCacheSize(),
197 50 * cachedTransformProvider.getCacheSize());
198
199
200 final List<FieldKinematicTransform<T>> firstBatch = new ArrayList<>();
201 for (int i = 0; i < cachedTransformProvider.getCacheSize(); i++) {
202 firstBatch.add(cachedTransformProvider.getKinematicTransform(dates.get(i)));
203 }
204 for (int i = 0; i < 1000; i++) {
205
206 final int k = random.nextInt(firstBatch.size());
207 Assertions.assertSame(firstBatch.get(k), cachedTransformProvider.getKinematicTransform(dates.get(k)));
208 }
209 final FieldKinematicTransform<T> t14 = cachedTransformProvider.getKinematicTransform(dates.get(14));
210
211
212 for (int i = 0; i < dates.size(); i++) {
213 Assertions.assertNotNull(cachedTransformProvider.getKinematicTransform(dates.get(dates.size() - 1 - i)));
214 Assertions.assertNotNull(cachedTransformProvider.getKinematicTransform(dates.get(14)));
215 }
216
217 for (int i = 0; i < 100; i++) {
218
219
220 final int k = random.nextInt(firstBatch.size());
221 final FieldKinematicTransform<T> t = cachedTransformProvider.getKinematicTransform(dates.get(k));
222 final FieldKinematicTransform<T> backAndForth = FieldKinematicTransform.compose(dates.get(k), firstBatch.get(k), t.getInverse());
223 if (k != 14) {
224 Assertions.assertNotSame(firstBatch.get(k), t);
225 }
226 Assertions.assertEquals(0.0, backAndForth.getRotation().getAngle().getReal(), 1.0e-20);
227 Assertions.assertEquals(0.0, backAndForth.getTranslation().getNorm().getReal(), 1.0e-20);
228 }
229
230
231 Assertions.assertSame(t14, cachedTransformProvider.getKinematicTransform(dates.get(14)));
232
233 }
234
235 @Test
236 public void testExhaustStatic() {
237 doTestExhaustStatic(Binary64Field.getInstance());
238 }
239
240 private <T extends CalculusFieldElement<T>> void doTestExhaustStatic(final Field<T> field) {
241 final RandomGenerator random = new Well19937a(0x3b18a628c1a8b5e9L);
242 final FieldCachedTransformProvider<T> cachedTransformProvider = buildCache(20);
243 final List<FieldAbsoluteDate<T>> dates = generateDates(field,
244 random,
245 10 * cachedTransformProvider.getCacheSize(),
246 50 * cachedTransformProvider.getCacheSize());
247
248
249 final List<FieldStaticTransform<T>> firstBatch = new ArrayList<>();
250 for (int i = 0; i < cachedTransformProvider.getCacheSize(); i++) {
251 firstBatch.add(cachedTransformProvider.getStaticTransform(dates.get(i)));
252 }
253 for (int i = 0; i < 1000; i++) {
254
255 final int k = random.nextInt(firstBatch.size());
256 Assertions.assertSame(firstBatch.get(k), cachedTransformProvider.getStaticTransform(dates.get(k)));
257 }
258 final FieldStaticTransform<T> t14 = cachedTransformProvider.getStaticTransform(dates.get(14));
259
260
261 for (int i = 0; i < dates.size(); i++) {
262 Assertions.assertNotNull(cachedTransformProvider.getStaticTransform(dates.get(dates.size() - 1 - i)));
263 Assertions.assertNotNull(cachedTransformProvider.getStaticTransform(dates.get(14)));
264 }
265
266 for (int i = 0; i < 100; i++) {
267
268
269 final int k = random.nextInt(firstBatch.size());
270 final FieldStaticTransform<T> t = cachedTransformProvider.getStaticTransform(dates.get(k));
271 final FieldStaticTransform<T> backAndForth = FieldStaticTransform.compose(dates.get(k), firstBatch.get(k), t.getInverse());
272 if (k != 14) {
273 Assertions.assertNotSame(firstBatch.get(k), t);
274 }
275 Assertions.assertEquals(0.0, backAndForth.getRotation().getAngle().getReal(), 1.0e-20);
276 Assertions.assertEquals(0.0, backAndForth.getTranslation().getNorm().getReal(), 1.0e-20);
277 }
278
279
280 Assertions.assertSame(t14, cachedTransformProvider.getStaticTransform(dates.get(14)));
281
282 }
283
284 private <T extends CalculusFieldElement<T>> FieldCachedTransformProvider<T> buildCache(final int size) {
285 final Function<FieldAbsoluteDate<T>, FieldTransform<T>> fullGenerator =
286 date -> earth1.getTransformTo(inertialFrame, date);
287 final Function<FieldAbsoluteDate<T>, FieldKinematicTransform<T>> kinematicGenerator =
288 date -> earth1.getKinematicTransformTo(inertialFrame, date);
289 final Function<FieldAbsoluteDate<T>, FieldStaticTransform<T>> staticGenerator =
290 date -> earth1.getStaticTransformTo(inertialFrame, date);
291 return new FieldCachedTransformProvider<>(earth1, inertialFrame,
292 fullGenerator, kinematicGenerator, staticGenerator,
293 size);
294 }
295
296 private <T extends CalculusFieldElement<T>> List<FieldAbsoluteDate<T>> generateDates(final Field<T> field,
297 final RandomGenerator random,
298 final int total,
299 final int history) {
300 final List<FieldAbsoluteDate<T>> dates = new ArrayList<>(total);
301 for (int i = 0; i < total; i++) {
302 final int index = i - random.nextInt(history);
303 final FieldAbsoluteDate<T> date = index < 0 || index >= dates.size() ?
304 FieldAbsoluteDate.getArbitraryEpoch(field).
305 shiftedBy(Constants.JULIAN_DAY * random.nextDouble()) :
306 dates.get(index);
307 dates.add(date);
308 }
309 return dates;
310 }
311
312 @BeforeEach
313 public void setUp() {
314 Utils.setDataRoot("regular-data");
315 final Frame earthFrame = FramesFactory.getITRF(IERSConventions.IERS_2010, false);
316 this.inertialFrame = FramesFactory.getEME2000();
317 this.earth1 = new CountingFrame(earthFrame);
318 this.earth2 = new CountingFrame(earthFrame);
319 }
320
321 @AfterEach
322 public void tearDown() {
323 inertialFrame = null;
324 earth1 = null;
325 earth2 = null;
326 }
327
328
329 private static class CountingFrame extends Frame {
330 int count;
331
332 CountingFrame(final Frame frame) {
333 super(frame, Transform.IDENTITY, "counting", false);
334 count = 0;
335 }
336
337 public <T extends CalculusFieldElement<T>> FieldTransform<T>
338 getTransformTo(final Frame destination, final FieldAbsoluteDate<T> date) {
339 ++count;
340 return super.getTransformTo(destination, date);
341 }
342
343 public <T extends CalculusFieldElement<T>> FieldKinematicTransform<T>
344 getKinematicTransformTo(final Frame destination, final FieldAbsoluteDate<T> date) {
345 ++count;
346 return super.getKinematicTransformTo(destination, date);
347 }
348
349 public <T extends CalculusFieldElement<T>> FieldStaticTransform<T>
350 getStaticTransformTo(final Frame destination, final FieldAbsoluteDate<T> date) {
351 ++count;
352 return super.getStaticTransformTo(destination, date);
353 }
354
355 }
356
357 }