NumericalPropagatorBuilder.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.propagation.conversion;

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

  21. import org.orekit.attitudes.Attitude;
  22. import org.orekit.attitudes.AttitudeProvider;
  23. import org.orekit.attitudes.FrameAlignedProvider;
  24. import org.orekit.estimation.leastsquares.BatchLSModel;
  25. import org.orekit.estimation.leastsquares.ModelObserver;
  26. import org.orekit.estimation.measurements.ObservedMeasurement;
  27. import org.orekit.forces.ForceModel;
  28. import org.orekit.forces.gravity.NewtonianAttraction;
  29. import org.orekit.forces.maneuvers.ImpulseManeuver;
  30. import org.orekit.orbits.Orbit;
  31. import org.orekit.orbits.PositionAngleType;
  32. import org.orekit.propagation.PropagationType;
  33. import org.orekit.propagation.Propagator;
  34. import org.orekit.propagation.SpacecraftState;
  35. import org.orekit.propagation.integration.AdditionalDerivativesProvider;
  36. import org.orekit.propagation.numerical.NumericalPropagator;
  37. import org.orekit.utils.ParameterDriver;
  38. import org.orekit.utils.ParameterDriversList;

  39. /** Builder for numerical propagator.
  40.  * @author Pascal Parraud
  41.  * @since 6.0
  42.  */
  43. public class NumericalPropagatorBuilder extends AbstractIntegratedPropagatorBuilder<NumericalPropagator> {

  44.     /** Force models used during the extrapolation of the orbit. */
  45.     private final List<ForceModel> forceModels;

  46.     /** Impulse maneuvers. */
  47.     private final List<ImpulseManeuver> impulseManeuvers;

  48.     /** Build a new instance.
  49.      * <p>
  50.      * The reference orbit is used as a model to {@link
  51.      * #createInitialOrbit() create initial orbit}. It defines the
  52.      * inertial frame, the central attraction coefficient, and is also used together
  53.      * with the {@code positionScale} to convert from the {@link
  54.      * ParameterDriver#setNormalizedValue(double) normalized} parameters used by the
  55.      * callers of this builder to the real orbital parameters.
  56.      * The default attitude provider is aligned with the orbit's inertial frame.
  57.      * </p>
  58.      *
  59.      * @param referenceOrbit reference orbit from which real orbits will be built
  60.      * @param builder first order integrator builder
  61.      * @param positionAngleType position angle type to use
  62.      * @param positionScale scaling factor used for orbital parameters normalization
  63.      * (typically set to the expected standard deviation of the position)
  64.      * @since 8.0
  65.      * @see #NumericalPropagatorBuilder(Orbit, ODEIntegratorBuilder, PositionAngleType,
  66.      * double, AttitudeProvider)
  67.      */
  68.     public NumericalPropagatorBuilder(final Orbit referenceOrbit,
  69.                                       final ODEIntegratorBuilder builder,
  70.                                       final PositionAngleType positionAngleType,
  71.                                       final double positionScale) {
  72.         this(referenceOrbit, builder, positionAngleType, positionScale,
  73.              FrameAlignedProvider.of(referenceOrbit.getFrame()));
  74.     }

  75.     /** Build a new instance.
  76.      * <p>
  77.      * The reference orbit is used as a model to {@link
  78.      * #createInitialOrbit() create initial orbit}. It defines the
  79.      * inertial frame, the central attraction coefficient, and is also used together
  80.      * with the {@code positionScale} to convert from the {@link
  81.      * ParameterDriver#setNormalizedValue(double) normalized} parameters used by the
  82.      * callers of this builder to the real orbital parameters.
  83.      * </p>
  84.      * @param referenceOrbit reference orbit from which real orbits will be built
  85.      * @param builder first order integrator builder
  86.      * @param positionAngleType position angle type to use
  87.      * @param positionScale scaling factor used for orbital parameters normalization
  88.      * (typically set to the expected standard deviation of the position)
  89.      * @param attitudeProvider attitude law.
  90.      * @since 10.1
  91.      */
  92.     public NumericalPropagatorBuilder(final Orbit referenceOrbit,
  93.                                       final ODEIntegratorBuilder builder,
  94.                                       final PositionAngleType positionAngleType,
  95.                                       final double positionScale,
  96.                                       final AttitudeProvider attitudeProvider) {
  97.         super(referenceOrbit, builder, positionAngleType, positionScale, PropagationType.OSCULATING, attitudeProvider, Propagator.DEFAULT_MASS);
  98.         this.forceModels = new ArrayList<>();
  99.         this.impulseManeuvers = new ArrayList<>();
  100.     }

  101.     /**
  102.      * Add impulse maneuver.
  103.      * @param impulseManeuver impulse maneuver
  104.      * @since 12.2
  105.      */
  106.     public void addImpulseManeuver(final ImpulseManeuver impulseManeuver) {
  107.         impulseManeuvers.add(impulseManeuver);
  108.     }

  109.     /**
  110.      * Remove all impulse maneuvers.
  111.      * @since 12.2
  112.      */
  113.     public void clearImpulseManeuvers() {
  114.         impulseManeuvers.clear();
  115.     }

  116.     /** Get the list of all force models.
  117.      * @return the list of all force models
  118.      * @since 9.2
  119.      */
  120.     public List<ForceModel> getAllForceModels()
  121.     {
  122.         return Collections.unmodifiableList(forceModels);
  123.     }

  124.     /** Add a force model to the global perturbation model.
  125.      * <p>If this method is not called at all, the integrated orbit will follow
  126.      * a Keplerian evolution only.</p>
  127.      * @param model perturbing {@link ForceModel} to add
  128.      */
  129.     public void addForceModel(final ForceModel model) {
  130.         if (model instanceof NewtonianAttraction) {
  131.             // we want to add the central attraction force model
  132.             if (hasNewtonianAttraction()) {
  133.                 // there is already a central attraction model, replace it
  134.                 forceModels.set(forceModels.size() - 1, model);
  135.             } else {
  136.                 // there are no central attraction model yet, add it at the end of the list
  137.                 forceModels.add(model);
  138.             }
  139.         } else {
  140.             // we want to add a perturbing force model
  141.             if (hasNewtonianAttraction()) {
  142.                 // insert the new force model before Newtonian attraction,
  143.                 // which should always be the last one in the list
  144.                 forceModels.add(forceModels.size() - 1, model);
  145.             } else {
  146.                 // we only have perturbing force models up to now, just append at the end of the list
  147.                 forceModels.add(model);
  148.             }
  149.         }

  150.         addSupportedParameters(model.getParametersDrivers());
  151.     }

  152.     /** {@inheritDoc} */
  153.     public NumericalPropagator buildPropagator(final double[] normalizedParameters) {

  154.         setParameters(normalizedParameters);
  155.         final Orbit           orbit    = createInitialOrbit();
  156.         final Attitude        attitude =
  157.                 getAttitudeProvider().getAttitude(orbit, orbit.getDate(), getFrame());
  158.         final SpacecraftState state    = new SpacecraftState(orbit, attitude).withMass(getMass());

  159.         final NumericalPropagator propagator = new NumericalPropagator(
  160.                 getIntegratorBuilder().buildIntegrator(orbit, getOrbitType(), getPositionAngleType()),
  161.                 getAttitudeProvider());
  162.         propagator.setOrbitType(getOrbitType());
  163.         propagator.setPositionAngleType(getPositionAngleType());

  164.         // Configure force models
  165.         if (!hasNewtonianAttraction()) {
  166.             // There are no central attraction model yet, add it at the end of the list
  167.             addForceModel(new NewtonianAttraction(orbit.getMu()));
  168.         }
  169.         for (ForceModel model : forceModels) {
  170.             propagator.addForceModel(model);
  171.         }
  172.         impulseManeuvers.forEach(propagator::addEventDetector);

  173.         propagator.resetInitialState(state);

  174.         // Add additional derivatives providers to the propagator
  175.         for (AdditionalDerivativesProvider provider: getAdditionalDerivativesProviders()) {
  176.             propagator.addAdditionalDerivativesProvider(provider);
  177.         }

  178.         return propagator;

  179.     }

  180.     /** {@inheritDoc} */
  181.     @Override
  182.     public BatchLSModel buildLeastSquaresModel(final PropagatorBuilder[] builders,
  183.                                                final List<ObservedMeasurement<?>> measurements,
  184.                                                final ParameterDriversList estimatedMeasurementsParameters,
  185.                                                final ModelObserver observer) {
  186.         return new BatchLSModel(builders, measurements, estimatedMeasurementsParameters, observer);
  187.     }

  188.     /** Check if Newtonian attraction force model is available.
  189.      * <p>
  190.      * Newtonian attraction is always the last force model in the list.
  191.      * </p>
  192.      * @return true if Newtonian attraction force model is available
  193.      */
  194.     private boolean hasNewtonianAttraction() {
  195.         final int last = forceModels.size() - 1;
  196.         return last >= 0 && forceModels.get(last) instanceof NewtonianAttraction;
  197.     }

  198. }