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 java.util.List;
20  import java.util.stream.Stream;
21  
22  import org.orekit.attitudes.InertialProvider;
23  import org.orekit.errors.OrekitException;
24  import org.orekit.errors.OrekitMessages;
25  import org.orekit.files.general.EphemerisFile.EphemerisSegment;
26  import org.orekit.frames.Frame;
27  import org.orekit.orbits.CartesianOrbit;
28  import org.orekit.orbits.Orbit;
29  import org.orekit.propagation.BoundedPropagator;
30  import org.orekit.propagation.Propagator;
31  import org.orekit.propagation.SpacecraftState;
32  import org.orekit.propagation.analytical.AbstractAnalyticalPropagator;
33  import org.orekit.time.AbsoluteDate;
34  import org.orekit.utils.ImmutableTimeStampedCache;
35  import org.orekit.utils.TimeStampedPVCoordinates;
36  
37  /**
38   * A {@link Propagator} based on a {@link EphemerisSegment}.
39   *
40   * <p> The {@link #getPVCoordinates(AbsoluteDate, Frame)} is implemented without using the
41   * {@link #propagate(AbsoluteDate)} methods so using this class as a {@link
42   * org.orekit.utils.PVCoordinatesProvider} still behaves as expected when the ephemeris
43   * file did not have a valid gravitational parameter.
44   * @param <C> type of the Cartesian coordinates
45   *
46   * @author Evan Ward
47   */
48  class EphemerisSegmentPropagator<C extends TimeStampedPVCoordinates> extends AbstractAnalyticalPropagator
49          implements BoundedPropagator {
50  
51      /**
52       * Sorted cache of state vectors. A duplication of the information in {@link
53       * #ephemeris} that could be avoided by duplicating the logic of {@link
54       * ImmutableTimeStampedCache#getNeighbors(AbsoluteDate)} for a general {@link List}.
55       */
56      private final ImmutableTimeStampedCache<C> cache;
57      /** Tabular data from which this propagator is built. */
58      private final EphemerisSegment<C> ephemeris;
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       */
69      EphemerisSegmentPropagator(final EphemerisSegment<C> ephemeris) {
70          super(new InertialProvider(ephemeris.getInertialFrame()));
71          this.cache = new ImmutableTimeStampedCache<>(
72                  ephemeris.getInterpolationSamples(),
73                  ephemeris.getCoordinates());
74          this.ephemeris = ephemeris;
75          this.ephemerisFrame = ephemeris.getFrame();
76          this.inertialFrame = ephemeris.getInertialFrame();
77          // set the initial state so getFrame() works
78          final TimeStampedPVCoordinates ic = cache.getEarliest();
79          final TimeStampedPVCoordinates icInertial = ephemerisFrame
80                  .getTransformTo(inertialFrame, ic.getDate())
81                  .transformPVCoordinates(ic);
82          super.resetInitialState(
83                  new SpacecraftState(
84                          new CartesianOrbit(
85                                  icInertial, inertialFrame, ephemeris.getMu()
86                          ),
87                          getAttitudeProvider().getAttitude(
88                                  icInertial.toTaylorProvider(inertialFrame),
89                                  ic.getDate(),
90                                  inertialFrame),
91                          DEFAULT_MASS
92                  )
93          );
94      }
95  
96      @Override
97      public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate date, final Frame frame) {
98          final Stream<C> neighbors = this.cache.getNeighbors(date);
99          final TimeStampedPVCoordinates point =
100                 TimeStampedPVCoordinates.interpolate(date, ephemeris.getAvailableDerivatives(), neighbors);
101         return ephemerisFrame.getTransformTo(frame, date).transformPVCoordinates(point);
102     }
103 
104     @Override
105     protected Orbit propagateOrbit(final AbsoluteDate date) {
106         final TimeStampedPVCoordinates pv = this.getPVCoordinates(date, inertialFrame);
107         return new CartesianOrbit(pv, inertialFrame, this.ephemeris.getMu());
108     }
109 
110     @Override
111     public AbsoluteDate getMinDate() {
112         return ephemeris.getStart();
113     }
114 
115     @Override
116     public AbsoluteDate getMaxDate() {
117         return ephemeris.getStop();
118     }
119 
120     @Override
121     protected double getMass(final AbsoluteDate date) {
122         return DEFAULT_MASS;
123     }
124 
125     @Override
126     public SpacecraftState getInitialState() {
127         return this.basicPropagate(this.getMinDate());
128     }
129 
130     @Override
131     protected void resetIntermediateState(final SpacecraftState state,
132                                           final boolean forward) {
133         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
134     }
135 
136     @Override
137     public void resetInitialState(final SpacecraftState state) {
138         throw new OrekitException(OrekitMessages.NON_RESETABLE_STATE);
139     }
140 
141 }