1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 package org.orekit.ssa.collision.shorttermencounter.probability.twod;
42
43 import org.hipparchus.CalculusFieldElement;
44 import org.hipparchus.Field;
45 import org.hipparchus.linear.FieldVector;
46 import org.hipparchus.linear.MatrixUtils;
47 import org.hipparchus.stat.StatUtils;
48 import org.hipparchus.util.FastMath;
49 import org.hipparchus.util.MathArrays;
50 import org.hipparchus.util.MathUtils;
51 import org.orekit.ssa.metrics.FieldProbabilityOfCollision;
52 import org.orekit.ssa.metrics.ProbabilityOfCollision;
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83 public class Laas2015 extends AbstractShortTermEncounter2DPOCMethod {
84
85
86 public static final double DEFAULT_SCALING_THRESHOLD = 1e10;
87
88
89
90
91
92 private final double absoluteAccuracy;
93
94
95 private final int maxNumberOfTerms;
96
97
98
99
100
101
102
103
104
105
106 public Laas2015() {
107 this(1.E-30, 37000);
108 }
109
110
111
112
113
114 public Laas2015(final double absoluteAccuracy, final int maxNumberOfTerms) {
115 super(ShortTermEncounter2DPOCMethodType.LAAS_2015.name());
116 this.absoluteAccuracy = absoluteAccuracy;
117 this.maxNumberOfTerms = maxNumberOfTerms;
118 }
119
120
121 public final ProbabilityOfCollision compute(final double xm, final double ym,
122 final double sigmaX,
123 final double sigmaY,
124 final double radius) {
125
126
127
128 final double xmSquared = xm * xm;
129 final double ymSquared = ym * ym;
130 final double sigmaXSq = sigmaX * sigmaX;
131 final double sigmaYSq = sigmaY * sigmaY;
132 final double radiusSquared = radius * radius;
133
134 final double p = 1. / (2. * (sigmaX * sigmaX));
135 final double phiY = 1. - (sigmaX / sigmaY * sigmaX / sigmaY);
136 final double omegaX = (xm / (2. * sigmaXSq)) * (xm / (2. * sigmaXSq));
137 final double omegaY = (ym / (2. * sigmaYSq)) * (ym / (2. * sigmaYSq));
138 final double bigOmega = phiY * 0.5 + (omegaX + omegaY) / p;
139
140 final double alpha0 = 0.5 * FastMath.exp(-(xmSquared / sigmaXSq + ymSquared / sigmaYSq) * 0.5) / sigmaX / sigmaY;
141
142
143 final double l0 = alpha0 * (1. - FastMath.exp(-p * radiusSquared)) / p;
144
145
146 final double u0Temp = alpha0 * (FastMath.exp(p * bigOmega * radiusSquared) -
147 FastMath.exp(-p * radiusSquared)) / (p * (1. + bigOmega));
148 final double u0 = u0Temp > 1 ? 1 : u0Temp;
149
150
151 if (u0 - l0 <= absoluteAccuracy) {
152 return new ProbabilityOfCollision(StatUtils.mean(u0, l0), u0, l0, getName(),
153 isAMaximumProbabilityOfCollisionMethod());
154 }
155
156 else {
157 final int n1 = (int) (2. * FastMath.ceil(FastMath.E * p * radiusSquared * (1. + bigOmega)));
158 final double n2_inter =
159 alpha0 * FastMath.exp(p * radiusSquared * bigOmega) /
160 (absoluteAccuracy * p * FastMath.sqrt(MathUtils.TWO_PI * n1) *
161 (1. + bigOmega));
162 final int n2 = (int) FastMath.ceil(FastMath.log(2, n2_inter));
163
164
165 int nMax = FastMath.max(n1, n2) - 1;
166 nMax = FastMath.min(nMax, maxNumberOfTerms);
167
168
169 final double pSquared = p * p;
170 final double pCubed = pSquared * p;
171 final double pTimesRadiusSquared = p * radiusSquared;
172 final double radiusFourth = radiusSquared * radiusSquared;
173 final double radiusSixth = radiusFourth * radiusSquared;
174 final double phiYSquared = phiY * phiY;
175 final double pPhiY = p * phiY;
176 final double omegaSum = omegaX + omegaY;
177 final double pSqTimesHalfPhiYSqPlusOne = pSquared * MathArrays.linearCombination(0.5, phiYSquared, 1., 1.);
178
179 final double recurrentTerm0 = MathArrays.linearCombination(0.5, phiY, 1., 1.);
180 final double recurrentTerm1 = MathArrays.linearCombination(p, recurrentTerm0, 1., omegaSum);
181 final double recurrentTerm2 = MathArrays.linearCombination(1., pSqTimesHalfPhiYSqPlusOne, 2., pPhiY * omegaY);
182 final double recurrentTerm3 = recurrentTerm1 * recurrentTerm1;
183
184 final double auxiliaryTerm0 = radiusSixth * pCubed * phiYSquared * omegaX;
185 final double auxiliaryTerm1 = radiusFourth * pSquared * phiY;
186 final double auxiliaryTerm2 = 2. * omegaX * recurrentTerm0;
187
188 final double auxiliaryTerm3 = phiY * MathArrays.linearCombination(2., omegaX, 1.5, p) + omegaSum;
189 final double auxiliaryTerm4 = pPhiY * recurrentTerm0 * 2.;
190 final double auxiliaryTerm5 = p * (2. * phiY + 1.);
191
192 double kPlus2 = 2.;
193 double kPlus3 = 3.;
194 double kPlus4 = 4.;
195 double kPlus5 = 5.;
196 double halfY = 2.5;
197
198
199 double c0 = alpha0 * radiusSquared;
200 double c1 = c0 * radiusSquared * 0.5 * recurrentTerm1;
201 double c2 = c0 * (radiusFourth / 12.) * (recurrentTerm3 + recurrentTerm2);
202 double c3 = c0 * (radiusSixth / 144.) * (recurrentTerm1 * (recurrentTerm3 + 3. * recurrentTerm2) +
203 2. * (pCubed * (1. + phiYSquared * phiY * 0.5) + 3. * pSquared * phiYSquared * omegaY));
204 final double[] initialCoefficients = new double[] { c0, c1, c2, c3 };
205
206 double sum = 0.;
207 double rescalingCounter = 0.;
208 for (int i = 0; i < FastMath.min(nMax, 4); i++) {
209 sum += initialCoefficients[i];
210
211
212 if (sum > DEFAULT_SCALING_THRESHOLD) {
213 rescalingCounter += FastMath.log10(DEFAULT_SCALING_THRESHOLD);
214 c0 /= DEFAULT_SCALING_THRESHOLD;
215 c1 /= DEFAULT_SCALING_THRESHOLD;
216 c2 /= DEFAULT_SCALING_THRESHOLD;
217 c3 /= DEFAULT_SCALING_THRESHOLD;
218 sum /= DEFAULT_SCALING_THRESHOLD;
219 }
220
221 }
222
223
224 double temp;
225 for (int k = 0; k < nMax - 4; k++) {
226
227
228 if (sum > DEFAULT_SCALING_THRESHOLD) {
229 rescalingCounter += FastMath.log10(DEFAULT_SCALING_THRESHOLD);
230 c0 /= DEFAULT_SCALING_THRESHOLD;
231 c1 /= DEFAULT_SCALING_THRESHOLD;
232 c2 /= DEFAULT_SCALING_THRESHOLD;
233 c3 /= DEFAULT_SCALING_THRESHOLD;
234 sum /= DEFAULT_SCALING_THRESHOLD;
235 }
236
237
238 final double denominator = kPlus4 * kPlus3;
239
240 temp = c3 * MathArrays.linearCombination(1, recurrentTerm1, kPlus3, auxiliaryTerm5);
241 temp -= c2 * pTimesRadiusSquared * MathArrays.linearCombination(halfY, auxiliaryTerm4, 1, auxiliaryTerm3) /
242 kPlus4;
243 temp += c1 * auxiliaryTerm1 * MathArrays.linearCombination(halfY, pPhiY, 1., auxiliaryTerm2) / denominator;
244 temp -= c0 * auxiliaryTerm0 / (denominator * kPlus2);
245 temp *= radiusSquared / (kPlus4 * kPlus5);
246
247 c0 = c1;
248 c1 = c2;
249 c2 = c3;
250 c3 = temp;
251
252
253 kPlus2 = kPlus3;
254 kPlus3 = kPlus4;
255 kPlus4 = kPlus5;
256 kPlus5 = kPlus5 + 1.;
257 halfY += 1.;
258
259
260 sum += c3;
261
262 }
263
264 final double value = sum *
265 FastMath.exp(MathArrays.linearCombination(FastMath.log(10.), rescalingCounter, -p, radiusSquared));
266
267 return new ProbabilityOfCollision(value, l0, u0, getName(), isAMaximumProbabilityOfCollisionMethod());
268 }
269 }
270
271
272 public final <T extends CalculusFieldElement<T>> FieldProbabilityOfCollision<T> compute(final T xm, final T ym,
273 final T sigmaX,
274 final T sigmaY,
275 final T radius) {
276
277
278
279 final Field<T> field = xm.getField();
280 final T zero = field.getZero();
281 final T one = field.getOne();
282
283 final T xmSquared = xm.square();
284 final T ymSquared = ym.square();
285 final T sigmaXSquared = sigmaX.square();
286 final T sigmaYSquared = sigmaY.square();
287 final T twoSigmaXY = sigmaX.multiply(sigmaY).multiply(2);
288 final T radiusSquared = radius.square();
289 final T radiusFourth = radiusSquared.square();
290 final T radiusSixth = radiusFourth.multiply(radiusSquared);
291
292 final T p = sigmaX.square().reciprocal().multiply(0.5);
293 final T pTimesRadiusSquared = p.multiply(radiusSquared);
294 final T phiY = sigmaXSquared.divide(sigmaYSquared).negate().add(1.);
295 final T omegaX = xm.divide(sigmaXSquared.multiply(2.)).pow(2.);
296 final T omegaY = ym.divide(sigmaYSquared.multiply(2.)).pow(2.);
297 final T omegaSum = omegaX.add(omegaY);
298 final T bigOmega = phiY.multiply(0.5).add(omegaX.add(omegaY).divide(p));
299
300 final T minusP = p.negate();
301 final T pSquared = p.square();
302 final T pCubed = p.multiply(pSquared);
303 final T pPhiY = p.multiply(phiY);
304 final T phiYSquared = phiY.square();
305 final T pRadiusSquaredBigOmega = p.multiply(radiusSquared).multiply(bigOmega);
306 final T bigOmegaPlusOne = bigOmega.add(1.);
307 final T pSqTimesHalfPhiYSqPlusOne = pSquared.multiply(phiYSquared.multiply(0.5).add(1.));
308
309 final T alpha0 = xmSquared.divide(sigmaXSquared).add(ymSquared.divide(sigmaYSquared)).multiply(-0.5).exp()
310 .divide(twoSigmaXY);
311
312
313 final T l0 = alpha0.multiply(radiusSquared.multiply(minusP).exp().negate().add(1.)).divide(p);
314
315
316 final T u0Temp = alpha0.multiply(pRadiusSquaredBigOmega.exp().subtract(radiusSquared.multiply(minusP).exp()))
317 .divide(p.multiply(bigOmegaPlusOne));
318 final T u0 = u0Temp.getReal() > 1 ? one : u0Temp;
319
320
321 if (u0.getReal() - l0.getReal() <= absoluteAccuracy) {
322 return new FieldProbabilityOfCollision<>(u0.add(l0).multiply(0.5), u0, l0, getName(),
323 isAMaximumProbabilityOfCollisionMethod());
324 }
325
326 else {
327 final int n1 = (int) (2. *
328 FastMath.ceil(FastMath.E * p.multiply(radiusSquared).multiply(bigOmegaPlusOne).getReal()));
329 final double n2_inter =
330 alpha0.getReal() * FastMath.exp(pRadiusSquaredBigOmega.getReal()) /
331 (absoluteAccuracy * p.getReal() * FastMath.sqrt(MathUtils.TWO_PI * n1) *
332 (1. + bigOmega.getReal()));
333 final int n2 = (int) FastMath.ceil(FastMath.log(2., n2_inter));
334
335
336 int nMax = FastMath.max(n1, n2) - 1;
337 nMax = FastMath.min(nMax, maxNumberOfTerms);
338
339
340 final T recurrentTerm0 = phiY.multiply(0.5).add(1);
341 final T recurrentTerm1 = p.multiply(recurrentTerm0).add(omegaSum);
342 final T recurrentTerm2 = pSqTimesHalfPhiYSqPlusOne.add(pPhiY.multiply(omegaY).multiply(2.));
343 final T recurrentTerm3 = recurrentTerm1.multiply(recurrentTerm1);
344
345 final T auxiliaryTerm0 = radiusSixth.multiply(pCubed).multiply(phiYSquared).multiply(omegaX);
346 final T auxiliaryTerm1 = radiusFourth.multiply(pSquared).multiply(phiY);
347 final T auxiliaryTerm2 = omegaX.multiply(recurrentTerm0).multiply(2.);
348 final T auxiliaryTerm3 = phiY.multiply(omegaX.multiply(2.).add(p.multiply(1.5))).add(omegaSum);
349 final T auxiliaryTerm4 = pPhiY.multiply(recurrentTerm0).multiply(2.);
350 final T auxiliaryTerm5 = p.multiply(phiY.multiply(2.).add(1.));
351
352 T kPlus2 = one.newInstance(2.);
353 T kPlus3 = one.newInstance(3.);
354 T kPlus4 = one.newInstance(4.);
355 T kPlus5 = one.newInstance(5.);
356 T halfY = one.newInstance(2.5);
357
358
359 T c0 = alpha0.multiply(radiusSquared);
360 T c1 = c0.multiply(radiusSquared).multiply(0.5).multiply(recurrentTerm1);
361 T c2 = c0.multiply(radiusFourth.divide(12.)).multiply(recurrentTerm3.add(recurrentTerm2));
362 T c3 = c0.multiply(radiusSixth.divide(144.)).multiply(
363 recurrentTerm1.multiply(recurrentTerm2.multiply(3.).add(recurrentTerm3))
364 .add(pCubed.multiply(2.).multiply(phiYSquared.multiply(phiY).multiply(0.5).add(1.)))
365 .add(pSquared.multiply(phiYSquared).multiply(omegaY).multiply(6.)));
366 final FieldVector<T> initialCoefficients = MatrixUtils.createFieldVector(field, 4);
367 initialCoefficients.setEntry(0, c0);
368 initialCoefficients.setEntry(1, c1);
369 initialCoefficients.setEntry(2, c2);
370 initialCoefficients.setEntry(3, c3);
371
372 T sum = zero;
373 T rescalingCounter = zero;
374 for (int i = 0; i < FastMath.min(nMax, 4); i++) {
375 sum = sum.add(initialCoefficients.getEntry(i));
376
377
378 if (sum.getReal() > DEFAULT_SCALING_THRESHOLD) {
379 rescalingCounter = rescalingCounter.add(FastMath.log10(DEFAULT_SCALING_THRESHOLD));
380 c0 = c0.divide(DEFAULT_SCALING_THRESHOLD);
381 c1 = c1.divide(DEFAULT_SCALING_THRESHOLD);
382 c2 = c2.divide(DEFAULT_SCALING_THRESHOLD);
383 c3 = c3.divide(DEFAULT_SCALING_THRESHOLD);
384 sum = sum.divide(DEFAULT_SCALING_THRESHOLD);
385 }
386
387 }
388
389
390 T temp;
391 for (int k = 0; k < nMax - 4; k++) {
392
393
394 if (sum.getReal() > DEFAULT_SCALING_THRESHOLD) {
395 rescalingCounter = rescalingCounter.add(FastMath.log10(DEFAULT_SCALING_THRESHOLD));
396 c0 = c0.divide(DEFAULT_SCALING_THRESHOLD);
397 c1 = c1.divide(DEFAULT_SCALING_THRESHOLD);
398 c2 = c2.divide(DEFAULT_SCALING_THRESHOLD);
399 c3 = c3.divide(DEFAULT_SCALING_THRESHOLD);
400 sum = sum.divide(DEFAULT_SCALING_THRESHOLD);
401 }
402
403
404 final T denominator = kPlus4.multiply(kPlus3);
405
406 temp = c3.multiply(recurrentTerm1.add(auxiliaryTerm5.multiply(kPlus3)));
407 temp = temp.subtract(
408 c2.multiply(pTimesRadiusSquared).multiply(auxiliaryTerm4.multiply(halfY).add(auxiliaryTerm3))
409 .divide(kPlus4));
410 temp = temp.add(
411 c1.multiply(auxiliaryTerm1).multiply(pPhiY.multiply(halfY).add(auxiliaryTerm2)).divide(denominator));
412 temp = temp.subtract(c0.multiply(auxiliaryTerm0).divide(denominator.multiply(kPlus2)));
413 temp = temp.multiply(radiusSquared.divide(kPlus4.multiply(kPlus5)));
414
415 c0 = c1;
416 c1 = c2;
417 c2 = c3;
418 c3 = temp;
419
420
421 kPlus2 = kPlus3;
422 kPlus3 = kPlus4;
423 kPlus4 = kPlus5;
424 kPlus5 = kPlus5.add(1.);
425 halfY = halfY.add(1.);
426
427
428 sum = sum.add(c3);
429
430 }
431 final T value =
432 sum.multiply((rescalingCounter.multiply(FastMath.log(10.)).subtract(pTimesRadiusSquared)).exp());
433
434 return new FieldProbabilityOfCollision<>(value, l0, u0, getName(), isAMaximumProbabilityOfCollisionMethod());
435
436 }
437 }
438
439
440 @Override
441 public ShortTermEncounter2DPOCMethodType getType() {
442 return ShortTermEncounter2DPOCMethodType.LAAS_2015;
443 }
444
445 }