1   /* Contributed in the public domain.
2    * Licensed to CS GROUP (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.files.general;
18  
19  import org.hipparchus.geometry.euclidean.threed.Vector3D;
20  import org.orekit.attitudes.AttitudeProvider;
21  import org.orekit.errors.OrekitException;
22  import org.orekit.errors.OrekitMessages;
23  import org.orekit.files.general.EphemerisFile.EphemerisSegment;
24  import org.orekit.frames.Frame;
25  import org.orekit.orbits.CartesianOrbit;
26  import org.orekit.orbits.Orbit;
27  import org.orekit.propagation.BoundedPropagator;
28  import org.orekit.propagation.Propagator;
29  import org.orekit.propagation.SpacecraftState;
30  import org.orekit.propagation.analytical.AbstractAnalyticalPropagator;
31  import org.orekit.time.AbsoluteDate;
32  import org.orekit.utils.SortedListTrimmer;
33  import org.orekit.utils.TimeStampedPVCoordinates;
34  import org.orekit.utils.TimeStampedPVCoordinatesHermiteInterpolator;
35  
36  import java.util.ArrayList;
37  import java.util.List;
38  
39  /**
40   * A {@link Propagator} based on a {@link EphemerisSegment}.
41   *
42   * <p> The {@link #getPVCoordinates(AbsoluteDate, Frame)} is implemented without using the
43   * {@link #propagate(AbsoluteDate)} methods so using this class as a {@link
44   * org.orekit.utils.PVCoordinatesProvider} still behaves as expected when the ephemeris
45   * file did not have a valid gravitational parameter.
46   * @param <C> type of the Cartesian coordinates
47   *
48   * @author Evan Ward
49   */
50  public class EphemerisSegmentPropagator<C extends TimeStampedPVCoordinates> extends AbstractAnalyticalPropagator
51          implements BoundedPropagator {
52  
53      /** Tabular data from which this propagator is built. */
54      private final EphemerisSegment<C> ephemeris;
55      /** Interpolator to use.
56       * @since 12.2
57       */
58      private final TimeStampedPVCoordinatesHermiteInterpolator interpolator;
59      /** Inertial frame used for creating orbits. */
60      private final Frame inertialFrame;
61      /** Frame of the ephemeris data. */
62      private final Frame ephemerisFrame;
63  
64      /**
65       * Create a {@link Propagator} from an ephemeris segment.
66       *
67       * @param ephemeris segment containing the data for this propagator.
68       * @param attitudeProvider provider for attitude computation
69       */
70      public EphemerisSegmentPropagator(final EphemerisSegment<C> ephemeris,
71                                        final AttitudeProvider attitudeProvider) {
72          super(attitudeProvider);
73          this.ephemeris      = ephemeris;
74          this.interpolator   = new TimeStampedPVCoordinatesHermiteInterpolator(ephemeris.getInterpolationSamples(),
75                                                                                ephemeris.getAvailableDerivatives());
76          this.ephemerisFrame = ephemeris.getFrame();
77          this.inertialFrame  = ephemeris.getInertialFrame();
78          // set the initial state so getFrame() works
79          final TimeStampedPVCoordinates ic = ephemeris.getCoordinates().get(0);
80          final TimeStampedPVCoordinates icInertial = ephemerisFrame
81                  .getTransformTo(inertialFrame, ic.getDate())
82                  .transformPVCoordinates(ic);
83          super.resetInitialState(
84                  new SpacecraftState(
85                          new CartesianOrbit(
86                                  icInertial, inertialFrame, ephemeris.getMu()
87                          ),
88                          getAttitudeProvider().getAttitude(
89                                  icInertial.toTaylorProvider(inertialFrame),
90                                  ic.getDate(),
91                                  inertialFrame)
92                          ).withMass(DEFAULT_MASS)
93          );
94      }
95  
96      @Override
97      public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame frame) {
98          final TimeStampedPVCoordinates interpolatedPVCoordinates = interpolate(date);
99          return ephemerisFrame.getTransformTo(frame, date).transformPVCoordinates(interpolatedPVCoordinates);
100     }
101 
102     @Override
103     public Vector3D getPosition(final AbsoluteDate date, final Frame frame) {
104         final Vector3D interpolatedPosition = interpolate(date).getPosition();
105         return ephemerisFrame.getStaticTransformTo(frame, date).transformPosition(interpolatedPosition);
106     }
107 
108     @Override
109     public Orbit propagateOrbit(final AbsoluteDate date) {
110         final TimeStampedPVCoordinates pv = this.getPVCoordinates(date, inertialFrame);
111         return new CartesianOrbit(pv, inertialFrame, this.ephemeris.getMu());
112     }
113 
114     @Override
115     public AbsoluteDate getMinDate() {
116         return ephemeris.getStart();
117     }
118 
119     @Override
120     public AbsoluteDate getMaxDate() {
121         return ephemeris.getStop();
122     }
123 
124     @Override
125     protected double getMass(final AbsoluteDate date) {
126         return DEFAULT_MASS;
127     }
128 
129     @Override
130     public SpacecraftState getInitialState() {
131         return this.basicPropagate(this.getMinDate());
132     }
133 
134     @Override
135     protected void resetIntermediateState(final SpacecraftState state,
136                                           final boolean forward) {
137         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
138     }
139 
140     @Override
141     public void resetInitialState(final SpacecraftState state) {
142         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
143     }
144 
145     /** Interpolate ephemeris segment at date.
146      *
147      * @param date interpolation date
148      * @return interpolated position-velocity vector
149      */
150     private TimeStampedPVCoordinates interpolate(final AbsoluteDate date) {
151         final List<C> neighbors = new SortedListTrimmer(interpolator.getNbInterpolationPoints()).
152                                   getNeighborsSubList(date, ephemeris.getCoordinates());
153 
154         // cast stream to super type
155         final List<TimeStampedPVCoordinates> castedNeighbors = new ArrayList<>(neighbors.size());
156         castedNeighbors.addAll(neighbors);
157 
158         // create interpolator
159         return interpolator.interpolate(date, castedNeighbors);
160     }
161 
162 }