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