AbstractIntegratedPropagator.java
- /* Copyright 2002-2013 CS Systèmes d'Information
- * Licensed to CS Systèmes d'Information (CS) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * CS licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.orekit.propagation.integration;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import org.apache.commons.math3.exception.MathIllegalArgumentException;
- import org.apache.commons.math3.exception.MathIllegalStateException;
- import org.apache.commons.math3.ode.AbstractIntegrator;
- import org.apache.commons.math3.ode.ContinuousOutputModel;
- import org.apache.commons.math3.ode.EquationsMapper;
- import org.apache.commons.math3.ode.ExpandableStatefulODE;
- import org.apache.commons.math3.ode.FirstOrderDifferentialEquations;
- import org.apache.commons.math3.ode.SecondaryEquations;
- import org.apache.commons.math3.ode.nonstiff.ClassicalRungeKuttaIntegrator;
- import org.apache.commons.math3.ode.sampling.StepHandler;
- import org.apache.commons.math3.ode.sampling.StepInterpolator;
- import org.apache.commons.math3.util.FastMath;
- import org.apache.commons.math3.util.Precision;
- import org.orekit.attitudes.AttitudeProvider;
- import org.orekit.errors.OrekitException;
- import org.orekit.errors.OrekitExceptionWrapper;
- import org.orekit.errors.OrekitMessages;
- import org.orekit.errors.PropagationException;
- import org.orekit.frames.Frame;
- import org.orekit.orbits.Orbit;
- import org.orekit.orbits.OrbitType;
- import org.orekit.orbits.PositionAngle;
- import org.orekit.propagation.AbstractPropagator;
- import org.orekit.propagation.BoundedPropagator;
- import org.orekit.propagation.SpacecraftState;
- import org.orekit.propagation.events.AbstractReconfigurableDetector;
- import org.orekit.propagation.events.EventDetector;
- import org.orekit.propagation.events.handlers.EventHandler;
- import org.orekit.propagation.sampling.OrekitStepHandler;
- import org.orekit.propagation.sampling.OrekitStepInterpolator;
- import org.orekit.time.AbsoluteDate;
- /** Common handling of {@link org.orekit.propagation.Propagator Propagator}
- * methods for both numerical and semi-analytical propagators.
- * @author Luc Maisonobe
- */
- public abstract class AbstractIntegratedPropagator extends AbstractPropagator {
- /** Event detectors not related to force models. */
- private final List<EventDetector> detectors;
- /** Integrator selected by the user for the orbital extrapolation process. */
- private final AbstractIntegrator integrator;
- /** Mode handler. */
- private ModeHandler modeHandler;
- /** Additional equations. */
- private List<AdditionalEquations> additionalEquations;
- /** Counter for differential equations calls. */
- private int calls;
- /** Mapper between raw double components and space flight dynamics objects. */
- private StateMapper stateMapper;
- /** Complete equation to be integrated. */
- private ExpandableStatefulODE mathODE;
- /** Underlying raw rawInterpolator. */
- private StepInterpolator mathInterpolator;
- /** Build a new instance.
- * @param integrator numerical integrator to use for propagation.
- */
- protected AbstractIntegratedPropagator(final AbstractIntegrator integrator) {
- detectors = new ArrayList<EventDetector>();
- additionalEquations = new ArrayList<AdditionalEquations>();
- this.integrator = integrator;
- }
- /** Initialize the mapper. */
- protected void initMapper() {
- stateMapper = createMapper(null, Double.NaN, null, null, null, null);
- }
- /** {@inheritDoc} */
- public void setAttitudeProvider(final AttitudeProvider attitudeProvider) {
- super.setAttitudeProvider(attitudeProvider);
- stateMapper = createMapper(stateMapper.getReferenceDate(), stateMapper.getMu(),
- stateMapper.getOrbitType(), stateMapper.getPositionAngleType(),
- attitudeProvider, stateMapper.getFrame());
- }
- /** Set propagation orbit type.
- * @param orbitType orbit type to use for propagation
- */
- protected void setOrbitType(final OrbitType orbitType) {
- stateMapper = createMapper(stateMapper.getReferenceDate(), stateMapper.getMu(),
- orbitType, stateMapper.getPositionAngleType(),
- stateMapper.getAttitudeProvider(), stateMapper.getFrame());
- }
- /** Get propagation parameter type.
- * @return orbit type used for propagation
- */
- protected OrbitType getOrbitType() {
- return stateMapper.getOrbitType();
- }
- /** Set position angle type.
- * <p>
- * The position parameter type is meaningful only if {@link
- * #getOrbitType() propagation orbit type}
- * support it. As an example, it is not meaningful for propagation
- * in {@link OrbitType#CARTESIAN Cartesian} parameters.
- * </p>
- * @param positionAngleType angle type to use for propagation
- */
- protected void setPositionAngleType(final PositionAngle positionAngleType) {
- stateMapper = createMapper(stateMapper.getReferenceDate(), stateMapper.getMu(),
- stateMapper.getOrbitType(), positionAngleType,
- stateMapper.getAttitudeProvider(), stateMapper.getFrame());
- }
- /** Get propagation parameter type.
- * @return angle type to use for propagation
- */
- protected PositionAngle getPositionAngleType() {
- return stateMapper.getPositionAngleType();
- }
- /** Set the central attraction coefficient μ.
- * @param mu central attraction coefficient (m<sup>3</sup>/s<sup>2</sup>)
- */
- public void setMu(final double mu) {
- stateMapper = createMapper(stateMapper.getReferenceDate(), mu,
- stateMapper.getOrbitType(), stateMapper.getPositionAngleType(),
- stateMapper.getAttitudeProvider(), stateMapper.getFrame());
- }
- /** Get the central attraction coefficient μ.
- * @return mu central attraction coefficient (m<sup>3</sup>/s<sup>2</sup>)
- * @see #setMu(double)
- */
- public double getMu() {
- return stateMapper.getMu();
- }
- /** Get the number of calls to the differential equations computation method.
- * <p>The number of calls is reset each time the {@link #propagate(AbsoluteDate)}
- * method is called.</p>
- * @return number of calls to the differential equations computation method
- */
- public int getCalls() {
- return calls;
- }
- /** {@inheritDoc} */
- @Override
- public boolean isAdditionalStateManaged(final String name) {
- // first look at already integrated states
- if (super.isAdditionalStateManaged(name)) {
- return true;
- }
- // then look at states we integrate ourselves
- for (final AdditionalEquations equation : additionalEquations) {
- if (equation.getName().equals(name)) {
- return true;
- }
- }
- return false;
- }
- /** {@inheritDoc} */
- @Override
- public String[] getManagedAdditionalStates() {
- final String[] alreadyIntegrated = super.getManagedAdditionalStates();
- final String[] managed = new String[alreadyIntegrated.length + additionalEquations.size()];
- System.arraycopy(alreadyIntegrated, 0, managed, 0, alreadyIntegrated.length);
- for (int i = 0; i < additionalEquations.size(); ++i) {
- managed[i + alreadyIntegrated.length] = additionalEquations.get(i).getName();
- }
- return managed;
- }
- /** Add a set of user-specified equations to be integrated along with the orbit propagation.
- * @param additional additional equations
- * @exception OrekitException if a set of equations with the same name is already present
- */
- public void addAdditionalEquations(final AdditionalEquations additional)
- throws OrekitException {
- // check if the name is already used
- if (isAdditionalStateManaged(additional.getName())) {
- // this set of equations is already registered, complain
- throw new OrekitException(OrekitMessages.ADDITIONAL_STATE_NAME_ALREADY_IN_USE,
- additional.getName());
- }
- // this is really a new set of equations, add it
- additionalEquations.add(additional);
- }
- /** {@inheritDoc} */
- public <T extends EventDetector> void addEventDetector(final T detector) {
- detectors.add(detector);
- }
- /** {@inheritDoc} */
- public Collection<EventDetector> getEventsDetectors() {
- return Collections.unmodifiableCollection(detectors);
- }
- /** {@inheritDoc} */
- public void clearEventsDetectors() {
- detectors.clear();
- }
- /** Set up all user defined event detectors.
- */
- protected void setUpUserEventDetectors() {
- for (final EventDetector detector : detectors) {
- setUpEventDetector(integrator, detector);
- }
- }
- /** Wrap an Orekit event detector and register it to the integrator.
- * @param integ integrator into which event detector should be registered
- * @param detector event detector to wrap
- * @param <T> class type for the generic version
- */
- protected <T extends EventDetector> void setUpEventDetector(final AbstractIntegrator integ,
- final T detector) {
- integ.addEventHandler(new AdaptedEventDetector<T>(detector),
- detector.getMaxCheckInterval(),
- detector.getThreshold(),
- detector.getMaxIterationCount());
- }
- /** {@inheritDoc}
- * <p>Note that this method has the side effect of replacing the step handlers
- * of the underlying integrator set up in the {@link
- * #AbstractIntegratedPropagator(AbstractIntegrator) constructor}. So if a specific
- * step handler is needed, it should be added after this method has been callled.</p>
- */
- public void setSlaveMode() {
- super.setSlaveMode();
- if (integrator != null) {
- integrator.clearStepHandlers();
- }
- modeHandler = null;
- }
- /** {@inheritDoc}
- * <p>Note that this method has the side effect of replacing the step handlers
- * of the underlying integrator set up in the {@link
- * #AbstractIntegratedPropagator(AbstractIntegrator) constructor}. So if a specific
- * step handler is needed, it should be added after this method has been callled.</p>
- */
- public void setMasterMode(final OrekitStepHandler handler) {
- super.setMasterMode(handler);
- integrator.clearStepHandlers();
- final AdaptedStepHandler wrapped = new AdaptedStepHandler(handler);
- integrator.addStepHandler(wrapped);
- modeHandler = wrapped;
- }
- /** {@inheritDoc}
- * <p>Note that this method has the side effect of replacing the step handlers
- * of the underlying integrator set up in the {@link
- * #AbstractIntegratedPropagator(AbstractIntegrator) constructor}. So if a specific
- * step handler is needed, it should be added after this method has been called.</p>
- */
- public void setEphemerisMode() {
- super.setEphemerisMode();
- integrator.clearStepHandlers();
- final EphemerisModeHandler ephemeris = new EphemerisModeHandler();
- modeHandler = ephemeris;
- integrator.addStepHandler(ephemeris);
- }
- /** {@inheritDoc} */
- public BoundedPropagator getGeneratedEphemeris()
- throws IllegalStateException {
- if (getMode() != EPHEMERIS_GENERATION_MODE) {
- throw OrekitException.createIllegalStateException(OrekitMessages.PROPAGATOR_NOT_IN_EPHEMERIS_GENERATION_MODE);
- }
- return ((EphemerisModeHandler) modeHandler).getEphemeris();
- }
- /** Create a mapper between raw double components and spacecraft state.
- /** Simple constructor.
- * <p>
- * The position parameter type is meaningful only if {@link
- * #getOrbitType() propagation orbit type}
- * support it. As an example, it is not meaningful for propagation
- * in {@link OrbitType#CARTESIAN Cartesian} parameters.
- * </p>
- * @param referenceDate reference date
- * @param mu central attraction coefficient (m<sup>3</sup>/s<sup>2</sup>)
- * @param orbitType orbit type to use for mapping
- * @param positionAngleType angle type to use for propagation
- * @param attitudeProvider attitude provider
- * @param frame inertial frame
- * @return new mapper
- */
- protected abstract StateMapper createMapper(final AbsoluteDate referenceDate, final double mu,
- final OrbitType orbitType, final PositionAngle positionAngleType,
- final AttitudeProvider attitudeProvider, final Frame frame);
- /** Get the differential equations to integrate (for main state only).
- * @param integ numerical integrator to use for propagation.
- * @return differential equations for main state
- */
- protected abstract MainStateEquations getMainStateEquations(final AbstractIntegrator integ);
- /** {@inheritDoc} */
- public SpacecraftState propagate(final AbsoluteDate target) throws PropagationException {
- try {
- if (getStartDate() == null) {
- if (getInitialState() == null) {
- throw new PropagationException(OrekitMessages.INITIAL_STATE_NOT_SPECIFIED_FOR_ORBIT_PROPAGATION);
- }
- setStartDate(getInitialState().getDate());
- }
- return propagate(getStartDate(), target);
- } catch (OrekitException oe) {
- // recover a possible embedded PropagationException
- for (Throwable t = oe; t != null; t = t.getCause()) {
- if (t instanceof PropagationException) {
- throw (PropagationException) t;
- }
- }
- throw new PropagationException(oe);
- }
- }
- /** {@inheritDoc} */
- public SpacecraftState propagate(final AbsoluteDate tStart, final AbsoluteDate tEnd)
- throws PropagationException {
- try {
- if (getInitialState() == null) {
- throw new PropagationException(OrekitMessages.INITIAL_STATE_NOT_SPECIFIED_FOR_ORBIT_PROPAGATION);
- }
- if (!tStart.equals(getInitialState().getDate())) {
- // if propagation start date is not initial date,
- // propagate from initial to start date without event detection
- propagate(tStart, false);
- }
- // propagate from start date to end date with event detection
- return propagate(tEnd, true);
- } catch (OrekitException oe) {
- // recover a possible embedded PropagationException
- for (Throwable t = oe; t != null; t = t.getCause()) {
- if (t instanceof PropagationException) {
- throw (PropagationException) t;
- }
- }
- throw new PropagationException(oe);
- }
- }
- /** Propagation with or without event detection.
- * @param tEnd target date to which orbit should be propagated
- * @param activateHandlers if true, step and event handlers should be activated
- * @return state at end of propagation
- * @exception PropagationException if orbit cannot be propagated
- */
- protected SpacecraftState propagate(final AbsoluteDate tEnd, final boolean activateHandlers)
- throws PropagationException {
- try {
- if (getInitialState().getDate().equals(tEnd)) {
- // don't extrapolate
- return getInitialState();
- }
- // space dynamics view
- stateMapper = createMapper(getInitialState().getDate(), stateMapper.getMu(),
- stateMapper.getOrbitType(), stateMapper.getPositionAngleType(),
- stateMapper.getAttitudeProvider(), getInitialState().getFrame());
- // set propagation orbit type
- final Orbit initialOrbit = stateMapper.getOrbitType().convertType(getInitialState().getOrbit());
- if (Double.isNaN(getMu())) {
- setMu(initialOrbit.getMu());
- }
- if (getInitialState().getMass() <= 0.0) {
- throw new PropagationException(OrekitMessages.SPACECRAFT_MASS_BECOMES_NEGATIVE,
- getInitialState().getMass());
- }
- integrator.clearEventHandlers();
- // set up events added by user
- setUpUserEventDetectors();
- // convert space flight dynamics API to math API
- mathODE = createODE(integrator);
- mathInterpolator = null;
- // initialize mode handler
- if (modeHandler != null) {
- modeHandler.initialize(activateHandlers);
- }
- // mathematical integration
- try {
- beforeIntegration(getInitialState(), tEnd);
- integrator.integrate(mathODE, tEnd.durationFrom(getInitialState().getDate()));
- afterIntegration();
- } catch (OrekitExceptionWrapper oew) {
- throw oew.getException();
- }
- // get final state
- SpacecraftState finalState =
- stateMapper.mapArrayToState(mathODE.getTime(), mathODE.getPrimaryState());
- finalState = updateAdditionalStates(finalState);
- for (int i = 0; i < additionalEquations.size(); ++i) {
- final double[] secondary = mathODE.getSecondaryState(i);
- finalState = finalState.addAdditionalState(additionalEquations.get(i).getName(),
- secondary);
- }
- resetInitialState(finalState);
- setStartDate(finalState.getDate());
- return finalState;
- } catch (PropagationException pe) {
- throw pe;
- } catch (OrekitException oe) {
- throw new PropagationException(oe);
- } catch (MathIllegalArgumentException miae) {
- throw PropagationException.unwrap(miae);
- } catch (MathIllegalStateException mise) {
- throw PropagationException.unwrap(mise);
- }
- }
- /** Create an ODE with all equations.
- * @param integ numerical integrator to use for propagation.
- * @return a new ode
- * @exception OrekitException if initial state cannot be mapped
- */
- private ExpandableStatefulODE createODE(final AbstractIntegrator integ)
- throws OrekitException {
- // retrieve initial state
- final double[] initialStateVector = new double[getBasicDimension()];
- stateMapper.mapStateToArray(getInitialState(), initialStateVector);
- // main part of the ODE
- final ExpandableStatefulODE ode =
- new ExpandableStatefulODE(new ConvertedMainStateEquations(getMainStateEquations(integ)));
- ode.setTime(0.0);
- ode.setPrimaryState(initialStateVector);
- // secondary part of the ODE
- for (int i = 0; i < additionalEquations.size(); ++i) {
- final AdditionalEquations additional = additionalEquations.get(i);
- final double[] data = getInitialState().getAdditionalState(additional.getName());
- final SecondaryEquations secondary =
- new ConvertedSecondaryStateEquations(additional, data.length);
- ode.addSecondaryEquations(secondary);
- ode.setSecondaryState(i, data);
- }
- return ode;
- }
- /** Method called just before integration.
- * <p>
- * The default implementation does nothing, it may be specialized in subclasses.
- * </p>
- * @param initialState initial state
- * @param tEnd target date at which state should be propagated
- * @exception OrekitException if hook cannot be run
- */
- protected void beforeIntegration(final SpacecraftState initialState,
- final AbsoluteDate tEnd)
- throws OrekitException {
- // do nothing by default
- }
- /** Method called just after integration.
- * <p>
- * The default implementation does nothing, it may be specialized in subclasses.
- * </p>
- * @exception OrekitException if hook cannot be run
- */
- protected void afterIntegration()
- throws OrekitException {
- // do nothing by default
- }
- /** Get state vector dimension without additional parameters.
- * @return state vector dimension without additional parameters.
- */
- public int getBasicDimension() {
- return 7;
- }
- /** Get a complete state with all additional equations.
- * @param t current value of the independent <I>time</I> variable
- * @param y array containing the current value of the state vector
- * @return complete state
- * @exception OrekitException if state cannot be mapped
- */
- private SpacecraftState getCompleteState(final double t, final double[] y)
- throws OrekitException {
- // main state
- SpacecraftState state = stateMapper.mapArrayToState(t, y);
- // pre-integrated additional states
- state = updateAdditionalStates(state);
- // additional states integrated here
- if (!additionalEquations.isEmpty()) {
- if (mathODE.getTotalDimension() <= y.length) {
- // the provided y vector already contains everything needed
- final EquationsMapper[] em = mathODE.getSecondaryMappers();
- for (int i = 0; i < additionalEquations.size(); ++i) {
- final double[] secondary = new double[em[i].getDimension()];
- System.arraycopy(y, em[i].getFirstIndex(), secondary, 0, secondary.length);
- state = state.addAdditionalState(additionalEquations.get(i).getName(),
- secondary);
- }
- } else {
- // the y array doesn't contain the additional equations data
- // TODO: remove this case when MATH-965 fix is officially published
- // (i.e for the next Apache Commons Math version after 3.2)
- // The fix for MATH-965 ensures that y always contains all
- // needed data, including additional states, so the workaround
- // below will not be needed anymore
- if (mathInterpolator == null) {
- // we are still in the first step, before the step handler call
- // we build a temporary interpolator just for this step
- final double step = FastMath.abs(integrator.getCurrentSignedStepsize());
- final ClassicalRungeKuttaIntegrator firstStepIntegrator =
- new ClassicalRungeKuttaIntegrator(step);
- firstStepIntegrator.addStepHandler(new StepHandler() {
- /** {@inheritDoc} */
- public void init(final double t0, final double[] y0, final double t) {
- }
- /** {@inheritDoc} */
- public void handleStep(final StepInterpolator interpolator, final boolean isLast) {
- mathInterpolator = interpolator;
- }
- });
- final ExpandableStatefulODE localODE = createODE(firstStepIntegrator);
- firstStepIntegrator.clearEventHandlers();
- firstStepIntegrator.integrate(localODE, step);
- }
- // extract the additional data from the spied interpolator
- mathInterpolator.setInterpolatedTime(t);
- for (int i = 0; i < additionalEquations.size(); ++i) {
- final double[] secondary = mathInterpolator.getInterpolatedSecondaryState(i);
- state = state.addAdditionalState(additionalEquations.get(i).getName(),
- secondary);
- }
- }
- }
- return state;
- }
- /** Differential equations for the main state (orbit, attitude and mass). */
- public interface MainStateEquations {
- /** Compute differential equations for main state.
- * @param state current state
- * @return derivatives of main state
- * @throws OrekitException if differentials cannot be computed
- */
- double[] computeDerivatives(final SpacecraftState state) throws OrekitException;
- }
- /** Differential equations for the main state (orbit, attitude and mass), with converted API. */
- private class ConvertedMainStateEquations implements FirstOrderDifferentialEquations {
- /** Main state equations. */
- private final MainStateEquations main;
- /** Simple constructor.
- * @param main main state equations
- */
- public ConvertedMainStateEquations(final MainStateEquations main) {
- this.main = main;
- calls = 0;
- }
- /** {@inheritDoc} */
- public int getDimension() {
- return getBasicDimension();
- }
- /** {@inheritDoc} */
- public void computeDerivatives(final double t, final double[] y, final double[] yDot)
- throws OrekitExceptionWrapper {
- try {
- // update space dynamics view
- SpacecraftState currentState = stateMapper.mapArrayToState(t, y);
- currentState = updateAdditionalStates(currentState);
- // compute main state differentials
- final double[] mainDot = main.computeDerivatives(currentState);
- System.arraycopy(mainDot, 0, yDot, 0, mainDot.length);
- } catch (OrekitException oe) {
- throw new OrekitExceptionWrapper(oe);
- }
- // increment calls counter
- ++calls;
- }
- }
- /** Differential equations for the secondary state (Jacobians, user variables ...), with converted API. */
- private class ConvertedSecondaryStateEquations implements SecondaryEquations {
- /** Additional equations. */
- private final AdditionalEquations equations;
- /** Dimension of the additional state. */
- private final int dimension;
- /** Simple constructor.
- * @param equations additional equations
- * @param dimension dimension of the additional state
- */
- public ConvertedSecondaryStateEquations(final AdditionalEquations equations,
- final int dimension) {
- this.equations = equations;
- this.dimension = dimension;
- }
- /** {@inheritDoc} */
- public int getDimension() {
- return dimension;
- }
- /** {@inheritDoc} */
- public void computeDerivatives(final double t, final double[] primary,
- final double[] primaryDot, final double[] secondary,
- final double[] secondaryDot)
- throws OrekitExceptionWrapper {
- try {
- // update space dynamics view
- SpacecraftState currentState = stateMapper.mapArrayToState(t, primary);
- currentState = updateAdditionalStates(currentState);
- currentState = currentState.addAdditionalState(equations.getName(), secondary);
- // compute additional derivatives
- final double[] additionalMainDot =
- equations.computeDerivatives(currentState, secondaryDot);
- if (additionalMainDot != null) {
- // the additional equations have an effect on main equations
- for (int i = 0; i < additionalMainDot.length; ++i) {
- primaryDot[i] += additionalMainDot[i];
- }
- }
- } catch (OrekitException oe) {
- throw new OrekitExceptionWrapper(oe);
- }
- }
- }
- /** Adapt an {@link org.orekit.propagation.events.EventDetector}
- * to commons-math {@link org.apache.commons.math3.ode.events.EventHandler} interface.
- * @param <T> class type for the generic version
- * @author Fabien Maussion
- */
- private class AdaptedEventDetector<T extends EventDetector> implements org.apache.commons.math3.ode.events.EventHandler {
- /** Underlying event detector. */
- private final T detector;
- /** Time of the previous call to g. */
- private double lastT;
- /** Value from the previous call to g. */
- private double lastG;
- /** Build a wrapped event detector.
- * @param detector event detector to wrap
- */
- public AdaptedEventDetector(final T detector) {
- this.detector = detector;
- this.lastT = Double.NaN;
- this.lastG = Double.NaN;
- }
- /** {@inheritDoc} */
- public void init(final double t0, final double[] y0, final double t) {
- try {
- detector.init(getCompleteState(t0, y0), stateMapper.mapDoubleToDate(t));
- this.lastT = Double.NaN;
- this.lastG = Double.NaN;
- } catch (OrekitException oe) {
- throw new OrekitExceptionWrapper(oe);
- }
- }
- /** {@inheritDoc} */
- public double g(final double t, final double[] y) {
- try {
- if (!Precision.equals(lastT, t, 1)) {
- lastT = t;
- lastG = detector.g(getCompleteState(t, y));
- }
- return lastG;
- } catch (OrekitException oe) {
- throw new OrekitExceptionWrapper(oe);
- }
- }
- /** {@inheritDoc} */
- public Action eventOccurred(final double t, final double[] y, final boolean increasing) {
- try {
- final SpacecraftState state = getCompleteState(t, y);
- final EventHandler.Action whatNext;
- if (detector instanceof AbstractReconfigurableDetector) {
- @SuppressWarnings("unchecked")
- final EventHandler<T> handler = ((AbstractReconfigurableDetector<T>) detector).getHandler();
- whatNext = handler.eventOccurred(state, detector, increasing);
- } else {
- @SuppressWarnings("deprecation")
- final EventDetector.Action a = detector.eventOccurred(state, increasing);
- whatNext = AbstractReconfigurableDetector.convert(a);
- }
- switch (whatNext) {
- case STOP :
- return Action.STOP;
- case RESET_STATE :
- return Action.RESET_STATE;
- case RESET_DERIVATIVES :
- return Action.RESET_DERIVATIVES;
- default :
- return Action.CONTINUE;
- }
- } catch (OrekitException oe) {
- throw new OrekitExceptionWrapper(oe);
- }
- }
- /** {@inheritDoc} */
- public void resetState(final double t, final double[] y) {
- try {
- final SpacecraftState oldState = getCompleteState(t, y);
- final SpacecraftState newState;
- if (detector instanceof AbstractReconfigurableDetector) {
- @SuppressWarnings("unchecked")
- final EventHandler<T> handler = ((AbstractReconfigurableDetector<T>) detector).getHandler();
- newState = handler.resetState(detector, oldState);
- } else {
- @SuppressWarnings("deprecation")
- final SpacecraftState s = detector.resetState(oldState);
- newState = s;
- }
- // main part
- stateMapper.mapStateToArray(newState, y);
- // secondary part
- final EquationsMapper[] em = mathODE.getSecondaryMappers();
- for (int i = 0; i < additionalEquations.size(); ++i) {
- final double[] secondary =
- newState.getAdditionalState(additionalEquations.get(i).getName());
- System.arraycopy(secondary, 0, y, em[i].getFirstIndex(), secondary.length);
- }
- } catch (OrekitException oe) {
- throw new OrekitExceptionWrapper(oe);
- }
- }
- }
- /** Adapt an {@link org.orekit.propagation.sampling.OrekitStepHandler}
- * to commons-math {@link StepHandler} interface.
- * @author Luc Maisonobe
- */
- private class AdaptedStepHandler
- implements OrekitStepInterpolator, StepHandler, ModeHandler {
- /** Underlying handler. */
- private final OrekitStepHandler handler;
- /** Flag for handler . */
- private boolean activate;
- /** Build an instance.
- * @param handler underlying handler to wrap
- */
- public AdaptedStepHandler(final OrekitStepHandler handler) {
- this.handler = handler;
- }
- /** {@inheritDoc} */
- public void initialize(final boolean activateHandlers) {
- this.activate = activateHandlers;
- }
- /** {@inheritDoc} */
- public void init(final double t0, final double[] y0, final double t) {
- try {
- handler.init(getCompleteState(t0, y0), stateMapper.mapDoubleToDate(t));
- } catch (OrekitException oe) {
- throw new OrekitExceptionWrapper(oe);
- }
- }
- /** {@inheritDoc} */
- public void handleStep(final StepInterpolator interpolator, final boolean isLast) {
- try {
- mathInterpolator = interpolator;
- if (activate) {
- handler.handleStep(this, isLast);
- }
- } catch (PropagationException pe) {
- throw new OrekitExceptionWrapper(pe);
- }
- }
- /** Get the current grid date.
- * @return current grid date
- */
- public AbsoluteDate getCurrentDate() {
- return stateMapper.mapDoubleToDate(mathInterpolator.getCurrentTime());
- }
- /** Get the previous grid date.
- * @return previous grid date
- */
- public AbsoluteDate getPreviousDate() {
- return stateMapper.mapDoubleToDate(mathInterpolator.getPreviousTime());
- }
- /** Get the interpolated date.
- * <p>If {@link #setInterpolatedDate(AbsoluteDate) setInterpolatedDate}
- * has not been called, the date returned is the same as {@link
- * #getCurrentDate() getCurrentDate}.</p>
- * @return interpolated date
- * @see #setInterpolatedDate(AbsoluteDate)
- * @see #getInterpolatedState()
- */
- public AbsoluteDate getInterpolatedDate() {
- return stateMapper.mapDoubleToDate(mathInterpolator.getInterpolatedTime());
- }
- /** Set the interpolated date.
- * <p>It is possible to set the interpolation date outside of the current
- * step range, but accuracy will decrease as date is farther.</p>
- * @param date interpolated date to set
- * @see #getInterpolatedDate()
- * @see #getInterpolatedState()
- */
- public void setInterpolatedDate(final AbsoluteDate date) {
- mathInterpolator.setInterpolatedTime(stateMapper.mapDateToDouble(date));
- }
- /** Get the interpolated state.
- * @return interpolated state at the current interpolation date
- * @exception OrekitException if state cannot be interpolated or converted
- * @see #getInterpolatedDate()
- * @see #setInterpolatedDate(AbsoluteDate)
- */
- public SpacecraftState getInterpolatedState() throws OrekitException {
- try {
- SpacecraftState s =
- stateMapper.mapArrayToState(mathInterpolator.getInterpolatedTime(),
- mathInterpolator.getInterpolatedState());
- s = updateAdditionalStates(s);
- for (int i = 0; i < additionalEquations.size(); ++i) {
- final double[] secondary = mathInterpolator.getInterpolatedSecondaryState(i);
- s = s.addAdditionalState(additionalEquations.get(i).getName(), secondary);
- }
- return s;
- } catch (OrekitExceptionWrapper oew) {
- throw oew.getException();
- }
- }
- /** Check is integration direction is forward in date.
- * @return true if integration is forward in date
- */
- public boolean isForward() {
- return mathInterpolator.isForward();
- }
- }
- private class EphemerisModeHandler implements ModeHandler, StepHandler {
- /** Underlying raw mathematical model. */
- private ContinuousOutputModel model;
- /** Generated ephemeris. */
- private BoundedPropagator ephemeris;
- /** Flag for handler . */
- private boolean activate;
- /** Creates a new instance of EphemerisModeHandler which must be
- * filled by the propagator.
- */
- public EphemerisModeHandler() {
- }
- /** {@inheritDoc} */
- public void initialize(final boolean activateHandlers) {
- this.activate = activateHandlers;
- this.model = new ContinuousOutputModel();
- // ephemeris will be generated when last step is processed
- this.ephemeris = null;
- }
- /** Get the generated ephemeris.
- * @return a new instance of the generated ephemeris
- */
- public BoundedPropagator getEphemeris() {
- return ephemeris;
- }
- /** {@inheritDoc} */
- public void handleStep(final StepInterpolator interpolator, final boolean isLast)
- throws OrekitExceptionWrapper {
- try {
- if (activate) {
- model.handleStep(interpolator, isLast);
- if (isLast) {
- // set up the boundary dates
- final double tI = model.getInitialTime();
- final double tF = model.getFinalTime();
- final AbsoluteDate startDate = stateMapper.mapDoubleToDate(tI);
- final AbsoluteDate minDate;
- final AbsoluteDate maxDate;
- if (tF < tI) {
- minDate = stateMapper.mapDoubleToDate(tF);
- maxDate = startDate;
- } else {
- minDate = startDate;
- maxDate = stateMapper.mapDoubleToDate(tF);
- }
- // get the initial additional states that are not managed
- final Map<String, double[]> unmanaged = new HashMap<String, double[]>();
- for (final Map.Entry<String, double[]> initial : getInitialState().getAdditionalStates().entrySet()) {
- if (!isAdditionalStateManaged(initial.getKey())) {
- // this additional state was in the initial state, but is unknown to the propagator
- // we simply copy its initial value as is
- unmanaged.put(initial.getKey(), initial.getValue());
- }
- }
- // get the names of additional states managed by differential equations
- final String[] names = new String[additionalEquations.size()];
- for (int i = 0; i < names.length; ++i) {
- names[i] = additionalEquations.get(i).getName();
- }
- // create the ephemeris
- ephemeris = new IntegratedEphemeris(startDate, minDate, maxDate,
- stateMapper, model, unmanaged,
- getAdditionalStateProviders(), names);
- }
- }
- } catch (OrekitException oe) {
- throw new OrekitExceptionWrapper(oe);
- }
- }
- /** {@inheritDoc} */
- public void init(final double t0, final double[] y0, final double t) {
- model.init(t0, y0, t);
- }
- }
- }