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