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                          DEFAULT_MASS
93                  )
94          );
95      }
96  
97      @Override
98      public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame frame) {
99          final TimeStampedPVCoordinates interpolatedPVCoordinates = interpolate(date);
100         return ephemerisFrame.getTransformTo(frame, date).transformPVCoordinates(interpolatedPVCoordinates);
101     }
102 
103     @Override
104     public Vector3D getPosition(final AbsoluteDate date, final Frame frame) {
105         final Vector3D interpolatedPosition = interpolate(date).getPosition();
106         return ephemerisFrame.getStaticTransformTo(frame, date).transformPosition(interpolatedPosition);
107     }
108 
109     @Override
110     protected Orbit propagateOrbit(final AbsoluteDate date) {
111         final TimeStampedPVCoordinates pv = this.getPVCoordinates(date, inertialFrame);
112         return new CartesianOrbit(pv, inertialFrame, this.ephemeris.getMu());
113     }
114 
115     @Override
116     public AbsoluteDate getMinDate() {
117         return ephemeris.getStart();
118     }
119 
120     @Override
121     public AbsoluteDate getMaxDate() {
122         return ephemeris.getStop();
123     }
124 
125     @Override
126     protected double getMass(final AbsoluteDate date) {
127         return DEFAULT_MASS;
128     }
129 
130     @Override
131     public SpacecraftState getInitialState() {
132         return this.basicPropagate(this.getMinDate());
133     }
134 
135     @Override
136     protected void resetIntermediateState(final SpacecraftState state,
137                                           final boolean forward) {
138         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
139     }
140 
141     @Override
142     public void resetInitialState(final SpacecraftState state) {
143         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
144     }
145 
146     /** Interpolate ephemeris segment at date.
147      *
148      * @param date interpolation date
149      * @return interpolated position-velocity vector
150      */
151     private TimeStampedPVCoordinates interpolate(final AbsoluteDate date) {
152         final List<C> neighbors = new SortedListTrimmer(interpolator.getNbInterpolationPoints()).
153                                   getNeighborsSubList(date, ephemeris.getCoordinates());
154 
155         // cast stream to super type
156         final List<TimeStampedPVCoordinates> castedNeighbors = new ArrayList<>(neighbors.size());
157         castedNeighbors.addAll(neighbors);
158 
159         // create interpolator
160         return interpolator.interpolate(date, castedNeighbors);
161     }
162 
163 }