Ephemeris.java
- /* Copyright 2002-2024 CS GROUP
- * Licensed to CS GROUP (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 org.hipparchus.exception.LocalizedCoreFormats;
- import org.hipparchus.exception.MathIllegalArgumentException;
- import org.hipparchus.linear.RealMatrix;
- import org.orekit.attitudes.Attitude;
- import org.orekit.attitudes.AttitudeProvider;
- import org.orekit.attitudes.FrameAlignedProvider;
- import org.orekit.errors.OrekitException;
- import org.orekit.errors.OrekitIllegalArgumentException;
- import org.orekit.errors.OrekitIllegalStateException;
- import org.orekit.errors.OrekitMessages;
- import org.orekit.frames.Frame;
- import org.orekit.orbits.Orbit;
- import org.orekit.propagation.AbstractMatricesHarvester;
- import org.orekit.propagation.BoundedPropagator;
- import org.orekit.propagation.SpacecraftState;
- import org.orekit.propagation.SpacecraftStateInterpolator;
- import org.orekit.propagation.StateCovariance;
- import org.orekit.time.AbsoluteDate;
- import org.orekit.time.AbstractTimeInterpolator;
- import org.orekit.time.TimeInterpolator;
- import org.orekit.time.TimeStampedPair;
- import org.orekit.utils.DoubleArrayDictionary;
- import org.orekit.utils.ImmutableTimeStampedCache;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Optional;
- /**
- * This class is designed to accept and handle tabulated orbital entries. Tabulated entries are classified and then
- * extrapolated in way to obtain continuous output, with accuracy and computation methods configured by the user.
- *
- * @author Fabien Maussion
- * @author Véronique Pommier-Maurussane
- * @author Luc Maisonobe
- * @author Vincent Cucchietti
- */
- public class Ephemeris extends AbstractAnalyticalPropagator implements BoundedPropagator {
- /** First date in range. */
- private final AbsoluteDate minDate;
- /** Last date in range. */
- private final AbsoluteDate maxDate;
- /** Reference frame. */
- private final Frame frame;
- /** Names of the additional states. */
- private final String[] additional;
- /** List of spacecraft states. */
- private final transient ImmutableTimeStampedCache<SpacecraftState> statesCache;
- /** List of covariances. **/
- private final transient ImmutableTimeStampedCache<StateCovariance> covariancesCache;
- /** Spacecraft state interpolator. */
- private final transient TimeInterpolator<SpacecraftState> stateInterpolator;
- /** State covariance interpolator. */
- private final transient TimeInterpolator<TimeStampedPair<Orbit, StateCovariance>> covarianceInterpolator;
- /** Flag defining if states are defined using an orbit or an absolute position-velocity-acceleration. */
- private final transient boolean statesAreOrbitDefined;
- /**
- * Legacy constructor with tabulated states and default Hermite interpolation.
- * <p>
- * As this implementation of interpolation is polynomial, it should be used only with small samples (about 10-20 points)
- * in order to avoid <a href="http://en.wikipedia.org/wiki/Runge%27s_phenomenon">Runge's phenomenon</a> and numerical
- * problems (including NaN appearing).
- *
- * @param states list of spacecraft states
- * @param interpolationPoints number of points to use in interpolation
- *
- * @throws MathIllegalArgumentException if the number of states is smaller than the number of points to use in
- * interpolation
- * @throws OrekitIllegalArgumentException if states are not defined the same way (orbit or absolute
- * position-velocity-acceleration)
- * @see #Ephemeris(List, TimeInterpolator, List, TimeInterpolator)
- * @see SpacecraftStateInterpolator
- */
- public Ephemeris(final List<SpacecraftState> states, final int interpolationPoints)
- throws MathIllegalArgumentException {
- // If states is empty an exception will be thrown in the other constructor
- this(states, new SpacecraftStateInterpolator(interpolationPoints,
- states.get(0).getFrame(),
- states.get(0).getFrame()),
- new ArrayList<>(), null);
- }
- /**
- * Constructor with tabulated states.
- *
- * @param states list of spacecraft states
- * @param stateInterpolator spacecraft state interpolator
- *
- * @throws MathIllegalArgumentException if the number of states is smaller than the number of points to use in
- * interpolation
- * @throws OrekitIllegalArgumentException if states are not defined the same way (orbit or absolute
- * position-velocity-acceleration)
- * @see #Ephemeris(List, TimeInterpolator, List, TimeInterpolator)
- */
- public Ephemeris(final List<SpacecraftState> states, final TimeInterpolator<SpacecraftState> stateInterpolator)
- throws MathIllegalArgumentException {
- this(states, stateInterpolator, new ArrayList<>(), null);
- }
- /**
- * Constructor with tabulated states.
- *
- * @param states list of spacecraft states
- * @param stateInterpolator spacecraft state interpolator
- * @param attitudeProvider attitude law to use, null by default
- *
- * @throws MathIllegalArgumentException if the number of states is smaller than the number of points to use in
- * interpolation
- * @throws OrekitIllegalArgumentException if states are not defined the same way (orbit or absolute
- * position-velocity-acceleration)
- * @see #Ephemeris(List, TimeInterpolator, List, TimeInterpolator)
- */
- public Ephemeris(final List<SpacecraftState> states, final TimeInterpolator<SpacecraftState> stateInterpolator,
- final AttitudeProvider attitudeProvider)
- throws MathIllegalArgumentException {
- this(states, stateInterpolator, new ArrayList<>(), null, attitudeProvider);
- }
- /**
- * Constructor with tabulated states and associated covariances.
- *
- * @param states list of spacecraft states
- * @param stateInterpolator spacecraft state interpolator
- * @param covariances tabulated covariances associated to tabulated states ephemeris bounds to be doing extrapolation
- * @param covarianceInterpolator covariance interpolator
- *
- * @throws MathIllegalArgumentException if the number of states is smaller than the number of points to use in
- * interpolation
- * @throws OrekitIllegalArgumentException if states are not defined the same way (orbit or absolute
- * position-velocity-acceleration)
- * @throws OrekitIllegalArgumentException if number of states is different from the number of covariances
- * @throws OrekitIllegalStateException if dates between states and associated covariances are different
- * @see #Ephemeris(List, TimeInterpolator, List, TimeInterpolator, AttitudeProvider)
- * @since 9.0
- */
- public Ephemeris(final List<SpacecraftState> states,
- final TimeInterpolator<SpacecraftState> stateInterpolator,
- final List<StateCovariance> covariances,
- final TimeInterpolator<TimeStampedPair<Orbit, StateCovariance>> covarianceInterpolator)
- throws MathIllegalArgumentException {
- this(states, stateInterpolator, covariances, covarianceInterpolator,
- // if states is empty an exception will be thrown in the other constructor
- states.isEmpty() ? null : FrameAlignedProvider.of(states.get(0).getFrame()));
- }
- /**
- * Constructor with tabulated states and associated covariances.
- * <p>
- * The user is expected to explicitly define an attitude provider if they want to use one. Otherwise, it is null by
- * default
- *
- * @param states list of spacecraft states
- * @param stateInterpolator spacecraft state interpolator
- * @param covariances tabulated covariances associated to tabulated states
- * @param covarianceInterpolator covariance interpolator
- * @param attitudeProvider attitude law to use, null by default
- *
- * @throws MathIllegalArgumentException if the number of states is smaller than the number of points to use in
- * interpolation
- * @throws OrekitIllegalArgumentException if states are not defined the same way (orbit or absolute
- * position-velocity-acceleration)
- * @throws OrekitIllegalArgumentException if number of states is different from the number of covariances
- * @throws OrekitIllegalStateException if dates between states and associated covariances are different
- * @since 10.1
- */
- public Ephemeris(final List<SpacecraftState> states,
- final TimeInterpolator<SpacecraftState> stateInterpolator,
- final List<StateCovariance> covariances,
- final TimeInterpolator<TimeStampedPair<Orbit, StateCovariance>> covarianceInterpolator,
- final AttitudeProvider attitudeProvider)
- throws MathIllegalArgumentException {
- super(attitudeProvider);
- // Check input consistency
- checkInputConsistency(states, stateInterpolator, covariances, covarianceInterpolator);
- // Initialize variables
- final SpacecraftState s0 = states.get(0);
- minDate = s0.getDate();
- maxDate = states.get(states.size() - 1).getDate();
- frame = s0.getFrame();
- final List<DoubleArrayDictionary.Entry> as = s0.getAdditionalStatesValues().getData();
- additional = new String[as.size()];
- for (int i = 0; i < additional.length; ++i) {
- additional[i] = as.get(i).getKey();
- }
- this.statesCache = new ImmutableTimeStampedCache<>(stateInterpolator.getNbInterpolationPoints(), states);
- this.stateInterpolator = stateInterpolator;
- this.covarianceInterpolator = covarianceInterpolator;
- if (covarianceInterpolator != null) {
- this.covariancesCache = new ImmutableTimeStampedCache<>(covarianceInterpolator.getNbInterpolationPoints(),
- covariances);
- } else {
- this.covariancesCache = null;
- }
- this.statesAreOrbitDefined = s0.isOrbitDefined();
- // Initialize initial state
- super.resetInitialState(getInitialState());
- }
- /**
- * Check input consistency between states, covariances and their associated interpolators.
- *
- * @param states spacecraft states sample
- * @param stateInterpolator spacecraft state interpolator
- * @param covariances covariances sample
- * @param covarianceInterpolator covariance interpolator
- */
- public static void checkInputConsistency(final List<SpacecraftState> states,
- final TimeInterpolator<SpacecraftState> stateInterpolator,
- final List<StateCovariance> covariances,
- final TimeInterpolator<TimeStampedPair<Orbit, StateCovariance>> covarianceInterpolator) {
- // Checks to perform is states are provided
- if (!states.isEmpty()) {
- // Check given that given states definition are consistent
- // (all defined by either orbits or absolute position-velocity-acceleration coordinates)
- SpacecraftStateInterpolator.checkStatesDefinitionsConsistency(states);
- // Check that every interpolator used in the state interpolator are compatible with the sample size
- AbstractTimeInterpolator.checkInterpolatorCompatibilityWithSampleSize(stateInterpolator, states.size());
- // Additional checks if covariances are provided
- if (!covariances.isEmpty()) {
- // Check that every interpolator used in the state covariance interpolator are compatible with the sample size
- AbstractTimeInterpolator.checkInterpolatorCompatibilityWithSampleSize(covarianceInterpolator,
- covariances.size());
- // Check states and covariances consistency
- checkStatesAndCovariancesConsistency(states, covariances);
- }
- }
- else {
- throw new OrekitIllegalArgumentException(OrekitMessages.NOT_ENOUGH_DATA, 0);
- }
- }
- /**
- * Check that given states and covariances are consistent.
- *
- * @param states tabulates states to check
- * @param covariances tabulated covariances associated to tabulated states to check
- */
- public static void checkStatesAndCovariancesConsistency(final List<SpacecraftState> states,
- final List<StateCovariance> covariances) {
- final int nbStates = states.size();
- // Check that we have an equal number of states and covariances
- if (nbStates != covariances.size()) {
- throw new OrekitIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
- states.size(),
- covariances.size());
- }
- // Check that states and covariance are defined at the same date
- for (int i = 0; i < nbStates; i++) {
- if (!states.get(i).getDate().isCloseTo(covariances.get(i).getDate(),
- TimeStampedPair.DEFAULT_DATE_EQUALITY_THRESHOLD)) {
- throw new OrekitIllegalStateException(OrekitMessages.STATE_AND_COVARIANCE_DATES_MISMATCH,
- states.get(i).getDate(), covariances.get(i).getDate());
- }
- }
- }
- /**
- * Get the first date of the range.
- *
- * @return the first date of the range
- */
- public AbsoluteDate getMinDate() {
- return minDate;
- }
- /**
- * Get the last date of the range.
- *
- * @return the last date of the range
- */
- public AbsoluteDate getMaxDate() {
- return maxDate;
- }
- /** {@inheritDoc} */
- @Override
- public Frame getFrame() {
- return frame;
- }
- /**
- * Get the covariance at given date.
- * <p>
- * BEWARE : If this instance has been created without sample of covariances and/or with spacecraft states defined with
- * absolute position-velocity-acceleration, it will return an empty {@link Optional}.
- *
- * @param date date at which the covariance is desired
- *
- * @return covariance at given date
- *
- * @see Optional
- */
- public Optional<StateCovariance> getCovariance(final AbsoluteDate date) {
- if (covarianceInterpolator != null && covariancesCache != null && statesAreOrbitDefined) {
- // Build list of time stamped pair of orbits and their associated covariances
- final List<TimeStampedPair<Orbit, StateCovariance>> sample = buildOrbitAndCovarianceSample();
- // Interpolate
- final TimeStampedPair<Orbit, StateCovariance> interpolatedOrbitAndCovariance =
- covarianceInterpolator.interpolate(date, sample);
- return Optional.of(interpolatedOrbitAndCovariance.getSecond());
- }
- else {
- return Optional.empty();
- }
- }
- /** @return sample of orbits and their associated covariances */
- private List<TimeStampedPair<Orbit, StateCovariance>> buildOrbitAndCovarianceSample() {
- final List<TimeStampedPair<Orbit, StateCovariance>> sample = new ArrayList<>();
- final List<SpacecraftState> states = statesCache.getAll();
- final List<StateCovariance> covariances = covariancesCache.getAll();
- for (int i = 0; i < states.size(); i++) {
- sample.add(new TimeStampedPair<>(states.get(i).getOrbit(), covariances.get(i)));
- }
- return sample;
- }
- /** {@inheritDoc} */
- @Override
- public SpacecraftState basicPropagate(final AbsoluteDate date) {
- final AbsoluteDate centralDate =
- AbstractTimeInterpolator.getCentralDate(date, statesCache, stateInterpolator.getExtrapolationThreshold());
- final SpacecraftState evaluatedState = stateInterpolator.interpolate(date, statesCache.getNeighbors(centralDate));
- final AttitudeProvider attitudeProvider = getAttitudeProvider();
- if (attitudeProvider == null) {
- return evaluatedState;
- }
- else {
- final Attitude calculatedAttitude;
- // Verify if orbit is defined
- if (evaluatedState.isOrbitDefined()) {
- calculatedAttitude =
- attitudeProvider.getAttitude(evaluatedState.getOrbit(), date, evaluatedState.getFrame());
- return new SpacecraftState(evaluatedState.getOrbit(), calculatedAttitude, evaluatedState.getMass(),
- evaluatedState.getAdditionalStatesValues(),
- evaluatedState.getAdditionalStatesDerivatives());
- }
- else {
- calculatedAttitude =
- attitudeProvider.getAttitude(evaluatedState.getAbsPVA(), date, evaluatedState.getFrame());
- return new SpacecraftState(evaluatedState.getAbsPVA(), calculatedAttitude, evaluatedState.getMass(),
- evaluatedState.getAdditionalStatesValues(),
- evaluatedState.getAdditionalStatesDerivatives());
- }
- }
- }
- /** {@inheritDoc} */
- protected Orbit propagateOrbit(final AbsoluteDate date) {
- return basicPropagate(date).getOrbit();
- }
- /** {@inheritDoc} */
- protected double getMass(final AbsoluteDate date) {
- return basicPropagate(date).getMass();
- }
- /**
- * Try (and fail) to reset the initial state.
- * <p>
- * This method always throws an exception, as ephemerides cannot be reset.
- * </p>
- *
- * @param state new initial state to consider
- */
- public void resetInitialState(final SpacecraftState state) {
- throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
- }
- /** {@inheritDoc} */
- protected void resetIntermediateState(final SpacecraftState state, final boolean forward) {
- throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
- }
- /** {@inheritDoc} */
- public SpacecraftState getInitialState() {
- return basicPropagate(getMinDate());
- }
- /** {@inheritDoc} */
- @Override
- public boolean isAdditionalStateManaged(final String name) {
- // the additional state may be managed by a specific provider in the base class
- if (super.isAdditionalStateManaged(name)) {
- return true;
- }
- // the additional state may be managed in the states sample
- for (final String a : additional) {
- if (a.equals(name)) {
- return true;
- }
- }
- return false;
- }
- /** {@inheritDoc} */
- @Override
- public String[] getManagedAdditionalStates() {
- final String[] upperManaged = super.getManagedAdditionalStates();
- final String[] managed = new String[upperManaged.length + additional.length];
- System.arraycopy(upperManaged, 0, managed, 0, upperManaged.length);
- System.arraycopy(additional, 0, managed, upperManaged.length, additional.length);
- return managed;
- }
- /** {@inheritDoc} */
- @Override
- protected AbstractMatricesHarvester createHarvester(final String stmName, final RealMatrix initialStm,
- final DoubleArrayDictionary initialJacobianColumns) {
- // In order to not throw an Orekit exception during ephemeris based orbit determination
- // The default behavior of the method is overridden to return a null parameter
- return null;
- }
- /** Get state interpolator.
- * @return state interpolator
- */
- public TimeInterpolator<SpacecraftState> getStateInterpolator() {
- return stateInterpolator;
- }
- /** Get covariance interpolator.
- * @return optional covariance interpolator
- * @see Optional
- */
- public Optional<TimeInterpolator<TimeStampedPair<Orbit, StateCovariance>>> getCovarianceInterpolator() {
- return Optional.ofNullable(covarianceInterpolator);
- }
- }