1   /* Copyright 2002-2021 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.propagation.numerical.cr3bp;
18  
19  import java.util.Collections;
20  import java.util.List;
21  import java.util.stream.Stream;
22  
23  import org.hipparchus.Field;
24  import org.hipparchus.CalculusFieldElement;
25  import org.hipparchus.analysis.differentiation.DSFactory;
26  import org.hipparchus.analysis.differentiation.DerivativeStructure;
27  import org.hipparchus.analysis.differentiation.FDSFactory;
28  import org.hipparchus.analysis.differentiation.FieldDerivativeStructure;
29  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
30  import org.hipparchus.geometry.euclidean.threed.Vector3D;
31  import org.hipparchus.util.FastMath;
32  import org.orekit.bodies.CR3BPSystem;
33  import org.orekit.forces.AbstractForceModel;
34  import org.orekit.propagation.FieldSpacecraftState;
35  import org.orekit.propagation.SpacecraftState;
36  import org.orekit.propagation.events.EventDetector;
37  import org.orekit.propagation.events.FieldEventDetector;
38  import org.orekit.utils.ParameterDriver;
39  
40  /** Class calculating the acceleration induced by CR3BP model.
41   * @see "Dynamical systems, the three-body problem, and space mission design, Koon, Lo, Marsden, Ross"
42   * @author Vincent Mouraux
43   * @since 10.2
44   */
45  public class CR3BPForceModel extends AbstractForceModel {
46  
47      /** Suffix for parameter name for Mass Ratio enabling Jacobian processing. */
48      public static final String MASS_RATIO_SUFFIX =  "CR3BP System Mass Ratio";
49  
50      /**
51       * Central attraction scaling factor.
52       * <p>
53       * We use a power of 2 to avoid numeric noise introduction in the
54       * multiplications/divisions sequences.
55       * </p>
56       */
57      private static final double MU_SCALE = FastMath.scalb(1.0, 32);
58  
59      /** Driver for gravitational parameter. */
60      private final ParameterDriver muParameterDriver;
61  
62      /** Simple constructor.
63       * @param cr3bp Name of the CR3BP System
64       */
65      public CR3BPForceModel(final CR3BPSystem cr3bp) {
66          muParameterDriver = new ParameterDriver(cr3bp.getName() + MASS_RATIO_SUFFIX,
67                                                  cr3bp.getMassRatio(), MU_SCALE, 0.0,
68                                                  Double.POSITIVE_INFINITY);
69      }
70  
71      /** {@inheritDoc} */
72      public Vector3D acceleration(final SpacecraftState s,
73                                   final double[] parameters) {
74  
75          // Spacecraft Velocity
76          final double vx = s.getPVCoordinates().getVelocity().getX();
77          final double vy = s.getPVCoordinates().getVelocity().getY();
78  
79          // Spacecraft Potential
80          final DerivativeStructure potential = getPotential(s);
81  
82          // Potential derivatives
83          final double[] dU = potential.getAllDerivatives();
84  
85          // first order derivatives index
86          final int idX = potential.getFactory().getCompiler().getPartialDerivativeIndex(1, 0, 0);
87          final int idY = potential.getFactory().getCompiler().getPartialDerivativeIndex(0, 1, 0);
88          final int idZ = potential.getFactory().getCompiler().getPartialDerivativeIndex(0, 0, 1);
89  
90          // Acceleration calculation according to CR3BP Analytical Model
91          final double accx = dU[idX] + 2.0 * vy;
92          final double accy = dU[idY] - 2.0 * vx;
93          final double accz = dU[idZ];
94  
95          // compute absolute acceleration
96          return new Vector3D(accx, accy, accz);
97  
98      }
99  
100     /** {@inheritDoc} */
101     public <T extends CalculusFieldElement<T>> FieldVector3D<T> acceleration(final FieldSpacecraftState<T> s,
102                                                                          final T[] parameters) {
103 
104         // Spacecraft Velocity
105         final T vx = s.getPVCoordinates().getVelocity().getX();
106         final T vy = s.getPVCoordinates().getVelocity().getY();
107 
108         // Spacecraft Potential
109         final FieldDerivativeStructure<T> fieldPotential = getPotential(s);
110         // Potential derivatives
111         final T[] dU = fieldPotential.getAllDerivatives();
112 
113         // first order derivatives index
114         final int idX = fieldPotential.getFactory().getCompiler().getPartialDerivativeIndex(1, 0, 0);
115         final int idY = fieldPotential.getFactory().getCompiler().getPartialDerivativeIndex(0, 1, 0);
116         final int idZ = fieldPotential.getFactory().getCompiler().getPartialDerivativeIndex(0, 0, 1);
117 
118         // Acceleration calculation according to CR3BP Analytical Model
119         final T accx = dU[idX].add(vy.multiply(2.0));
120         final T accy = dU[idY].subtract(vx.multiply(2.0));
121         final T accz = dU[idZ];
122 
123         // compute absolute acceleration
124         return new FieldVector3D<>(accx, accy, accz);
125 
126     }
127 
128     /**
129      * Calculate spacecraft potential.
130      * @param s SpacecraftState
131      * @return Spacecraft Potential
132      */
133     public DerivativeStructure getPotential(final SpacecraftState s) {
134 
135         // Spacecraft Position
136         final double x = s.getPVCoordinates().getPosition().getX();
137         final double y = s.getPVCoordinates().getPosition().getY();
138         final double z = s.getPVCoordinates().getPosition().getZ();
139 
140         final DSFactory factoryP = new DSFactory(3, 2);
141         final DerivativeStructure fpx = factoryP.variable(0, x);
142         final DerivativeStructure fpy = factoryP.variable(1, y);
143         final DerivativeStructure fpz = factoryP.variable(2, z);
144 
145         final DerivativeStructure zero = fpx.getField().getZero();
146 
147         // Get CR3BP System mass ratio
148         final DerivativeStructure mu = zero.add(muParameterDriver.getValue());
149 
150         // Normalized distances between primaries and barycenter in CR3BP
151         final DerivativeStructure d1 = mu;
152         final DerivativeStructure d2 = mu.negate().add(1.0);
153 
154         // Norm of the Spacecraft position relative to the primary body
155         final DerivativeStructure r1 =
156             FastMath.sqrt((fpx.add(d1)).multiply(fpx.add(d1)).add(fpy.multiply(fpy))
157                 .add(fpz.multiply(fpz)));
158 
159         // Norm of the Spacecraft position relative to the secondary body
160         final DerivativeStructure r2 =
161             FastMath.sqrt((fpx.subtract(d2)).multiply(fpx.subtract(d2))
162                 .add(fpy.multiply(fpy)).add(fpz.multiply(fpz)));
163 
164         // Potential of the Spacecraft
165         return (mu.negate().add(1.0).divide(r1)).add(mu.divide(r2))
166                 .add(fpx.multiply(fpx).add(fpy.multiply(fpy)).multiply(0.5)).add(d1.multiply(d2).multiply(0.5));
167     }
168 
169     /**
170      * Calculate spacecraft potential.
171      * @param <T> Field element
172      * @param s SpacecraftState
173      * @return Spacecraft Potential
174      */
175     public <T extends CalculusFieldElement<T>> FieldDerivativeStructure<T> getPotential(final FieldSpacecraftState<T> s) {
176 
177         // Spacecraft Position
178         final T x = s.getPVCoordinates().getPosition().getX();
179         final T y = s.getPVCoordinates().getPosition().getY();
180         final T z = s.getPVCoordinates().getPosition().getZ();
181 
182         final FDSFactory<T> factoryP = new FDSFactory<>(s.getDate().getField(), 3, 2);
183         final FieldDerivativeStructure<T> fpx = factoryP.variable(0, x);
184         final FieldDerivativeStructure<T> fpy = factoryP.variable(1, y);
185         final FieldDerivativeStructure<T> fpz = factoryP.variable(2, z);
186         final FieldDerivativeStructure<T> zero = fpx.getField().getZero();
187 
188         // Get CR3BP System mass ratio
189         final FieldDerivativeStructure<T> mu = zero.add(muParameterDriver.getValue());
190 
191         // Normalized distances between primaries and barycenter in CR3BP
192         final FieldDerivativeStructure<T> d1 = mu;
193         final FieldDerivativeStructure<T> d2 = mu.negate().add(1.0);
194 
195         // Norm of the Spacecraft position relative to the primary body
196         final FieldDerivativeStructure<T> r1 =
197             FastMath.sqrt((fpx.add(d1)).multiply(fpx.add(d1)).add(fpy.multiply(fpy))
198                 .add(fpz.multiply(fpz)));
199 
200         // Norm of the Spacecraft position relative to the secondary body
201         final FieldDerivativeStructure<T> r2 =
202             FastMath.sqrt((fpx.subtract(d2)).multiply(fpx.subtract(d2))
203                 .add(fpy.multiply(fpy)).add(fpz.multiply(fpz)));
204 
205         // Potential of the Spacecraft
206         return (mu.negate().add(1.0).divide(r1)).add(mu.divide(r2))
207                 .add(fpx.multiply(fpx).add(fpy.multiply(fpy)).multiply(0.5)).add(d1.multiply(d2).multiply(0.5));
208     }
209 
210     /** {@inheritDoc} */
211     public Stream<EventDetector> getEventsDetectors() {
212         return Stream.empty();
213     }
214 
215     @Override
216     /** {@inheritDoc} */
217     public <T extends CalculusFieldElement<T>> Stream<FieldEventDetector<T>> getFieldEventsDetectors(final Field<T> field) {
218         return Stream.empty();
219     }
220 
221     /** {@inheritDoc} */
222     public List<ParameterDriver> getParametersDrivers() {
223         return Collections.singletonList(muParameterDriver);
224     }
225 
226     /** {@inheritDoc} */
227     public boolean dependsOnPositionOnly() {
228         return true;
229     }
230 }