FieldAbstractIntegratedPropagator.java

  1. /* Copyright 2002-2018 CS Systèmes d'Information
  2.  * Licensed to CS Systèmes d'Information (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.OrekitExceptionWrapper;
  45. import org.orekit.errors.OrekitIllegalStateException;
  46. import org.orekit.errors.OrekitMessages;
  47. import org.orekit.frames.Frame;
  48. import org.orekit.orbits.FieldOrbit;
  49. import org.orekit.orbits.OrbitType;
  50. import org.orekit.orbits.PositionAngle;
  51. import org.orekit.propagation.FieldAbstractPropagator;
  52. import org.orekit.propagation.FieldBoundedPropagator;
  53. import org.orekit.propagation.FieldSpacecraftState;
  54. import org.orekit.propagation.events.FieldEventDetector;
  55. import org.orekit.propagation.events.handlers.FieldEventHandler;
  56. import org.orekit.propagation.sampling.FieldOrekitStepHandler;
  57. import org.orekit.propagation.sampling.FieldOrekitStepInterpolator;
  58. import org.orekit.time.FieldAbsoluteDate;


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

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

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

  68.     /** Mode handler. */
  69.     private FieldModeHandler<T> modeHandler;

  70.     /** Additional equations. */
  71.     private List<FieldAdditionalEquations<T>> additionalEquations;

  72.     /** Counter for differential equations calls. */
  73.     private int calls;

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

  76.     /** Equations mapper. */
  77.     private FieldEquationsMapper<T> equationsMapper;

  78.     /** Underlying raw rawInterpolator. */
  79.     private FieldODEStateInterpolator<T> mathInterpolator;

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

  82.     /** Output only the mean orbit. <br/>
  83.      * <p>
  84.      * This is used only in the case of semianalitical propagators where there is a clear separation between
  85.      * mean and short periodic elements. It is ignored by the Numerical propagator.
  86.      * </p>
  87.      */
  88.     private boolean meanOrbit;

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

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

  117.     /** Initialize the mapper. */
  118.     protected void initMapper() {
  119.         stateMapper = createMapper(null, Double.NaN, null, null, null, null);
  120.     }

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

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

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

  142.     /** Check if only the mean elements should be used in a semianalitical propagation.
  143.      * @return true if only mean elements have to be used
  144.      */
  145.     protected boolean isMeanOrbit() {
  146.         return meanOrbit;
  147.     }

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

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

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

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

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

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

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

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

  204.         return false;
  205.     }

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

  217.     /** Add a set of user-specified equations to be integrated along with the orbit propagation.
  218.      * @param additional additional equations
  219.      * @exception OrekitException if a set of equations with the same name is already present
  220.      */
  221.     public void addAdditionalEquations(final FieldAdditionalEquations<T> additional)
  222.         throws OrekitException {

  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, boolean) 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, boolean) 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, boolean) 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, double 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) throws OrekitException {
  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.         throws OrekitException {
  355.         try {

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

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

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

  366.         } catch (OrekitException oe) {

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

  374.         }
  375.     }

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

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


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

  402.             integrator.clearEventHandlers();
  403.             // set up events added by user
  404.             setUpUserEventDetectors();

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

  417.                 beforeIntegration(getInitialState(), tEnd);
  418.                 mathFinalState = integrator.integrate(mathODE, mathInitialState,
  419.                                                       tEnd.durationFrom(getInitialState().getDate()));

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

  441.             return finalState;

  442.         } catch (OrekitException pe) {
  443.             throw pe;
  444.         } catch (MathIllegalArgumentException miae) {
  445.             throw OrekitException.unwrap(miae);
  446.         } catch (MathIllegalStateException mise) {
  447.             throw OrekitException.unwrap(mise);
  448.         }
  449.     }

  450.     /** Get the initial state for integration.
  451.      * @return initial state for integration
  452.      * @exception OrekitException if initial state cannot be retrieved
  453.      */
  454.     protected FieldSpacecraftState<T> getInitialIntegrationState() throws OrekitException {
  455.         return getInitialState();
  456.     }

  457.     /** Create an initial state.
  458.      * @param initialState initial state in flight dynamics world
  459.      * @return initial state in mathematics world
  460.      * @exception OrekitException if initial state cannot be mapped
  461.      */
  462.     private FieldODEState<T> createInitialState(final FieldSpacecraftState<T> initialState)
  463.         throws OrekitException {

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

  467.         // secondary part of the ODE
  468.         final T[][] secondary = MathArrays.buildArray(initialState.getA().getField(), additionalEquations.size(), -1);
  469.         for (int i = 0; i < additionalEquations.size(); ++i) {
  470.             final FieldAdditionalEquations<T> additional = additionalEquations.get(i);
  471.             final T[] addState = getInitialState().getAdditionalState(additional.getName());
  472.             secondary[i] = MathArrays.buildArray(initialState.getA().getField(), addState.length);
  473.             for (int j = 0; j < addState.length; j++) {
  474.                 secondary[i][j] = addState[j];
  475.             }
  476.         }

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

  478.     }

  479.     /** Create an ODE with all equations.
  480.      * @param integ numerical integrator to use for propagation.
  481.      * @param mathInitialState initial state
  482.      * @return a new ode
  483.      * @exception OrekitException if initial state cannot be mapped
  484.      */
  485.     private FieldExpandableODE<T> createODE(final FieldODEIntegrator<T> integ,
  486.                                     final FieldODEState<T> mathInitialState)
  487.         throws OrekitException {

  488.         final FieldExpandableODE<T> ode =
  489.                 new FieldExpandableODE<>(new ConvertedMainStateEquations(getMainStateEquations(integ)));

  490.         // secondary part of the ODE
  491.         for (int i = 0; i < additionalEquations.size(); ++i) {
  492.             final FieldAdditionalEquations<T> additional = additionalEquations.get(i);
  493.             final FieldSecondaryODE<T> secondary =
  494.                     new ConvertedSecondaryStateEquations(additional,
  495.                                                          mathInitialState.getSecondaryStateDimension(i + 1));
  496.             ode.addSecondaryEquations(secondary);
  497.         }

  498.         return ode;

  499.     }

  500.     /** Method called just before integration.
  501.      * <p>
  502.      * The default implementation does nothing, it may be specialized in subclasses.
  503.      * </p>
  504.      * @param initialState initial state
  505.      * @param tEnd target date at which state should be propagated
  506.      * @exception OrekitException if hook cannot be run
  507.      */
  508.     protected void beforeIntegration(final FieldSpacecraftState<T> initialState,
  509.                                      final FieldAbsoluteDate<T> tEnd)
  510.         throws OrekitException {
  511.         // do nothing by default
  512.     }

  513.     /** Method called just after integration.
  514.      * <p>
  515.      * The default implementation does nothing, it may be specialized in subclasses.
  516.      * </p>
  517.      * @exception OrekitException if hook cannot be run
  518.      */
  519.     protected void afterIntegration()
  520.         throws OrekitException {
  521.         // do nothing by default
  522.     }

  523.     /** Get state vector dimension without additional parameters.
  524.      * @return state vector dimension without additional parameters.
  525.      */
  526.     public int getBasicDimension() {
  527.         return 7;

  528.     }

  529.     /** Get the integrator used by the propagator.
  530.      * @return the integrator.
  531.      */
  532.     protected FieldODEIntegrator<T> getIntegrator() {
  533.         return integrator;
  534.     }

  535.     /** Get a complete state with all additional equations.
  536.      * @param t current value of the independent <I>time</I> variable
  537.      * @param ts array containing the current value of the state vector
  538.      * @param tsDot array containing the current value of the state vector derivative
  539.      * @return complete state
  540.      * @exception OrekitException if state cannot be mapped
  541.      */
  542.     private FieldSpacecraftState<T> getCompleteState(final T t, final T[] ts, final T[] tsDot)
  543.         throws OrekitException {

  544.         // main state
  545.         FieldSpacecraftState<T> state = stateMapper.mapArrayToState(t, ts, tsDot, true);  //not sure of the mean orbit, should be true
  546.         // pre-integrated additional states
  547.         state = updateAdditionalStates(state);

  548.         // additional states integrated here
  549.         if (!additionalEquations.isEmpty()) {

  550.             for (int i = 0; i < additionalEquations.size(); ++i) {
  551.                 state = state.addAdditionalState(additionalEquations.get(i).getName(),
  552.                                                  equationsMapper.extractEquationData(i + 1, ts));
  553.             }

  554.         }

  555.         return state;

  556.     }

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

  559.         /**
  560.          * Initialize the equations at the start of propagation. This method will be
  561.          * called before any calls to {@link #computeDerivatives(FieldSpacecraftState)}.
  562.          *
  563.          * <p> The default implementation of this method does nothing.
  564.          *
  565.          * @param initialState initial state information at the start of propagation.
  566.          * @param target       date of propagation. Not equal to {@code
  567.          *                     initialState.getDate()}.
  568.          * @throws OrekitException if there is an Orekit related error during
  569.          *                         initialization.
  570.          */
  571.         void init(FieldSpacecraftState<T> initialState, FieldAbsoluteDate<T> target)
  572.             throws OrekitException;

  573.         /** Compute differential equations for main state.
  574.          * @param state current state
  575.          * @return derivatives of main state
  576.          * @throws OrekitException if differentials cannot be computed
  577.          */
  578.         T[] computeDerivatives(FieldSpacecraftState<T> state) throws OrekitException;

  579.     }

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

  582.         /** Main state equations. */
  583.         private final MainStateEquations<T> main;

  584.         /** Simple constructor.
  585.          * @param main main state equations
  586.          */
  587.         ConvertedMainStateEquations(final MainStateEquations<T> main) {
  588.             this.main = main;
  589.             calls = 0;
  590.         }

  591.         /** {@inheritDoc} */
  592.         public int getDimension() {
  593.             return getBasicDimension();
  594.         }

  595.         @Override
  596.         public void init(final T t0, final T[] y0, final T finalTime) {
  597.             try {
  598.                 // update space dynamics view
  599.                 FieldSpacecraftState<T> initialState = stateMapper.mapArrayToState(t0, y0, null, true);
  600.                 initialState = updateAdditionalStates(initialState);
  601.                 final FieldAbsoluteDate<T> target = stateMapper.mapDoubleToDate(finalTime);
  602.                 main.init(initialState, target);
  603.             } catch (OrekitException oe) {
  604.                 throw new OrekitExceptionWrapper(oe);
  605.             }
  606.         }
  607.         /** {@inheritDoc} */
  608.         public T[] computeDerivatives(final T t, final T[] y)
  609.             throws OrekitExceptionWrapper {
  610.             try {

  611.                 // increment calls counter
  612.                 ++calls;

  613.                 // update space dynamics view
  614.                 FieldSpacecraftState<T> currentState = stateMapper.mapArrayToState(t, y, null, true);
  615.                 currentState = updateAdditionalStates(currentState);

  616.                 // compute main state differentials
  617.                 return main.computeDerivatives(currentState);

  618.             } catch (OrekitException oe) {
  619.                 throw new OrekitExceptionWrapper(oe);
  620.             }
  621.         }

  622.     }

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

  625.         /** Additional equations. */
  626.         private final FieldAdditionalEquations<T> equations;

  627.         /** Dimension of the additional state. */
  628.         private final int dimension;

  629.         /** Simple constructor.
  630.          * @param equations additional equations
  631.          * @param dimension dimension of the additional state
  632.          */
  633.         ConvertedSecondaryStateEquations(final FieldAdditionalEquations<T> equations,
  634.                                          final int dimension) {
  635.             this.equations = equations;
  636.             this.dimension = dimension;
  637.         }

  638.         /** {@inheritDoc} */
  639.         @Override
  640.         public int getDimension() {
  641.             return dimension;
  642.         }

  643.         /** {@inheritDoc} */
  644.         @Override
  645.         public void init(final T t0, final T[] primary0,
  646.                          final T[] secondary0, final T finalTime) {
  647.             try {
  648.                 // update space dynamics view
  649.                 FieldSpacecraftState<T> initialState = stateMapper.mapArrayToState(t0, primary0, null, true);
  650.                 initialState = updateAdditionalStates(initialState);
  651.                 initialState = initialState.addAdditionalState(equations.getName(), secondary0);
  652.                 final FieldAbsoluteDate<T> target = stateMapper.mapDoubleToDate(finalTime);
  653.                 equations.init(initialState, target);
  654.             } catch (OrekitException oe) {
  655.                 throw new OrekitExceptionWrapper(oe);
  656.             }

  657.         }

  658.         /** {@inheritDoc} */
  659.         @Override
  660.         public T[] computeDerivatives(final T t, final T[] primary,
  661.                                       final T[] primaryDot, final T[] secondary)
  662.             throws OrekitExceptionWrapper {

  663.             try {

  664.                 // update space dynamics view
  665.                 FieldSpacecraftState<T> currentState = stateMapper.mapArrayToState(t, primary, primaryDot, true);
  666.                 currentState = updateAdditionalStates(currentState);
  667.                 currentState = currentState.addAdditionalState(equations.getName(), secondary);

  668.                 // compute additional derivatives
  669.                 final T[] secondaryDot = MathArrays.buildArray(getField(), secondary.length);
  670.                 final T[] additionalMainDot =
  671.                         equations.computeDerivatives(currentState, secondaryDot);
  672.                 if (additionalMainDot != null) {
  673.                     // the additional equations have an effect on main equations
  674.                     for (int i = 0; i < additionalMainDot.length; ++i) {
  675.                         primaryDot[i] = primaryDot[i].add(additionalMainDot[i]);
  676.                     }
  677.                 }
  678.                 return secondaryDot;

  679.             } catch (OrekitException oe) {
  680.                 throw new OrekitExceptionWrapper(oe);
  681.             }

  682.         }

  683.     }

  684.     /** Adapt an {@link org.orekit.propagation.events.FieldEventDetector<T>}
  685.      * to Hipparchus {@link org.hipparchus.ode.events.FieldODEEventHandler<T>} interface.
  686.      * @param <T> class type for the generic version
  687.      * @author Fabien Maussion
  688.      */
  689.     private class FieldAdaptedEventDetector implements FieldODEEventHandler<T> {

  690.         /** Underlying event detector. */
  691.         private final FieldEventDetector<T> detector;

  692.         /** Time of the previous call to g. */
  693.         private T lastT;

  694.         /** Value from the previous call to g. */
  695.         private T lastG;

  696.         /** Build a wrapped event detector.
  697.          * @param detector event detector to wrap
  698.         */
  699.         FieldAdaptedEventDetector(final FieldEventDetector<T> detector) {
  700.             this.detector = detector;
  701.             this.lastT    = getField().getZero().add(Double.NaN);
  702.             this.lastG    = getField().getZero().add(Double.NaN);
  703.         }

  704.         /** {@inheritDoc} */
  705.         public void init(final FieldODEStateAndDerivative<T> s0, final T t) {
  706.             try {

  707.                 detector.init(getCompleteState(s0.getTime(), s0.getCompleteState(), s0.getCompleteDerivative()),
  708.                               stateMapper.mapDoubleToDate(t));
  709.                 this.lastT = getField().getZero().add(Double.NaN);
  710.                 this.lastG = getField().getZero().add(Double.NaN);

  711.             } catch (OrekitException oe) {
  712.                 throw new OrekitExceptionWrapper(oe);
  713.             }
  714.         }

  715.         /** {@inheritDoc} */
  716.         public T g(final FieldODEStateAndDerivative<T> s) {
  717.             try {
  718.                 if (!Precision.equals(lastT.getReal(), s.getTime().getReal(), 0)) {
  719.                     lastT = s.getTime();
  720.                     lastG = detector.g(getCompleteState(s.getTime(), s.getCompleteState(), s.getCompleteDerivative()));
  721.                 }
  722.                 return lastG;
  723.             } catch (OrekitException oe) {
  724.                 throw new OrekitExceptionWrapper(oe);
  725.             }
  726.         }

  727.         /** {@inheritDoc} */
  728.         public Action eventOccurred(final FieldODEStateAndDerivative<T> s, final boolean increasing) {
  729.             try {

  730.                 final FieldEventHandler.Action whatNext = detector.eventOccurred(getCompleteState(s.getTime(),
  731.                                                                                                   s.getCompleteState(),
  732.                                                                                                   s.getCompleteDerivative()),
  733.                                                                             increasing);

  734.                 switch (whatNext) {
  735.                     case STOP :
  736.                         return Action.STOP;
  737.                     case RESET_STATE :
  738.                         return Action.RESET_STATE;
  739.                     case RESET_DERIVATIVES :
  740.                         return Action.RESET_DERIVATIVES;
  741.                     default :
  742.                         return Action.CONTINUE;
  743.                 }
  744.             } catch (OrekitException oe) {
  745.                 throw new OrekitExceptionWrapper(oe);
  746.             }
  747.         }

  748.         /** {@inheritDoc} */
  749.         public FieldODEState<T> resetState(final FieldODEStateAndDerivative<T> s) {
  750.             try {

  751.                 final FieldSpacecraftState<T> oldState = getCompleteState(s.getTime(), s.getCompleteState(), s.getCompleteDerivative());
  752.                 final FieldSpacecraftState<T> newState = detector.resetState(oldState);

  753.                 // main part
  754.                 final T[] primary    = MathArrays.buildArray(getField(), s.getPrimaryStateDimension());
  755.                 stateMapper.mapStateToArray(newState, primary, null);

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

  758.                 for (int i = 0; i < additionalEquations.size(); ++i) {
  759.                     final FieldAdditionalEquations<T> additional = additionalEquations.get(i);
  760.                     final T[] NState = newState.getAdditionalState(additional.getName());
  761.                     secondary[i] = MathArrays.buildArray(getField(), NState.length);
  762.                     for (int j = 0; j < NState.length; j++)
  763.                         secondary[i][j] = NState[j];
  764.                 }

  765.                 return new FieldODEState<>(newState.getDate().durationFrom(getStartDate()),
  766.                                            primary, secondary);

  767.             } catch (OrekitException oe) {
  768.                 throw new OrekitExceptionWrapper(oe);
  769.             }
  770.         }

  771.     }

  772.     /** Adapt an {@link org.orekit.propagation.sampling.FieldOrekitStepHandler<T>}
  773.      * to Hipparchus {@link FieldODEStepHandler<T>} interface.
  774.      * @author Luc Maisonobe
  775.      */
  776.     private class FieldAdaptedStepHandler
  777.         implements FieldOrekitStepInterpolator<T>, FieldODEStepHandler<T>, FieldModeHandler<T> {

  778.         /** Underlying handler. */
  779.         private final FieldOrekitStepHandler<T> handler;

  780.         /** Flag for handler . */
  781.         private boolean activate;

  782.         /** Build an instance.
  783.          * @param handler underlying handler to wrap
  784.          */
  785.         FieldAdaptedStepHandler(final FieldOrekitStepHandler<T> handler) {
  786.             this.handler = handler;
  787.         }

  788.         /** {@inheritDoc} */
  789.         public void initialize(final boolean activateHandlers,
  790.                                final FieldAbsoluteDate<T> targetDate) {
  791.             this.activate = activateHandlers;
  792.         }
  793.         /** {@inheritDoc} */
  794.         public void init(final FieldODEStateAndDerivative<T> s0, final T t) {
  795.             try {
  796.                 handler.init(getCompleteState(s0.getTime(), s0.getCompleteState(), s0.getCompleteDerivative()),
  797.                              stateMapper.mapDoubleToDate(t));
  798.             } catch (OrekitException oe) {
  799.                 throw new OrekitExceptionWrapper(oe);
  800.             }
  801.         }

  802.         /** {@inheritDoc} */
  803.         public void handleStep(final FieldODEStateInterpolator<T> interpolator, final boolean isLast) {
  804.             try {
  805.                 mathInterpolator = interpolator;
  806.                 if (activate) {
  807.                     handler.handleStep(this, isLast);
  808.                 }
  809.             } catch (OrekitException oe) {
  810.                 throw new OrekitExceptionWrapper(oe);
  811.             }
  812.         }

  813.         /** {@inheritDoc}} */
  814.         @Override
  815.         public FieldSpacecraftState<T> getPreviousState()
  816.             throws OrekitException {
  817.             return convert(mathInterpolator.getPreviousState());
  818.         }

  819.         /** {@inheritDoc}} */
  820.         @Override
  821.         public FieldSpacecraftState<T> getCurrentState()
  822.             throws OrekitException {
  823.             return convert(mathInterpolator.getCurrentState());
  824.         }

  825.         /** {@inheritDoc}} */
  826.         @Override
  827.         public FieldSpacecraftState<T> getInterpolatedState(final FieldAbsoluteDate<T> date)
  828.             throws OrekitException {
  829.             return convert(mathInterpolator.getInterpolatedState(date.durationFrom(getStartDate())));
  830.         }

  831.         /** Get the interpolated state.
  832.          * @param os mathematical state
  833.          * @return interpolated state at the current interpolation date
  834.          * @exception OrekitException if state cannot be interpolated or converted
  835.          * @exception OrekitException if underlying interpolator cannot handle
  836.          * the date
  837.          * @see #getInterpolatedDate()
  838.          * @see #setInterpolatedDate(FieldAbsoluteDate<T>)
  839.          */
  840.         private FieldSpacecraftState<T> convert(final FieldODEStateAndDerivative<T> os)
  841.             throws OrekitException {
  842.             try {

  843.                 FieldSpacecraftState<T> s =
  844.                         stateMapper.mapArrayToState(os.getTime(),
  845.                                                     os.getPrimaryState(),
  846.                                                     os.getPrimaryDerivative(),
  847.                                                     meanOrbit);
  848.                 s = updateAdditionalStates(s);
  849.                 for (int i = 0; i < additionalEquations.size(); ++i) {
  850.                     final T[] secondary = os.getSecondaryState(i + 1);
  851.                     s = s.addAdditionalState(additionalEquations.get(i).getName(), secondary);
  852.                 }

  853.                 return s;

  854.             } catch (OrekitException oe) {
  855.                 throw new OrekitException(oe);
  856.             } catch (OrekitExceptionWrapper oew) {
  857.                 throw new OrekitException(oew.getException());
  858.             }
  859.         }

  860.         /** Check is integration direction is forward in date.
  861.          * @return true if integration is forward in date
  862.          */
  863.         public boolean isForward() {
  864.             return mathInterpolator.isForward();
  865.         }

  866.     }

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

  868.         /** Underlying raw mathematical model. */
  869.         private FieldDenseOutputModel<T> model;

  870.         /** Generated ephemeris. */
  871.         private FieldBoundedPropagator<T> ephemeris;

  872.         /** Flag for handler . */
  873.         private boolean activate;

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

  876.         /** Creates a new instance of FieldEphemerisModeHandler which must be
  877.          *  filled by the propagator.
  878.          */
  879.         FieldEphemerisModeHandler() {
  880.         }

  881.         /** {@inheritDoc} */
  882.         public void initialize(final boolean activateHandlers,
  883.                                final FieldAbsoluteDate<T> targetDate) {
  884.             this.activate = activateHandlers;
  885.             this.model    = new FieldDenseOutputModel<>();
  886.             this.endDate  = targetDate;

  887.             // ephemeris will be generated when last step is processed
  888.             this.ephemeris = null;

  889.         }

  890.         /** Get the generated ephemeris.
  891.          * @return a new instance of the generated ephemeris
  892.          */
  893.         public FieldBoundedPropagator<T> getEphemeris() {
  894.             return ephemeris;
  895.         }

  896.         /** {@inheritDoc} */
  897.         public void handleStep(final FieldODEStateInterpolator<T> interpolator, final boolean isLast)
  898.             throws OrekitExceptionWrapper {
  899.             try {
  900.                 if (activate) {
  901.                     model.handleStep(interpolator, isLast);
  902.                     if (isLast) {

  903.                         // set up the boundary dates
  904.                         final T tI = model.getInitialTime();
  905.                         final T tF = model.getFinalTime();
  906.                         // tI is almost? always zero
  907.                         final FieldAbsoluteDate<T> startDate =
  908.                                 stateMapper.mapDoubleToDate(tI);
  909.                         final FieldAbsoluteDate<T> finalDate =
  910.                                 stateMapper.mapDoubleToDate(tF, this.endDate);
  911.                         final FieldAbsoluteDate<T> minDate;
  912.                         final FieldAbsoluteDate<T> maxDate;
  913.                         if (tF.getReal() < tI.getReal()) {
  914.                             minDate = finalDate;
  915.                             maxDate = startDate;
  916.                         } else {
  917.                             minDate = startDate;
  918.                             maxDate = finalDate;
  919.                         }

  920.                         // get the initial additional states that are not managed
  921.                         final Map<String, T[]> unmanaged = new HashMap<String, T[]>();
  922.                         for (final Map.Entry<String, T[]> initial : getInitialState().getAdditionalStates().entrySet()) {
  923.                             if (!isAdditionalStateManaged(initial.getKey())) {
  924.                                 // this additional state was in the initial state, but is unknown to the propagator
  925.                                 // we simply copy its initial value as is
  926.                                 unmanaged.put(initial.getKey(), initial.getValue());
  927.                             }
  928.                         }

  929.                         // get the names of additional states managed by differential equations
  930.                         final String[] names = new String[additionalEquations.size()];
  931.                         for (int i = 0; i < names.length; ++i) {
  932.                             names[i] = additionalEquations.get(i).getName();
  933.                         }

  934.                         // create the ephemeris
  935.                         ephemeris = new FieldIntegratedEphemeris<>(startDate, minDate, maxDate,
  936.                                                                    stateMapper, meanOrbit, model, unmanaged,
  937.                                                                    getAdditionalStateProviders(), names);

  938.                     }
  939.                 }
  940.             } catch (OrekitException oe) {
  941.                 throw new OrekitExceptionWrapper(oe);
  942.             }
  943.         }

  944.         /** {@inheritDoc} */
  945.         public void init(final FieldODEStateAndDerivative<T> s0, final T t) {
  946.             model.init(s0, t);
  947.         }

  948.     }

  949. }