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