1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.bodies;
18
19 import org.hipparchus.analysis.UnivariateFunction;
20 import org.hipparchus.analysis.solvers.AllowedSolution;
21 import org.hipparchus.analysis.solvers.BracketingNthOrderBrentSolver;
22 import org.hipparchus.analysis.solvers.UnivariateSolverUtils;
23 import org.hipparchus.geometry.euclidean.threed.Vector3D;
24 import org.hipparchus.util.FastMath;
25 import org.orekit.frames.CR3BPRotatingFrame;
26 import org.orekit.frames.Frame;
27 import org.orekit.frames.Transform;
28 import org.orekit.time.AbsoluteDate;
29 import org.orekit.utils.AbsolutePVCoordinates;
30 import org.orekit.utils.LagrangianPoints;
31 import org.orekit.utils.PVCoordinates;
32 import org.orekit.utils.TimeStampedPVCoordinates;
33
34
35
36
37
38
39
40
41
42 public class CR3BPSystem {
43
44
45 private static final double RELATIVE_ACCURACY = 1e-14;
46
47
48 private static final double ABSOLUTE_ACCURACY = 1e-3;
49
50
51 private static final double FUNCTION_ACCURACY = 0;
52
53
54 private static final int MAX_ORDER = 5;
55
56
57 private static final int MAX_EVALUATIONS = 10000;
58
59
60 private final double mu;
61
62
63 private final double dDim;
64
65
66 private final double vDim;
67
68
69 private final double tDim;
70
71
72 private final String name;
73
74
75 private final Frame rotatingFrame;
76
77
78 private final CelestialBody primaryBody;
79
80
81 private final CelestialBody secondaryBody;
82
83
84 private Vector3D l1Position;
85
86
87 private Vector3D l2Position;
88
89
90 private Vector3D l3Position;
91
92
93 private Vector3D l4Position;
94
95
96 private Vector3D l5Position;
97
98
99 private final double gamma1;
100
101
102 private final double gamma2;
103
104
105 private final double gamma3;
106
107
108
109
110
111
112
113
114
115
116
117 public CR3BPSystem(final CelestialBody primaryBody, final CelestialBody secondaryBody, final double a) {
118 this(primaryBody, secondaryBody, a, secondaryBody.getGM() / (secondaryBody.getGM() + primaryBody.getGM()));
119 }
120
121
122
123
124
125
126
127
128
129
130
131
132 public CR3BPSystem(final CelestialBody primaryBody, final CelestialBody secondaryBody, final double a, final double mu) {
133 this.primaryBody = primaryBody;
134 this.secondaryBody = secondaryBody;
135
136 this.name = primaryBody.getName() + "_" + secondaryBody.getName();
137
138 final double mu1 = primaryBody.getGM();
139
140 this.mu = mu;
141 this.dDim = a;
142 this.vDim = FastMath.sqrt(mu1 / dDim);
143 this.tDim = 2 * FastMath.PI * dDim / vDim;
144 this.rotatingFrame = new CR3BPRotatingFrame(mu, primaryBody, secondaryBody);
145
146 computeLagrangianPointsPosition();
147
148
149
150
151 final double x1 = l1Position.getX();
152 final double dCP1 = 1 - mu;
153 this.gamma1 = dCP1 - x1;
154
155
156 final double x2 = l2Position.getX();
157 final double dCP2 = 1 - mu;
158 this.gamma2 = x2 - dCP2;
159
160
161 final double x3 = l3Position.getX();
162 final double dCP3 = -mu;
163 this.gamma3 = dCP3 - x3;
164
165 }
166
167
168
169 private void computeLagrangianPointsPosition() {
170
171
172
173 final BracketingNthOrderBrentSolver solver =
174 new BracketingNthOrderBrentSolver(RELATIVE_ACCURACY,
175 ABSOLUTE_ACCURACY,
176 FUNCTION_ACCURACY, MAX_ORDER);
177
178 final double baseR1 = 1 - FastMath.cbrt(mu / 3);
179 final UnivariateFunction l1Equation = x -> {
180 final double leq1 =
181 x * (x + mu) * (x + mu) * (x + mu - 1) * (x + mu - 1);
182 final double leq2 = (1 - mu) * (x + mu - 1) * (x + mu - 1);
183 final double leq3 = mu * (x + mu) * (x + mu);
184 return leq1 - leq2 + leq3;
185 };
186 final double[] searchInterval1 =
187 UnivariateSolverUtils.bracket(l1Equation, baseR1, -mu,
188 1 - mu, 1E-6, 1,
189 MAX_EVALUATIONS);
190
191 final double r1 =
192 solver.solve(MAX_EVALUATIONS, l1Equation, searchInterval1[0],
193 searchInterval1[1], AllowedSolution.ANY_SIDE);
194
195 this.l1Position = new Vector3D(r1, 0.0, 0.0);
196
197
198 final double baseR2 = 1 + FastMath.cbrt(mu / 3);
199 final UnivariateFunction l2Equation = x -> {
200 final double leq21 =
201 x * (x + mu) * (x + mu) * (x + mu - 1) * (x + mu - 1);
202 final double leq22 = (1 - mu) * (x + mu - 1) * (x + mu - 1);
203 final double leq23 = mu * (x + mu) * (x + mu);
204 return leq21 - leq22 - leq23;
205 };
206 final double[] searchInterval2 =
207 UnivariateSolverUtils.bracket(l2Equation, baseR2, 1 - mu, 2, 1E-6,
208 1, MAX_EVALUATIONS);
209
210 final double r2 =
211 solver.solve(MAX_EVALUATIONS, l2Equation, searchInterval2[0],
212 searchInterval2[1], AllowedSolution.ANY_SIDE);
213
214 this.l2Position = new Vector3D(r2, 0.0, 0.0);
215
216
217 final double baseR3 = -(1 + 5 * mu / 12);
218 final UnivariateFunction l3Equation = x -> {
219 final double leq31 =
220 x * (x + mu) * (x + mu) * (x + mu - 1) * (x + mu - 1);
221 final double leq32 = (1 - mu) * (x + mu - 1) * (x + mu - 1);
222 final double leq33 = mu * (x + mu) * (x + mu);
223 return leq31 + leq32 + leq33;
224 };
225 final double[] searchInterval3 =
226 UnivariateSolverUtils.bracket(l3Equation, baseR3, -2, -mu, 1E-6, 1,
227 MAX_EVALUATIONS);
228
229 final double r3 =
230 solver.solve(MAX_EVALUATIONS, l3Equation, searchInterval3[0],
231 searchInterval3[1], AllowedSolution.ANY_SIDE);
232
233 this.l3Position = new Vector3D(r3, 0.0, 0.0);
234
235
236 this.l4Position = new Vector3D(0.5 - mu, FastMath.sqrt(3) / 2, 0);
237
238
239 this.l5Position = new Vector3D(0.5 - mu, -FastMath.sqrt(3) / 2, 0);
240 }
241
242
243
244
245 public double getMassRatio() {
246 return mu;
247 }
248
249
250
251
252 public double getDdim() {
253 return dDim;
254 }
255
256
257
258
259 public double getVdim() {
260 return vDim;
261 }
262
263
264
265
266 public double getTdim() {
267 return tDim;
268 }
269
270
271
272
273 public String getName() {
274 return name;
275 }
276
277
278
279
280 public CelestialBody getPrimary() {
281 return primaryBody;
282 }
283
284
285
286
287 public CelestialBody getSecondary() {
288 return secondaryBody;
289 }
290
291
292
293
294 public Frame getRotatingFrame() {
295 return rotatingFrame;
296 }
297
298
299
300
301
302 public Vector3D getLPosition(final LagrangianPoints lagrangianPoint) {
303
304 final Vector3D lPosition;
305
306 switch (lagrangianPoint) {
307
308 case L1:
309 lPosition = l1Position;
310 break;
311
312 case L3:
313 lPosition = l3Position;
314 break;
315
316 case L4:
317 lPosition = l4Position;
318 break;
319
320 case L5:
321 lPosition = l5Position;
322 break;
323
324 default:
325 lPosition = l2Position;
326 break;
327
328 }
329 return lPosition;
330 }
331
332
333
334
335
336
337 public double getGamma(final LagrangianPoints lagrangianPoint) {
338
339 final double gamma;
340
341 switch (lagrangianPoint) {
342
343 case L1:
344 gamma = gamma1;
345 break;
346
347 case L2:
348 gamma = gamma2;
349 break;
350
351 case L3:
352 gamma = gamma3;
353 break;
354
355 default:
356 gamma = 0;
357 }
358 return gamma;
359 }
360
361
362
363
364
365
366
367 private PVCoordinates getRealPV(final PVCoordinates pv0, final AbsoluteDate date, final Frame outputFrame) {
368
369
370
371
372
373 final Frame primaryInertialFrame = primaryBody.getInertiallyOrientedFrame();
374 final TimeStampedPVCoordinates pv21 = secondaryBody.getPVCoordinates(date, primaryInertialFrame);
375
376
377 final double dist12 = pv21.getPosition().getNorm();
378 final double vCircular = FastMath.sqrt(primaryBody.getGM() / dist12);
379
380
381 final PVCoordinates pvDim = new PVCoordinates(pv0.getPosition().scalarMultiply(dist12),
382 pv0.getVelocity().scalarMultiply(vCircular));
383
384
385 final Transform rotatingToPrimaryInertial = rotatingFrame.getTransformTo(primaryInertialFrame, date);
386
387
388 final PVCoordinates pv2 = rotatingToPrimaryInertial.transformPVCoordinates(pvDim);
389
390
391
392 final Transform primaryInertialToOutputFrame = primaryInertialFrame.getTransformTo(outputFrame, date);
393
394 return primaryInertialToOutputFrame.transformPVCoordinates(pv2);
395 }
396
397
398
399
400
401
402
403
404
405 public AbsolutePVCoordinates getRealAPV(final AbsolutePVCoordinates apv0, final AbsoluteDate initialDate, final Frame outputFrame) {
406
407 final double duration = apv0.getDate().durationFrom(initialDate) * tDim / (2 * FastMath.PI);
408 final AbsoluteDate date = initialDate.shiftedBy(duration);
409
410
411 final PVCoordinates pv3 = getRealPV(apv0.getPVCoordinates(), date, outputFrame);
412
413 return new AbsolutePVCoordinates(outputFrame, date, pv3);
414 }
415
416 }