TimeSpanParametricAcceleration.java

  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.empirical;

  18. import java.util.ArrayList;
  19. import java.util.Collections;
  20. import java.util.List;

  21. import org.hipparchus.CalculusFieldElement;
  22. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  23. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  24. import org.hipparchus.util.MathArrays;
  25. import org.orekit.attitudes.AttitudeProvider;
  26. import org.orekit.propagation.FieldSpacecraftState;
  27. import org.orekit.propagation.SpacecraftState;
  28. import org.orekit.time.AbsoluteDate;
  29. import org.orekit.time.FieldAbsoluteDate;
  30. import org.orekit.utils.ParameterDriver;
  31. import org.orekit.utils.ParameterDriversProvider;
  32. import org.orekit.utils.TimeSpanMap;
  33. import org.orekit.utils.TimeSpanMap.Span;

  34. /** Time span parametric acceleration model.
  35.  *  <p>
  36.  *  This class is closely related to {@link org.orekit.forces.empirical.ParametricAcceleration ParametricAcceleration} class.<br>
  37.  *  The difference is that it has a {@link TimeSpanMap} of {@link AccelerationModel} objects as attribute
  38.  *  instead of a single {@link AccelerationModel} object. <br>
  39.  *  The idea behind this model is to allow the user to design a parametric acceleration model that can see its physical parameters
  40.  *  change with time, at dates chosen by the user. <br>
  41.  *  </p>
  42.  *  <p>
  43.  *  This is a behavior that can be sought in precise orbit determination.<br>
  44.  *  Indeed for this type of application, the empirical parameters must be revalued at
  45.  *  each new orbit.
  46.  *  </p>
  47.  *  <b>Usage</b>:<ul>
  48.  *  <li><u>Construction</u>: constructor takes an acceleration direction, an attitude mode (or an inertial flag) and
  49.  *  an AccelerationModel model.<br>
  50.  *  This last model will be your initial AccelerationModel model and it will be initially valid for the whole time line.<br>
  51.  *  The real validity of this first entry will be truncated as other AccelerationModel models are added.
  52.  *  <li><u>Time spans</u>: AccelerationModel models are added using methods {@link #addAccelerationModelValidAfter(AccelerationModel, AbsoluteDate)}
  53.  *   or {@link #addAccelerationModelValidBefore(AccelerationModel, AbsoluteDate)}.<br>
  54.  *   Recommendations are the same than the ones in {@link TimeSpanMap}, meaning: <ul>
  55.  *   <li>As an entry is added, it truncates the validity of the neighboring entries already present in the map;
  56.  *   <li><b>The transition dates should be entered only once</b>. Repeating a transition date will lead to unexpected result and is not supported;
  57.  *   <li>It is advised to order your AccelerationModel models chronologically when adding them to avoid any confusion.
  58.  *   </ul>
  59.  *   <li><u>Naming the parameter drivers</u>: It is strongly advised to give a custom name to the {@link ParameterDriver}(s)
  60.  *   of each AccelerationModel model that is added to the object. This will allow you keeping track of the evolution of your models.<br>
  61.  *   Different names are mandatory to differentiate the different drivers.<br>
  62.  *   Since there is no default name for acceleration model parameters, you must handle the driver names to consider
  63.  *   different names when adding a new acceleration model.
  64.  *   </ul>
  65.  * @author Bryan Cazabonne
  66.  * @since 10.3
  67.  */
  68. public class TimeSpanParametricAcceleration extends AbstractParametricAcceleration {

  69.     /** TimeSpanMap of AccelerationModel objects. */
  70.     private final TimeSpanMap<AccelerationModel> accelerationModelTimeSpanMap;

  71.     /** Simple constructor.
  72.      * @param direction acceleration direction in overridden spacecraft frame
  73.      * @param isInertial if true, direction is defined in the same inertial
  74.      * frame used for propagation (i.e. {@link SpacecraftState#getFrame()}),
  75.      * otherwise direction is defined in spacecraft frame (i.e. using the
  76.      * propagation {@link
  77.      * org.orekit.propagation.Propagator#setAttitudeProvider(AttitudeProvider)
  78.      * attitude law})
  79.      * @param accelerationModel acceleration model used to compute the contribution of the empirical acceleration
  80.      */
  81.     public TimeSpanParametricAcceleration(final Vector3D direction,
  82.                                           final boolean isInertial,
  83.                                           final AccelerationModel accelerationModel) {
  84.         this(direction, isInertial, null, accelerationModel);
  85.     }

  86.     /** Simple constructor.
  87.      * @param direction acceleration direction in overridden spacecraft frame
  88.      * frame used for propagation (i.e. {@link SpacecraftState#getFrame()}),
  89.      * otherwise direction is defined in spacecraft frame (i.e. using the
  90.      * propagation {@link
  91.      * org.orekit.propagation.Propagator#setAttitudeProvider(AttitudeProvider)
  92.      * attitude law})
  93.      * @param attitudeOverride provider for attitude used to compute acceleration
  94.      * @param accelerationModel acceleration model used to compute the contribution of the empirical acceleration
  95.      */
  96.     public TimeSpanParametricAcceleration(final Vector3D direction,
  97.                                           final AttitudeProvider attitudeOverride,
  98.                                           final AccelerationModel accelerationModel) {
  99.         this(direction, false, attitudeOverride, accelerationModel);
  100.     }

  101.     /** Simple constructor.
  102.      * @param direction acceleration direction in overridden spacecraft frame
  103.      * @param isInertial if true, direction is defined in the same inertial
  104.      * frame used for propagation (i.e. {@link SpacecraftState#getFrame()}),
  105.      * otherwise direction is defined in spacecraft frame (i.e. using the
  106.      * propagation {@link
  107.      * org.orekit.propagation.Propagator#setAttitudeProvider(AttitudeProvider)
  108.      * attitude law})
  109.      * @param attitudeOverride provider for attitude used to compute acceleration
  110.      * @param accelerationModel acceleration model used to compute the contribution of the empirical acceleration
  111.      */
  112.     private TimeSpanParametricAcceleration(final Vector3D direction,
  113.                                            final boolean isInertial,
  114.                                            final AttitudeProvider attitudeOverride,
  115.                                            final AccelerationModel accelerationModel) {
  116.         super(direction, isInertial, attitudeOverride);
  117.         this.accelerationModelTimeSpanMap = new TimeSpanMap<>(accelerationModel);
  118.     }

  119.     /** {@inheritDoc} */
  120.     @Override
  121.     public void init(final SpacecraftState initialState, final AbsoluteDate target) {
  122.         accelerationModelTimeSpanMap.forEach(accelerationModel -> accelerationModel.init(initialState, target));
  123.     }

  124.     /** Add an AccelerationModel entry valid before a limit date.<br>
  125.      * <p>
  126.      * Using <code>addAccelerationModelValidBefore(entry, t)</code> will make <code>entry</code>
  127.      * valid in ]-∞, t[ (note the open bracket).
  128.      * <p>
  129.      * <b>WARNING</b>: Since there is no default name for acceleration model parameters,
  130.      * the user must handle itself the driver names to consider different names
  131.      * (i.e. different parameters) when adding a new acceleration model.
  132.      * @param accelerationModel AccelerationModel entry
  133.      * @param latestValidityDate date before which the entry is valid
  134.      * (must be different from <b>all</b> dates already used for transitions)
  135.      */
  136.     public void addAccelerationModelValidBefore(final AccelerationModel accelerationModel, final AbsoluteDate latestValidityDate) {
  137.         accelerationModelTimeSpanMap.addValidBefore(accelerationModel, latestValidityDate, false);
  138.     }

  139.     /** Add a AccelerationModel entry valid after a limit date.<br>
  140.      * <p>
  141.      * Using <code>addAccelerationModelValidAfter(entry, t)</code> will make <code>entry</code>
  142.      * valid in [t, +∞[ (note the closed bracket).
  143.      * <p>
  144.      * <b>WARNING</b>: Since there is no default name for acceleration model parameters,
  145.      * the user must handle itself the driver names to consider different names
  146.      * (i.e. different parameters) when adding a new acceleration model.
  147.      * @param accelerationModel AccelerationModel entry
  148.      * @param earliestValidityDate date after which the entry is valid
  149.      * (must be different from <b>all</b> dates already used for transitions)
  150.      */
  151.     public void addAccelerationModelValidAfter(final AccelerationModel accelerationModel, final AbsoluteDate earliestValidityDate) {
  152.         accelerationModelTimeSpanMap.addValidAfter(accelerationModel, earliestValidityDate, false);
  153.     }

  154.     /** Get the {@link AccelerationModel} model valid at a date.
  155.      * @param date the date of validity
  156.      * @return the AccelerationModel model valid at date
  157.      */
  158.     public AccelerationModel getAccelerationModel(final AbsoluteDate date) {
  159.         return accelerationModelTimeSpanMap.get(date);
  160.     }

  161.     /** Get the {@link AccelerationModel} {@link Span} containing a specified date.
  162.      * @param date date belonging to the desired time span
  163.      * @return the AccelerationModel time span containing the specified date
  164.      */
  165.     public Span<AccelerationModel> getAccelerationModelSpan(final AbsoluteDate date) {
  166.         return accelerationModelTimeSpanMap.getSpan(date);
  167.     }

  168.     /** Extract a range of the {@link AccelerationModel} map.
  169.      * <p>
  170.      * The object returned will be a new independent instance that will contain
  171.      * only the transitions that lie in the specified range.
  172.      * </p>
  173.      * See the {@link TimeSpanMap#extractRange TimeSpanMap.extractRange method} for more.
  174.      * @param start earliest date at which a transition is included in the range
  175.      * (may be set to {@link AbsoluteDate#PAST_INFINITY} to keep all early transitions)
  176.      * @param end latest date at which a transition is included in the r
  177.      * (may be set to {@link AbsoluteDate#FUTURE_INFINITY} to keep all late transitions)
  178.      * @return a new TimeSpanMap instance of AccelerationModel with all transitions restricted to the specified range
  179.      */
  180.     public TimeSpanMap<AccelerationModel> extractAccelerationModelRange(final AbsoluteDate start, final AbsoluteDate end) {
  181.         return accelerationModelTimeSpanMap.extractRange(start, end);
  182.     }

  183.     /** Get the first {@link Span time span} of the acceleration model time span map.
  184.      * @return the first {@link Span time span} of the acceleration model time span map
  185.      * @since 11.1
  186.      */
  187.     public Span<AccelerationModel> getFirstSpan() {
  188.         return accelerationModelTimeSpanMap.getFirstSpan();
  189.     }

  190.     /** {@inheritDoc} */
  191.     @Override
  192.     public Vector3D acceleration(final SpacecraftState state,
  193.                                  final double[] parameters) {

  194.         // Date
  195.         final AbsoluteDate date = state.getDate();

  196.         // Compute inertial direction
  197.         final Vector3D inertialDirection = getAccelerationDirection(state);

  198.         // Extract the proper parameters valid at date from the input array
  199.         final double[] extractedParameters = extractParameters(parameters, date);

  200.         // Compute and return the parametric acceleration
  201.         return new Vector3D(getAccelerationModel(date).signedAmplitude(state, extractedParameters), inertialDirection);

  202.     }

  203.     /** {@inheritDoc} */
  204.     @Override
  205.     public <T extends CalculusFieldElement<T>> FieldVector3D<T> acceleration(final FieldSpacecraftState<T> state,
  206.                                                                          final T[] parameters) {

  207.         // Date
  208.         final FieldAbsoluteDate<T> date = state.getDate();

  209.         // Compute inertial direction
  210.         final FieldVector3D<T> inertialDirection = getAccelerationDirection(state);

  211.         // Extract the proper parameters valid at date from the input array
  212.         final T[] extractedParameters = extractParameters(parameters, date);

  213.         // Compute and return the parametric acceleration
  214.         return new FieldVector3D<>(getAccelerationModel(date.toAbsoluteDate()).signedAmplitude(state, extractedParameters), inertialDirection);

  215.     }

  216.     /** {@inheritDoc}
  217.      * <p>
  218.      * All the parameter drivers of all AccelerationModel models are returned in an array.
  219.      * Models are ordered chronologically.
  220.      * </p>
  221.      */
  222.     @Override
  223.     public List<ParameterDriver> getParametersDrivers() {

  224.         // Get all transitions from the TimeSpanMap
  225.         final List<ParameterDriver> listParameterDrivers = new ArrayList<>();

  226.         // Loop on the spans
  227.         for (Span<AccelerationModel> span = getFirstSpan(); span != null; span = span.next()) {
  228.             // Add all the parameter drivers of the time span
  229.             for (ParameterDriver driver : span.getData().getParametersDrivers()) {
  230.                 // Add the driver only if the name does not exist already
  231.                 if (!ParameterDriversProvider.findByName(listParameterDrivers, driver.getName())) {
  232.                     listParameterDrivers.add(driver);
  233.                 }
  234.             }
  235.         }

  236.         // Return an array of parameter drivers with no duplicated name
  237.         return Collections.unmodifiableList(listParameterDrivers);

  238.     }

  239.     /** Extract the proper parameter drivers' values from the array in input of the
  240.      * {@link #acceleration(SpacecraftState, double[]) acceleration} method.
  241.      *  Parameters are filtered given an input date.
  242.      * @param parameters the input parameters array
  243.      * @param date the date
  244.      * @return the parameters given the date
  245.      */
  246.     public double[] extractParameters(final double[] parameters, final AbsoluteDate date) {

  247.         // Get the acceleration model parameter drivers of the date
  248.         final List<ParameterDriver> empiricalParameterDriver = getAccelerationModel(date).getParametersDrivers();

  249.         // Find out the indexes of the parameters in the whole array of parameters
  250.         final List<ParameterDriver> allParameters = getParametersDrivers();
  251.         final double[] outParameters = new double[empiricalParameterDriver.size()];
  252.         int index = 0;
  253.         for (int i = 0; i < allParameters.size(); i++) {
  254.             final String driverName = allParameters.get(i).getName();
  255.             for (ParameterDriver accDriver : empiricalParameterDriver) {
  256.                 if (accDriver.getName().equals(driverName)) {
  257.                     outParameters[index++] = parameters[i];
  258.                 }
  259.             }
  260.         }
  261.         return outParameters;
  262.     }

  263.     /** Extract the proper parameter drivers' values from the array in input of the
  264.      * {@link #acceleration(FieldSpacecraftState, CalculusFieldElement[]) acceleration} method.
  265.      *  Parameters are filtered given an input date.
  266.      * @param parameters the input parameters array
  267.      * @param date the date
  268.      * @param <T> extends CalculusFieldElement
  269.      * @return the parameters given the date
  270.      */
  271.     public <T extends CalculusFieldElement<T>> T[] extractParameters(final T[] parameters,
  272.                                                                  final FieldAbsoluteDate<T> date) {

  273.         // Get the acceleration parameter drivers of the date
  274.         final List<ParameterDriver> empiricalParameterDriver = getAccelerationModel(date.toAbsoluteDate()).getParametersDrivers();

  275.         // Find out the indexes of the parameters in the whole array of parameters
  276.         final List<ParameterDriver> allParameters = getParametersDrivers();
  277.         final T[] outParameters = MathArrays.buildArray(date.getField(), empiricalParameterDriver.size());
  278.         int index = 0;
  279.         for (int i = 0; i < allParameters.size(); i++) {
  280.             final String driverName = allParameters.get(i).getName();
  281.             for (ParameterDriver accDriver : empiricalParameterDriver) {
  282.                 if (accDriver.getName().equals(driverName)) {
  283.                     outParameters[index++] = parameters[i];
  284.                 }
  285.             }
  286.         }
  287.         return outParameters;
  288.     }

  289. }