1   /* Copyright 2002-2025 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.ArrayList;
20  import java.util.List;
21  
22  import org.hipparchus.CalculusFieldElement;
23  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
24  import org.hipparchus.geometry.euclidean.threed.Vector3D;
25  import org.orekit.attitudes.AttitudeProvider;
26  import org.orekit.propagation.FieldSpacecraftState;
27  import org.orekit.propagation.SpacecraftState;
28  import org.orekit.time.AbsoluteDate;
29  import org.orekit.utils.ParameterDriver;
30  
31  /** This class implements a parametric acceleration.
32   * <p>Parametric accelerations are intended to model lesser-known
33   * forces, estimating a few defining parameters from a parametric
34   * function using orbit determination. Typical parametric functions
35   * are polynomial (often limited to a constant term) and harmonic
36   * (often with either orbital period or half orbital period).</p>
37   * <p>An important operational example is the infamous GPS Y-bias,
38   * which is thought to be related to a radiator thermal radiation.
39   * Other examples could be to model leaks that produce roughly constant
40   * trust in some spacecraft-related direction.</p>
41   * <p>The acceleration direction is considered constant in either:
42   * </p>
43   * <ul>
44   *   <li>inertial frame</li>
45   *   <li>spacecraft frame</li>
46   *   <li>a dedicated attitude frame overriding spacecraft attitude
47   *   (this could for example be used to model solar arrays orientation
48   *   if the force is related to solar arrays)</li>
49   * </ul>
50   * <p>
51   * If the direction of the acceleration is unknown, then three instances
52   * of this class should be used, one along the X axis, one along the Y
53   * axis and one along the Z axis and their parameters estimated as usual.
54   * </p>
55   * @since 10.3
56   * @author Luc Maisonobe
57   * @author Bryan Cazabonne
58   * @author Melina Vanel
59   */
60  public class ParametricAcceleration extends AbstractParametricAcceleration {
61  
62      /** Acceleration model. */
63      private final AccelerationModel accelerationModel;
64  
65      /** Simple constructor.
66       * @param direction acceleration direction in overridden spacecraft frame
67       * @param isInertial if true, direction is defined in the same inertial
68       * frame used for propagation (i.e. {@link SpacecraftState#getFrame()}),
69       * otherwise direction is defined in spacecraft frame (i.e. using the
70       * propagation {@link
71       * org.orekit.propagation.Propagator#setAttitudeProvider(AttitudeProvider)
72       * attitude law})
73       * @param accelerationModel acceleration model used to compute the contribution of the empirical acceleration
74       * direction
75       */
76      public ParametricAcceleration(final Vector3D direction,
77                                    final boolean isInertial,
78                                    final AccelerationModel accelerationModel) {
79          this(direction, isInertial, null, accelerationModel);
80      }
81  
82      /** Simple constructor.
83       * @param direction acceleration direction in overridden spacecraft frame
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 attitudeOverride provider for attitude used to compute acceleration
90       * @param accelerationModel acceleration model used to compute the contribution of the empirical acceleration
91       * direction
92       */
93      public ParametricAcceleration(final Vector3D direction,
94                                    final AttitudeProvider attitudeOverride,
95                                    final AccelerationModel accelerationModel) {
96          this(direction, false, attitudeOverride, accelerationModel);
97      }
98  
99      /** Simple constructor.
100      * @param direction acceleration direction in overridden spacecraft frame
101      * @param isInertial if true, direction is defined in the same inertial
102      * frame used for propagation (i.e. {@link SpacecraftState#getFrame()}),
103      * otherwise direction is defined in spacecraft frame (i.e. using the
104      * propagation {@link
105      * org.orekit.propagation.Propagator#setAttitudeProvider(AttitudeProvider)
106      * attitude law})
107      * @param attitudeOverride provider for attitude used to compute acceleration
108      * @param accelerationModel acceleration model used to compute the contribution of the empirical acceleration
109      * direction
110      */
111     private ParametricAcceleration(final Vector3D direction,
112                                    final boolean isInertial,
113                                    final AttitudeProvider attitudeOverride,
114                                    final AccelerationModel accelerationModel) {
115         super(direction, isInertial, attitudeOverride);
116         this.accelerationModel = accelerationModel;
117     }
118 
119     /** {@inheritDoc} */
120     @Override
121     public List<ParameterDriver> getParametersDrivers() {
122         final List<ParameterDriver> parameterDrivers = new ArrayList<>(accelerationModel.getParametersDrivers());
123         if (getAttitudeOverride() != null) {
124             parameterDrivers.addAll(getAttitudeOverride().getParametersDrivers());
125         }
126         return parameterDrivers;
127     }
128 
129     /** {@inheritDoc} */
130     @Override
131     public void init(final SpacecraftState initialState, final AbsoluteDate target) {
132         accelerationModel.init(initialState, target);
133     }
134 
135     /** {@inheritDoc} */
136     @Override
137     public Vector3D acceleration(final SpacecraftState state,
138                                  final double[] parameters) {
139         final Vector3D inertialDirection = getAccelerationDirection(state);
140 
141         // Call the acceleration model to compute the acceleration
142         return new Vector3D(accelerationModel.signedAmplitude(state, parameters), inertialDirection);
143 
144     }
145 
146     /** {@inheritDoc} */
147     @Override
148     public <T extends CalculusFieldElement<T>> FieldVector3D<T> acceleration(final FieldSpacecraftState<T> state,
149                                                                              final T[] parameters) {
150         final FieldVector3D<T> inertialDirection = getAccelerationDirection(state);
151 
152         // Call the acceleration model to compute the acceleration
153         return new FieldVector3D<>(accelerationModel.signedAmplitude(state, parameters), inertialDirection);
154 
155     }
156 
157 }