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