1   /* Copyright 2002-2023 CS GROUP
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.ssa.collision.shorttermencounter.probability.twod;
18  
19  import org.hipparchus.Field;
20  import org.hipparchus.analysis.differentiation.DSFactory;
21  import org.hipparchus.analysis.differentiation.DerivativeStructure;
22  import org.hipparchus.analysis.integration.FieldTrapezoidIntegrator;
23  import org.hipparchus.analysis.integration.TrapezoidIntegrator;
24  import org.hipparchus.linear.FieldMatrix;
25  import org.hipparchus.linear.RealMatrix;
26  import org.hipparchus.util.Binary64;
27  import org.hipparchus.util.Binary64Field;
28  import org.junit.jupiter.api.Assertions;
29  import org.junit.jupiter.api.BeforeAll;
30  import org.junit.jupiter.api.Disabled;
31  import org.junit.jupiter.api.DisplayName;
32  import org.junit.jupiter.api.Test;
33  import org.orekit.Utils;
34  import org.orekit.data.DataSource;
35  import org.orekit.files.ccsds.ndm.ParserBuilder;
36  import org.orekit.files.ccsds.ndm.cdm.Cdm;
37  import org.orekit.frames.Frame;
38  import org.orekit.frames.FramesFactory;
39  import org.orekit.frames.LOFType;
40  import org.orekit.orbits.CartesianOrbit;
41  import org.orekit.orbits.FieldCartesianOrbit;
42  import org.orekit.orbits.FieldOrbit;
43  import org.orekit.orbits.Orbit;
44  import org.orekit.propagation.FieldStateCovariance;
45  import org.orekit.propagation.StateCovariance;
46  import org.orekit.ssa.collision.shorttermencounter.probability.twod.armellinutils.ArmellinDataLoader;
47  import org.orekit.ssa.collision.shorttermencounter.probability.twod.armellinutils.ArmellinDataRow;
48  import org.orekit.ssa.metrics.FieldProbabilityOfCollision;
49  import org.orekit.ssa.metrics.ProbabilityOfCollision;
50  import org.orekit.time.AbsoluteDate;
51  import org.orekit.time.FieldAbsoluteDate;
52  import org.orekit.utils.Constants;
53  import org.orekit.utils.FieldPVCoordinates;
54  
55  import java.io.IOException;
56  import java.util.List;
57  
58  class Patera2005Test {
59  
60      /** Patera method (2005) to compute probability of collision. */
61      private final ShortTermEncounter2DPOCMethod method = new Patera2005();
62  
63      @BeforeAll
64      static void initializeOrekitData() {
65          Utils.setDataRoot("regular-data");
66      }
67  
68      @Test
69      @DisplayName("Chan test case 01")
70      void ChanTestCase01() {
71          // GIVEN
72          final double xm     = 0;
73          final double ym     = 10;
74          final double sigmaX = 25;
75          final double sigmaY = 50;
76          final double radius = 5;
77  
78          // WHEN
79          final ProbabilityOfCollision result = method.compute(xm, ym, sigmaX, sigmaY, radius);
80  
81          // THEN
82          Assertions.assertEquals(9.741e-3, result.getValue(), 1e-6);
83      }
84  
85      @Test
86      @DisplayName("Chan test case 02")
87      void ChanTestCase02() {
88          // GIVEN
89          final double xm     = 10;
90          final double ym     = 0;
91          final double sigmaX = 25;
92          final double sigmaY = 50;
93          final double radius = 5;
94  
95          // WHEN
96          final ProbabilityOfCollision result = method.compute(xm, ym, sigmaX, sigmaY, radius);
97  
98          // THEN
99          Assertions.assertEquals(9.181e-3, result.getValue(), 1e-6);
100     }
101 
102     @Test
103     @DisplayName("Chan test case 03")
104     void ChanTestCase03() {
105         // GIVEN
106         final double xm     = 0;
107         final double ym     = 10;
108         final double sigmaX = 25;
109         final double sigmaY = 75;
110         final double radius = 5;
111 
112         // WHEN
113         final ProbabilityOfCollision result = method.compute(xm, ym, sigmaX, sigmaY, radius);
114 
115         // THEN
116         Assertions.assertEquals(6.571e-3, result.getValue(), 1e-6);
117     }
118 
119     @Test
120     @DisplayName("Chan test case 04")
121     void ChanTestCase04() {
122         // GIVEN
123         final double xm     = 10;
124         final double ym     = 0;
125         final double sigmaX = 25;
126         final double sigmaY = 75;
127         final double radius = 5;
128 
129         // WHEN
130         final ProbabilityOfCollision result = method.compute(xm, ym, sigmaX, sigmaY, radius);
131 
132         // THEN
133         Assertions.assertEquals(6.125e-3, result.getValue(), 1e-6);
134     }
135 
136     @Test
137     @DisplayName("Chan test case 05")
138     void ChanTestCase05() {
139         // GIVEN
140         final double xm     = 0;
141         final double ym     = 1000;
142         final double sigmaX = 1000;
143         final double sigmaY = 3000;
144         final double radius = 10;
145 
146         // WHEN
147         final ProbabilityOfCollision result = method.compute(xm, ym, sigmaX, sigmaY, radius);
148 
149         // THEN
150         Assertions.assertEquals(1.577e-5, result.getValue(), 1e-8);
151     }
152 
153     @Test
154     @DisplayName("Chan test case 06")
155     void ChanTestCase06() {
156         // GIVEN
157         final double xm     = 1000;
158         final double ym     = 0;
159         final double sigmaX = 1000;
160         final double sigmaY = 3000;
161         final double radius = 10;
162 
163         // WHEN
164         final ProbabilityOfCollision result = method.compute(xm, ym, sigmaX, sigmaY, radius);
165 
166         // THEN
167         Assertions.assertEquals(1.011e-5, result.getValue(), 1e-8);
168     }
169 
170     @Test
171     @DisplayName("Chan test case 07")
172     void ChanTestCase07() {
173         // GIVEN
174         final double xm     = 0;
175         final double ym     = 10000;
176         final double sigmaX = 1000;
177         final double sigmaY = 3000;
178         final double radius = 10;
179 
180         // WHEN
181         final ProbabilityOfCollision result = method.compute(xm, ym, sigmaX, sigmaY, radius);
182 
183         // THEN
184         Assertions.assertEquals(6.443e-8, result.getValue(), 1e-11);
185     }
186 
187     @Test
188     @DisplayName("Chan test case 08")
189     void ChanTestCase08() {
190         // GIVEN
191         final double xm     = 10000;
192         final double ym     = 0;
193         final double sigmaX = 1000;
194         final double sigmaY = 3000;
195         final double radius = 10;
196 
197         // WHEN
198         final ProbabilityOfCollision result = method.compute(xm, ym, sigmaX, sigmaY, radius);
199 
200         // THEN
201         Assertions.assertEquals(3.219e-27, result.getValue(), 1e-30);
202     }
203 
204     @Test
205     @DisplayName("Chan test case 09")
206     void ChanTestCase09() {
207         // GIVEN
208         final double xm     = 0;
209         final double ym     = 10000;
210         final double sigmaX = 1000;
211         final double sigmaY = 10000;
212         final double radius = 10;
213 
214         // WHEN
215         final ProbabilityOfCollision result = method.compute(xm, ym, sigmaX, sigmaY, radius);
216 
217         // THEN
218         Assertions.assertEquals(3.033e-6, result.getValue(), 1e-9);
219     }
220 
221     @Test
222     @DisplayName("Chan test case 10")
223     void ChanTestCase10() {
224         // GIVEN
225         final double xm     = 10000;
226         final double ym     = 0;
227         final double sigmaX = 1000;
228         final double sigmaY = 10000;
229         final double radius = 10;
230 
231         // WHEN
232         final ProbabilityOfCollision result = method.compute(xm, ym, sigmaX, sigmaY, radius);
233 
234         // THEN
235         Assertions.assertEquals(9.656e-28, result.getValue(), 1e-31);
236     }
237 
238     @Test
239     @DisplayName("Chan test case 11")
240     void ChanTestCase11() {
241         // GIVEN
242         final double xm     = 0;
243         final double ym     = 5000;
244         final double sigmaX = 1000;
245         final double sigmaY = 3000;
246         final double radius = 50;
247 
248         // WHEN
249         final ProbabilityOfCollision result = method.compute(xm, ym, sigmaX, sigmaY, radius);
250 
251         // THEN
252         Assertions.assertEquals(1.039e-4, result.getValue(), 1e-7);
253     }
254 
255     @Test
256     @DisplayName("Chan test case 12")
257     void ChanTestCase12() {
258         // GIVEN
259         final double xm     = 5000;
260         final double ym     = 0;
261         final double sigmaX = 1000;
262         final double sigmaY = 3000;
263         final double radius = 50;
264 
265         // WHEN
266         final ProbabilityOfCollision result = method.compute(xm, ym, sigmaX, sigmaY, radius);
267 
268         // THEN
269         Assertions.assertEquals(1.564e-9, result.getValue(), 1e-12);
270     }
271 
272     @Test
273     @DisplayName("CSM test case 1")
274     void CsmTestCase1() {
275         // GIVEN
276         final double xm     = 84.875546;
277         final double ym     = 60.583685;
278         final double sigmaX = 57.918666;
279         final double sigmaY = 152.8814468;
280         final double radius = 10.3;
281 
282         // WHEN
283         final ProbabilityOfCollision result = method.compute(xm, ym, sigmaX, sigmaY, radius);
284 
285         // THEN
286         Assertions.assertEquals(1.9002e-3, result.getValue(), 1e-7);
287     }
288 
289     @Test
290     @DisplayName("CSM test case 2")
291     void CsmTestCase2() {
292         // GIVEN
293         final double xm     = -81.618369;
294         final double ym     = 115.055899;
295         final double sigmaX = 15.988242;
296         final double sigmaY = 5756.840725;
297         final double radius = 1.3;
298 
299         // WHEN
300         final ProbabilityOfCollision result = method.compute(xm, ym, sigmaX, sigmaY, radius);
301 
302         // THEN
303         Assertions.assertEquals(2.0553e-11, result.getValue(), 1e-15);
304     }
305 
306     @Test
307     @DisplayName("CSM test case 3")
308     void CsmTestCase3() {
309         // GIVEN
310         final double xm     = 102.177247;
311         final double ym     = 693.405893;
312         final double sigmaX = 94.230921;
313         final double sigmaY = 643.409272;
314         final double radius = 5.3;
315 
316         // WHEN
317         final ProbabilityOfCollision result = method.compute(xm, ym, sigmaX, sigmaY, radius);
318 
319         // THEN
320         Assertions.assertEquals(7.2003e-5, result.getValue(), 1e-9);
321     }
322 
323     @Test
324     @DisplayName("CDM test case 1")
325     void CdmTestCase1() {
326         // GIVEN
327         final double xm     = -752.672701;
328         final double ym     = 644.939441;
329         final double sigmaX = 445.859950;
330         final double sigmaY = 6095.858688;
331         final double radius = 3.5;
332 
333         // WHEN
334         final ProbabilityOfCollision result = method.compute(xm, ym, sigmaX, sigmaY, radius);
335 
336         // THEN
337         Assertions.assertEquals(5.3904e-7, result.getValue(), 1e-11);
338     }
339 
340     @Test
341     @DisplayName("CDM test case 2")
342     void CdmTestCase2() {
343         // GIVEN
344         final double xm     = -692.362272;
345         final double ym     = 4475.456261;
346         final double sigmaX = 193.454603;
347         final double sigmaY = 562.027293;
348         final double radius = 13.2;
349 
350         // WHEN
351         final ProbabilityOfCollision result = method.compute(xm, ym, sigmaX, sigmaY, radius);
352 
353         // THEN
354         Assertions.assertEquals(2.2795e-20, result.getValue(), 1e-24);
355     }
356 
357     @Test
358     @DisplayName("Alfano test case 3")
359     void AlfanoTestCase3() {
360         // GIVEN
361         final double xm     = -3.8872073;
362         final double ym     = 0.1591646;
363         final double sigmaX = 1.4101830;
364         final double sigmaY = 114.2585190;
365         final double radius = 15;
366 
367         // WHEN
368         final ProbabilityOfCollision result = method.compute(xm, ym, sigmaX, sigmaY, radius);
369 
370         // THEN
371         Assertions.assertEquals(1.0038e-1, result.getValue(), 1e-5);
372     }
373 
374     @Disabled("Alfano test case 5 (Patera2005 method) : This test is numerically unstable and is ignored as it doesn't " +
375             "use realistic values. More info about this case in Romain SERRA thesis : \"Romain Serra. Opérations de proximité en orbite :\n"
376             + " * évaluation du risque de collision et calcul de manoeuvres optimales pour l’évitement et le rendez-vous. Automatique /\n"
377             + " * Robotique. INSA de Toulouse, 2015. Français. NNT : 2015ISAT0035. tel-01261497\"")
378     @Test
379     @DisplayName("Alfano test case 5")
380     void AlfanoTestCase5() {
381         // GIVEN
382         final double xm     = -1.2217895;
383         final double ym     = 2.1230067;
384         final double sigmaX = 0.0373279;
385         final double sigmaY = 177.8109003;
386         final double radius = 10;
387 
388         // WHEN
389         final ProbabilityOfCollision result = method.compute(xm, ym, sigmaX, sigmaY, radius);
390 
391         // THEN
392         Assertions.assertEquals(4.4509e-2, result.getValue(), 1e-6);
393     }
394 
395     @Test
396     @DisplayName(
397             "Test Patera2005 special function on Roberto Armellin slightly modified case 210 in his data available here :" +
398                     " github.com/arma1978/conjunction. The goal is to have a case where combined radius = miss distance and"
399                     +
400                     " case 210 was already very close." +
401                     " We expect to find a probability very similar to what is GIVEN in his data")
402     void testReturnValueCloseToUnmodifiedCase210() throws IOException {
403         // GIVEN
404         final int                           rowIndex = 209;
405         final List<ArmellinDataRow>         rows     = ArmellinDataLoader.load();
406         final ShortTermEncounter2DPOCMethod patera   = new Patera2005();
407 
408         final Frame        frame = FramesFactory.getGCRF();
409         final AbsoluteDate date  = new AbsoluteDate();
410         final double       mu    = Constants.IERS2010_EARTH_MU;
411 
412         // We force the combined radius to be equal to the miss distance (divide by two and change km to m)
413         final double halfCombinedRadius = rows.get(rowIndex).getMissDistance() * 500;
414 
415         final Orbit primary = new CartesianOrbit(rows.get(rowIndex).getPrimaryPVCoordinates(),
416                 frame, date, mu);
417         final RealMatrix primaryCovarianceMatrix = rows.get(rowIndex).getPrimaryCovarianceMatrixInPrimaryRTN();
418         final StateCovariance primaryCovariance =
419                 new StateCovariance(primaryCovarianceMatrix, date, LOFType.QSW_INERTIAL);
420 
421         final Orbit secondary = new CartesianOrbit(
422                 rows.get(rowIndex).getSecondaryPVCoordinates(), frame, date, mu);
423         final RealMatrix secondaryCovarianceMatrix = rows.get(rowIndex)
424                 .getSecondaryCovarianceMatrixInSecondaryRTN();
425         final StateCovariance secondaryCovariance = new StateCovariance(secondaryCovarianceMatrix, date,
426                 LOFType.QSW_INERTIAL);
427 
428         // WHEN
429         final ProbabilityOfCollision pateraResult =
430                 patera.compute(primary, primaryCovariance, halfCombinedRadius, secondary, secondaryCovariance,
431                         halfCombinedRadius);
432 
433         // THEN
434         Assertions.assertEquals(0.0012768565223002992, pateraResult.getValue(), 1e-19);
435 
436     }
437 
438     @Test
439     @DisplayName(
440             "Test probability from a real CDM. It has been mentioned in https://forum.orekit.org/t/collision-package-in-development/2638/16"
441                     + " and define an expected probability of collision of 0.004450713 which is higher than the value found using"
442                     + " the methods provided in this ssa package because the CSpOC use the projection of a square containing the"
443                     + " collision disk instead of the collision disk directly. Hence an overestimation of the probability of"
444                     + " collision. This test serves as a non regression test")
445     void testComputeProbabilityFromACdm() {
446 
447         // GIVEN
448         final String     cdmPath = "/ccsds/cdm/ION_SCV8_vs_STARLINK_1233.txt";
449         final DataSource data    = new DataSource(cdmPath, () -> getClass().getResourceAsStream(cdmPath));
450         final Cdm        cdm     = new ParserBuilder().buildCdmParser().parseMessage(data);
451 
452         // Radii taken from comments in the conjunction data message
453         final double primaryRadius   = 5;
454         final double secondaryRadius = 5;
455 
456         final AbstractShortTermEncounter1DNumerical2DPOCMethod customMethod = new Patera2005();
457 
458         // WHEN
459         final ProbabilityOfCollision result = customMethod.compute(cdm, primaryRadius, secondaryRadius,
460                 new TrapezoidIntegrator(), 50, 1e-15);
461 
462         // THEN
463         Assertions.assertEquals(0.003496517644384083, result.getValue(), 1e-18);
464     }
465 
466     @Test
467     @DisplayName("Chan test case 01 Field version")
468     void ChanTestCase01Field() {
469         // GIVEN
470         final Binary64 xm     = new Binary64(0);
471         final Binary64 ym     = new Binary64(10);
472         final Binary64 sigmaX = new Binary64(25);
473         final Binary64 sigmaY = new Binary64(50);
474         final Binary64 radius = new Binary64(5);
475 
476         // WHEN
477         final FieldProbabilityOfCollision<Binary64> result = method.compute(xm, ym, sigmaX, sigmaY, radius);
478 
479         // THEN
480         Assertions.assertEquals(9.741e-3, result.getValue().getReal(), 1e-6);
481     }
482 
483     @Test
484     @DisplayName("Chan test case 02 Field version")
485     void ChanTestCase02Field() {
486         // GIVEN
487         final Binary64 xm     = new Binary64(10);
488         final Binary64 ym     = new Binary64(0);
489         final Binary64 sigmaX = new Binary64(25);
490         final Binary64 sigmaY = new Binary64(50);
491         final Binary64 radius = new Binary64(5);
492 
493         // WHEN
494         final FieldProbabilityOfCollision<Binary64> result = method.compute(xm, ym, sigmaX, sigmaY, radius);
495 
496         // THEN
497         Assertions.assertEquals(9.181e-3, result.getValue().getReal(), 1e-6);
498     }
499 
500     @Test
501     @DisplayName("Chan test case 03 Field version")
502     void ChanTestCase03Field() {
503         // GIVEN
504         final Binary64 xm     = new Binary64(0);
505         final Binary64 ym     = new Binary64(10);
506         final Binary64 sigmaX = new Binary64(25);
507         final Binary64 sigmaY = new Binary64(75);
508         final Binary64 radius = new Binary64(5);
509 
510         // WHEN
511         final FieldProbabilityOfCollision<Binary64> result = method.compute(xm, ym, sigmaX, sigmaY, radius);
512 
513         // THEN
514         Assertions.assertEquals(6.571e-3, result.getValue().getReal(), 1e-6);
515     }
516 
517     @Test
518     @DisplayName("Chan test case 04 Field version")
519     void ChanTestCase04Field() {
520         // GIVEN
521         final Binary64 xm     = new Binary64(10);
522         final Binary64 ym     = new Binary64(0);
523         final Binary64 sigmaX = new Binary64(25);
524         final Binary64 sigmaY = new Binary64(75);
525         final Binary64 radius = new Binary64(5);
526 
527         // WHEN
528         final FieldProbabilityOfCollision<Binary64> result = method.compute(xm, ym, sigmaX, sigmaY, radius);
529 
530         // THEN
531         Assertions.assertEquals(6.125e-3, result.getValue().getReal(), 1e-6);
532     }
533 
534     @Test
535     @DisplayName("Chan test case 05 Field version")
536     void ChanTestCase05Field() {
537         // GIVEN
538         final Binary64 xm     = new Binary64(0);
539         final Binary64 ym     = new Binary64(1000);
540         final Binary64 sigmaX = new Binary64(1000);
541         final Binary64 sigmaY = new Binary64(3000);
542         final Binary64 radius = new Binary64(10);
543 
544         // WHEN
545         final FieldProbabilityOfCollision<Binary64> result = method.compute(xm, ym, sigmaX, sigmaY, radius);
546 
547         // THEN
548         Assertions.assertEquals(1.577e-5, result.getValue().getReal(), 1e-8);
549     }
550 
551     @Test
552     @DisplayName("Chan test case 06 Field version")
553     void ChanTestCase06Field() {
554         // GIVEN
555         final Binary64 xm     = new Binary64(1000);
556         final Binary64 ym     = new Binary64(0);
557         final Binary64 sigmaX = new Binary64(1000);
558         final Binary64 sigmaY = new Binary64(3000);
559         final Binary64 radius = new Binary64(10);
560 
561         // WHEN
562         final FieldProbabilityOfCollision<Binary64> result = method.compute(xm, ym, sigmaX, sigmaY, radius);
563 
564         // THEN
565         Assertions.assertEquals(1.011e-5, result.getValue().getReal(), 1e-8);
566     }
567 
568     @Test
569     @DisplayName("Chan test case 07 Field version")
570     void ChanTestCase07Field() {
571         // GIVEN
572         final Binary64 xm     = new Binary64(0);
573         final Binary64 ym     = new Binary64(10000);
574         final Binary64 sigmaX = new Binary64(1000);
575         final Binary64 sigmaY = new Binary64(3000);
576         final Binary64 radius = new Binary64(10);
577 
578         // WHEN
579         final FieldProbabilityOfCollision<Binary64> result = method.compute(xm, ym, sigmaX, sigmaY, radius);
580 
581         // THEN
582         Assertions.assertEquals(6.443e-8, result.getValue().getReal(), 1e-11);
583     }
584 
585     @Test
586     @DisplayName("Chan test case 08 Field version")
587     void ChanTestCase08Field() {
588         // GIVEN
589         final Binary64 xm     = new Binary64(10000);
590         final Binary64 ym     = new Binary64(0);
591         final Binary64 sigmaX = new Binary64(1000);
592         final Binary64 sigmaY = new Binary64(3000);
593         final Binary64 radius = new Binary64(10);
594 
595         // WHEN
596         final FieldProbabilityOfCollision<Binary64> result = method.compute(xm, ym, sigmaX, sigmaY, radius);
597 
598         // THEN
599         Assertions.assertEquals(3.219e-27, result.getValue().getReal(), 1e-30);
600     }
601 
602     @Test
603     @DisplayName("Chan test case 09 Field version")
604     void ChanTestCase09Field() {
605         // GIVEN
606         final Binary64 xm     = new Binary64(0);
607         final Binary64 ym     = new Binary64(10000);
608         final Binary64 sigmaX = new Binary64(1000);
609         final Binary64 sigmaY = new Binary64(10000);
610         final Binary64 radius = new Binary64(10);
611 
612         // WHEN
613         final FieldProbabilityOfCollision<Binary64> result = method.compute(xm, ym, sigmaX, sigmaY, radius);
614 
615         // THEN
616         Assertions.assertEquals(3.033e-6, result.getValue().getReal(), 1e-9);
617     }
618 
619     @Test
620     @DisplayName("Chan test case 10 Field version")
621     void ChanTestCase10Field() {
622         // GIVEN
623         final Binary64 xm     = new Binary64(10000);
624         final Binary64 ym     = new Binary64(0);
625         final Binary64 sigmaX = new Binary64(1000);
626         final Binary64 sigmaY = new Binary64(10000);
627         final Binary64 radius = new Binary64(10);
628 
629         // WHEN
630         final FieldProbabilityOfCollision<Binary64> result = method.compute(xm, ym, sigmaX, sigmaY, radius);
631 
632         // THEN
633         Assertions.assertEquals(9.656e-28, result.getValue().getReal(), 1e-31);
634     }
635 
636     @Test
637     @DisplayName("Chan test case 11 Field version")
638     void ChanTestCase11Field() {
639         // GIVEN
640         final Binary64 xm     = new Binary64(0);
641         final Binary64 ym     = new Binary64(5000);
642         final Binary64 sigmaX = new Binary64(1000);
643         final Binary64 sigmaY = new Binary64(3000);
644         final Binary64 radius = new Binary64(50);
645 
646         // WHEN
647         final FieldProbabilityOfCollision<Binary64> result = method.compute(xm, ym, sigmaX, sigmaY, radius);
648 
649         // THEN
650         Assertions.assertEquals(1.039e-4, result.getValue().getReal(), 1e-7);
651     }
652 
653     @Test
654     @DisplayName("Chan test case 12 Field version")
655     void ChanTestCase12Field() {
656         // GIVEN
657         final Binary64 xm     = new Binary64(5000);
658         final Binary64 ym     = new Binary64(0);
659         final Binary64 sigmaX = new Binary64(1000);
660         final Binary64 sigmaY = new Binary64(3000);
661         final Binary64 radius = new Binary64(50);
662 
663         // WHEN
664         final FieldProbabilityOfCollision<Binary64> result = method.compute(xm, ym, sigmaX, sigmaY, radius);
665 
666         // THEN
667         Assertions.assertEquals(1.564e-9, result.getValue().getReal(), 1e-12);
668     }
669 
670     @Test
671     @DisplayName("CSM test case 1 Field version")
672     void CsmTestCase1Field() {
673         // GIVEN
674         final Binary64 xm     = new Binary64(84.875546);
675         final Binary64 ym     = new Binary64(60.583685);
676         final Binary64 sigmaX = new Binary64(57.918666);
677         final Binary64 sigmaY = new Binary64(152.8814468);
678         final Binary64 radius = new Binary64(10.3);
679 
680         // WHEN
681         final FieldProbabilityOfCollision<Binary64> result = method.compute(xm, ym, sigmaX, sigmaY, radius);
682 
683         // THEN
684         Assertions.assertEquals(1.9002e-3, result.getValue().getReal(), 1e-7);
685     }
686 
687     @Test
688     @DisplayName("CSM test case 2 Field version")
689     void CsmTestCase2Field() {
690         // GIVEN
691         final Binary64 xm     = new Binary64(-81.618369);
692         final Binary64 ym     = new Binary64(115.055899);
693         final Binary64 sigmaX = new Binary64(15.988242);
694         final Binary64 sigmaY = new Binary64(5756.840725);
695         final Binary64 radius = new Binary64(1.3);
696 
697         // WHEN
698         final FieldProbabilityOfCollision<Binary64> result = method.compute(xm, ym, sigmaX, sigmaY, radius);
699 
700         // THEN
701         Assertions.assertEquals(2.0553e-11, result.getValue().getReal(), 1e-15);
702     }
703 
704     @Test
705     @DisplayName("CSM test case 3 Field version")
706     void CsmTestCase3Field() {
707         // GIVEN
708         final Binary64 xm     = new Binary64(102.177247);
709         final Binary64 ym     = new Binary64(693.405893);
710         final Binary64 sigmaX = new Binary64(94.230921);
711         final Binary64 sigmaY = new Binary64(643.409272);
712         final Binary64 radius = new Binary64(5.3);
713 
714         // WHEN
715         final FieldProbabilityOfCollision<Binary64> result = method.compute(xm, ym, sigmaX, sigmaY, radius);
716 
717         // THEN
718         Assertions.assertEquals(7.2003e-5, result.getValue().getReal(), 1e-9);
719     }
720 
721     @Test
722     @DisplayName("CDM test case 1 Field version")
723     void CdmTestCase1Field() {
724         // GIVEN
725         final Binary64 xm     = new Binary64(-752.672701);
726         final Binary64 ym     = new Binary64(644.939441);
727         final Binary64 sigmaX = new Binary64(445.859950);
728         final Binary64 sigmaY = new Binary64(6095.858688);
729         final Binary64 radius = new Binary64(3.5);
730 
731         // WHEN
732         final FieldProbabilityOfCollision<Binary64> result = method.compute(xm, ym, sigmaX, sigmaY, radius);
733 
734         // THEN
735         Assertions.assertEquals(5.3904e-7, result.getValue().getReal(), 1e-11);
736     }
737 
738     @Test
739     @DisplayName("CDM test case 2 Field version")
740     void CdmTestCase2Field() {
741         // GIVEN
742         final Binary64 xm     = new Binary64(-692.362272);
743         final Binary64 ym     = new Binary64(4475.456261);
744         final Binary64 sigmaX = new Binary64(193.454603);
745         final Binary64 sigmaY = new Binary64(562.027293);
746         final Binary64 radius = new Binary64(13.2);
747 
748         // WHEN
749         final FieldProbabilityOfCollision<Binary64> result = method.compute(xm, ym, sigmaX, sigmaY, radius);
750 
751         // THEN
752         Assertions.assertEquals(2.2795e-20, result.getValue().getReal(), 1e-24);
753     }
754 
755     @Test
756     @DisplayName("Alfano test case 3 Field version")
757     void AlfanoTestCase3Field() {
758         // GIVEN
759         final Binary64 xm     = new Binary64(-3.8872073);
760         final Binary64 ym     = new Binary64(0.1591646);
761         final Binary64 sigmaX = new Binary64(1.4101830);
762         final Binary64 sigmaY = new Binary64(114.2585190);
763         final Binary64 radius = new Binary64(15);
764 
765         // WHEN
766         final FieldProbabilityOfCollision<Binary64> result = method.compute(xm, ym, sigmaX, sigmaY, radius);
767 
768         // THEN
769         Assertions.assertEquals(1.0038e-1, result.getValue().getReal(), 1e-5);
770     }
771 
772     @Disabled(
773             "Alfano test case 5 (field version) (Patera2005 method) : This test is numerically unstable and is ignored as it doesn't "
774                     +
775                     "use realistic values. More info about this case in Romain SERRA thesis : \"Romain Serra. Opérations de proximité en orbite :\n"
776                     + " * évaluation du risque de collision et calcul de manoeuvres optimales pour l’évitement et le rendez-vous. Automatique /\n"
777                     + " * Robotique. INSA de Toulouse, 2015. Français. NNT : 2015ISAT0035. tel-01261497\"")
778     @Test
779     @DisplayName("Alfano test case 5 Field version")
780     void AlfanoTestCase5Field() {
781         // GIVEN
782         final Binary64 xm     = new Binary64(-1.2217895);
783         final Binary64 ym     = new Binary64(2.1230067);
784         final Binary64 sigmaX = new Binary64(0.0373279);
785         final Binary64 sigmaY = new Binary64(177.8109003);
786         final Binary64 radius = new Binary64(10);
787 
788         // WHEN
789         final FieldProbabilityOfCollision<Binary64> result = method.compute(xm, ym, sigmaX, sigmaY, radius);
790 
791         // THEN
792         Assertions.assertEquals(4.4509e-2, result.getValue().getReal(), 1e-6);
793     }
794 
795     @Test
796     @DisplayName("Test impact on the probability of collision of a slight difference in combined radius in Chan test case 4")
797     void testReturnExpectedValueWhenIntroducingSmallChangeOnCombinedRadius() {
798         // GIVEN
799         final DSFactory factory = new DSFactory(1, 10);
800 
801         final double xmNominal     = 10;
802         final double ymNominal     = 0;
803         final double sigmaXNominal = 25;
804         final double sigmaYNominal = 75;
805         final double radiusNominal = 5;
806         final double dRadius       = 2.5;
807 
808         final DerivativeStructure xm     = factory.constant(xmNominal);
809         final DerivativeStructure ym     = factory.constant(ymNominal);
810         final DerivativeStructure sigmaX = factory.constant(sigmaXNominal);
811         final DerivativeStructure sigmaY = factory.constant(sigmaYNominal);
812         final DerivativeStructure radius = factory.variable(0, radiusNominal);
813 
814         // WHEN
815         final FieldProbabilityOfCollision<DerivativeStructure> resultNominal =
816                 method.compute(xm, ym, sigmaX, sigmaY, radius);
817         final double taylorResult = resultNominal.getValue().taylor(dRadius);
818         final double exactResult =
819                 method.compute(xmNominal, ymNominal, sigmaXNominal, sigmaYNominal, radiusNominal + dRadius).getValue();
820 
821         // THEN
822         Assertions.assertEquals(6.1e-3, resultNominal.getValue().getReal(), 1e-4);
823         Assertions.assertEquals(exactResult, taylorResult, 1e-16);
824     }
825 
826     @Test
827     @DisplayName(
828             "Test Patera2005 special function on Roberto Armellin slightly modified case 210 in his data available here :" +
829                     " github.com/arma1978/conjunction. The goal is to have a case where combined radius = miss distance and"
830                     +
831                     " case 210 was already very close." +
832                     " We expect to find a probability very similar to what is GIVEN in his data")
833     void testReturnValueCloseToUnmodifiedCase210Field() throws IOException {
834         // GIVEN
835         final int                           rowIndex = 209;
836         final List<ArmellinDataRow>         rows     = ArmellinDataLoader.load();
837         final ShortTermEncounter2DPOCMethod patera   = new Patera2005();
838 
839         final Field<Binary64>             field = Binary64Field.getInstance();
840         final Frame                       frame = FramesFactory.getGCRF();
841         final FieldAbsoluteDate<Binary64> date  = new FieldAbsoluteDate<>(field);
842         final Binary64                    mu    = new Binary64(Constants.IERS2010_EARTH_MU);
843 
844         // We force the combined radius to be equal to the miss distance (divide by two and change km to m)
845         final Binary64 halfCombinedRadius = new Binary64(rows.get(rowIndex).getMissDistance() * 500);
846 
847         // Primary
848         final FieldOrbit<Binary64> primary =
849                 new FieldCartesianOrbit<>(new FieldPVCoordinates<>(field, rows.get(rowIndex).getPrimaryPVCoordinates()),
850                         frame, date, mu);
851         final FieldMatrix<Binary64> primaryCovarianceMatrix =
852                 rows.get(rowIndex).getPrimaryFieldCovarianceMatrixInPrimaryRTN();
853         final FieldStateCovariance<Binary64> primaryCovariance =
854                 new FieldStateCovariance<>(primaryCovarianceMatrix, date, LOFType.QSW_INERTIAL);
855 
856         // Secondary
857         final FieldOrbit<Binary64> secondary = new FieldCartesianOrbit<>(
858                 new FieldPVCoordinates<>(field, rows.get(rowIndex).getSecondaryPVCoordinates()), frame, date, mu);
859         final FieldMatrix<Binary64> secondaryCovarianceMatrix =
860                 rows.get(rowIndex).getSecondaryFieldCovarianceMatrixInPrimaryRTN();
861         final FieldStateCovariance<Binary64> secondaryCovariance =
862                 new FieldStateCovariance<>(secondaryCovarianceMatrix, date, LOFType.QSW_INERTIAL);
863 
864         // WHEN
865         final FieldProbabilityOfCollision<Binary64> pateraResult =
866                 patera.compute(primary, primaryCovariance, halfCombinedRadius, secondary, secondaryCovariance,
867                         halfCombinedRadius);
868 
869         // THEN
870         Assertions.assertEquals(0.0012768565222964375, pateraResult.getValue().getReal(), 1e-19);
871 
872     }
873 
874     @Test
875     @DisplayName("Test probability from a custom CDM. Initial frame is in ITRF so it has been " +
876             "modified to GCRF. Hence we do not expect to find the same probability of collision as the one in the CDM." +
877             "This is a non regression test." +
878             "There is a negligible difference with the non field version because the combined covariance matrix is not " +
879             "diagonalized using the same method")
880     void testComputeProbabilityFromACdmField() {
881 
882         // GIVEN
883         final String     cdmPath = "/ccsds/cdm/ION_SCV8_vs_STARLINK_1233.txt";
884         final DataSource data    = new DataSource(cdmPath, () -> getClass().getResourceAsStream(cdmPath));
885         final Cdm        cdm     = new ParserBuilder().buildCdmParser().parseMessage(data);
886 
887         final Field<Binary64> field = Binary64Field.getInstance();
888 
889         // Radii taken from comments in the conjunction data message
890         final Binary64 primaryRadius   = new Binary64(5);
891         final Binary64 secondaryRadius = new Binary64(5);
892 
893         final AbstractShortTermEncounter1DNumerical2DPOCMethod customMethod = new Patera2005();
894 
895         // WHEN
896         final FieldProbabilityOfCollision<Binary64> result = customMethod.compute(cdm, primaryRadius, secondaryRadius,
897                 new FieldTrapezoidIntegrator<>(field),
898                 55,
899                 1e-15);
900 
901         // THEN
902         Assertions.assertEquals(0.0034965176443840836, result.getValue().getReal(), 1e-19);
903     }
904 
905 
906     @Test
907     @DisplayName("Alfano test case 1 (CDM) from NASA CARA")
908     void AlfanoCDMTestCase01() {
909         // Inputs from NASA CARA
910         String cdmName = "AlfanoTestCase01.cdm";
911         final double combinedHbr = 15.;
912 
913         // Excepted outcome
914         final double expectedPc = 0.146749549;
915         final double tolerance = 1e-6;
916 
917         computeAndCheckCollisionProbability(cdmName, combinedHbr, expectedPc, tolerance);
918     }
919 
920     @Test
921     @DisplayName("Alfano test case 2 (CDM) from NASA CARA")
922     void AlfanoCDMTestCase02() {
923         // Inputs from NASA CARA
924         String cdmName = "AlfanoTestCase02.cdm";
925         final double combinedHbr = 4.;
926 
927         // Excepted outcome
928         final double expectedPc = 0.006222267;
929         final double tolerance = 1e-6;
930 
931         computeAndCheckCollisionProbability(cdmName, combinedHbr, expectedPc, tolerance);
932     }
933 
934     @Test
935     @DisplayName("Alfano test case 3 (CDM) from NASA CARA")
936     void AlfanoCDMTestCase03() {
937         // Inputs from NASA CARA
938         String cdmName = "AlfanoTestCase03.cdm";
939         final double combinedHbr = 15.;
940 
941         // Excepted outcome
942         final double expectedPc = 0.100351176;
943         final double tolerance = 1e-6;
944 
945         computeAndCheckCollisionProbability(cdmName, combinedHbr, expectedPc, tolerance);
946     }
947 
948     @Test
949     @DisplayName("Alfano test case 4 (CDM) from NASA CARA")
950     void AlfanoCDMTestCase04() {
951         // Inputs from NASA CARA
952         String cdmName = "AlfanoTestCase04.cdm";
953         final double combinedHbr = 15.;
954 
955         // Excepted outcome
956         final double expectedPc = 0.049323406;
957         final double tolerance = 1e-5;
958 
959         computeAndCheckCollisionProbability(cdmName, combinedHbr, expectedPc, tolerance);
960     }
961 
962     @Test
963     @DisplayName("Alfano test case 5 (CDM) from NASA CARA")
964     void AlfanoCDMTestCase05() {
965         // Inputs from NASA CARA
966         String cdmName = "AlfanoTestCase05.cdm";
967         final double combinedHbr = 10.;
968 
969         // Excepted outcome
970         final double expectedPc = 0.044487386;
971         final double tolerance = 1e-5;
972 
973         computeAndCheckCollisionProbability(cdmName, combinedHbr, expectedPc, tolerance);
974     }
975 
976     @Test
977     @DisplayName("Alfano test case 6 (CDM) from NASA CARA")
978     void AlfanoCDMTestCase06() {
979         // Inputs from NASA CARA
980         String cdmName = "AlfanoTestCase06.cdm";
981         final double combinedHbr = 10.;
982 
983         // Excepted outcome
984         final double expectedPc = 0.004335455;
985         final double tolerance = 1e-8;
986 
987         computeAndCheckCollisionProbability(cdmName, combinedHbr, expectedPc, tolerance);
988     }
989 
990     @Test
991     @DisplayName("Alfano test case 7 (CDM) from NASA CARA")
992     void AlfanoCDMTestCase07() {
993         // Inputs from NASA CARA
994         String cdmName = "AlfanoTestCase07.cdm";
995         final double combinedHbr = 10.;
996 
997         // Excepted outcome
998         final double expectedPc = 0.000158147;
999         final double tolerance = 1e-9;
1000 
1001         computeAndCheckCollisionProbability(cdmName, combinedHbr, expectedPc, tolerance);
1002     }
1003 
1004     @Test
1005     @DisplayName("Alfano test case 8 (CDM) from NASA CARA")
1006     void AlfanoCDMTestCase08() {
1007         // Inputs from NASA CARA
1008         String cdmName = "AlfanoTestCase08.cdm";
1009         final double combinedHbr = 4.;
1010 
1011         // Excepted outcome
1012         final double expectedPc = 0.036948008;
1013         final double tolerance = 1e-5;
1014 
1015         computeAndCheckCollisionProbability(cdmName, combinedHbr, expectedPc, tolerance);
1016     }
1017 
1018     @Test
1019     @DisplayName("Alfano test case 9 (CDM) from NASA CARA")
1020     void AlfanoCDMTestCase09() {
1021         // Inputs from NASA CARA
1022         String cdmName = "AlfanoTestCase09.cdm";
1023         final double combinedHbr = 6.;
1024 
1025         // Excepted outcome
1026         final double expectedPc = 0.290146291;
1027         final double tolerance = 2e-5;
1028 
1029         computeAndCheckCollisionProbability(cdmName, combinedHbr, expectedPc, tolerance);
1030     }
1031 
1032     // Alfano test case 10 is a duplicate of test 9 in the NASA CARA unit tests.
1033 
1034     @Test
1035     @DisplayName("Alfano test case 11 (CDM) from NASA CARA")
1036     void AlfanoCDMTestCase11() {
1037         // Inputs from NASA CARA
1038         String cdmName = "AlfanoTestCase11.cdm";
1039         final double combinedHbr = 4.;
1040 
1041         // Excepted outcome
1042         final double expectedPc = 0.002672026;
1043         final double tolerance = 1e-7;
1044 
1045         computeAndCheckCollisionProbability(cdmName, combinedHbr, expectedPc, tolerance);
1046     }
1047 
1048     private void computeAndCheckCollisionProbability(
1049             final String cdmName,
1050             final double combinedHbr,
1051             final double expected,
1052             final double tolerance) {
1053 
1054         // Given
1055         final String     cdmPath = "/ccsds/cdm/" + cdmName;
1056         final DataSource data    = new DataSource(cdmPath, () -> getClass().getResourceAsStream(cdmPath));
1057         final Cdm        cdm     = new ParserBuilder().buildCdmParser().parseMessage(data);
1058 
1059         // When
1060         final ProbabilityOfCollision result = method.compute(cdm, combinedHbr);
1061 
1062         // Then
1063         Assertions.assertEquals(expected, result.getValue(), tolerance);
1064     }
1065 }