AbstractPropagatorBuilder.java

  1. /* Copyright 2002-2024 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.propagation.conversion;

  18. import org.hipparchus.exception.LocalizedCoreFormats;
  19. import org.hipparchus.util.FastMath;
  20. import org.orekit.attitudes.AttitudeProvider;
  21. import org.orekit.attitudes.FrameAlignedProvider;
  22. import org.orekit.errors.OrekitException;
  23. import org.orekit.errors.OrekitIllegalArgumentException;
  24. import org.orekit.errors.OrekitMessages;
  25. import org.orekit.forces.gravity.NewtonianAttraction;
  26. import org.orekit.frames.Frame;
  27. import org.orekit.orbits.Orbit;
  28. import org.orekit.orbits.OrbitType;
  29. import org.orekit.orbits.PositionAngleType;
  30. import org.orekit.propagation.Propagator;
  31. import org.orekit.propagation.integration.AdditionalDerivativesProvider;
  32. import org.orekit.time.AbsoluteDate;
  33. import org.orekit.utils.ParameterDriver;
  34. import org.orekit.utils.ParameterDriversList;
  35. import org.orekit.utils.ParameterDriversList.DelegatingDriver;
  36. import org.orekit.utils.ParameterObserver;
  37. import org.orekit.utils.TimeSpanMap;
  38. import org.orekit.utils.TimeSpanMap.Span;

  39. import java.util.ArrayList;
  40. import java.util.List;

  41. /** Base class for propagator builders.
  42.  * @author Pascal Parraud
  43.  * @since 7.1
  44.  */
  45. public abstract class AbstractPropagatorBuilder implements PropagatorBuilder {

  46.     /** Central attraction scaling factor.
  47.      * <p>
  48.      * We use a power of 2 to avoid numeric noise introduction
  49.      * in the multiplications/divisions sequences.
  50.      * </p>
  51.      */
  52.     private static final double MU_SCALE = FastMath.scalb(1.0, 32);

  53.     /** Date of the initial orbit. */
  54.     private AbsoluteDate initialOrbitDate;

  55.     /** Frame in which the orbit is propagated. */
  56.     private final Frame frame;

  57.     /** Central attraction coefficient (m³/s²). */
  58.     private double mu;

  59.     /** Initial mass. */
  60.     private double mass;

  61.     /** Drivers for orbital parameters. */
  62.     private final ParameterDriversList orbitalDrivers;

  63.     /** List of the supported parameters. */
  64.     private ParameterDriversList propagationDrivers;

  65.     /** Orbit type to use. */
  66.     private final OrbitType orbitType;

  67.     /** Position angle type to use. */
  68.     private final PositionAngleType positionAngleType;

  69.     /** Position scale to use for the orbital drivers. */
  70.     private final double positionScale;

  71.     /** Attitude provider for the propagator. */
  72.     private AttitudeProvider attitudeProvider;

  73.     /** Additional derivatives providers.
  74.      * @since 11.1
  75.      */
  76.     private List<AdditionalDerivativesProvider> additionalDerivativesProviders;

  77.     /** Build a new instance.
  78.      * <p>
  79.      * The template orbit is used as a model to {@link
  80.      * #createInitialOrbit() create initial orbit}. It defines the
  81.      * inertial frame, the central attraction coefficient, the orbit type, and is also
  82.      * used together with the {@code positionScale} to convert from the {@link
  83.      * ParameterDriver#setNormalizedValue(double) normalized} parameters used by the
  84.      * callers of this builder to the real orbital parameters. The default attitude
  85.      * provider is aligned with the orbit's inertial frame.
  86.      * </p>
  87.      * <p>
  88.      * By default, all the {@link #getOrbitalParametersDrivers() orbital parameters drivers}
  89.      * are selected, which means that if the builder is used for orbit determination or
  90.      * propagator conversion, all orbital parameters will be estimated. If only a subset
  91.      * of the orbital parameters must be estimated, caller must retrieve the orbital
  92.      * parameters by calling {@link #getOrbitalParametersDrivers()} and then call
  93.      * {@link ParameterDriver#setSelected(boolean) setSelected(false)}.
  94.      * </p>
  95.      * @param templateOrbit reference orbit from which real orbits will be built
  96.      * @param positionAngleType position angle type to use
  97.      * @param positionScale scaling factor used for orbital parameters normalization
  98.      * (typically set to the expected standard deviation of the position)
  99.      * @param addDriverForCentralAttraction if true, a {@link ParameterDriver} should
  100.      * be set up for central attraction coefficient
  101.      * @since 8.0
  102.      * @see #AbstractPropagatorBuilder(Orbit, PositionAngleType, double, boolean,
  103.      * AttitudeProvider)
  104.      */
  105.     protected AbstractPropagatorBuilder(final Orbit templateOrbit, final PositionAngleType positionAngleType,
  106.                                         final double positionScale, final boolean addDriverForCentralAttraction) {
  107.         this(templateOrbit, positionAngleType, positionScale, addDriverForCentralAttraction,
  108.              new FrameAlignedProvider(templateOrbit.getFrame()), Propagator.DEFAULT_MASS);
  109.     }
  110.     /** Build a new instance.
  111.      * <p>
  112.      * The template orbit is used as a model to {@link
  113.      * #createInitialOrbit() create initial orbit}. It defines the
  114.      * inertial frame, the central attraction coefficient, the orbit type, and is also
  115.      * used together with the {@code positionScale} to convert from the {@link
  116.      * ParameterDriver#setNormalizedValue(double) normalized} parameters used by the
  117.      * callers of this builder to the real orbital parameters.
  118.      * </p>
  119.      * <p>
  120.      * By default, all the {@link #getOrbitalParametersDrivers() orbital parameters drivers}
  121.      * are selected, which means that if the builder is used for orbit determination or
  122.      * propagator conversion, all orbital parameters will be estimated. If only a subset
  123.      * of the orbital parameters must be estimated, caller must retrieve the orbital
  124.      * parameters by calling {@link #getOrbitalParametersDrivers()} and then call
  125.      * {@link ParameterDriver#setSelected(boolean) setSelected(false)}.
  126.      * </p>
  127.      * @param templateOrbit reference orbit from which real orbits will be built
  128.      * @param positionAngleType position angle type to use
  129.      * @param positionScale scaling factor used for orbital parameters normalization
  130.      * (typically set to the expected standard deviation of the position)
  131.      * @param addDriverForCentralAttraction if true, a {@link ParameterDriver} should
  132.      * be set up for central attraction coefficient
  133.      * @param attitudeProvider for the propagator.
  134.      * @since 10.1
  135.      * @see #AbstractPropagatorBuilder(Orbit, PositionAngleType, double, boolean)
  136.      */
  137.     protected AbstractPropagatorBuilder(final Orbit templateOrbit,
  138.                                         final PositionAngleType positionAngleType,
  139.                                         final double positionScale,
  140.                                         final boolean addDriverForCentralAttraction,
  141.                                         final AttitudeProvider attitudeProvider) {
  142.         this(templateOrbit, positionAngleType, positionScale, addDriverForCentralAttraction, attitudeProvider,
  143.                 Propagator.DEFAULT_MASS);
  144.     }

  145.     /** Build a new instance.
  146.      * <p>
  147.      * The template orbit is used as a model to {@link
  148.      * #createInitialOrbit() create initial orbit}. It defines the
  149.      * inertial frame, the central attraction coefficient, the orbit type, and is also
  150.      * used together with the {@code positionScale} to convert from the {@link
  151.      * ParameterDriver#setNormalizedValue(double) normalized} parameters used by the
  152.      * callers of this builder to the real orbital parameters.
  153.      * </p>
  154.      * <p>
  155.      * By default, all the {@link #getOrbitalParametersDrivers() orbital parameters drivers}
  156.      * are selected, which means that if the builder is used for orbit determination or
  157.      * propagator conversion, all orbital parameters will be estimated. If only a subset
  158.      * of the orbital parameters must be estimated, caller must retrieve the orbital
  159.      * parameters by calling {@link #getOrbitalParametersDrivers()} and then call
  160.      * {@link ParameterDriver#setSelected(boolean) setSelected(false)}.
  161.      * </p>
  162.      * @param templateOrbit reference orbit from which real orbits will be built
  163.      * @param positionAngleType position angle type to use
  164.      * @param positionScale scaling factor used for orbital parameters normalization
  165.      * (typically set to the expected standard deviation of the position)
  166.      * @param addDriverForCentralAttraction if true, a {@link ParameterDriver} should
  167.      * be set up for central attraction coefficient
  168.      * @param attitudeProvider for the propagator.
  169.      * @param initialMass mass
  170.      * @since 12.2
  171.      * @see #AbstractPropagatorBuilder(Orbit, PositionAngleType, double, boolean)
  172.      */
  173.     protected AbstractPropagatorBuilder(final Orbit templateOrbit,
  174.                                         final PositionAngleType positionAngleType,
  175.                                         final double positionScale,
  176.                                         final boolean addDriverForCentralAttraction,
  177.                                         final AttitudeProvider attitudeProvider, final double initialMass) {

  178.         this.initialOrbitDate    = templateOrbit.getDate();
  179.         this.frame               = templateOrbit.getFrame();
  180.         this.mu                  = templateOrbit.getMu();
  181.         this.propagationDrivers  = new ParameterDriversList();
  182.         this.orbitType           = templateOrbit.getType();
  183.         this.positionAngleType = positionAngleType;
  184.         this.positionScale       = positionScale;
  185.         this.orbitalDrivers      = orbitType.getDrivers(positionScale, templateOrbit, positionAngleType);
  186.         this.attitudeProvider = attitudeProvider;
  187.         this.mass         = initialMass;
  188.         for (final DelegatingDriver driver : orbitalDrivers.getDrivers()) {
  189.             driver.setSelected(true);
  190.         }

  191.         this.additionalDerivativesProviders  = new ArrayList<>();

  192.         if (addDriverForCentralAttraction) {
  193.             final ParameterDriver muDriver = new ParameterDriver(NewtonianAttraction.CENTRAL_ATTRACTION_COEFFICIENT,
  194.                                                                  mu, MU_SCALE, 0, Double.POSITIVE_INFINITY);
  195.             muDriver.addObserver(new ParameterObserver() {
  196.                 /** {@inheridDoc} */
  197.                 @Override
  198.                 public void valueChanged(final double previousValue, final ParameterDriver driver, final AbsoluteDate date) {
  199.                     // getValue(), can be called without argument as mu driver should have only one span
  200.                     AbstractPropagatorBuilder.this.mu = driver.getValue();
  201.                 }

  202.                 @Override
  203.                 public void valueSpanMapChanged(final TimeSpanMap<Double> previousValueSpanMap, final ParameterDriver driver) {
  204.                     // getValue(), can be called without argument as mu driver should have only one span
  205.                     AbstractPropagatorBuilder.this.mu = driver.getValue();
  206.                 }
  207.             });
  208.             propagationDrivers.add(muDriver);
  209.         }

  210.     }

  211.     /** Get the mass.
  212.      * @return the mass
  213.      * @since 9.2
  214.      */
  215.     public double getMass()
  216.     {
  217.         return mass;
  218.     }

  219.     /** Set the initial mass.
  220.      * @param mass the mass (kg)
  221.      */
  222.     public void setMass(final double mass) {
  223.         this.mass = mass;
  224.     }

  225.     /** {@inheritDoc} */
  226.     public OrbitType getOrbitType() {
  227.         return orbitType;
  228.     }

  229.     /** {@inheritDoc} */
  230.     public PositionAngleType getPositionAngleType() {
  231.         return positionAngleType;
  232.     }

  233.     /** {@inheritDoc} */
  234.     public AbsoluteDate getInitialOrbitDate() {
  235.         return initialOrbitDate;
  236.     }

  237.     /** {@inheritDoc} */
  238.     public Frame getFrame() {
  239.         return frame;
  240.     }

  241.     /** {@inheritDoc} */
  242.     public ParameterDriversList getOrbitalParametersDrivers() {
  243.         return orbitalDrivers;
  244.     }

  245.     /** {@inheritDoc} */
  246.     public ParameterDriversList getPropagationParametersDrivers() {
  247.         return propagationDrivers;
  248.     }

  249.     @Override
  250.     public AbstractPropagatorBuilder clone() {
  251.         try {
  252.             return (AbstractPropagatorBuilder) super.clone();
  253.         } catch (CloneNotSupportedException cnse) {
  254.             throw new OrekitException(OrekitMessages.PROPAGATOR_BUILDER_NOT_CLONEABLE);
  255.         }
  256.     }

  257.     /**
  258.      * Get the attitude provider.
  259.      *
  260.      * @return the attitude provider
  261.      * @since 10.1
  262.      */
  263.     public AttitudeProvider getAttitudeProvider() {
  264.         return attitudeProvider;
  265.     }

  266.     /**
  267.      * Set the attitude provider.
  268.      *
  269.      * @param attitudeProvider attitude provider
  270.      * @since 10.1
  271.      */
  272.     public void setAttitudeProvider(final AttitudeProvider attitudeProvider) {
  273.         this.attitudeProvider = attitudeProvider;
  274.     }

  275.     /** Get the position scale.
  276.      * @return the position scale used to scale the orbital drivers
  277.      */
  278.     public double getPositionScale() {
  279.         return positionScale;
  280.     }

  281.     /** {@inheritDoc} */
  282.     @Override
  283.     public double getMu() {
  284.         return mu;
  285.     }

  286.     /** Get the number of estimated values for selected parameters.
  287.      * @return number of estimated values for selected parameters
  288.      */
  289.     private int getNbValuesForSelected() {

  290.         int count = 0;

  291.         // count orbital parameters
  292.         for (final ParameterDriver driver : orbitalDrivers.getDrivers()) {
  293.             if (driver.isSelected()) {
  294.                 count += driver.getNbOfValues();
  295.             }
  296.         }

  297.         // count propagation parameters
  298.         for (final ParameterDriver driver : propagationDrivers.getDrivers()) {
  299.             if (driver.isSelected()) {
  300.                 count += driver.getNbOfValues();
  301.             }
  302.         }

  303.         return count;

  304.     }

  305.     /** {@inheritDoc} */
  306.     public double[] getSelectedNormalizedParameters() {

  307.         // allocate array
  308.         final double[] selected = new double[getNbValuesForSelected()];

  309.         // fill data
  310.         int index = 0;
  311.         for (final ParameterDriver driver : orbitalDrivers.getDrivers()) {
  312.             if (driver.isSelected()) {
  313.                 for (int spanNumber = 0; spanNumber < driver.getNbOfValues(); ++spanNumber ) {
  314.                     selected[index++] = driver.getNormalizedValue(AbsoluteDate.ARBITRARY_EPOCH);
  315.                 }
  316.             }
  317.         }
  318.         for (final ParameterDriver driver : propagationDrivers.getDrivers()) {
  319.             if (driver.isSelected()) {
  320.                 for (int spanNumber = 0; spanNumber < driver.getNbOfValues(); ++spanNumber ) {
  321.                     selected[index++] = driver.getNormalizedValue(AbsoluteDate.ARBITRARY_EPOCH);
  322.                 }
  323.             }
  324.         }

  325.         return selected;

  326.     }

  327.     /** Build an initial orbit using the current selected parameters.
  328.      * <p>
  329.      * This method is a stripped down version of {@link #buildPropagator(double[])}
  330.      * that only builds the initial orbit and not the full propagator.
  331.      * </p>
  332.      * @return an initial orbit
  333.      * @since 8.0
  334.      */
  335.     protected Orbit createInitialOrbit() {
  336.         final double[] unNormalized = new double[orbitalDrivers.getNbParams()];
  337.         for (int i = 0; i < unNormalized.length; ++i) {
  338.             unNormalized[i] = orbitalDrivers.getDrivers().get(i).getValue(initialOrbitDate);
  339.         }
  340.         return getOrbitType().mapArrayToOrbit(unNormalized, null, positionAngleType, initialOrbitDate, mu, frame);
  341.     }

  342.     /** Set the selected parameters.
  343.      * @param normalizedParameters normalized values for the selected parameters
  344.      */
  345.     protected void setParameters(final double[] normalizedParameters) {


  346.         if (normalizedParameters.length != getNbValuesForSelected()) {
  347.             throw new OrekitIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  348.                                                      normalizedParameters.length,
  349.                                                      getNbValuesForSelected());
  350.         }

  351.         int index = 0;

  352.         // manage orbital parameters
  353.         for (final ParameterDriver driver : orbitalDrivers.getDrivers()) {
  354.             if (driver.isSelected()) {
  355.                 // If the parameter driver contains only 1 value to estimate over the all time range, which
  356.                 // is normally always the case for orbital drivers
  357.                 if (driver.getNbOfValues() == 1) {
  358.                     driver.setNormalizedValue(normalizedParameters[index++], null);

  359.                 } else {

  360.                     for (Span<Double> span = driver.getValueSpanMap().getFirstSpan(); span != null; span = span.next()) {
  361.                         driver.setNormalizedValue(normalizedParameters[index++], span.getStart());
  362.                     }
  363.                 }
  364.             }
  365.         }

  366.         // manage propagation parameters
  367.         for (final ParameterDriver driver : propagationDrivers.getDrivers()) {

  368.             if (driver.isSelected()) {

  369.                 for (Span<Double> span = driver.getValueSpanMap().getFirstSpan(); span != null; span = span.next()) {
  370.                     driver.setNormalizedValue(normalizedParameters[index++], span.getStart());
  371.                 }
  372.             }
  373.         }
  374.     }

  375.     /**
  376.      * Add supported parameters.
  377.      *
  378.      * @param drivers drivers for the parameters
  379.      */
  380.     protected void addSupportedParameters(final List<ParameterDriver> drivers) {
  381.         drivers.forEach(propagationDrivers::add);
  382.         propagationDrivers.sort();
  383.     }

  384.     /** Reset the orbit in the propagator builder.
  385.      * @param newOrbit New orbit to set in the propagator builder
  386.      */
  387.     public void resetOrbit(final Orbit newOrbit) {

  388.         // Map the new orbit in an array of double
  389.         final double[] orbitArray = new double[6];
  390.         orbitType.mapOrbitToArray(newOrbit, getPositionAngleType(), orbitArray, null);

  391.         // Update all the orbital drivers, selected or unselected
  392.         // Reset values and reference values
  393.         final List<DelegatingDriver> orbitalDriversList = getOrbitalParametersDrivers().getDrivers();
  394.         int i = 0;
  395.         for (DelegatingDriver driver : orbitalDriversList) {
  396.             driver.setReferenceValue(orbitArray[i]);
  397.             driver.setValue(orbitArray[i++], newOrbit.getDate());
  398.         }

  399.         // Change the initial orbit date in the builder
  400.         this.initialOrbitDate = newOrbit.getDate();
  401.     }

  402.     /** Add a set of user-specified equations to be integrated along with the orbit propagation (author Shiva Iyer).
  403.      * @param provider provider for additional derivatives
  404.      * @since 11.1
  405.      */
  406.     public void addAdditionalDerivativesProvider(final AdditionalDerivativesProvider provider) {
  407.         additionalDerivativesProviders.add(provider);
  408.     }

  409.     /** Get the list of additional equations.
  410.      * @return the list of additional equations
  411.      * @since 11.1
  412.      */
  413.     protected List<AdditionalDerivativesProvider> getAdditionalDerivativesProviders() {
  414.         return additionalDerivativesProviders;
  415.     }

  416.     /** Deselects orbital and propagation drivers. */
  417.     public void deselectDynamicParameters() {
  418.         for (ParameterDriver driver : getPropagationParametersDrivers().getDrivers()) {
  419.             driver.setSelected(false);
  420.         }
  421.         for (ParameterDriver driver : getOrbitalParametersDrivers().getDrivers()) {
  422.             driver.setSelected(false);
  423.         }
  424.     }

  425. }