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  
18  package org.orekit.forces.maneuvers.propulsion;
19  
20  import org.hipparchus.CalculusFieldElement;
21  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
22  import org.hipparchus.geometry.euclidean.threed.Vector3D;
23  import org.hipparchus.util.Precision;
24  import org.orekit.attitudes.Attitude;
25  import org.orekit.attitudes.FieldAttitude;
26  import org.orekit.propagation.FieldSpacecraftState;
27  import org.orekit.propagation.SpacecraftState;
28  import org.orekit.utils.Constants;
29  
30  /** Interface for a thrust-based propulsion model.
31   * @author Maxime Journot
32   * @since 10.2
33   */
34  public interface ThrustPropulsionModel extends PropulsionModel {
35  
36      /** Get the specific impulse (s).
37       * @param s current spacecraft state
38       * @return specific impulse (s).
39       */
40      default double getIsp(SpacecraftState s) {
41          final double flowRate = getFlowRate(s);
42          return -getControl3DVectorCostType().evaluate(getThrustVector(s)) / (Constants.G0_STANDARD_GRAVITY * flowRate);
43      }
44  
45      /** Get the thrust direction in spacecraft frame.
46       * <p>
47       * Return a zero vector if there is no thrust for given spacecraft state.
48       * @param s current spacecraft state
49       * @return thrust direction in spacecraft frame
50       */
51      default Vector3D getDirection(SpacecraftState s) {
52          final Vector3D thrustVector = getThrustVector(s);
53          final double   norm         = thrustVector.getNorm();
54          if (norm <= Precision.EPSILON) {
55              return Vector3D.ZERO;
56          }
57          return thrustVector.scalarMultiply(1. / norm);
58      }
59  
60      /** Get the thrust vector in spacecraft frame (N).
61       * @param s current spacecraft state
62       * @return thrust vector in spacecraft frame (N)
63       */
64      Vector3D getThrustVector(SpacecraftState s);
65  
66      /** Get the flow rate (kg/s).
67       * @param s current spacecraft state
68       * @return flow rate (kg/s)
69       */
70      double getFlowRate(SpacecraftState s);
71  
72      /** Get the thrust vector in spacecraft frame (N).
73       * @param s current spacecraft state
74       * @param parameters propulsion model parameters
75       * @return thrust vector in spacecraft frame (N)
76       */
77      Vector3D getThrustVector(SpacecraftState s, double[] parameters);
78  
79      /** Get the flow rate (kg/s).
80       * @param s current spacecraft state
81       * @param parameters propulsion model parameters
82       * @return flow rate (kg/s)
83       */
84      double getFlowRate(SpacecraftState s, double[] parameters);
85  
86      /** Get the thrust vector in spacecraft frame (N).
87       * @param s current spacecraft state
88       * @param parameters propulsion model parameters
89       * @param <T> extends CalculusFieldElement&lt;T&gt;
90       * @return thrust vector in spacecraft frame (N)
91       */
92      <T extends CalculusFieldElement<T>> FieldVector3D<T> getThrustVector(FieldSpacecraftState<T> s, T[] parameters);
93  
94      /** Get the flow rate (kg/s).
95       * @param s current spacecraft state
96       * @param parameters propulsion model parameters
97       * @param <T> extends CalculusFieldElement&lt;T&gt;
98       * @return flow rate (kg/s)
99       */
100     <T extends CalculusFieldElement<T>> T getFlowRate(FieldSpacecraftState<T> s, T[] parameters);
101 
102     /** {@inheritDoc}
103      * Acceleration is computed here using the thrust vector in S/C frame.
104      */
105     @Override
106     default Vector3D getAcceleration(SpacecraftState s,
107                                     final Attitude maneuverAttitude,
108                                     double[] parameters) {
109 
110         final Vector3D thrustVector = getThrustVector(s, parameters);
111         final double thrust = thrustVector.getNorm();
112         if (thrust == 0) {
113             return Vector3D.ZERO;
114         }
115         final Vector3D direction = thrustVector.normalize();
116 
117         // Compute thrust acceleration in inertial frame
118         // It seems under-efficient to rotate direction and apply thrust
119         // instead of just rotating the whole thrust vector itself.
120         // However it has to be done that way to avoid numerical discrepancies with legacy tests.
121         return new Vector3D(thrust / s.getMass(),
122                             maneuverAttitude.getRotation().applyInverseTo(direction));
123     }
124 
125     /** {@inheritDoc}
126      * Acceleration is computed here using the thrust vector in S/C frame.
127      */
128     @Override
129     default <T extends CalculusFieldElement<T>> FieldVector3D<T> getAcceleration(FieldSpacecraftState<T> s,
130                                                                             final FieldAttitude<T> maneuverAttitude,
131                                                                             T[] parameters) {
132         // Extract thrust & direction from thrust vector
133         final FieldVector3D<T> thrustVector = getThrustVector(s, parameters);
134         final T thrust = thrustVector.getNorm();
135         if (thrust.isZero()) {
136             return FieldVector3D.getZero(s.getDate().getField());
137         }
138         final FieldVector3D<T> direction = thrustVector.normalize();
139 
140         // Compute thrust acceleration in inertial frame
141         // It seems under-efficient to rotate direction and apply thrust
142         // instead of just rotating the whole thrust vector itself.
143         // However it has to be done that way to avoid numerical discrepancies with legacy tests.
144         return new FieldVector3D<>(thrust.divide(s.getMass()),
145                         maneuverAttitude.getRotation().applyInverseTo(direction));
146     }
147 
148     /** {@inheritDoc}
149      * Mass derivatives are directly extracted here from the flow rate value.
150      */
151     @Override
152     default double getMassDerivatives(SpacecraftState s, double[] parameters) {
153         return getFlowRate(s, parameters);
154     }
155 
156     /** {@inheritDoc}
157      * Mass derivatives are directly extracted here from the flow rate value.
158      */
159     @Override
160     default <T extends CalculusFieldElement<T>> T getMassDerivatives(FieldSpacecraftState<T> s, T[] parameters) {
161         return getFlowRate(s, parameters);
162     }
163 
164 }