1   /* Copyright 2002-2024 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.forces.empirical;
18  
19  import java.util.List;
20  import java.util.stream.Stream;
21  
22  import org.hipparchus.CalculusFieldElement;
23  import org.hipparchus.Field;
24  import org.hipparchus.geometry.euclidean.threed.FieldRotation;
25  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
26  import org.hipparchus.geometry.euclidean.threed.Rotation;
27  import org.hipparchus.geometry.euclidean.threed.Vector3D;
28  import org.orekit.attitudes.AttitudeProvider;
29  import org.orekit.forces.ForceModel;
30  import org.orekit.propagation.FieldSpacecraftState;
31  import org.orekit.propagation.SpacecraftState;
32  import org.orekit.propagation.events.EventDetector;
33  import org.orekit.propagation.events.FieldEventDetector;
34  import org.orekit.time.AbsoluteDate;
35  import org.orekit.time.FieldAbsoluteDate;
36  import org.orekit.utils.ParameterDriver;
37  
38  /** This class implements a parametric acceleration.
39   * <p>Parametric accelerations are intended to model lesser-known
40   * forces, estimating a few defining parameters from a parametric
41   * function using orbit determination. Typical parametric functions
42   * are polynomial (often limited to a constant term) and harmonic
43   * (often with either orbital period or half orbital period).</p>
44   * <p>An important operational example is the infamous GPS Y-bias,
45   * which is thought to be related to a radiator thermal radiation.
46   * Other examples could be to model leaks that produce roughly constant
47   * trust in some spacecraft-related direction.</p>
48   * <p>The acceleration direction is considered constant in either:
49   * </p>
50   * <ul>
51   *   <li>inertial frame</li>
52   *   <li>spacecraft frame</li>
53   *   <li>a dedicated attitude frame overriding spacecraft attitude
54   *   (this could for example be used to model solar arrays orientation
55   *   if the force is related to solar arrays)</li>
56   * </ul>
57   * <p>
58   * If the direction of the acceleration is unknown, then three instances
59   * of this class should be used, one along the X axis, one along the Y
60   * axis and one along the Z axis and their parameters estimated as usual.
61   * </p>
62   * @since 10.3
63   * @author Luc Maisonobe
64   * @author Bryan Cazabonne
65   * @author Melina Vanel
66   */
67  public class ParametricAcceleration implements ForceModel {
68  
69      /** Direction of the acceleration in defining frame. */
70      private final Vector3D direction;
71  
72      /** Flag for inertial acceleration direction. */
73      private final boolean isInertial;
74  
75      /** The attitude to override, if set. */
76      private final AttitudeProvider attitudeOverride;
77  
78      /** Acceleration model. */
79      private final AccelerationModel accelerationModel;
80  
81      /** Simple constructor.
82       * @param direction acceleration direction in overridden spacecraft frame
83       * @param isInertial if true, direction is defined in the same inertial
84       * frame used for propagation (i.e. {@link SpacecraftState#getFrame()}),
85       * otherwise direction is defined in spacecraft frame (i.e. using the
86       * propagation {@link
87       * org.orekit.propagation.Propagator#setAttitudeProvider(AttitudeProvider)
88       * attitude law})
89       * @param accelerationModel acceleration model used to compute the contribution of the empirical acceleration
90       * direction
91       */
92      public ParametricAcceleration(final Vector3D direction,
93                                    final boolean isInertial,
94                                    final AccelerationModel accelerationModel) {
95          this(direction, isInertial, null, accelerationModel);
96      }
97  
98      /** Simple constructor.
99       * @param direction acceleration direction in overridden spacecraft frame
100      * frame used for propagation (i.e. {@link SpacecraftState#getFrame()}),
101      * otherwise direction is defined in spacecraft frame (i.e. using the
102      * propagation {@link
103      * org.orekit.propagation.Propagator#setAttitudeProvider(AttitudeProvider)
104      * attitude law})
105      * @param attitudeOverride provider for attitude used to compute acceleration
106      * @param accelerationModel acceleration model used to compute the contribution of the empirical acceleration
107      * direction
108      */
109     public ParametricAcceleration(final Vector3D direction,
110                                   final AttitudeProvider attitudeOverride,
111                                   final AccelerationModel accelerationModel) {
112         this(direction, false, attitudeOverride, accelerationModel);
113     }
114 
115     /** Simple constructor.
116      * @param direction acceleration direction in overridden spacecraft frame
117      * @param isInertial if true, direction is defined in the same inertial
118      * frame used for propagation (i.e. {@link SpacecraftState#getFrame()}),
119      * otherwise direction is defined in spacecraft frame (i.e. using the
120      * propagation {@link
121      * org.orekit.propagation.Propagator#setAttitudeProvider(AttitudeProvider)
122      * attitude law})
123      * @param attitudeOverride provider for attitude used to compute acceleration
124      * @param accelerationModel acceleration model used to compute the contribution of the empirical acceleration
125      * direction
126      */
127     private ParametricAcceleration(final Vector3D direction,
128                                    final boolean isInertial,
129                                    final AttitudeProvider attitudeOverride,
130                                    final AccelerationModel accelerationModel) {
131         this.direction         = direction;
132         this.isInertial        = isInertial;
133         this.attitudeOverride  = attitudeOverride;
134         this.accelerationModel = accelerationModel;
135     }
136 
137     /** {@inheritDoc} */
138     @Override
139     public boolean dependsOnPositionOnly() {
140         return isInertial;
141     }
142 
143     /** {@inheritDoc} */
144     @Override
145     public List<ParameterDriver> getParametersDrivers() {
146         return accelerationModel.getParametersDrivers();
147     }
148 
149     /** {@inheritDoc} */
150     @Override
151     public void init(final SpacecraftState initialState, final AbsoluteDate target) {
152         accelerationModel.init(initialState, target);
153     }
154 
155     /** {@inheritDoc} */
156     @Override
157     public Vector3D acceleration(final SpacecraftState state,
158                                  final double[] parameters) {
159 
160         // Date
161         final AbsoluteDate date = state.getDate();
162 
163         final Vector3D inertialDirection;
164         if (isInertial) {
165             // the acceleration direction is already defined in the inertial frame
166             inertialDirection = direction;
167         } else {
168             final Rotation rotation;
169             if (attitudeOverride == null) {
170                 // the acceleration direction is defined in spacecraft frame as set by the propagator
171                 rotation = state.getAttitude().getRotation();
172             } else {
173                 // the acceleration direction is defined in a dedicated frame
174                 rotation = attitudeOverride.getAttitudeRotation(state.getOrbit(), date, state.getFrame());
175             }
176             inertialDirection = rotation.applyInverseTo(direction);
177         }
178 
179         // Call the acceleration model to compute the acceleration
180         return new Vector3D(accelerationModel.signedAmplitude(state, parameters), inertialDirection);
181 
182     }
183 
184     /** {@inheritDoc} */
185     @Override
186     public <T extends CalculusFieldElement<T>> FieldVector3D<T> acceleration(final FieldSpacecraftState<T> state,
187                                                                          final T[] parameters) {
188 
189         // Date
190         final FieldAbsoluteDate<T> date = state.getDate();
191 
192         final FieldVector3D<T> inertialDirection;
193         if (isInertial) {
194             // the acceleration direction is already defined in the inertial frame
195             inertialDirection = new FieldVector3D<>(date.getField(), direction);
196         } else {
197             final FieldRotation<T> rotation;
198             if (attitudeOverride == null) {
199                 // the acceleration direction is defined in spacecraft frame as set by the propagator
200                 rotation = state.getAttitude().getRotation();
201             } else {
202                 // the acceleration direction is defined in a dedicated frame
203                 rotation = attitudeOverride.getAttitudeRotation(state.getOrbit(), date, state.getFrame());
204             }
205             inertialDirection = rotation.applyInverseTo(direction);
206         }
207 
208         // Call the acceleration model to compute the acceleration
209         return new FieldVector3D<>(accelerationModel.signedAmplitude(state, parameters), inertialDirection);
210 
211     }
212 
213 
214     /** {@inheritDoc} */
215     @Override
216     public Stream<EventDetector> getEventDetectors() {
217         return Stream.empty();
218     }
219 
220     /** {@inheritDoc} */
221     @Override
222     public <T extends CalculusFieldElement<T>> Stream<FieldEventDetector<T>> getFieldEventDetectors(final Field<T> field) {
223         return Stream.empty();
224     }
225 
226 }