1   /* Copyright 2020 Exotrail
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    * Exotrail 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.maneuvers.propulsion;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.geometry.euclidean.threed.Rotation;
21  import org.hipparchus.geometry.euclidean.threed.Vector3D;
22  import org.orekit.attitudes.Attitude;
23  import org.orekit.attitudes.AttitudeProvider;
24  import org.orekit.attitudes.FieldAttitude;
25  import org.orekit.errors.OrekitException;
26  import org.orekit.errors.OrekitMessages;
27  import org.orekit.frames.Frame;
28  import org.orekit.frames.LOF;
29  import org.orekit.time.AbsoluteDate;
30  import org.orekit.time.FieldAbsoluteDate;
31  import org.orekit.utils.FieldPVCoordinatesProvider;
32  import org.orekit.utils.PVCoordinatesProvider;
33  
34  /**
35   * This class is used in to both manage the attitude of the satellite and the
36   * direction of thrust.
37   *<p>
38   * It is used in ConfigurableLowThrustManeuver to set the spacecraft attitude
39   * according to the expected thrust direction.
40   *<p>
41   * The direction can be variable or fixed, defined in the spaceraft frame, a
42   * Local Orbital Frame or a user frame.
43   *<p>
44   * It is also possible to use an external attitude provider.
45   *
46   * @author Mikael Fillastre
47   * @author Andrea Fiorentino
48   * @since 10.2
49   */
50  public class ThrustDirectionAndAttitudeProvider implements AttitudeProvider {
51  
52      /** Field name for error message. */
53      private static final String FIELD_NAME_VARIABLE_DIRECTION = "variableDirectionInFrame";
54  
55      /** Field name for error message. */
56      private static final String FIELD_NAME_DIRECTION_FRAME = "thrustDirectionFrame";
57  
58      /** Field name for error message. */
59      private static final String FIELD_NAME_LOF_TYPE = "thrustDirectionLof";
60  
61      /** Types, see builders for details. */
62      private enum ThrustDirectionAndAttitudeProviderType {
63          /** SATELLITE_ATTITUDE. */
64          SATELLITE_ATTITUDE,
65          /** CUSTOM_ATTITUDE. */
66          CUSTOM_ATTITUDE,
67          /** DIRECTION_IN_LOF. */
68          DIRECTION_IN_LOF,
69          /** DIRECTION_IN_FRAME. */
70          DIRECTION_IN_FRAME
71      }
72  
73      /** Type. */
74      private final ThrustDirectionAndAttitudeProviderType type;
75  
76      /**
77       * External attitude provider, for CUSTOM_ATTITUDE type. Set to null otherwise.
78       */
79      private final AttitudeProvider attitudeProvider;
80  
81      /**
82       * Direction provider, for DIRECTION_IN_LOF and DIRECTION_IN_FRAME types. Set to
83       * null otherwise.
84       */
85      private final ThrustDirectionProvider variableDirectionInFrame;
86  
87      /** Thruster axis in satellite frame. */
88      private final Vector3D thrusterAxisInSatelliteFrame;
89  
90      /**
91       * Reference frame for thrust direction, for DIRECTION_IN_FRAME type. Set to
92       * null otherwise.
93       */
94      private final Frame thrustDirectionFrame;
95  
96      /**
97       * Local Orbital Frame, for DIRECTION_IN_LOF local orbital frame. Set to null otherwise.
98       */
99      private final LOF thrustDirectionLof;
100 
101     /**
102      * Internal constructor.
103      * @param type                         Type
104      * @param attitudeProvider             External attitude provider, for
105      *                                     CUSTOM_ATTITUDE type. Set to null
106      *                                     otherwise
107      * @param variableDirectionInFrame     Direction provider, for DIRECTION_IN_LOF
108      *                                     and DIRECTION_IN_FRAME types. Set to null
109      *                                     otherwise.
110      * @param thrusterAxisInSatelliteFrame Thruster axis in satellite frame
111      * @param frame                        Reference frame for thrust direction
112      * @param thrustDirectionLof           Local Orbital Frame, for DIRECTION_IN_LOF local orbital frame
113      *                                     (set to null otherwise)
114      */
115     private ThrustDirectionAndAttitudeProvider(final ThrustDirectionAndAttitudeProviderType type,
116             final AttitudeProvider attitudeProvider, final ThrustDirectionProvider variableDirectionInFrame,
117             final Vector3D thrusterAxisInSatelliteFrame, final Frame frame, final LOF thrustDirectionLof) {
118         this.type = type;
119         this.attitudeProvider = attitudeProvider;
120         this.variableDirectionInFrame = variableDirectionInFrame;
121         this.thrustDirectionFrame = frame;
122         this.thrustDirectionLof = thrustDirectionLof;
123         this.thrusterAxisInSatelliteFrame = thrusterAxisInSatelliteFrame;
124     }
125 
126     /**
127      * Throw an error if a mandatory parameter is not set.
128      * @param parameter value
129      * @param name      name of the parameter (for user message)
130      * @param type      type to add details to user
131      */
132     private static void checkParameterNotNull(final Object parameter, final String name,
133             final ThrustDirectionAndAttitudeProviderType type) {
134         if (parameter == null) {
135             throw new OrekitException(OrekitMessages.PARAMETER_NOT_SET, name,
136                     "ThrustDirectionAndAttitudeProvider-" + type.toString());
137         }
138     }
139 
140     /**
141      * Build a ThrustDirectionAndAttitudeProvider from a fixed direction in the
142      * satellite frame. The satellite attitude won't be managed by this object
143      *
144      * @param direction constant direction in the satellite frame
145      * @return a new instance
146      */
147     public static ThrustDirectionAndAttitudeProvider buildFromFixedDirectionInSatelliteFrame(final Vector3D direction) {
148         final ThrustDirectionAndAttitudeProvider obj = new ThrustDirectionAndAttitudeProvider(
149                 ThrustDirectionAndAttitudeProviderType.SATELLITE_ATTITUDE, null, null, direction, null, null);
150         checkParameterNotNull(direction, "thrusterAxisInSatelliteFrame", obj.type);
151         return obj;
152     }
153 
154     /**
155      * Build a ThrustDirectionAndAttitudeProvider where the attitude is provided by
156      * an external. Object the direction of thrust will be constant
157      *
158      * @param attitudeProvider the object that provide the satellite attitude
159      * @param direction        thruster axis in satellite frame
160      * @return a new instance
161      */
162     public static ThrustDirectionAndAttitudeProvider buildFromCustomAttitude(final AttitudeProvider attitudeProvider,
163             final Vector3D direction) {
164         final ThrustDirectionAndAttitudeProvider obj = new ThrustDirectionAndAttitudeProvider(
165                 ThrustDirectionAndAttitudeProviderType.CUSTOM_ATTITUDE, attitudeProvider, null, direction, null, null);
166         checkParameterNotNull(attitudeProvider, "attitudeProvider", obj.type);
167         checkParameterNotNull(direction, "direction", obj.type);
168         return obj;
169     }
170 
171     /**
172      * Build a ThrustDirectionAndAttitudeProvider by a variable direction in a
173      * custom frame.
174      *
175      * @param thrustDirectionFrame         reference frame for thrust direction
176      * @param variableDirectionInFrame     the object providing the thrust direction
177      * @param thrusterAxisInSatelliteFrame thruster axis in satellite frame
178      * @return a new instance
179      */
180     public static ThrustDirectionAndAttitudeProvider buildFromDirectionInFrame(final Frame thrustDirectionFrame,
181             final ThrustDirectionProvider variableDirectionInFrame, final Vector3D thrusterAxisInSatelliteFrame) {
182         final ThrustDirectionAndAttitudeProvider obj = new ThrustDirectionAndAttitudeProvider(
183                 ThrustDirectionAndAttitudeProviderType.DIRECTION_IN_FRAME, null, variableDirectionInFrame,
184                 thrusterAxisInSatelliteFrame, thrustDirectionFrame, null);
185         checkParameterNotNull(variableDirectionInFrame, FIELD_NAME_VARIABLE_DIRECTION, obj.type);
186         checkParameterNotNull(thrustDirectionFrame, FIELD_NAME_DIRECTION_FRAME, obj.type);
187         return obj;
188     }
189 
190     /**
191      * Build a ThrustDirectionAndAttitudeProvider by a variable direction in a Local
192      * Orbital Frame.
193      *
194      * @param thrustDirectionLof           local orbital frame
195      * @param variableDirectionInFrame     the object providing the thrust direction
196      * @param thrusterAxisInSatelliteFrame thruster axis in satellite frame
197      * @return a new instance
198      */
199     public static ThrustDirectionAndAttitudeProvider buildFromDirectionInLOF(final LOF thrustDirectionLof,
200             final ThrustDirectionProvider variableDirectionInFrame, final Vector3D thrusterAxisInSatelliteFrame) {
201         final ThrustDirectionAndAttitudeProvider obj = new ThrustDirectionAndAttitudeProvider(
202                 ThrustDirectionAndAttitudeProviderType.DIRECTION_IN_LOF, null, variableDirectionInFrame,
203                 thrusterAxisInSatelliteFrame, null, thrustDirectionLof);
204         checkParameterNotNull(variableDirectionInFrame, FIELD_NAME_VARIABLE_DIRECTION, obj.type);
205         checkParameterNotNull(thrustDirectionLof, FIELD_NAME_LOF_TYPE, obj.type);
206         return obj;
207     }
208 
209     /**
210      * Thruster axis in satellite frame.
211      * @return field
212      */
213     public Vector3D getThrusterAxisInSatelliteFrame() {
214         return thrusterAxisInSatelliteFrame;
215     }
216 
217     /** {@inheritDoc} */
218     @Override
219     public Attitude getAttitude(final PVCoordinatesProvider pvProv, final AbsoluteDate date, final Frame frame) {
220         switch (type) {
221             case CUSTOM_ATTITUDE:
222                 return attitudeProvider.getAttitude(pvProv, date, frame);
223             case DIRECTION_IN_FRAME:
224             case DIRECTION_IN_LOF:
225                 return getAttitudeFromFrame(pvProv, date, frame);
226             default:
227                 throw new OrekitException(OrekitMessages.INVALID_TYPE_FOR_FUNCTION,
228                         "ThrustDirectionAndAttitudeProvider.getAttitude", "type", type.toString());
229         }
230     }
231 
232     /** {@inheritDoc} */
233     @Override
234     public <T extends CalculusFieldElement<T>> FieldAttitude<T> getAttitude(final FieldPVCoordinatesProvider<T> pvProv,
235             final FieldAbsoluteDate<T> date, final Frame frame) {
236         throw new OrekitException(OrekitMessages.FUNCTION_NOT_IMPLEMENTED,
237                 "ThrustDirectionAndAttitudeProvider with CalculusFieldElement");
238     }
239 
240     /**
241      * Compute the attitude for DIRECTION_IN_FRAME or DIRECTION_IN_LOF types.
242      * @param pvProv local position-velocity provider around current date
243      * @param date   current date
244      * @param frame  reference frame from which attitude is computed
245      * @return attitude attitude on the specified date and position-velocity state
246      */
247     protected Attitude getAttitudeFromFrame(final PVCoordinatesProvider pvProv, final AbsoluteDate date,
248             final Frame frame) {
249 
250         final Rotation inertial2ThrusterFrame;
251         if (type.equals(ThrustDirectionAndAttitudeProviderType.DIRECTION_IN_FRAME)) {
252             inertial2ThrusterFrame = frame.getStaticTransformTo(thrustDirectionFrame, date).getRotation();
253         } else { // LOF
254             inertial2ThrusterFrame = thrustDirectionLof.rotationFromInertial(date, pvProv.getPVCoordinates(date, frame));
255         }
256 
257         final Vector3D thrustDirection = variableDirectionInFrame.computeThrustDirection(pvProv, date, frame);
258         final Vector3D thrustDirectionInertial = inertial2ThrusterFrame.applyInverseTo(thrustDirection);
259 
260         final Rotation attitude = new Rotation(getThrusterAxisInSatelliteFrame(), thrustDirectionInertial);
261         final Attitude att = new Attitude(date, frame, attitude.revert(), Vector3D.ZERO, Vector3D.ZERO);
262 
263         return att;
264     }
265 
266     /**
267      * Attitude provider to use.
268      * @return null in mode SATELLITE_ATTITUDE
269      */
270     public AttitudeProvider getManeuverAttitudeProvider() {
271         AttitudeProvider attitudeProviderToReturn = null;
272         if (type != ThrustDirectionAndAttitudeProviderType.SATELLITE_ATTITUDE) {
273             attitudeProviderToReturn = this;
274         } // else default behavior
275         return attitudeProviderToReturn;
276     }
277 
278 }