1   /* Copyright 2002-2021 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.inertia;
18  
19  import java.util.Collections;
20  import java.util.List;
21  import java.util.stream.Stream;
22  
23  import org.hipparchus.Field;
24  import org.hipparchus.CalculusFieldElement;
25  import org.hipparchus.geometry.euclidean.threed.FieldRotation;
26  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
27  import org.hipparchus.geometry.euclidean.threed.Rotation;
28  import org.hipparchus.geometry.euclidean.threed.Vector3D;
29  import org.orekit.errors.OrekitException;
30  import org.orekit.errors.OrekitIllegalArgumentException;
31  import org.orekit.errors.OrekitMessages;
32  import org.orekit.forces.AbstractForceModel;
33  import org.orekit.frames.FieldTransform;
34  import org.orekit.frames.Frame;
35  import org.orekit.frames.Transform;
36  import org.orekit.propagation.FieldSpacecraftState;
37  import org.orekit.propagation.SpacecraftState;
38  import org.orekit.propagation.events.EventDetector;
39  import org.orekit.propagation.events.FieldEventDetector;
40  import org.orekit.utils.AbsolutePVCoordinates;
41  import org.orekit.utils.ParameterDriver;
42  
43  /** Inertial force model.
44   * <p>
45   * This force model adds the pseudo-forces due to inertia between the
46   * integrating frame and a reference inertial frame from which
47   * this force model is built.
48   * </p>
49   * <p>
50   * Two typical use-cases are propagating {@link AbsolutePVCoordinates} in either:
51   * </p>
52   * <ul>
53   *   <li>a non-inertial frame (for example propagating in the rotating {@link
54   *       org.orekit.frames.FramesFactory#getITRF(org.orekit.utils.IERSConventions, boolean) ITRF}
55   *       frame),</li>
56   *   <li>an inertial frame that is not related to the main attracting body (for example
57   *       propagating in {@link org.orekit.frames.FramesFactory#getEME2000() EME2000} frame a
58   *       trajectory about the Sun and Jupiter).</li>
59   * </ul>
60   * <p>
61   * In the second used case above, the attraction from the two main bodies, i.e. the Sun and
62   * Jupiter, should be represented by {@link org.orekit.forces.gravity.SingleBodyAbsoluteAttraction}
63   * instances.
64   * </p>
65   * @see org.orekit.forces.gravity.SingleBodyAbsoluteAttraction
66   * @author Guillaume Obrecht
67   * @author Luc Maisonobe
68   */
69  public class InertialForces extends AbstractForceModel  {
70  
71      /** Reference inertial frame to use to compute inertial forces. */
72      private Frame referenceInertialFrame;
73  
74      /** Simple constructor.
75       * @param referenceInertialFrame the pseudo-inertial frame to use as reference for the inertial forces
76       * @exception OrekitIllegalArgumentException if frame is not a {@link
77       * Frame#isPseudoInertial pseudo-inertial frame}
78       */
79      public InertialForces(final Frame referenceInertialFrame)
80          throws OrekitIllegalArgumentException {
81          if (!referenceInertialFrame.isPseudoInertial()) {
82              throw new OrekitIllegalArgumentException(OrekitMessages.NON_PSEUDO_INERTIAL_FRAME_NOT_SUITABLE_AS_REFERENCE_FOR_INERTIAL_FORCES,
83                                                       referenceInertialFrame.getName());
84          }
85          this.referenceInertialFrame = referenceInertialFrame;
86      }
87  
88      /** {@inheritDoc} */
89      @Override
90      public boolean dependsOnPositionOnly() {
91          return false;
92      }
93  
94      /** {@inheritDoc} */
95      @Override
96      public Vector3D acceleration(final SpacecraftState s, final double[] parameters) {
97  
98          final Transform inertToStateFrame = referenceInertialFrame.getTransformTo(s.getFrame(), s.getDate());
99          final Vector3D  a1                = inertToStateFrame.getCartesian().getAcceleration();
100         final Rotation  r1                = inertToStateFrame.getAngular().getRotation();
101         final Vector3D  o1                = inertToStateFrame.getAngular().getRotationRate();
102         final Vector3D  oDot1             = inertToStateFrame.getAngular().getRotationAcceleration();
103 
104         final Vector3D  p2                = s.getPVCoordinates().getPosition();
105         final Vector3D  v2                = s.getPVCoordinates().getVelocity();
106 
107         final Vector3D crossCrossP        = Vector3D.crossProduct(o1,    Vector3D.crossProduct(o1, p2));
108         final Vector3D crossV             = Vector3D.crossProduct(o1,    v2);
109         final Vector3D crossDotP          = Vector3D.crossProduct(oDot1, p2);
110 
111         // we intentionally DON'T include s.getPVCoordinates().getAcceleration()
112         // because we want only the coupling effect of the frames transforms
113         return r1.applyTo(a1).subtract(new Vector3D(2, crossV, 1, crossCrossP, 1, crossDotP));
114 
115     }
116 
117     /** {@inheritDoc} */
118     @Override
119     public <T extends CalculusFieldElement<T>> FieldVector3D<T> acceleration(final FieldSpacecraftState<T> s,
120                                                                          final T[] parameters) {
121 
122         final FieldTransform<T> inertToStateFrame = referenceInertialFrame.getTransformTo(s.getFrame(), s.getDate());
123         final FieldVector3D<T>  a1                = inertToStateFrame.getCartesian().getAcceleration();
124         final FieldRotation<T>  r1                = inertToStateFrame.getAngular().getRotation();
125         final FieldVector3D<T>  o1                = inertToStateFrame.getAngular().getRotationRate();
126         final FieldVector3D<T>  oDot1             = inertToStateFrame.getAngular().getRotationAcceleration();
127 
128         final FieldVector3D<T>  p2                = s.getPVCoordinates().getPosition();
129         final FieldVector3D<T>  v2                = s.getPVCoordinates().getVelocity();
130 
131         final FieldVector3D<T> crossCrossP        = FieldVector3D.crossProduct(o1,    FieldVector3D.crossProduct(o1, p2));
132         final FieldVector3D<T> crossV             = FieldVector3D.crossProduct(o1,    v2);
133         final FieldVector3D<T> crossDotP          = FieldVector3D.crossProduct(oDot1, p2);
134 
135         // we intentionally DON'T include s.getPVCoordinates().getAcceleration()
136         // because we want only the coupling effect of the frames transforms
137         return r1.applyTo(a1).subtract(new FieldVector3D<>(2, crossV, 1, crossCrossP, 1, crossDotP));
138 
139     }
140 
141     /** {@inheritDoc} */
142     @Override
143     public Stream<EventDetector> getEventsDetectors() {
144         return Stream.empty();
145     }
146 
147     /** {@inheritDoc} */
148     @Override
149     public <T extends CalculusFieldElement<T>> Stream<FieldEventDetector<T>>
150         getFieldEventsDetectors(final Field<T> field) {
151         return Stream.empty();
152     }
153 
154     /** {@inheritDoc} */
155     @Override
156     public List<ParameterDriver> getParametersDrivers() {
157         return Collections.emptyList();
158     }
159 
160     /** {@inheritDoc} */
161     @Override
162     public ParameterDriver getParameterDriver(final String name) {
163         throw new OrekitException(OrekitMessages.UNSUPPORTED_PARAMETER_NAME, "<none>");
164     }
165 
166 }