<commit_before>/* Copyright 2002-2017 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.Serializable;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.hipparchus.exception.LocalizedCoreFormats;
import org.hipparchus.exception.MathIllegalArgumentException;
import org.hipparchus.util.FastMath;
import org.orekit.attitudes.Attitude;
import org.orekit.attitudes.AttitudeProvider;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitInternalError;
import org.orekit.errors.OrekitMessages;
import org.orekit.frames.Frame;
import org.orekit.orbits.Orbit;
import org.orekit.propagation.BoundedPropagator;
import org.orekit.propagation.SpacecraftState;
import org.orekit.time.AbsoluteDate;
import org.orekit.utils.ImmutableTimeStampedCache;
import org.orekit.utils.PVCoordinatesProvider;
import org.orekit.utils.TimeStampedPVCoordinates;

/** 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 <NAME>
 * @author <NAME>
 * @author <NAME>
 */
public class Ephemeris extends AbstractAnalyticalPropagator implements BoundedPropagator, Serializable {

    /** Default extrapolation time threshold: 1ms.
     * @since 9.0
     **/
    public static final double DEFAULT_EXTRAPOLATION_THRESHOLD_SEC = 1e-3;

    /** Serializable UID. */
    private static final long serialVersionUID = 20170606L;

     /** First date in range. */
    private final AbsoluteDate minDate;

    /** Last date in range. */
    private final AbsoluteDate maxDate;

    /** The extrapolation threshold beyond which the propagation will fail. **/
    private final double extrapolationThreshold;

    /** Reference frame. */
    private final Frame frame;

    /** Names of the additional states. */
    private final String[] additional;

    /** Local PV Provider used for computing attitude. **/
    private LocalPVProvider pvProvider;

    /** Thread-safe cache. */
    private final transient ImmutableTimeStampedCache<SpacecraftState> cache;

    /** Constructor with tabulated states.
     * <p>
     * This constructor allows extrapolating outside of the states time span
     * by up to the 1ms {@link #DEFAULT_EXTRAPOLATION_THRESHOLD_SEC default
     * extrapolation threshold}.
     * </p>
     * @param states tabulates states
     * @param interpolationPoints number of points to use in interpolation
     * @exception OrekitException if some states have incompatible additional states
     * @exception MathIllegalArgumentException if the number of states is smaller than
     * the number of points to use in interpolation
     * @see #Ephemeris(List, int, double)
     */
    public Ephemeris(final List<SpacecraftState> states, final int interpolationPoints)
        throws OrekitException, MathIllegalArgumentException {
        this(states, interpolationPoints, DEFAULT_EXTRAPOLATION_THRESHOLD_SEC);
    }

    /** Constructor with tabulated states.
     * @param states tabulates states
     * @param interpolationPoints number of points to use in interpolation
     * @param extrapolationThreshold the largest time difference in seconds between
     * the start or stop boundary of the ephemeris bounds to be doing extrapolation
     * @exception OrekitException if some states have incompatible additional states
     * @exception MathIllegalArgumentException if the number of states is smaller than
     * the number of points to use in interpolation
     * @since 9.0
     */
    public Ephemeris(final List<SpacecraftState> states, final int interpolationPoints,
                     final double extrapolationThreshold)
        throws OrekitException, MathIllegalArgumentException {

        super(DEFAULT_LAW);

        if (states.size() < interpolationPoints) {
            throw new MathIllegalArgumentException(LocalizedCoreFormats.INSUFFICIENT_DIMENSION,
                                                   states.size(), interpolationPoints);
        }

        final SpacecraftState s0 = states.get(0);
        minDate = s0.getDate();
        maxDate = states.get(states.size() - 1).getDate();
        frame = s0.getFrame();

        final Set<String> names0 = s0.getAdditionalStates().keySet();
        additional = names0.toArray(new String[names0.size()]);

        // check all states handle the same additional states
        for (final SpacecraftState state : states) {
            s0.ensureCompatibleAdditionalStates(state);
        }

        pvProvider = new LocalPVProvider();

        // user needs to explicitly set attitude provider if they want to use one
        setAttitudeProvider(null);

        // set up cache
        cache = new ImmutableTimeStampedCache<SpacecraftState>(interpolationPoints, states);

        this.extrapolationThreshold = extrapolationThreshold;
    }

    /** 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;
    }

    /** Get the maximum timespan outside of the stored ephemeris that is allowed
     * for extrapolation.
     * @return the extrapolation threshold in seconds
     */
    public double getExtrapolationThreshold() {
        return extrapolationThreshold;
    }

    @Override
    public Frame getFrame() {
        return frame;
    }

    @Override
    /** {@inheritDoc} */
    public SpacecraftState basicPropagate(final AbsoluteDate date) throws OrekitException {
        final SpacecraftState evaluatedState;

        if (date.compareTo(minDate) < 0 && FastMath.abs(date.durationFrom(minDate)) <= extrapolationThreshold) {
            final double dt = date.durationFrom(getMinDate());
            evaluatedState = cache.getEarliest().shiftedBy(dt);
        } else if (date.compareTo(maxDate) > 0 && FastMath.abs(date.durationFrom(maxDate)) <= extrapolationThreshold) {
            final double dt = date.durationFrom(getMaxDate());
            evaluatedState = cache.getLatest().shiftedBy(dt);
        } else {
            final List<SpacecraftState> neighbors = cache.getNeighbors(date).collect(Collectors.toList());
            evaluatedState = neighbors.get(0).interpolate(date, neighbors);
        }

        final AttitudeProvider attitudeProvider = getAttitudeProvider();

        if (attitudeProvider == null) {
            return evaluatedState;
        } else {
            pvProvider.setCurrentState(evaluatedState);
            final Attitude calculatedAttitude = attitudeProvider.getAttitude(pvProvider, date,
                                                                             evaluatedState.getFrame());
            return new SpacecraftState(evaluatedState.getOrbit(), calculatedAttitude, evaluatedState.getMass());
        }
    }

    /** {@inheritDoc} */
    protected Orbit propagateOrbit(final AbsoluteDate date) throws OrekitException {
        return basicPropagate(date).getOrbit();
    }

    /** {@inheritDoc} */<commit_msg>Use the interpolator also for small extrapolations.<commit_after>/* Copyright 2002-2017 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.Serializable;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.hipparchus.exception.LocalizedCoreFormats;
import org.hipparchus.exception.MathIllegalArgumentException;
import org.hipparchus.util.FastMath;
import org.orekit.attitudes.Attitude;
import org.orekit.attitudes.AttitudeProvider;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitInternalError;
import org.orekit.errors.OrekitMessages;
import org.orekit.frames.Frame;
import org.orekit.orbits.Orbit;
import org.orekit.propagation.BoundedPropagator;
import org.orekit.propagation.SpacecraftState;
import org.orekit.time.AbsoluteDate;
import org.orekit.utils.ImmutableTimeStampedCache;
import org.orekit.utils.PVCoordinatesProvider;
import org.orekit.utils.TimeStampedPVCoordinates;

/** 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 <NAME>
 * @author <NAME>
 * @author <NAME>
 */
public class Ephemeris extends AbstractAnalyticalPropagator implements BoundedPropagator, Serializable {

    /** Default extrapolation time threshold: 1ms.
     * @since 9.0
     **/
    public static final double DEFAULT_EXTRAPOLATION_THRESHOLD_SEC = 1e-3;

    /** Serializable UID. */
    private static final long serialVersionUID = 20170606L;

     /** First date in range. */
    private final AbsoluteDate minDate;

    /** Last date in range. */
    private final AbsoluteDate maxDate;

    /** The extrapolation threshold beyond which the propagation will fail. **/
    private final double extrapolationThreshold;

    /** Reference frame. */
    private final Frame frame;

    /** Names of the additional states. */
    private final String[] additional;

    /** Local PV Provider used for computing attitude. **/
    private LocalPVProvider pvProvider;

    /** Thread-safe cache. */
    private final transient ImmutableTimeStampedCache<SpacecraftState> cache;

    /** Constructor with tabulated states.
     * <p>
     * This constructor allows extrapolating outside of the states time span
     * by up to the 1ms {@link #DEFAULT_EXTRAPOLATION_THRESHOLD_SEC default
     * extrapolation threshold}.
     * </p>
     * @param states tabulates states
     * @param interpolationPoints number of points to use in interpolation
     * @exception OrekitException if some states have incompatible additional states
     * @exception MathIllegalArgumentException if the number of states is smaller than
     * the number of points to use in interpolation
     * @see #Ephemeris(List, int, double)
     */
    public Ephemeris(final List<SpacecraftState> states, final int interpolationPoints)
        throws OrekitException, MathIllegalArgumentException {
        this(states, interpolationPoints, DEFAULT_EXTRAPOLATION_THRESHOLD_SEC);
    }

    /** Constructor with tabulated states.
     * @param states tabulates states
     * @param interpolationPoints number of points to use in interpolation
     * @param extrapolationThreshold the largest time difference in seconds between
     * the start or stop boundary of the ephemeris bounds to be doing extrapolation
     * @exception OrekitException if some states have incompatible additional states
     * @exception MathIllegalArgumentException if the number of states is smaller than
     * the number of points to use in interpolation
     * @since 9.0
     */
    public Ephemeris(final List<SpacecraftState> states, final int interpolationPoints,
                     final double extrapolationThreshold)
        throws OrekitException, MathIllegalArgumentException {

        super(DEFAULT_LAW);

        if (states.size() < interpolationPoints) {
            throw new MathIllegalArgumentException(LocalizedCoreFormats.INSUFFICIENT_DIMENSION,
                                                   states.size(), interpolationPoints);
        }

        final SpacecraftState s0 = states.get(0);
        minDate = s0.getDate();
        maxDate = states.get(states.size() - 1).getDate();
        frame = s0.getFrame();

        final Set<String> names0 = s0.getAdditionalStates().keySet();
        additional = names0.toArray(new String[names0.size()]);

        // check all states handle the same additional states
        for (final SpacecraftState state : states) {
            s0.ensureCompatibleAdditionalStates(state);
        }

        pvProvider = new LocalPVProvider();

        // user needs to explicitly set attitude provider if they want to use one
        setAttitudeProvider(null);

        // set up cache
        cache = new ImmutableTimeStampedCache<SpacecraftState>(interpolationPoints, states);

        this.extrapolationThreshold = extrapolationThreshold;
    }

    /** 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;
    }

    /** Get the maximum timespan outside of the stored ephemeris that is allowed
     * for extrapolation.
     * @return the extrapolation threshold in seconds
     */
    public double getExtrapolationThreshold() {
        return extrapolationThreshold;
    }

    @Override
    public Frame getFrame() {
        return frame;
    }

    @Override
    /** {@inheritDoc} */
    public SpacecraftState basicPropagate(final AbsoluteDate date) throws OrekitException {
        final SpacecraftState evaluatedState;

        final AbsoluteDate central;
        if (date.compareTo(minDate) < 0 && FastMath.abs(date.durationFrom(minDate)) <= extrapolationThreshold) {
            // avoid TimeStampedCacheException as we are still within the tolerance before minDate
            central = minDate;
        } else if (date.compareTo(maxDate) > 0 && FastMath.abs(date.durationFrom(maxDate)) <= extrapolationThreshold) {
            // avoid TimeStampedCacheException as we are still within the tolerance after maxDate
            central = maxDate;
        } else {
            central = date;
        }
        final List<SpacecraftState> neighbors = cache.getNeighbors(central).collect(Collectors.toList());
        evaluatedState = neighbors.get(0).interpolate(date, neighbors);

        final AttitudeProvider attitudeProvider = getAttitudeProvider();

        if (attitudeProvider == null) {
            return evaluatedState;
        } else {
            pvProvider.setCurrentState(evaluatedState);
            final Attitude calculatedAttitude = attitudeProvider.getAttitude(pvProvider, date,
                                                                             evaluatedState.getFrame());
            return new SpacecraftState(evaluatedState.getOrbit(), calculatedAttitude, evaluatedState.getMass());
        }
    }

    /** {@inheritDoc} */
    protected Orbit propagateOrbit(final AbsoluteDate date) throws OrekitException {
        return basicPropagate(date).getOrbit();
    }

    /** {@inheritDoc} */
{'fraction_non_alphanumeric': 0.07651487103541899, 'fraction_numerical': 0.005059854374922868, 'mean_word_length': 3.1260183299389004, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '137137', 'n_tokens_mistral': 4263, 'n_tokens_neox': 4035, 'n_words': 1351}