FieldIntegratedEphemeris.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.integration;

  18. import java.util.Arrays;
  19. import java.util.Collections;
  20. import java.util.List;
  21. import java.util.stream.Stream;

  22. import org.hipparchus.CalculusFieldElement;
  23. import org.hipparchus.Field;
  24. import org.hipparchus.ode.FieldDenseOutputModel;
  25. import org.hipparchus.ode.FieldODEStateAndDerivative;
  26. import org.orekit.attitudes.AttitudeProvider;
  27. import org.orekit.attitudes.AttitudeProviderModifier;
  28. import org.orekit.errors.OrekitException;
  29. import org.orekit.errors.OrekitMessages;
  30. import org.orekit.frames.Frame;
  31. import org.orekit.orbits.FieldOrbit;
  32. import org.orekit.propagation.FieldAdditionalDataProvider;
  33. import org.orekit.propagation.FieldBoundedPropagator;
  34. import org.orekit.propagation.FieldSpacecraftState;
  35. import org.orekit.propagation.PropagationType;
  36. import org.orekit.propagation.analytical.FieldAbstractAnalyticalPropagator;
  37. import org.orekit.propagation.events.EventDetector;
  38. import org.orekit.propagation.events.FieldEventDetector;
  39. import org.orekit.time.FieldAbsoluteDate;
  40. import org.orekit.utils.FieldDataDictionary;
  41. import org.orekit.utils.ParameterDriver;

  42. /** This class stores sequentially generated orbital parameters for
  43.  * later retrieval.
  44.  *
  45.  * <p>
  46.  * Instances of this class are built automatically when the {@link
  47.  * org.orekit.propagation.FieldPropagator#getEphemerisGenerator()
  48.  * getEphemerisGenerator} method has been called. They are created when propagation is over.
  49.  * Random access to any intermediate state of the orbit throughout the propagation range is
  50.  * possible afterwards through this object.
  51.  * </p>
  52.  * <p>
  53.  * A typical use case is for numerically integrated orbits, which can be used by
  54.  * algorithms that need to wander around according to their own algorithm without
  55.  * cumbersome tight links with the integrator.
  56.  * </p>
  57.  * <p>
  58.  * As this class implements the {@link org.orekit.propagation.Propagator Propagator}
  59.  * interface, it can itself be used in batch mode to build another instance of the
  60.  * same type. This is however not recommended since it would be a waste of resources.
  61.  * </p>
  62.  * <p>
  63.  * Note that this class stores all intermediate states along with interpolation
  64.  * models, so it may be memory intensive.
  65.  * </p>
  66.  *
  67.  * @see org.orekit.propagation.numerical.NumericalPropagator
  68.  * @author Mathieu Rom&eacute;ro
  69.  * @author Luc Maisonobe
  70.  * @author V&eacute;ronique Pommier-Maurussane
  71.  * @param <T> type of the field elements
  72.  */
  73. public class FieldIntegratedEphemeris <T extends CalculusFieldElement<T>>
  74.     extends FieldAbstractAnalyticalPropagator<T> implements FieldBoundedPropagator<T> {

  75.     /** Event detection requires evaluating the state slightly before / past an event. */
  76.     private static final double EXTRAPOLATION_TOLERANCE = 1.0;

  77.     /** Mapper between raw double components and spacecraft state. */
  78.     private final FieldStateMapper<T> mapper;

  79.     /** Type of orbit to output (mean or osculating).
  80.      * <p>
  81.      * This is used only in the case of semianalitical propagators where there is a clear separation between
  82.      * mean and short periodic elements. It is ignored by the Numerical propagator.
  83.      * </p>
  84.      */
  85.     private final PropagationType type;

  86.     /** Start date of the integration (can be min or max). */
  87.     private final FieldAbsoluteDate<T> startDate;

  88.     /** First date of the range. */
  89.     private final FieldAbsoluteDate<T> minDate;

  90.     /** Last date of the range. */
  91.     private final FieldAbsoluteDate<T> maxDate;

  92.     /** Underlying raw mathematical model. */
  93.     private final FieldDenseOutputModel<T> model;

  94.     /** Unmanaged additional states that must be simply copied. */
  95.     private final FieldDataDictionary<T> unmanaged;

  96.     /** Names of additional equations.
  97.      * @since 11.2
  98.      */
  99.     private final String[] equations;

  100.     /** Dimensions of additional equations.
  101.      * @since 11.2
  102.      */
  103.     private final int[] dimensions;

  104.     /** Creates a new instance of IntegratedEphemeris.
  105.      * @param startDate Start date of the integration (can be minDate or maxDate)
  106.      * @param minDate first date of the range
  107.      * @param maxDate last date of the range
  108.      * @param mapper mapper between raw double components and spacecraft state
  109.      * @param attitudeProvider attitude provider
  110.      * @param type type of orbit to output (mean or osculating)
  111.      * @param model underlying raw mathematical model
  112.      * @param unmanaged unmanaged additional states that must be simply copied
  113.      * @param providers generators for pre-integrated states
  114.      * @param equations names of additional equations
  115.      * @param dimensions dimensions of additional equations
  116.      * @since 13.0
  117.      */
  118.     public FieldIntegratedEphemeris(final FieldAbsoluteDate<T> startDate,
  119.                                     final FieldAbsoluteDate<T> minDate, final FieldAbsoluteDate<T> maxDate,
  120.                                     final FieldStateMapper<T> mapper, final AttitudeProvider attitudeProvider,
  121.                                     final PropagationType type, final FieldDenseOutputModel<T> model,
  122.                                     final FieldDataDictionary<T> unmanaged,
  123.                                     final List<FieldAdditionalDataProvider<?, T>> providers,
  124.                                     final String[] equations, final int[] dimensions) {

  125.         super(startDate.getField(), attitudeProvider);

  126.         this.startDate = startDate;
  127.         this.minDate   = minDate;
  128.         this.maxDate   = maxDate;
  129.         this.mapper    = mapper;
  130.         this.type      = type;
  131.         this.model     = model;
  132.         this.unmanaged = unmanaged;

  133.         // set up the pre-integrated providers
  134.         for (final FieldAdditionalDataProvider<?, T> provider : providers) {
  135.             addAdditionalDataProvider(provider);
  136.         }

  137.         this.equations  = equations.clone();
  138.         this.dimensions = dimensions.clone();

  139.         // set up initial state
  140.         super.resetInitialState(getInitialState());

  141.         // remove event detectors in attitude provider
  142.         setAttitudeProvider(new AttitudeProviderModifier() {
  143.             @Override
  144.             public AttitudeProvider getUnderlyingAttitudeProvider() {
  145.                 return attitudeProvider;
  146.             }

  147.             @Override
  148.             public Stream<EventDetector> getEventDetectors() {
  149.                 return Stream.of();
  150.             }

  151.             @Override
  152.             public <W extends CalculusFieldElement<W>> Stream<FieldEventDetector<W>> getFieldEventDetectors(final Field<W> field) {
  153.                 return Stream.of();
  154.             }
  155.         });
  156.     }

  157.     /** Interpolate the model at some date.
  158.      * @param date desired interpolation date
  159.      * @return state interpolated at date
  160.           * of supported range
  161.      */
  162.     private FieldODEStateAndDerivative<T> getInterpolatedState(final FieldAbsoluteDate<T> date) {

  163.         // compare using double precision instead of FieldAbsoluteDate<T>.compareTo(...)
  164.         // because time is expressed as a double when searching for events
  165.         if (date.compareTo(minDate.shiftedBy(-EXTRAPOLATION_TOLERANCE)) < 0) {
  166.             // date is outside of supported range
  167.             throw new OrekitException(OrekitMessages.OUT_OF_RANGE_EPHEMERIDES_DATE_BEFORE,
  168.                     date, minDate, maxDate, minDate.durationFrom(date).getReal());
  169.         }
  170.         if (date.compareTo(maxDate.shiftedBy(EXTRAPOLATION_TOLERANCE)) > 0) {
  171.             // date is outside of supported range
  172.             throw new OrekitException(OrekitMessages.OUT_OF_RANGE_EPHEMERIDES_DATE_AFTER,
  173.                     date, minDate, maxDate, date.durationFrom(maxDate).getReal());
  174.         }

  175.         return model.getInterpolatedState(date.durationFrom(startDate));

  176.     }

  177.     /** {@inheritDoc} */
  178.     @Override
  179.     public FieldSpacecraftState<T> basicPropagate(final FieldAbsoluteDate<T> date) {
  180.         final FieldODEStateAndDerivative<T> os = getInterpolatedState(date);
  181.         FieldSpacecraftState<T> state = mapper.mapArrayToState(mapper.mapDoubleToDate(os.getTime(), date),
  182.                                                                os.getPrimaryState(), os.getPrimaryDerivative(),
  183.                                                                type);
  184.         for (FieldDataDictionary<T>.Entry initial : unmanaged.getData()) {
  185.             state = state.addAdditionalData(initial.getKey(), initial.getValue());
  186.         }
  187.         return state;
  188.     }

  189.     /** {@inheritDoc} */
  190.     @Override
  191.     public FieldOrbit<T> propagateOrbit(final FieldAbsoluteDate<T> date,
  192.                                         final T[] parameters) {
  193.         return basicPropagate(date).getOrbit();
  194.     }

  195.     /** {@inheritDoc} */
  196.     @Override
  197.     protected T getMass(final FieldAbsoluteDate<T> date) {
  198.         return basicPropagate(date).getMass();
  199.     }

  200.     /** Get the first date of the range.
  201.      * @return the first date of the range
  202.      */
  203.     @Override
  204.     public FieldAbsoluteDate<T> getMinDate() {
  205.         return minDate;
  206.     }

  207.     /** Get the last date of the range.
  208.      * @return the last date of the range
  209.      */
  210.     @Override
  211.     public FieldAbsoluteDate<T> getMaxDate() {
  212.         return maxDate;
  213.     }

  214.     @Override
  215.     public Frame getFrame() {
  216.         return this.mapper.getFrame();
  217.     }

  218.     /** {@inheritDoc} */
  219.     @Override
  220.     public void resetInitialState(final FieldSpacecraftState<T> state) {
  221.         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
  222.     }

  223.     /** {@inheritDoc} */
  224.     @Override
  225.     protected void resetIntermediateState(final FieldSpacecraftState<T> state, final boolean forward) {
  226.         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
  227.     }

  228.     /** {@inheritDoc} */
  229.     @Override
  230.     public FieldSpacecraftState<T> getInitialState() {
  231.         return updateAdditionalData(basicPropagate(getMinDate()));
  232.     }

  233.     /** {@inheritDoc} */
  234.     @Override
  235.     public FieldSpacecraftState<T> updateAdditionalData(final FieldSpacecraftState<T> original) {

  236.         FieldSpacecraftState<T> updated = super.updateAdditionalData(original);

  237.         if (equations.length > 0) {
  238.             final FieldODEStateAndDerivative<T> osd                = getInterpolatedState(updated.getDate());
  239.             final T[]                           combinedState      = osd.getSecondaryState(1);
  240.             final T[]                           combinedDerivative = osd.getSecondaryDerivative(1);
  241.             int index = 0;
  242.             for (int i = 0; i < equations.length; ++i) {
  243.                 final T[] state      = Arrays.copyOfRange(combinedState,      index, index + dimensions[i]);
  244.                 final T[] derivative = Arrays.copyOfRange(combinedDerivative, index, index + dimensions[i]);
  245.                 updated = updated.
  246.                         addAdditionalData(equations[i], state).
  247.                           addAdditionalStateDerivative(equations[i], derivative);
  248.                 index += dimensions[i];
  249.             }
  250.         }

  251.         return updated;

  252.     }

  253.     /** {@inheritDoc} */
  254.     @Override
  255.     public List<ParameterDriver> getParametersDrivers() {
  256.         // Integrated Ephemeris propagation model does not have parameter drivers.
  257.         return Collections.emptyList();
  258.     }

  259. }