FieldAbstractIntegratedPropagator.java

  1. /* Copyright 2002-2020 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.ArrayList;
  19. import java.util.Collection;
  20. import java.util.Collections;
  21. import java.util.HashMap;
  22. import java.util.List;
  23. import java.util.Map;

  24. import org.hipparchus.Field;
  25. import org.hipparchus.RealFieldElement;
  26. import org.hipparchus.exception.MathIllegalArgumentException;
  27. import org.hipparchus.exception.MathIllegalStateException;
  28. import org.hipparchus.ode.FieldDenseOutputModel;
  29. import org.hipparchus.ode.FieldEquationsMapper;
  30. import org.hipparchus.ode.FieldExpandableODE;
  31. import org.hipparchus.ode.FieldODEIntegrator;
  32. import org.hipparchus.ode.FieldODEState;
  33. import org.hipparchus.ode.FieldODEStateAndDerivative;
  34. import org.hipparchus.ode.FieldOrdinaryDifferentialEquation;
  35. import org.hipparchus.ode.FieldSecondaryODE;
  36. import org.hipparchus.ode.events.Action;
  37. import org.hipparchus.ode.events.FieldODEEventHandler;
  38. import org.hipparchus.ode.sampling.FieldODEStateInterpolator;
  39. import org.hipparchus.ode.sampling.FieldODEStepHandler;
  40. import org.hipparchus.util.MathArrays;
  41. import org.hipparchus.util.Precision;
  42. import org.orekit.attitudes.AttitudeProvider;
  43. import org.orekit.errors.OrekitException;
  44. import org.orekit.errors.OrekitIllegalStateException;
  45. import org.orekit.errors.OrekitMessages;
  46. import org.orekit.frames.Frame;
  47. import org.orekit.orbits.OrbitType;
  48. import org.orekit.orbits.PositionAngle;
  49. import org.orekit.propagation.FieldAbstractPropagator;
  50. import org.orekit.propagation.FieldBoundedPropagator;
  51. import org.orekit.propagation.FieldSpacecraftState;
  52. import org.orekit.propagation.PropagationType;
  53. import org.orekit.propagation.events.FieldEventDetector;
  54. import org.orekit.propagation.sampling.FieldOrekitStepHandler;
  55. import org.orekit.propagation.sampling.FieldOrekitStepInterpolator;
  56. import org.orekit.time.FieldAbsoluteDate;


  57. /** Common handling of {@link org.orekit.propagation.FieldPropagator FieldPropagator}
  58.  *  methods for both numerical and semi-analytical propagators.
  59.  *  @author Luc Maisonobe
  60.  */
  61. public abstract class FieldAbstractIntegratedPropagator<T extends RealFieldElement<T>> extends FieldAbstractPropagator<T> {

  62.     /** Event detectors not related to force models. */
  63.     private final List<FieldEventDetector<T>> detectors;

  64.     /** Integrator selected by the user for the orbital extrapolation process. */
  65.     private final FieldODEIntegrator<T> integrator;

  66.     /** Mode handler. */
  67.     private FieldModeHandler<T> modeHandler;

  68.     /** Additional equations. */
  69.     private List<FieldAdditionalEquations<T>> additionalEquations;

  70.     /** Counter for differential equations calls. */
  71.     private int calls;

  72.     /** Mapper between raw double components and space flight dynamics objects. */
  73.     private FieldStateMapper<T> stateMapper;

  74.     /** Equations mapper. */
  75.     private FieldEquationsMapper<T> equationsMapper;

  76.     /** Underlying raw rawInterpolator. */
  77.     private FieldODEStateInterpolator<T> mathInterpolator;

  78.     /** Flag for resetting the state at end of propagation. */
  79.     private boolean resetAtEnd;

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

  87.     /** Build a new instance.
  88.      * @param integrator numerical integrator to use for propagation.
  89.      * @param propagationType type of orbit to output (mean or osculating).
  90.      * @param field Field used by default
  91.      */
  92.     protected FieldAbstractIntegratedPropagator(final Field<T> field, final FieldODEIntegrator<T> integrator, final PropagationType propagationType) {
  93.         super(field);
  94.         detectors            = new ArrayList<FieldEventDetector<T>>();
  95.         additionalEquations  = new ArrayList<FieldAdditionalEquations<T>>();
  96.         this.integrator      = integrator;
  97.         this.propagationType = propagationType;
  98.         this.resetAtEnd      = true;
  99.     }

  100.     /** Allow/disallow resetting the initial state at end of propagation.
  101.      * <p>
  102.      * By default, at the end of the propagation, the propagator resets the initial state
  103.      * to the final state, thus allowing a new propagation to be started from there without
  104.      * recomputing the part already performed. Calling this method with {@code resetAtEnd} set
  105.      * to false changes prevents such reset.
  106.      * </p>
  107.      * @param resetAtEnd if true, at end of each propagation, the {@link
  108.      * #getInitialState() initial state} will be reset to the final state of
  109.      * the propagation, otherwise the initial state will be preserved
  110.      * @since 9.0
  111.      */
  112.     public void setResetAtEnd(final boolean resetAtEnd) {
  113.         this.resetAtEnd = resetAtEnd;
  114.     }

  115.     /** Initialize the mapper.
  116.      * @param field Field used by default
  117.      */
  118.     protected void initMapper(final Field<T> field) {
  119.         final T zero = field.getZero();
  120.         stateMapper = createMapper(null, zero.add(Double.NaN), null, null, null, null);
  121.     }

  122.     /**  {@inheritDoc} */
  123.     public void setAttitudeProvider(final AttitudeProvider attitudeProvider) {
  124.         super.setAttitudeProvider(attitudeProvider);
  125.         stateMapper = createMapper(stateMapper.getReferenceDate(), stateMapper.getMu(),
  126.                                    stateMapper.getOrbitType(), stateMapper.getPositionAngleType(),
  127.                                    attitudeProvider, stateMapper.getFrame());
  128.     }

  129.     /** Set propagation orbit type.
  130.      * @param orbitType orbit type to use for propagation
  131.      */
  132.     protected void setOrbitType(final OrbitType orbitType) {
  133.         stateMapper = createMapper(stateMapper.getReferenceDate(), stateMapper.getMu(),
  134.                                    orbitType, stateMapper.getPositionAngleType(),
  135.                                    stateMapper.getAttitudeProvider(), stateMapper.getFrame());
  136.     }

  137.     /** Get propagation parameter type.
  138.      * @return orbit type used for propagation
  139.      */
  140.     protected OrbitType getOrbitType() {
  141.         return stateMapper.getOrbitType();
  142.     }

  143.     /** Check if only the mean elements should be used in a semianalitical propagation.
  144.      * @return {@link PropagationType MEAN} if only mean elements have to be used or
  145.      *         {@link PropagationType OSCULATING} if osculating elements have to be also used.
  146.      */
  147.     protected PropagationType isMeanOrbit() {
  148.         return propagationType;
  149.     }

  150.     /** Set position angle type.
  151.      * <p>
  152.      * The position parameter type is meaningful only if {@link
  153.      * #getOrbitType() propagation orbit type}
  154.      * support it. As an example, it is not meaningful for propagation
  155.      * in {@link OrbitType#CARTESIAN Cartesian} parameters.
  156.      * </p>
  157.      * @param positionAngleType angle type to use for propagation
  158.      */
  159.     protected void setPositionAngleType(final PositionAngle positionAngleType) {
  160.         stateMapper = createMapper(stateMapper.getReferenceDate(), stateMapper.getMu(),
  161.                                    stateMapper.getOrbitType(), positionAngleType,
  162.                                    stateMapper.getAttitudeProvider(), stateMapper.getFrame());
  163.     }

  164.     /** Get propagation parameter type.
  165.      * @return angle type to use for propagation
  166.      */
  167.     protected PositionAngle getPositionAngleType() {
  168.         return stateMapper.getPositionAngleType();
  169.     }

  170.     /** Set the central attraction coefficient μ.
  171.      * @param mu central attraction coefficient (m³/s²)
  172.      */
  173.     public void setMu(final T mu) {
  174.         stateMapper = createMapper(stateMapper.getReferenceDate(), mu,
  175.                                    stateMapper.getOrbitType(), stateMapper.getPositionAngleType(),
  176.                                    stateMapper.getAttitudeProvider(), stateMapper.getFrame());
  177.     }

  178.     /** Get the central attraction coefficient μ.
  179.      * @return mu central attraction coefficient (m³/s²)
  180.      * @see #setMu(RealFieldElement)
  181.      */
  182.     public T getMu() {
  183.         return stateMapper.getMu();
  184.     }

  185.     /** Get the number of calls to the differential equations computation method.
  186.      * <p>The number of calls is reset each time the {@link #propagate(FieldAbsoluteDate)}
  187.      * method is called.</p>
  188.      * @return number of calls to the differential equations computation method
  189.      */
  190.     public int getCalls() {
  191.         return calls;
  192.     }

  193.     /** {@inheritDoc} */
  194.     @Override
  195.     public boolean isAdditionalStateManaged(final String name) {

  196.         // first look at already integrated states
  197.         if (super.isAdditionalStateManaged(name)) {
  198.             return true;
  199.         }

  200.         // then look at states we integrate ourselves
  201.         for (final FieldAdditionalEquations<T> equation : additionalEquations) {
  202.             if (equation.getName().equals(name)) {
  203.                 return true;
  204.             }
  205.         }

  206.         return false;
  207.     }

  208.     /** {@inheritDoc} */
  209.     @Override
  210.     public String[] getManagedAdditionalStates() {
  211.         final String[] alreadyIntegrated = super.getManagedAdditionalStates();
  212.         final String[] managed = new String[alreadyIntegrated.length + additionalEquations.size()];
  213.         System.arraycopy(alreadyIntegrated, 0, managed, 0, alreadyIntegrated.length);
  214.         for (int i = 0; i < additionalEquations.size(); ++i) {
  215.             managed[i + alreadyIntegrated.length] = additionalEquations.get(i).getName();
  216.         }
  217.         return managed;
  218.     }

  219.     /** Add a set of user-specified equations to be integrated along with the orbit propagation.
  220.      * @param additional additional equations
  221.      */
  222.     public void addAdditionalEquations(final FieldAdditionalEquations<T> additional) {

  223.         // check if the name is already used
  224.         if (isAdditionalStateManaged(additional.getName())) {
  225.             // this set of equations is already registered, complain
  226.             throw new OrekitException(OrekitMessages.ADDITIONAL_STATE_NAME_ALREADY_IN_USE,
  227.                                       additional.getName());
  228.         }

  229.         // this is really a new set of equations, add it
  230.         additionalEquations.add(additional);

  231.     }

  232.     /** {@inheritDoc} */
  233.     public <D extends FieldEventDetector<T>> void addEventDetector(final D detector) {
  234.         detectors.add(detector);
  235.     }

  236.     /** {@inheritDoc} */
  237.     public Collection<FieldEventDetector<T>> getEventsDetectors() {
  238.         return Collections.unmodifiableCollection(detectors);
  239.     }

  240.     /** {@inheritDoc} */
  241.     public void clearEventsDetectors() {
  242.         detectors.clear();
  243.     }

  244.     /** Set up all user defined event detectors.
  245.      */
  246.     protected void setUpUserEventDetectors() {
  247.         for (final FieldEventDetector<T> detector : detectors) {
  248.             setUpEventDetector(integrator, detector);
  249.         }
  250.     }

  251.     /** Wrap an Orekit event detector and register it to the integrator.
  252.      * @param integ integrator into which event detector should be registered
  253.      * @param detector event detector to wrap
  254.      */
  255.     protected void setUpEventDetector(final FieldODEIntegrator<T> integ, final FieldEventDetector<T> detector) {
  256.         integ.addEventHandler(new FieldAdaptedEventDetector(detector),
  257.                               detector.getMaxCheckInterval().getReal(),
  258.                               detector.getThreshold().getReal(),
  259.                               detector.getMaxIterationCount());
  260.     }

  261.     /** {@inheritDoc}
  262.      * <p>Note that this method has the side effect of replacing the step handlers
  263.      * of the underlying integrator set up in the {@link
  264.      * #FieldAbstractIntegratedPropagator(Field, FieldODEIntegrator, PropagationType) constructor}. So if a specific
  265.      * step handler is needed, it should be added after this method has been callled.</p>
  266.      */
  267.     public void setSlaveMode() {
  268.         super.setSlaveMode();
  269.         if (integrator != null) {
  270.             integrator.clearStepHandlers();
  271.         }
  272.         modeHandler = null;
  273.     }

  274.     /** {@inheritDoc}
  275.      * <p>Note that this method has the side effect of replacing the step handlers
  276.      * of the underlying integrator set up in the {@link
  277.      * #FieldAbstractIntegratedPropagator(Field, FieldODEIntegrator, PropagationType) constructor}. So if a specific
  278.      * step handler is needed, it should be added after this method has been called.</p>
  279.      */
  280.     public void setMasterMode(final FieldOrekitStepHandler<T> handler) {
  281.         super.setMasterMode(handler);
  282.         integrator.clearStepHandlers();
  283.         final FieldAdaptedStepHandler wrapped = new FieldAdaptedStepHandler(handler);
  284.         integrator.addStepHandler(wrapped);
  285.         modeHandler = wrapped;
  286.     }

  287.     /** {@inheritDoc}
  288.      * <p>Note that this method has the side effect of replacing the step handlers
  289.      * of the underlying integrator set up in the {@link
  290.      * #FieldAbstractIntegratedPropagator(Field, FieldODEIntegrator, PropagationType) constructor}. So if a specific
  291.      * step handler is needed, it should be added after this method has been called.</p>
  292.      */
  293.     public void setEphemerisMode() {
  294.         super.setEphemerisMode();
  295.         integrator.clearStepHandlers();
  296.         final FieldEphemerisModeHandler ephemeris = new FieldEphemerisModeHandler();
  297.         modeHandler = ephemeris;
  298.         integrator.addStepHandler(ephemeris);
  299.     }

  300.     /** {@inheritDoc} */
  301.     public FieldBoundedPropagator<T> getGeneratedEphemeris()
  302.         throws IllegalStateException {
  303.         if (getMode() != EPHEMERIS_GENERATION_MODE) {
  304.             throw new OrekitIllegalStateException(OrekitMessages.PROPAGATOR_NOT_IN_EPHEMERIS_GENERATION_MODE);
  305.         }
  306.         return ((FieldEphemerisModeHandler) modeHandler).getEphemeris();
  307.     }

  308.     /** Create a mapper between raw double components and spacecraft state.
  309.     /** Simple constructor.
  310.      * <p>
  311.      * The position parameter type is meaningful only if {@link
  312.      * #getOrbitType() propagation orbit type}
  313.      * support it. As an example, it is not meaningful for propagation
  314.      * in {@link OrbitType#CARTESIAN Cartesian} parameters.
  315.      * </p>
  316.      * @param referenceDate reference date
  317.      * @param mu central attraction coefficient (m³/s²)
  318.      * @param orbitType orbit type to use for mapping
  319.      * @param positionAngleType angle type to use for propagation
  320.      * @param attitudeProvider attitude provider
  321.      * @param frame inertial frame
  322.      * @return new mapper
  323.      */
  324.     protected abstract FieldStateMapper<T> createMapper(FieldAbsoluteDate<T> referenceDate, T mu,
  325.                                                         OrbitType orbitType, PositionAngle positionAngleType,
  326.                                                         AttitudeProvider attitudeProvider, Frame frame);

  327.     /** Get the differential equations to integrate (for main state only).
  328.      * @param integ numerical integrator to use for propagation.
  329.      * @return differential equations for main state
  330.      */
  331.     protected abstract MainStateEquations<T> getMainStateEquations(FieldODEIntegrator<T> integ);

  332.     /** {@inheritDoc} */
  333.     public FieldSpacecraftState<T> propagate(final FieldAbsoluteDate<T> target) {
  334.         try {
  335.             if (getStartDate() == null) {
  336.                 if (getInitialState() == null) {
  337.                     throw new OrekitException(OrekitMessages.INITIAL_STATE_NOT_SPECIFIED_FOR_ORBIT_PROPAGATION);
  338.                 }
  339.                 setStartDate(getInitialState().getDate());
  340.             }
  341.             return propagate(getStartDate(), target);
  342.         } catch (OrekitException oe) {

  343.             // recover a possible embedded OrekitException
  344.             for (Throwable t = oe; t != null; t = t.getCause()) {
  345.                 if (t instanceof OrekitException) {
  346.                     throw (OrekitException) t;
  347.                 }
  348.             }
  349.             throw new OrekitException(oe);

  350.         }
  351.     }

  352.     /** {@inheritDoc} */
  353.     public FieldSpacecraftState<T> propagate(final FieldAbsoluteDate<T> tStart, final FieldAbsoluteDate<T> tEnd) {
  354.         try {

  355.             if (getInitialState() == null) {
  356.                 throw new OrekitException(OrekitMessages.INITIAL_STATE_NOT_SPECIFIED_FOR_ORBIT_PROPAGATION);
  357.             }

  358.             if (!tStart.equals(getInitialState().getDate())) {
  359.                 // if propagation start date is not initial date,
  360.                 // propagate from initial to start date without event detection
  361.                 propagate(tStart, false);
  362.             }

  363.             // propagate from start date to end date with event detection
  364.             return propagate(tEnd, true);

  365.         } catch (OrekitException oe) {

  366.             // recover a possible embedded OrekitException
  367.             for (Throwable t = oe; t != null; t = t.getCause()) {
  368.                 if (t instanceof OrekitException) {
  369.                     throw (OrekitException) t;
  370.                 }
  371.             }
  372.             throw new OrekitException(oe);

  373.         }
  374.     }

  375.     /** Propagation with or without event detection.
  376.      * @param tEnd target date to which orbit should be propagated
  377.      * @param activateHandlers if true, step and event handlers should be activated
  378.      * @return state at end of propagation
  379.      */
  380.     protected FieldSpacecraftState<T> propagate(final FieldAbsoluteDate<T> tEnd, final boolean activateHandlers) {
  381.         try {

  382.             initializePropagation();

  383.             if (getInitialState().getDate().equals(tEnd)) {
  384.                 // don't extrapolate
  385.                 return getInitialState();
  386.             }
  387.             // space dynamics view
  388.             stateMapper = createMapper(getInitialState().getDate(), stateMapper.getMu(),
  389.                                        stateMapper.getOrbitType(), stateMapper.getPositionAngleType(),
  390.                                        stateMapper.getAttitudeProvider(), getInitialState().getFrame());


  391.             // set propagation orbit type
  392.             //final FieldOrbit<T> initialOrbit = stateMapper.getOrbitType().convertType(getInitialState().getOrbit());
  393.             if (Double.isNaN(getMu().getReal())) {
  394.                 setMu(getInitialState().getMu());
  395.             }
  396.             if (getInitialState().getMass().getReal() <= 0.0) {
  397.                 throw new OrekitException(OrekitMessages.SPACECRAFT_MASS_BECOMES_NEGATIVE,
  398.                                                getInitialState().getMass());
  399.             }

  400.             integrator.clearEventHandlers();
  401.             // set up events added by user
  402.             setUpUserEventDetectors();

  403.             // convert space flight dynamics API to math API
  404.             final FieldSpacecraftState<T> initialIntegrationState = getInitialIntegrationState();
  405.             final FieldODEState<T> mathInitialState = createInitialState(initialIntegrationState);
  406.             final FieldExpandableODE<T> mathODE = createODE(integrator, mathInitialState);
  407.             equationsMapper = mathODE.getMapper();
  408.             mathInterpolator = null;
  409.             // initialize mode handler
  410.             if (modeHandler != null) {
  411.                 modeHandler.initialize(activateHandlers, tEnd);
  412.             }
  413.             // mathematical integration
  414.             final FieldODEStateAndDerivative<T> mathFinalState;

  415.             beforeIntegration(initialIntegrationState, tEnd);
  416.             mathFinalState = integrator.integrate(mathODE, mathInitialState,
  417.                                                   tEnd.durationFrom(getInitialState().getDate()));

  418.             afterIntegration();

  419.             // get final state
  420.             FieldSpacecraftState<T> finalState =
  421.                             stateMapper.mapArrayToState(stateMapper.mapDoubleToDate(mathFinalState.getTime(), tEnd),
  422.                                                         mathFinalState.getPrimaryState(),
  423.                                                         mathFinalState.getPrimaryDerivative(),
  424.                                                         propagationType);
  425.             finalState = updateAdditionalStates(finalState);
  426.             for (int i = 0; i < additionalEquations.size(); ++i) {
  427.                 final T[] secondary = mathFinalState.getSecondaryState(i + 1);
  428.                 finalState = finalState.addAdditionalState(additionalEquations.get(i).getName(),
  429.                                                            secondary);
  430.             }
  431.             if (resetAtEnd) {
  432.                 resetInitialState(finalState);
  433.                 setStartDate(finalState.getDate());
  434.             }

  435.             return finalState;

  436.         } catch (OrekitException pe) {
  437.             throw pe;
  438.         } catch (MathIllegalArgumentException miae) {
  439.             throw OrekitException.unwrap(miae);
  440.         } catch (MathIllegalStateException mise) {
  441.             throw OrekitException.unwrap(mise);
  442.         }
  443.     }

  444.     /** Get the initial state for integration.
  445.      * @return initial state for integration
  446.      */
  447.     protected FieldSpacecraftState<T> getInitialIntegrationState() {
  448.         return getInitialState();
  449.     }

  450.     /** Create an initial state.
  451.      * @param initialState initial state in flight dynamics world
  452.      * @return initial state in mathematics world
  453.      */
  454.     private FieldODEState<T> createInitialState(final FieldSpacecraftState<T> initialState) {

  455.         // retrieve initial state
  456.         final T[] primary  = MathArrays.buildArray(initialState.getA().getField(), getBasicDimension());
  457.         stateMapper.mapStateToArray(initialState, primary, null);

  458.         // secondary part of the ODE
  459.         final T[][] secondary = MathArrays.buildArray(initialState.getA().getField(), additionalEquations.size(), -1);
  460.         for (int i = 0; i < additionalEquations.size(); ++i) {
  461.             final FieldAdditionalEquations<T> additional = additionalEquations.get(i);
  462.             final T[] addState = getInitialState().getAdditionalState(additional.getName());
  463.             secondary[i] = MathArrays.buildArray(initialState.getA().getField(), addState.length);
  464.             for (int j = 0; j < addState.length; j++) {
  465.                 secondary[i][j] = addState[j];
  466.             }
  467.         }

  468.         return new FieldODEState<>(initialState.getA().getField().getZero(), primary, secondary);

  469.     }

  470.     /** Create an ODE with all equations.
  471.      * @param integ numerical integrator to use for propagation.
  472.      * @param mathInitialState initial state
  473.      * @return a new ode
  474.      */
  475.     private FieldExpandableODE<T> createODE(final FieldODEIntegrator<T> integ,
  476.                                     final FieldODEState<T> mathInitialState) {

  477.         final FieldExpandableODE<T> ode =
  478.                 new FieldExpandableODE<>(new ConvertedMainStateEquations(getMainStateEquations(integ)));

  479.         // secondary part of the ODE
  480.         for (int i = 0; i < additionalEquations.size(); ++i) {
  481.             final FieldAdditionalEquations<T> additional = additionalEquations.get(i);
  482.             final FieldSecondaryODE<T> secondary =
  483.                     new ConvertedSecondaryStateEquations(additional,
  484.                                                          mathInitialState.getSecondaryStateDimension(i + 1));
  485.             ode.addSecondaryEquations(secondary);
  486.         }

  487.         return ode;

  488.     }

  489.     /** Method called just before integration.
  490.      * <p>
  491.      * The default implementation does nothing, it may be specialized in subclasses.
  492.      * </p>
  493.      * @param initialState initial state
  494.      * @param tEnd target date at which state should be propagated
  495.      */
  496.     protected void beforeIntegration(final FieldSpacecraftState<T> initialState,
  497.                                      final FieldAbsoluteDate<T> tEnd) {
  498.         // do nothing by default
  499.     }

  500.     /** Method called just after integration.
  501.      * <p>
  502.      * The default implementation does nothing, it may be specialized in subclasses.
  503.      * </p>
  504.      */
  505.     protected void afterIntegration() {
  506.         // do nothing by default
  507.     }

  508.     /** Get state vector dimension without additional parameters.
  509.      * @return state vector dimension without additional parameters.
  510.      */
  511.     public int getBasicDimension() {
  512.         return 7;

  513.     }

  514.     /** Get the integrator used by the propagator.
  515.      * @return the integrator.
  516.      */
  517.     protected FieldODEIntegrator<T> getIntegrator() {
  518.         return integrator;
  519.     }

  520.     /** Get a complete state with all additional equations.
  521.      * @param t current value of the independent <I>time</I> variable
  522.      * @param ts array containing the current value of the state vector
  523.      * @param tsDot array containing the current value of the state vector derivative
  524.      * @return complete state
  525.      */
  526.     private FieldSpacecraftState<T> getCompleteState(final T t, final T[] ts, final T[] tsDot) {

  527.         // main state
  528.         FieldSpacecraftState<T> state = stateMapper.mapArrayToState(t, ts, tsDot, PropagationType.MEAN);  //not sure of the mean orbit, should be true
  529.         // pre-integrated additional states
  530.         state = updateAdditionalStates(state);

  531.         // additional states integrated here
  532.         if (!additionalEquations.isEmpty()) {

  533.             for (int i = 0; i < additionalEquations.size(); ++i) {
  534.                 state = state.addAdditionalState(additionalEquations.get(i).getName(),
  535.                                                  equationsMapper.extractEquationData(i + 1, ts));
  536.             }

  537.         }

  538.         return state;

  539.     }

  540.     /** Differential equations for the main state (orbit, attitude and mass). */
  541.     public interface MainStateEquations<T extends RealFieldElement<T>> {

  542.         /**
  543.          * Initialize the equations at the start of propagation. This method will be
  544.          * called before any calls to {@link #computeDerivatives(FieldSpacecraftState)}.
  545.          *
  546.          * <p> The default implementation of this method does nothing.
  547.          *
  548.          * @param initialState initial state information at the start of propagation.
  549.          * @param target       date of propagation. Not equal to {@code
  550.          *                     initialState.getDate()}.
  551.          */
  552.         void init(FieldSpacecraftState<T> initialState, FieldAbsoluteDate<T> target);

  553.         /** Compute differential equations for main state.
  554.          * @param state current state
  555.          * @return derivatives of main state
  556.          */
  557.         T[] computeDerivatives(FieldSpacecraftState<T> state);

  558.     }

  559.     /** Differential equations for the main state (orbit, attitude and mass), with converted API. */
  560.     private class ConvertedMainStateEquations implements FieldOrdinaryDifferentialEquation<T> {

  561.         /** Main state equations. */
  562.         private final MainStateEquations<T> main;

  563.         /** Simple constructor.
  564.          * @param main main state equations
  565.          */
  566.         ConvertedMainStateEquations(final MainStateEquations<T> main) {
  567.             this.main = main;
  568.             calls = 0;
  569.         }

  570.         /** {@inheritDoc} */
  571.         public int getDimension() {
  572.             return getBasicDimension();
  573.         }

  574.         @Override
  575.         public void init(final T t0, final T[] y0, final T finalTime) {
  576.             // update space dynamics view
  577.             FieldSpacecraftState<T> initialState = stateMapper.mapArrayToState(t0, y0, null, PropagationType.MEAN);
  578.             initialState = updateAdditionalStates(initialState);
  579.             final FieldAbsoluteDate<T> target = stateMapper.mapDoubleToDate(finalTime);
  580.             main.init(initialState, target);
  581.         }
  582.         /** {@inheritDoc} */
  583.         public T[] computeDerivatives(final T t, final T[] y) {

  584.             // increment calls counter
  585.             ++calls;

  586.             // update space dynamics view
  587.             FieldSpacecraftState<T> currentState = stateMapper.mapArrayToState(t, y, null, PropagationType.MEAN);
  588.             currentState = updateAdditionalStates(currentState);

  589.             // compute main state differentials
  590.             return main.computeDerivatives(currentState);

  591.         }

  592.     }

  593.     /** Differential equations for the secondary state (Jacobians, user variables ...), with converted API. */
  594.     private class ConvertedSecondaryStateEquations implements FieldSecondaryODE<T> {

  595.         /** Additional equations. */
  596.         private final FieldAdditionalEquations<T> equations;

  597.         /** Dimension of the additional state. */
  598.         private final int dimension;

  599.         /** Simple constructor.
  600.          * @param equations additional equations
  601.          * @param dimension dimension of the additional state
  602.          */
  603.         ConvertedSecondaryStateEquations(final FieldAdditionalEquations<T> equations,
  604.                                          final int dimension) {
  605.             this.equations = equations;
  606.             this.dimension = dimension;
  607.         }

  608.         /** {@inheritDoc} */
  609.         @Override
  610.         public int getDimension() {
  611.             return dimension;
  612.         }

  613.         /** {@inheritDoc} */
  614.         @Override
  615.         public void init(final T t0, final T[] primary0,
  616.                          final T[] secondary0, final T finalTime) {
  617.             // update space dynamics view
  618.             FieldSpacecraftState<T> initialState = stateMapper.mapArrayToState(t0, primary0, null, PropagationType.MEAN);
  619.             initialState = updateAdditionalStates(initialState);
  620.             initialState = initialState.addAdditionalState(equations.getName(), secondary0);
  621.             final FieldAbsoluteDate<T> target = stateMapper.mapDoubleToDate(finalTime);
  622.             equations.init(initialState, target);
  623.         }

  624.         /** {@inheritDoc} */
  625.         @Override
  626.         public T[] computeDerivatives(final T t, final T[] primary,
  627.                                       final T[] primaryDot, final T[] secondary) {

  628.             // update space dynamics view
  629.             FieldSpacecraftState<T> currentState = stateMapper.mapArrayToState(t, primary, primaryDot, PropagationType.MEAN);
  630.             currentState = updateAdditionalStates(currentState);
  631.             currentState = currentState.addAdditionalState(equations.getName(), secondary);

  632.             // compute additional derivatives
  633.             final T[] secondaryDot = MathArrays.buildArray(getField(), secondary.length);
  634.             final T[] additionalMainDot =
  635.                             equations.computeDerivatives(currentState, secondaryDot);
  636.             if (additionalMainDot != null) {
  637.                 // the additional equations have an effect on main equations
  638.                 for (int i = 0; i < additionalMainDot.length; ++i) {
  639.                     primaryDot[i] = primaryDot[i].add(additionalMainDot[i]);
  640.                 }
  641.             }

  642.             return secondaryDot;

  643.         }

  644.     }

  645.     /** Adapt an {@link org.orekit.propagation.events.FieldEventDetector<T>}
  646.      * to Hipparchus {@link org.hipparchus.ode.events.FieldODEEventHandler<T>} interface.
  647.      * @param <T> class type for the generic version
  648.      * @author Fabien Maussion
  649.      */
  650.     private class FieldAdaptedEventDetector implements FieldODEEventHandler<T> {

  651.         /** Underlying event detector. */
  652.         private final FieldEventDetector<T> detector;

  653.         /** Time of the previous call to g. */
  654.         private T lastT;

  655.         /** Value from the previous call to g. */
  656.         private T lastG;

  657.         /** Build a wrapped event detector.
  658.          * @param detector event detector to wrap
  659.         */
  660.         FieldAdaptedEventDetector(final FieldEventDetector<T> detector) {
  661.             this.detector = detector;
  662.             this.lastT    = getField().getZero().add(Double.NaN);
  663.             this.lastG    = getField().getZero().add(Double.NaN);
  664.         }

  665.         /** {@inheritDoc} */
  666.         public void init(final FieldODEStateAndDerivative<T> s0, final T t) {
  667.             detector.init(getCompleteState(s0.getTime(), s0.getCompleteState(), s0.getCompleteDerivative()),
  668.                           stateMapper.mapDoubleToDate(t));
  669.             this.lastT = getField().getZero().add(Double.NaN);
  670.             this.lastG = getField().getZero().add(Double.NaN);
  671.         }

  672.         /** {@inheritDoc} */
  673.         public T g(final FieldODEStateAndDerivative<T> s) {
  674.             if (!Precision.equals(lastT.getReal(), s.getTime().getReal(), 0)) {
  675.                 lastT = s.getTime();
  676.                 lastG = detector.g(getCompleteState(s.getTime(), s.getCompleteState(), s.getCompleteDerivative()));
  677.             }
  678.             return lastG;
  679.         }

  680.         /** {@inheritDoc} */
  681.         public Action eventOccurred(final FieldODEStateAndDerivative<T> s, final boolean increasing) {
  682.             return detector.eventOccurred(
  683.                     getCompleteState(
  684.                             s.getTime(),
  685.                             s.getCompleteState(),
  686.                             s.getCompleteDerivative()),
  687.                     increasing);
  688.         }

  689.         /** {@inheritDoc} */
  690.         public FieldODEState<T> resetState(final FieldODEStateAndDerivative<T> s) {

  691.             final FieldSpacecraftState<T> oldState = getCompleteState(s.getTime(), s.getCompleteState(), s.getCompleteDerivative());
  692.             final FieldSpacecraftState<T> newState = detector.resetState(oldState);
  693.             stateChanged(newState);

  694.             // main part
  695.             final T[] primary    = MathArrays.buildArray(getField(), s.getPrimaryStateDimension());
  696.             stateMapper.mapStateToArray(newState, primary, null);

  697.             // secondary part
  698.             final T[][] secondary    = MathArrays.buildArray(getField(), additionalEquations.size(), -1);

  699.             for (int i = 0; i < additionalEquations.size(); ++i) {
  700.                 final FieldAdditionalEquations<T> additional = additionalEquations.get(i);
  701.                 final T[] NState = newState.getAdditionalState(additional.getName());
  702.                 secondary[i] = MathArrays.buildArray(getField(), NState.length);
  703.                 for (int j = 0; j < NState.length; j++) {
  704.                     secondary[i][j] = NState[j];
  705.                 }
  706.             }

  707.             return new FieldODEState<>(newState.getDate().durationFrom(getStartDate()),
  708.                                        primary, secondary);
  709.         }

  710.     }

  711.     /** Adapt an {@link org.orekit.propagation.sampling.FieldOrekitStepHandler<T>}
  712.      * to Hipparchus {@link FieldODEStepHandler<T>} interface.
  713.      * @author Luc Maisonobe
  714.      */
  715.     private class FieldAdaptedStepHandler
  716.         implements FieldOrekitStepInterpolator<T>, FieldODEStepHandler<T>, FieldModeHandler<T> {

  717.         /** Underlying handler. */
  718.         private final FieldOrekitStepHandler<T> handler;

  719.         /** Flag for handler . */
  720.         private boolean activate;

  721.         /** Build an instance.
  722.          * @param handler underlying handler to wrap
  723.          */
  724.         FieldAdaptedStepHandler(final FieldOrekitStepHandler<T> handler) {
  725.             this.handler = handler;
  726.         }

  727.         /** {@inheritDoc} */
  728.         public void initialize(final boolean activateHandlers,
  729.                                final FieldAbsoluteDate<T> targetDate) {
  730.             this.activate = activateHandlers;
  731.         }
  732.         /** {@inheritDoc} */
  733.         public void init(final FieldODEStateAndDerivative<T> s0, final T t) {
  734.             handler.init(getCompleteState(s0.getTime(), s0.getCompleteState(), s0.getCompleteDerivative()),
  735.                          stateMapper.mapDoubleToDate(t));
  736.         }

  737.         /** {@inheritDoc} */
  738.         public void handleStep(final FieldODEStateInterpolator<T> interpolator, final boolean isLast) {
  739.             mathInterpolator = interpolator;
  740.             if (activate) {
  741.                 handler.handleStep(this, isLast);
  742.             }
  743.         }

  744.         /** {@inheritDoc}} */
  745.         @Override
  746.         public FieldSpacecraftState<T> getPreviousState() {
  747.             return convert(mathInterpolator.getPreviousState());
  748.         }

  749.         /** {@inheritDoc}} */
  750.         @Override
  751.         public FieldSpacecraftState<T> getCurrentState() {
  752.             return convert(mathInterpolator.getCurrentState());
  753.         }

  754.         /** {@inheritDoc}} */
  755.         @Override
  756.         public FieldSpacecraftState<T> getInterpolatedState(final FieldAbsoluteDate<T> date) {
  757.             return convert(mathInterpolator.getInterpolatedState(date.durationFrom(getStartDate())));
  758.         }

  759.         /** Get the interpolated state.
  760.          * @param os mathematical state
  761.          * @return interpolated state at the current interpolation date
  762.                            * the date
  763.          * @see #getInterpolatedDate()
  764.          * @see #setInterpolatedDate(FieldAbsoluteDate<T>)
  765.          */
  766.         private FieldSpacecraftState<T> convert(final FieldODEStateAndDerivative<T> os) {
  767.             try {

  768.                 FieldSpacecraftState<T> s =
  769.                         stateMapper.mapArrayToState(os.getTime(),
  770.                                                     os.getPrimaryState(),
  771.                                                     os.getPrimaryDerivative(),
  772.                                                     propagationType);
  773.                 s = updateAdditionalStates(s);
  774.                 for (int i = 0; i < additionalEquations.size(); ++i) {
  775.                     final T[] secondary = os.getSecondaryState(i + 1);
  776.                     s = s.addAdditionalState(additionalEquations.get(i).getName(), secondary);
  777.                 }

  778.                 return s;

  779.             } catch (OrekitException oe) {
  780.                 throw new OrekitException(oe);
  781.             }
  782.         }

  783.         /** Check is integration direction is forward in date.
  784.          * @return true if integration is forward in date
  785.          */
  786.         public boolean isForward() {
  787.             return mathInterpolator.isForward();
  788.         }

  789.     }

  790.     private class FieldEphemerisModeHandler implements FieldModeHandler<T>, FieldODEStepHandler<T> {

  791.         /** Underlying raw mathematical model. */
  792.         private FieldDenseOutputModel<T> model;

  793.         /** Generated ephemeris. */
  794.         private FieldBoundedPropagator<T> ephemeris;

  795.         /** Flag for handler . */
  796.         private boolean activate;

  797.         /** the user supplied end date. Propagation may not end on this date. */
  798.         private FieldAbsoluteDate<T> endDate;

  799.         /** Creates a new instance of FieldEphemerisModeHandler which must be
  800.          *  filled by the propagator.
  801.          */
  802.         FieldEphemerisModeHandler() {
  803.         }

  804.         /** {@inheritDoc} */
  805.         public void initialize(final boolean activateHandlers,
  806.                                final FieldAbsoluteDate<T> targetDate) {
  807.             this.activate = activateHandlers;
  808.             this.model    = new FieldDenseOutputModel<>();
  809.             this.endDate  = targetDate;

  810.             // ephemeris will be generated when last step is processed
  811.             this.ephemeris = null;

  812.         }

  813.         /** Get the generated ephemeris.
  814.          * @return a new instance of the generated ephemeris
  815.          */
  816.         public FieldBoundedPropagator<T> getEphemeris() {
  817.             return ephemeris;
  818.         }

  819.         /** {@inheritDoc} */
  820.         public void handleStep(final FieldODEStateInterpolator<T> interpolator, final boolean isLast) {
  821.             if (activate) {
  822.                 model.handleStep(interpolator, isLast);
  823.                 if (isLast) {

  824.                     // set up the boundary dates
  825.                     final T tI = model.getInitialTime();
  826.                     final T tF = model.getFinalTime();
  827.                     // tI is almost? always zero
  828.                     final FieldAbsoluteDate<T> startDate =
  829.                                     stateMapper.mapDoubleToDate(tI);
  830.                     final FieldAbsoluteDate<T> finalDate =
  831.                                     stateMapper.mapDoubleToDate(tF, this.endDate);
  832.                     final FieldAbsoluteDate<T> minDate;
  833.                     final FieldAbsoluteDate<T> maxDate;
  834.                     if (tF.getReal() < tI.getReal()) {
  835.                         minDate = finalDate;
  836.                         maxDate = startDate;
  837.                     } else {
  838.                         minDate = startDate;
  839.                         maxDate = finalDate;
  840.                     }

  841.                     // get the initial additional states that are not managed
  842.                     final Map<String, T[]> unmanaged = new HashMap<String, T[]>();
  843.                     for (final Map.Entry<String, T[]> initial : getInitialState().getAdditionalStates().entrySet()) {
  844.                         if (!isAdditionalStateManaged(initial.getKey())) {
  845.                             // this additional state was in the initial state, but is unknown to the propagator
  846.                             // we simply copy its initial value as is
  847.                             unmanaged.put(initial.getKey(), initial.getValue());
  848.                         }
  849.                     }

  850.                     // get the names of additional states managed by differential equations
  851.                     final String[] names = new String[additionalEquations.size()];
  852.                     for (int i = 0; i < names.length; ++i) {
  853.                         names[i] = additionalEquations.get(i).getName();
  854.                     }

  855.                     // create the ephemeris
  856.                     ephemeris = new FieldIntegratedEphemeris<>(startDate, minDate, maxDate,
  857.                                                                stateMapper, propagationType, model, unmanaged,
  858.                                                                getAdditionalStateProviders(), names);

  859.                 }

  860.             }
  861.         }

  862.         /** {@inheritDoc} */
  863.         public void init(final FieldODEStateAndDerivative<T> s0, final T t) {
  864.             model.init(s0, t);
  865.         }

  866.     }

  867. }