1   /* Copyright 2022-2025 Romain Serra
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.FastMath;
24  import org.hipparchus.util.MathUtils;
25  import org.orekit.forces.maneuvers.Control3DVectorCostType;
26  import org.orekit.time.AbsoluteDate;
27  import org.orekit.utils.ParameterDriver;
28  
29  import java.util.Arrays;
30  import java.util.Collections;
31  import java.util.List;
32  
33  /** Constant thrust propulsion model with:
34   *  - Constant thrust direction in spacecraft frame
35   *  - Parameter drivers (for estimation) for the thrust vector in spherical coordinates.
36   * @author Romain Serra
37   * @since 13.1
38   * @see BasicConstantThrustPropulsionModel
39   */
40  public class SphericalConstantThrustPropulsionModel extends AbstractConstantThrustPropulsionModel {
41  
42      /** Parameter name for thrust magnitude. */
43      public static final String THRUST_MAGNITUDE = "thrust magnitude";
44  
45      /** Parameter name for thrust right ascension. */
46      public static final String THRUST_RIGHT_ASCENSION = "thrust alpha";
47  
48      /** Parameter name for thrust declination. */
49      public static final String THRUST_DECLINATION = "thrust declination";
50  
51      /** Thrust scaling factor.
52       * <p>
53       * We use a power of 2 to avoid numeric noise introduction
54       * in the multiplications/divisions sequences.
55       * </p>
56       */
57      public static final double THRUST_SCALE = FastMath.scalb(1.0, -5);
58  
59      /** Driver for thrust magnitude. */
60      private final ParameterDriver thrustMagnitude;
61  
62      /** Driver for thrust right ascension in spacecraft frame. */
63      private final ParameterDriver thrustRightAscension;
64  
65      /** Driver for thrust declination in spacecraft frame. */
66      private final ParameterDriver thrustDeclination;
67  
68      /** Mass flow rate factor. */
69      private final double massFlowRateFactor;
70  
71      /** Generic constructor.
72       * @param isp isp (s)
73       * @param thrustMagnitude thrust magnitude (N)
74       * @param thrustDirection thrust direction in spacecraft frame
75       * @param name name of the maneuver
76       */
77      public SphericalConstantThrustPropulsionModel(final double isp, final double thrustMagnitude,
78                                                    final Vector3D thrustDirection, final String name) {
79          super(isp, thrustMagnitude, thrustDirection, Control3DVectorCostType.TWO_NORM, name);
80          this.massFlowRateFactor = -1. / ThrustPropulsionModel.getExhaustVelocity(isp);
81  
82          // Build the parameter drivers, using maneuver name as prefix
83          this.thrustMagnitude   = new ParameterDriver(name + THRUST_MAGNITUDE, thrustMagnitude, THRUST_SCALE,
84                  0.0, Double.POSITIVE_INFINITY);
85          this.thrustRightAscension   = new ParameterDriver(name + THRUST_RIGHT_ASCENSION, thrustDirection.getAlpha(), 1.,
86                  Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
87          this.thrustDeclination   = new ParameterDriver(name + THRUST_DECLINATION, thrustDirection.getDelta(), 1.,
88                  -MathUtils.SEMI_PI, MathUtils.SEMI_PI);
89      }
90  
91      /** Constructor with thrust vector.
92       * @param isp isp (s)
93       * @param thrustVector thrust vector in spacecraft frame (N)
94       * @param name name of the maneuver
95       */
96      public SphericalConstantThrustPropulsionModel(final double isp, final Vector3D thrustVector, final String name) {
97          this(isp, thrustVector.getNorm(), thrustVector.normalize(), name);
98      }
99  
100     /** {@inheritDoc} */
101     @Override
102     public Vector3D getThrustVector() {
103         // Thrust vector does not depend on spacecraft state for a constant maneuver.
104         // thrustDriver as only 1 value estimated over the whole time period
105         // by construction thrustDriver has only 1 value estimated over the all period
106         // that is why no argument is acceptable
107         return new Vector3D(thrustRightAscension.getValue(), thrustDeclination.getValue()).scalarMultiply(thrustMagnitude.getValue());
108     }
109 
110     /** {@inheritDoc} */
111     @Override
112     public Vector3D getThrustVector(final AbsoluteDate date) {
113         // Thrust vector does not depend on spacecraft state for a constant maneuver.
114         return new Vector3D(thrustRightAscension.getValue(date), thrustDeclination.getValue(date)).scalarMultiply(thrustMagnitude.getValue(date));
115     }
116 
117     /** {@inheritDoc} */
118     @Override
119     public double getFlowRate() {
120         // Thrust vector does not depend on spacecraft state for a constant maneuver.
121         // thrustDriver has only 1 value estimated over the whole time period
122         // by construction thrustDriver has only 1 value estimated over the all period
123         // that is why no argument is acceptable
124         return getThrustVector().getNorm() * massFlowRateFactor;
125     }
126 
127     /** {@inheritDoc} */
128     @Override
129     public double getFlowRate(final AbsoluteDate date) {
130         return getThrustVector(date).getNorm() * massFlowRateFactor;
131     }
132 
133     /** {@inheritDoc} */
134     @Override
135     public List<ParameterDriver> getParametersDrivers() {
136         return Collections.unmodifiableList(Arrays.asList(thrustMagnitude, thrustRightAscension, thrustDeclination));
137     }
138 
139     /** {@inheritDoc} */
140     @Override
141     public Vector3D getThrustVector(final double[] parameters) {
142         // Thrust vector does not depend on spacecraft state for a constant maneuver.
143         return new Vector3D(parameters[1], parameters[2]).scalarMultiply(parameters[0]);
144     }
145 
146     /** {@inheritDoc} */
147     @Override
148     public double getFlowRate(final double[] parameters) {
149         return getThrustVector(parameters).getNorm() * massFlowRateFactor;
150     }
151 
152     /** {@inheritDoc} */
153     @Override
154     public <T extends CalculusFieldElement<T>> FieldVector3D<T> getThrustVector(final T[] parameters) {
155         return new FieldVector3D<>(parameters[1], parameters[2]).scalarMultiply(parameters[0]);
156     }
157 
158     /** {@inheritDoc} */
159     @Override
160     public <T extends CalculusFieldElement<T>> T getFlowRate(final T[] parameters) {
161         return getThrustVector(parameters).getNorm().multiply(massFlowRateFactor);
162     }
163 }