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 java.util.ArrayList;
  19. import java.util.List;

  20. import org.hipparchus.exception.LocalizedCoreFormats;
  21. import org.hipparchus.util.FastMath;
  22. import org.orekit.attitudes.AttitudeProvider;
  23. import org.orekit.attitudes.FrameAlignedProvider;
  24. import org.orekit.errors.OrekitIllegalArgumentException;
  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.integration.AdditionalDerivativesProvider;
  31. import org.orekit.time.AbsoluteDate;
  32. import org.orekit.utils.ParameterDriver;
  33. import org.orekit.utils.ParameterDriversList;
  34. import org.orekit.utils.ParameterDriversList.DelegatingDriver;
  35. import org.orekit.utils.ParameterObserver;
  36. import org.orekit.utils.TimeSpanMap;
  37. import org.orekit.utils.TimeSpanMap.Span;

  38. /** Base class for propagator builders.
  39.  * @author Pascal Parraud
  40.  * @since 7.1
  41.  */
  42. public abstract class AbstractPropagatorBuilder implements PropagatorBuilder {

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

  50.     /** Date of the initial orbit. */
  51.     private AbsoluteDate initialOrbitDate;

  52.     /** Frame in which the orbit is propagated. */
  53.     private final Frame frame;

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

  56.     /** Drivers for orbital parameters. */
  57.     private final ParameterDriversList orbitalDrivers;

  58.     /** List of the supported parameters. */
  59.     private ParameterDriversList propagationDrivers;

  60.     /** Orbit type to use. */
  61.     private final OrbitType orbitType;

  62.     /** Position angle type to use. */
  63.     private final PositionAngleType positionAngleType;

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

  66.     /** Attitude provider for the propagator. */
  67.     private AttitudeProvider attitudeProvider;

  68.     /** Additional derivatives providers.
  69.      * @since 11.1
  70.      */
  71.     private List<AdditionalDerivativesProvider> additionalDerivativesProviders;

  72.     /** Build a new instance.
  73.      * <p>
  74.      * The template orbit is used as a model to {@link
  75.      * #createInitialOrbit() create initial orbit}. It defines the
  76.      * inertial frame, the central attraction coefficient, the orbit type, and is also
  77.      * used together with the {@code positionScale} to convert from the {@link
  78.      * ParameterDriver#setNormalizedValue(double) normalized} parameters used by the
  79.      * callers of this builder to the real orbital parameters. The default attitude
  80.      * provider is aligned with the orbit's inertial frame.
  81.      * </p>
  82.      * <p>
  83.      * By default, all the {@link #getOrbitalParametersDrivers() orbital parameters drivers}
  84.      * are selected, which means that if the builder is used for orbit determination or
  85.      * propagator conversion, all orbital parameters will be estimated. If only a subset
  86.      * of the orbital parameters must be estimated, caller must retrieve the orbital
  87.      * parameters by calling {@link #getOrbitalParametersDrivers()} and then call
  88.      * {@link ParameterDriver#setSelected(boolean) setSelected(false)}.
  89.      * </p>
  90.      * @param templateOrbit reference orbit from which real orbits will be built
  91.      * @param positionAngleType position angle type to use
  92.      * @param positionScale scaling factor used for orbital parameters normalization
  93.      * (typically set to the expected standard deviation of the position)
  94.      * @param addDriverForCentralAttraction if true, a {@link ParameterDriver} should
  95.      * be set up for central attraction coefficient
  96.      * @since 8.0
  97.      * @see #AbstractPropagatorBuilder(Orbit, PositionAngleType, double, boolean,
  98.      * AttitudeProvider)
  99.      */
  100.     protected AbstractPropagatorBuilder(final Orbit templateOrbit, final PositionAngleType positionAngleType,
  101.                                         final double positionScale, final boolean addDriverForCentralAttraction) {
  102.         this(templateOrbit, positionAngleType, positionScale, addDriverForCentralAttraction,
  103.              new FrameAlignedProvider(templateOrbit.getFrame()));
  104.     }

  105.     /** Build a new instance.
  106.      * <p>
  107.      * The template orbit is used as a model to {@link
  108.      * #createInitialOrbit() create initial orbit}. It defines the
  109.      * inertial frame, the central attraction coefficient, the orbit type, and is also
  110.      * used together with the {@code positionScale} to convert from the {@link
  111.      * ParameterDriver#setNormalizedValue(double) normalized} parameters used by the
  112.      * callers of this builder to the real orbital parameters.
  113.      * </p>
  114.      * <p>
  115.      * By default, all the {@link #getOrbitalParametersDrivers() orbital parameters drivers}
  116.      * are selected, which means that if the builder is used for orbit determination or
  117.      * propagator conversion, all orbital parameters will be estimated. If only a subset
  118.      * of the orbital parameters must be estimated, caller must retrieve the orbital
  119.      * parameters by calling {@link #getOrbitalParametersDrivers()} and then call
  120.      * {@link ParameterDriver#setSelected(boolean) setSelected(false)}.
  121.      * </p>
  122.      * @param templateOrbit reference orbit from which real orbits will be built
  123.      * @param positionAngleType position angle type to use
  124.      * @param positionScale scaling factor used for orbital parameters normalization
  125.      * (typically set to the expected standard deviation of the position)
  126.      * @param addDriverForCentralAttraction if true, a {@link ParameterDriver} should
  127.      * be set up for central attraction coefficient
  128.      * @param attitudeProvider for the propagator.
  129.      * @since 10.1
  130.      * @see #AbstractPropagatorBuilder(Orbit, PositionAngleType, double, boolean)
  131.      */
  132.     protected AbstractPropagatorBuilder(final Orbit templateOrbit,
  133.                                         final PositionAngleType positionAngleType,
  134.                                         final double positionScale,
  135.                                         final boolean addDriverForCentralAttraction,
  136.                                         final AttitudeProvider attitudeProvider) {

  137.         this.initialOrbitDate    = templateOrbit.getDate();
  138.         this.frame               = templateOrbit.getFrame();
  139.         this.mu                  = templateOrbit.getMu();
  140.         this.propagationDrivers  = new ParameterDriversList();
  141.         this.orbitType           = templateOrbit.getType();
  142.         this.positionAngleType = positionAngleType;
  143.         this.positionScale       = positionScale;
  144.         this.orbitalDrivers      = orbitType.getDrivers(positionScale, templateOrbit, positionAngleType);
  145.         this.attitudeProvider = attitudeProvider;
  146.         for (final DelegatingDriver driver : orbitalDrivers.getDrivers()) {
  147.             driver.setSelected(true);
  148.         }

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

  150.         if (addDriverForCentralAttraction) {
  151.             final ParameterDriver muDriver = new ParameterDriver(NewtonianAttraction.CENTRAL_ATTRACTION_COEFFICIENT,
  152.                                                                  mu, MU_SCALE, 0, Double.POSITIVE_INFINITY);
  153.             muDriver.addObserver(new ParameterObserver() {
  154.                 /** {@inheridDoc} */
  155.                 @Override
  156.                 public void valueChanged(final double previousValue, final ParameterDriver driver, final AbsoluteDate date) {
  157.                     // getValue(), can be called without argument as mu driver should have only one span
  158.                     AbstractPropagatorBuilder.this.mu = driver.getValue();
  159.                 }

  160.                 @Override
  161.                 public void valueSpanMapChanged(final TimeSpanMap<Double> previousValueSpanMap, final ParameterDriver driver) {
  162.                     // getValue(), can be called without argument as mu driver should have only one span
  163.                     AbstractPropagatorBuilder.this.mu = driver.getValue();
  164.                 }
  165.             });
  166.             propagationDrivers.add(muDriver);
  167.         }

  168.     }

  169.     /** {@inheritDoc} */
  170.     public OrbitType getOrbitType() {
  171.         return orbitType;
  172.     }

  173.     /** {@inheritDoc} */
  174.     public PositionAngleType getPositionAngleType() {
  175.         return positionAngleType;
  176.     }

  177.     /** {@inheritDoc} */
  178.     public AbsoluteDate getInitialOrbitDate() {
  179.         return initialOrbitDate;
  180.     }

  181.     /** {@inheritDoc} */
  182.     public Frame getFrame() {
  183.         return frame;
  184.     }

  185.     /** {@inheritDoc} */
  186.     public ParameterDriversList getOrbitalParametersDrivers() {
  187.         return orbitalDrivers;
  188.     }

  189.     /** {@inheritDoc} */
  190.     public ParameterDriversList getPropagationParametersDrivers() {
  191.         return propagationDrivers;
  192.     }

  193.     /**
  194.      * Get the attitude provider.
  195.      *
  196.      * @return the attitude provider
  197.      * @since 10.1
  198.      */
  199.     public AttitudeProvider getAttitudeProvider() {
  200.         return attitudeProvider;
  201.     }

  202.     /**
  203.      * Set the attitude provider.
  204.      *
  205.      * @param attitudeProvider attitude provider
  206.      * @since 10.1
  207.      */
  208.     public void setAttitudeProvider(final AttitudeProvider attitudeProvider) {
  209.         this.attitudeProvider = attitudeProvider;
  210.     }

  211.     /** Get the position scale.
  212.      * @return the position scale used to scale the orbital drivers
  213.      */
  214.     public double getPositionScale() {
  215.         return positionScale;
  216.     }

  217.     /** {@inheritDoc} */
  218.     @Override
  219.     public double getMu() {
  220.         return mu;
  221.     }

  222.     /** Get the number of estimated values for selected parameters.
  223.      * @return number of estimated values for selected parameters
  224.      */
  225.     private int getNbValuesForSelected() {

  226.         int count = 0;

  227.         // count orbital parameters
  228.         for (final ParameterDriver driver : orbitalDrivers.getDrivers()) {
  229.             if (driver.isSelected()) {
  230.                 count += driver.getNbOfValues();
  231.             }
  232.         }

  233.         // count propagation parameters
  234.         for (final ParameterDriver driver : propagationDrivers.getDrivers()) {
  235.             if (driver.isSelected()) {
  236.                 count += driver.getNbOfValues();
  237.             }
  238.         }

  239.         return count;

  240.     }

  241.     /** {@inheritDoc} */
  242.     public double[] getSelectedNormalizedParameters() {

  243.         // allocate array
  244.         final double[] selected = new double[getNbValuesForSelected()];

  245.         // fill data
  246.         int index = 0;
  247.         for (final ParameterDriver driver : orbitalDrivers.getDrivers()) {
  248.             if (driver.isSelected()) {
  249.                 for (int spanNumber = 0; spanNumber < driver.getNbOfValues(); ++spanNumber ) {
  250.                     selected[index++] = driver.getNormalizedValue(AbsoluteDate.ARBITRARY_EPOCH);
  251.                 }
  252.             }
  253.         }
  254.         for (final ParameterDriver driver : propagationDrivers.getDrivers()) {
  255.             if (driver.isSelected()) {
  256.                 for (int spanNumber = 0; spanNumber < driver.getNbOfValues(); ++spanNumber ) {
  257.                     selected[index++] = driver.getNormalizedValue(AbsoluteDate.ARBITRARY_EPOCH);
  258.                 }
  259.             }
  260.         }

  261.         return selected;

  262.     }

  263.     /** Build an initial orbit using the current selected parameters.
  264.      * <p>
  265.      * This method is a stripped down version of {@link #buildPropagator(double[])}
  266.      * that only builds the initial orbit and not the full propagator.
  267.      * </p>
  268.      * @return an initial orbit
  269.      * @since 8.0
  270.      */
  271.     protected Orbit createInitialOrbit() {
  272.         final double[] unNormalized = new double[orbitalDrivers.getNbParams()];
  273.         for (int i = 0; i < unNormalized.length; ++i) {
  274.             unNormalized[i] = orbitalDrivers.getDrivers().get(i).getValue(initialOrbitDate);
  275.         }
  276.         return getOrbitType().mapArrayToOrbit(unNormalized, null, positionAngleType, initialOrbitDate, mu, frame);
  277.     }

  278.     /** Set the selected parameters.
  279.      * @param normalizedParameters normalized values for the selected parameters
  280.      */
  281.     protected void setParameters(final double[] normalizedParameters) {


  282.         if (normalizedParameters.length != getNbValuesForSelected()) {
  283.             throw new OrekitIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  284.                                                      normalizedParameters.length,
  285.                                                      getNbValuesForSelected());
  286.         }

  287.         int index = 0;

  288.         // manage orbital parameters
  289.         for (final ParameterDriver driver : orbitalDrivers.getDrivers()) {
  290.             if (driver.isSelected()) {
  291.                 // If the parameter driver contains only 1 value to estimate over the all time range, which
  292.                 // is normally always the case for orbital drivers
  293.                 if (driver.getNbOfValues() == 1) {
  294.                     driver.setNormalizedValue(normalizedParameters[index++], null);

  295.                 } else {

  296.                     for (Span<Double> span = driver.getValueSpanMap().getFirstSpan(); span != null; span = span.next()) {
  297.                         driver.setNormalizedValue(normalizedParameters[index++], span.getStart());
  298.                     }
  299.                 }
  300.             }
  301.         }

  302.         // manage propagation parameters
  303.         for (final ParameterDriver driver : propagationDrivers.getDrivers()) {

  304.             if (driver.isSelected()) {

  305.                 for (Span<Double> span = driver.getValueSpanMap().getFirstSpan(); span != null; span = span.next()) {
  306.                     driver.setNormalizedValue(normalizedParameters[index++], span.getStart());
  307.                 }
  308.             }
  309.         }
  310.     }

  311.     /**
  312.      * Add supported parameters.
  313.      *
  314.      * @param drivers drivers for the parameters
  315.      */
  316.     protected void addSupportedParameters(final List<ParameterDriver> drivers) {
  317.         drivers.forEach(propagationDrivers::add);
  318.         propagationDrivers.sort();
  319.     }

  320.     /** Reset the orbit in the propagator builder.
  321.      * @param newOrbit New orbit to set in the propagator builder
  322.      */
  323.     public void resetOrbit(final Orbit newOrbit) {

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

  327.         // Update all the orbital drivers, selected or unselected
  328.         // Reset values and reference values
  329.         final List<DelegatingDriver> orbitalDriversList = getOrbitalParametersDrivers().getDrivers();
  330.         int i = 0;
  331.         for (DelegatingDriver driver : orbitalDriversList) {
  332.             driver.setReferenceValue(orbitArray[i]);
  333.             driver.setValue(orbitArray[i++], newOrbit.getDate());
  334.         }

  335.         // Change the initial orbit date in the builder
  336.         this.initialOrbitDate = newOrbit.getDate();
  337.     }

  338.     /** Add a set of user-specified equations to be integrated along with the orbit propagation (author Shiva Iyer).
  339.      * @param provider provider for additional derivatives
  340.      * @since 11.1
  341.      */
  342.     public void addAdditionalDerivativesProvider(final AdditionalDerivativesProvider provider) {
  343.         additionalDerivativesProviders.add(provider);
  344.     }

  345.     /** Get the list of additional equations.
  346.      * @return the list of additional equations
  347.      * @since 11.1
  348.      */
  349.     protected List<AdditionalDerivativesProvider> getAdditionalDerivativesProviders() {
  350.         return additionalDerivativesProviders;
  351.     }

  352.     /** Deselects orbital and propagation drivers. */
  353.     public void deselectDynamicParameters() {
  354.         for (ParameterDriver driver : getPropagationParametersDrivers().getDrivers()) {
  355.             driver.setSelected(false);
  356.         }
  357.         for (ParameterDriver driver : getOrbitalParametersDrivers().getDrivers()) {
  358.             driver.setSelected(false);
  359.         }
  360.     }

  361. }