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
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 /**
37 * Method computing the effective exhaust velocity from the specific impulse.
38 * @param isp specific impulse (s)
39 * @return effective exhaust velocity (m/s)
40 * @since 13.0
41 */
42 static double getExhaustVelocity(final double isp) {
43 return Constants.G0_STANDARD_GRAVITY * isp;
44 }
45
46 /** Get the specific impulse (s).
47 * @param s current spacecraft state
48 * @return specific impulse (s).
49 */
50 default double getIsp(SpacecraftState s) {
51 final double flowRate = getFlowRate(s);
52 return -getControl3DVectorCostType().evaluate(getThrustVector(s)) / (Constants.G0_STANDARD_GRAVITY * flowRate);
53 }
54
55 /** Get the thrust direction in spacecraft frame.
56 * <p>
57 * Return a zero vector if there is no thrust for given spacecraft state.
58 * @param s current spacecraft state
59 * @return thrust direction in spacecraft frame
60 */
61 default Vector3D getDirection(SpacecraftState s) {
62 final Vector3D thrustVector = getThrustVector(s);
63 final double norm = thrustVector.getNorm();
64 if (norm <= Precision.EPSILON) {
65 return Vector3D.ZERO;
66 }
67 return thrustVector.scalarMultiply(1. / norm);
68 }
69
70 /** Get the thrust vector in spacecraft frame (N).
71 * @param s current spacecraft state
72 * @return thrust vector in spacecraft frame (N)
73 */
74 Vector3D getThrustVector(SpacecraftState s);
75
76 /** Get the flow rate (kg/s).
77 * @param s current spacecraft state
78 * @return flow rate (kg/s)
79 */
80 double getFlowRate(SpacecraftState s);
81
82 /** Get the thrust vector in spacecraft frame (N).
83 * @param s current spacecraft state
84 * @param parameters propulsion model parameters
85 * @return thrust vector in spacecraft frame (N)
86 */
87 Vector3D getThrustVector(SpacecraftState s, double[] parameters);
88
89 /** Get the flow rate (kg/s).
90 * @param s current spacecraft state
91 * @param parameters propulsion model parameters
92 * @return flow rate (kg/s)
93 */
94 double getFlowRate(SpacecraftState s, double[] parameters);
95
96 /** Get the thrust vector in spacecraft frame (N).
97 * @param s current spacecraft state
98 * @param parameters propulsion model parameters
99 * @param <T> extends CalculusFieldElement<T>
100 * @return thrust vector in spacecraft frame (N)
101 */
102 <T extends CalculusFieldElement<T>> FieldVector3D<T> getThrustVector(FieldSpacecraftState<T> s, T[] parameters);
103
104 /** Get the flow rate (kg/s).
105 * @param s current spacecraft state
106 * @param parameters propulsion model parameters
107 * @param <T> extends CalculusFieldElement<T>
108 * @return flow rate (kg/s)
109 */
110 <T extends CalculusFieldElement<T>> T getFlowRate(FieldSpacecraftState<T> s, T[] parameters);
111
112 /** {@inheritDoc}
113 * Acceleration is computed here using the thrust vector in S/C frame.
114 */
115 @Override
116 default Vector3D getAcceleration(final SpacecraftState s, final Attitude maneuverAttitude,
117 final double[] parameters) {
118
119 final Vector3D thrustVector = getThrustVector(s, parameters);
120 final double thrustNorm = thrustVector.getNorm();
121 if (thrustNorm == 0) {
122 return Vector3D.ZERO;
123 }
124 final Vector3D direction = thrustVector.normalize();
125
126 // Compute thrust acceleration in inertial frame
127 // It seems under-efficient to rotate direction and apply thrust
128 // instead of just rotating the whole thrust vector itself.
129 // However it has to be done that way to avoid numerical discrepancies with legacy tests.
130 return new Vector3D(thrustNorm / s.getMass(),
131 maneuverAttitude.getRotation().applyInverseTo(direction));
132 }
133
134 /** {@inheritDoc}
135 * Acceleration is computed here using the thrust vector in S/C frame.
136 */
137 @Override
138 default <T extends CalculusFieldElement<T>> FieldVector3D<T> getAcceleration(final FieldSpacecraftState<T> s,
139 final FieldAttitude<T> maneuverAttitude,
140 final T[] parameters) {
141 // Extract thrust & direction from thrust vector
142 final FieldVector3D<T> thrustVector = getThrustVector(s, parameters);
143 final T thrustNorm = thrustVector.getNorm();
144 if (thrustNorm.getReal() == 0) {
145 return maneuverAttitude.getRotation().applyInverseTo(thrustVector.scalarMultiply(s.getMass().reciprocal()));
146 }
147 final FieldVector3D<T> direction = thrustVector.normalize();
148
149 // Compute thrust acceleration in inertial frame
150 // It seems under-efficient to rotate direction and apply thrust
151 // instead of just rotating the whole thrust vector itself.
152 // However it has to be done that way to avoid numerical discrepancies with legacy tests.
153 return new FieldVector3D<>(thrustNorm.divide(s.getMass()),
154 maneuverAttitude.getRotation().applyInverseTo(direction));
155 }
156
157 /** {@inheritDoc}
158 * Mass derivatives are directly extracted here from the flow rate value.
159 */
160 @Override
161 default double getMassDerivatives(SpacecraftState s, double[] parameters) {
162 return getFlowRate(s, parameters);
163 }
164
165 /** {@inheritDoc}
166 * Mass derivatives are directly extracted here from the flow rate value.
167 */
168 @Override
169 default <T extends CalculusFieldElement<T>> T getMassDerivatives(FieldSpacecraftState<T> s, T[] parameters) {
170 return getFlowRate(s, parameters);
171 }
172
173 }