KeplerianPropagator.java
- /* Copyright 2002-2018 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.analytical;
- import java.io.NotSerializableException;
- import java.io.Serializable;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.List;
- import java.util.Map;
- import java.util.SortedSet;
- import org.orekit.attitudes.Attitude;
- import org.orekit.attitudes.AttitudeProvider;
- import org.orekit.errors.OrekitException;
- import org.orekit.errors.OrekitInternalError;
- import org.orekit.orbits.Orbit;
- import org.orekit.orbits.OrbitType;
- import org.orekit.orbits.PositionAngle;
- import org.orekit.propagation.AdditionalStateProvider;
- import org.orekit.propagation.SpacecraftState;
- import org.orekit.time.AbsoluteDate;
- import org.orekit.utils.TimeSpanMap;
- /** Simple Keplerian orbit propagator.
- * @see Orbit
- * @author Guylaine Prat
- */
- public class KeplerianPropagator extends AbstractAnalyticalPropagator implements Serializable {
- /** Serializable UID. */
- private static final long serialVersionUID = 20151117L;
- /** Initial state. */
- private SpacecraftState initialState;
- /** All states. */
- private transient TimeSpanMap<SpacecraftState> states;
- /** Build a propagator from orbit only.
- * <p>The central attraction coefficient μ is set to the same value used
- * for the initial orbit definition. Mass and attitude provider are set to
- * unspecified non-null arbitrary values.</p>
- * @param initialOrbit initial orbit
- * @exception OrekitException if initial attitude cannot be computed
- */
- public KeplerianPropagator(final Orbit initialOrbit)
- throws OrekitException {
- this(initialOrbit, DEFAULT_LAW, initialOrbit.getMu(), DEFAULT_MASS);
- }
- /** Build a propagator from orbit and central attraction coefficient μ.
- * <p>Mass and attitude provider are set to unspecified non-null arbitrary values.</p>
- * @param initialOrbit initial orbit
- * @param mu central attraction coefficient (m³/s²)
- * @exception OrekitException if initial attitude cannot be computed
- */
- public KeplerianPropagator(final Orbit initialOrbit, final double mu)
- throws OrekitException {
- this(initialOrbit, DEFAULT_LAW, mu, DEFAULT_MASS);
- }
- /** Build a propagator from orbit and attitude provider.
- * <p>The central attraction coefficient μ is set to the same value
- * used for the initial orbit definition. Mass is set to an unspecified
- * non-null arbitrary value.</p>
- * @param initialOrbit initial orbit
- * @param attitudeProv attitude provider
- * @exception OrekitException if initial attitude cannot be computed
- */
- public KeplerianPropagator(final Orbit initialOrbit,
- final AttitudeProvider attitudeProv)
- throws OrekitException {
- this(initialOrbit, attitudeProv, initialOrbit.getMu(), DEFAULT_MASS);
- }
- /** Build a propagator from orbit, attitude provider and central attraction
- * coefficient μ.
- * <p>Mass is set to an unspecified non-null arbitrary value.</p>
- * @param initialOrbit initial orbit
- * @param attitudeProv attitude provider
- * @param mu central attraction coefficient (m³/s²)
- * @exception OrekitException if initial attitude cannot be computed
- */
- public KeplerianPropagator(final Orbit initialOrbit,
- final AttitudeProvider attitudeProv,
- final double mu)
- throws OrekitException {
- this(initialOrbit, attitudeProv, mu, DEFAULT_MASS);
- }
- /** Build propagator from orbit, attitude provider, central attraction
- * coefficient μ and mass.
- * @param initialOrbit initial orbit
- * @param attitudeProv attitude provider
- * @param mu central attraction coefficient (m³/s²)
- * @param mass spacecraft mass (kg)
- * @exception OrekitException if initial attitude cannot be computed
- */
- public KeplerianPropagator(final Orbit initialOrbit, final AttitudeProvider attitudeProv,
- final double mu, final double mass)
- throws OrekitException {
- super(attitudeProv);
- // ensure the orbit use the specified mu and has no non-Keplerian derivatives
- initialState = fixState(initialOrbit,
- getAttitudeProvider().getAttitude(initialOrbit,
- initialOrbit.getDate(),
- initialOrbit.getFrame()),
- mass, mu, Collections.emptyMap());
- states = new TimeSpanMap<SpacecraftState>(initialState);
- super.resetInitialState(initialState);
- }
- /** Fix state to use a specified mu and remove derivatives.
- * <p>
- * This ensures the propagation model (which is based on calling
- * {@link Orbit#shiftedBy(double)}) is Keplerian only and uses a specified mu.
- * </p>
- * @param orbit orbit to fix
- * @param attitude current attitude
- * @param mass current mass
- * @param mu gravity coefficient to use
- * @param additionalStates additional states
- * @return fixed orbit
- */
- private SpacecraftState fixState(final Orbit orbit, final Attitude attitude, final double mass,
- final double mu, final Map<String, double[]> additionalStates) {
- final OrbitType type = orbit.getType();
- final double[] stateVector = new double[6];
- type.mapOrbitToArray(orbit, PositionAngle.TRUE, stateVector, null);
- final Orbit fixedOrbit = type.mapArrayToOrbit(stateVector, null, PositionAngle.TRUE,
- orbit.getDate(), mu, orbit.getFrame());
- SpacecraftState fixedState = new SpacecraftState(fixedOrbit, attitude, mass);
- for (final Map.Entry<String, double[]> entry : additionalStates.entrySet()) {
- fixedState = fixedState.addAdditionalState(entry.getKey(), entry.getValue());
- }
- return fixedState;
- }
- /** {@inheritDoc} */
- public void resetInitialState(final SpacecraftState state)
- throws OrekitException {
- // ensure the orbit use the specified mu and has no non-Keplerian derivatives
- final double mu = initialState == null ? state.getMu() : initialState.getMu();
- final SpacecraftState fixedState = fixState(state.getOrbit(),
- state.getAttitude(),
- state.getMass(),
- mu,
- state.getAdditionalStates());
- initialState = fixedState;
- states = new TimeSpanMap<SpacecraftState>(initialState);
- super.resetInitialState(fixedState);
- }
- /** {@inheritDoc} */
- protected void resetIntermediateState(final SpacecraftState state, final boolean forward)
- throws OrekitException {
- if (forward) {
- states.addValidAfter(state, state.getDate());
- } else {
- states.addValidBefore(state, state.getDate());
- }
- }
- /** {@inheritDoc} */
- protected Orbit propagateOrbit(final AbsoluteDate date)
- throws OrekitException {
- // propagate orbit
- Orbit orbit = states.get(date).getOrbit();
- do {
- // we use a loop here to compensate for very small date shifts error
- // that occur with long propagation time
- orbit = orbit.shiftedBy(date.durationFrom(orbit.getDate()));
- } while (!date.equals(orbit.getDate()));
- return orbit;
- }
- /** {@inheritDoc}*/
- protected double getMass(final AbsoluteDate date) {
- return states.get(date).getMass();
- }
- /** Replace the instance with a data transfer object for serialization.
- * @return data transfer object that will be serialized
- * @exception NotSerializableException if an additional state provider is not serializable
- */
- private Object writeReplace() throws NotSerializableException {
- try {
- // managed states providers
- final List<AdditionalStateProvider> serializableProviders = new ArrayList<AdditionalStateProvider>();
- for (final AdditionalStateProvider provider : getAdditionalStateProviders()) {
- if (provider instanceof Serializable) {
- serializableProviders.add(provider);
- } else {
- throw new NotSerializableException(provider.getClass().getName());
- }
- }
- // states transitions
- final AbsoluteDate[] transitionDates;
- final SpacecraftState[] allStates;
- final SortedSet<TimeSpanMap.Transition<SpacecraftState>> transitions = states.getTransitions();
- if (transitions.size() == 1 && transitions.first().getBefore() == transitions.first().getAfter()) {
- // the single entry is a dummy one, without a real transition
- // we ignore it completely
- transitionDates = null;
- allStates = null;
- } else {
- transitionDates = new AbsoluteDate[transitions.size()];
- allStates = new SpacecraftState[transitions.size() + 1];
- int i = 0;
- for (final TimeSpanMap.Transition<SpacecraftState> transition : transitions) {
- if (i == 0) {
- // state before the first transition
- allStates[i] = transition.getBefore();
- }
- transitionDates[i] = transition.getDate();
- allStates[++i] = transition.getAfter();
- }
- }
- return new DataTransferObject(getInitialState().getOrbit(), getAttitudeProvider(),
- getInitialState().getMu(), getInitialState().getMass(),
- transitionDates, allStates,
- serializableProviders.toArray(new AdditionalStateProvider[serializableProviders.size()]));
- } catch (OrekitException orekitException) {
- // this should never happen
- throw new OrekitInternalError(null);
- }
- }
- /** Internal class used only for serialization. */
- private static class DataTransferObject implements Serializable {
- /** Serializable UID. */
- private static final long serialVersionUID = 20151202L;
- /** Initial orbit. */
- private final Orbit orbit;
- /** Attitude provider. */
- private final AttitudeProvider attitudeProvider;
- /** Central attraction coefficient (m³/s²). */
- private final double mu;
- /** Spacecraft mass (kg). */
- private final double mass;
- /** Transition dates (may be null). */
- private final AbsoluteDate[] transitionDates;
- /** States before and after transitions (may be null). */
- private final SpacecraftState[] allStates;
- /** Providers for additional states. */
- private final AdditionalStateProvider[] providers;
- /** Simple constructor.
- * @param orbit initial orbit
- * @param attitudeProvider attitude provider
- * @param mu central attraction coefficient (m³/s²)
- * @param mass initial spacecraft mass (kg)
- * @param transitionDates transition dates (may be null)
- * @param allStates states before and after transitions (may be null)
- * @param providers providers for additional states
- */
- DataTransferObject(final Orbit orbit,
- final AttitudeProvider attitudeProvider,
- final double mu, final double mass,
- final AbsoluteDate[] transitionDates,
- final SpacecraftState[] allStates,
- final AdditionalStateProvider[] providers) {
- this.orbit = orbit;
- this.attitudeProvider = attitudeProvider;
- this.mu = mu;
- this.mass = mass;
- this.transitionDates = transitionDates;
- this.allStates = allStates;
- this.providers = providers;
- }
- /** Replace the deserialized data transfer object with a {@link KeplerianPropagator}.
- * @return replacement {@link KeplerianPropagator}
- */
- private Object readResolve() {
- try {
- final KeplerianPropagator propagator =
- new KeplerianPropagator(orbit, attitudeProvider, mu, mass);
- for (final AdditionalStateProvider provider : providers) {
- propagator.addAdditionalStateProvider(provider);
- }
- if (transitionDates != null) {
- // override the state transitions
- propagator.states = new TimeSpanMap<SpacecraftState>(allStates[0]);
- for (int i = 0; i < transitionDates.length; ++i) {
- propagator.states.addValidAfter(allStates[i + 1], transitionDates[i]);
- }
- }
- return propagator;
- } catch (OrekitException oe) {
- throw new OrekitInternalError(oe);
- }
- }
- }
- }