1   /* Copyright 2002-2025 CS GROUP
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.propagation;
18  
19  import org.orekit.frames.Frame;
20  import org.orekit.frames.LOFType;
21  import org.orekit.orbits.Orbit;
22  import org.orekit.orbits.OrbitType;
23  import org.orekit.orbits.PositionAngleType;
24  import org.orekit.time.AbsoluteDate;
25  import org.orekit.time.AbstractTimeInterpolator;
26  import org.orekit.time.TimeInterpolator;
27  import org.orekit.time.TimeStampedPair;
28  
29  import java.util.List;
30  import java.util.stream.Collectors;
31  import java.util.stream.Stream;
32  
33  /**
34   * Abstract class for orbit and state covariance interpolator.
35   *
36   * @author Vincent Cucchietti
37   * @see Orbit
38   * @see StateCovariance
39   * @see TimeStampedPair
40   */
41  public abstract class AbstractStateCovarianceInterpolator
42          extends AbstractTimeInterpolator<TimeStampedPair<Orbit, StateCovariance>> {
43  
44      /** Default position angle for covariance expressed in Cartesian elements. */
45      public static final PositionAngleType DEFAULT_POSITION_ANGLE = PositionAngleType.MEAN;
46  
47      /** Default column dimension for position-velocity state covariance. */
48      public static final int COLUMN_DIM = 6;
49  
50      /** Default row dimension for position-velocity state covariance. */
51      public static final int ROW_DIM = 6;
52  
53      /** Output frame. */
54      private final Frame outFrame;
55  
56      /** Output local orbital frame. */
57      private final LOFType outLOF;
58  
59      /** Output orbit type. */
60      private final OrbitType outOrbitType;
61  
62      /** Output position angle type. */
63      private final PositionAngleType outPositionAngleType;
64  
65      /** Orbit interpolator. */
66      private final TimeInterpolator<Orbit> orbitInterpolator;
67  
68      /**
69       * Constructor.
70       *
71       * @param interpolationPoints number of interpolation points
72       * @param extrapolationThreshold extrapolation threshold beyond which the propagation will fail
73       * @param orbitInterpolator orbit interpolator
74       * @param outLOF local orbital frame
75       *
76       * @see Frame
77       * @see OrbitType
78       * @see PositionAngleType
79       */
80      public AbstractStateCovarianceInterpolator(final int interpolationPoints, final double extrapolationThreshold,
81                                                 final TimeInterpolator<Orbit> orbitInterpolator,
82                                                 final LOFType outLOF) {
83          super(interpolationPoints, extrapolationThreshold);
84          this.orbitInterpolator = orbitInterpolator;
85          this.outLOF            = outLOF;
86          this.outFrame          = null;
87          this.outOrbitType      = OrbitType.CARTESIAN;
88          this.outPositionAngleType = DEFAULT_POSITION_ANGLE;
89      }
90  
91      /**
92       * Constructor.
93       *
94       * @param interpolationPoints number of interpolation points
95       * @param extrapolationThreshold extrapolation threshold beyond which the propagation will fail
96       * @param orbitInterpolator orbit interpolator
97       * @param outFrame desired output covariance frame
98       * @param outPositionAngleType desired output position angle
99       * @param outOrbitType desired output orbit type
100      *
101      * @see Frame
102      * @see OrbitType
103      * @see PositionAngleType
104      */
105     public AbstractStateCovarianceInterpolator(final int interpolationPoints, final double extrapolationThreshold,
106                                                final TimeInterpolator<Orbit> orbitInterpolator,
107                                                final Frame outFrame,
108                                                final OrbitType outOrbitType,
109                                                final PositionAngleType outPositionAngleType) {
110         super(interpolationPoints, extrapolationThreshold);
111         this.orbitInterpolator = orbitInterpolator;
112         this.outLOF            = null;
113         this.outFrame          = outFrame;
114         this.outOrbitType      = outOrbitType;
115         this.outPositionAngleType = outPositionAngleType;
116     }
117 
118     /**
119      * Interpolate orbit and associated covariance.
120      *
121      * @param interpolationData interpolation data
122      *
123      * @return interpolated orbit and associated covariance
124      */
125     @Override
126     public TimeStampedPair<Orbit, StateCovariance> interpolate(final InterpolationData interpolationData) {
127 
128         // Interpolate orbit at interpolation date
129         final Orbit interpolatedOrbit = interpolateOrbit(interpolationData.getInterpolationDate(),
130                                                          interpolationData.getNeighborList());
131 
132         // Rebuild state covariance
133         final StateCovariance covarianceInOrbitFrame =
134                 computeInterpolatedCovarianceInOrbitFrame(interpolationData.getNeighborList(), interpolatedOrbit);
135 
136         // Output new blended StateCovariance instance in desired output
137         return expressCovarianceInDesiredOutput(interpolatedOrbit, covarianceInOrbitFrame);
138     }
139 
140     /** Get output frame.
141      * @return output frame. Can be null.
142      */
143     public Frame getOutFrame() {
144         return outFrame;
145     }
146 
147     /** Get output local orbital frame.
148      * @return output local orbital frame. Can be null.
149      */
150     public LOFType getOutLOF() {
151         return outLOF;
152     }
153 
154     /** Get output orbit type.
155      * @return output orbit type.
156      */
157     public OrbitType getOutOrbitType() {
158         return outOrbitType;
159     }
160 
161     /** Get output position angle type.
162      * @return output position angle.
163      */
164     public PositionAngleType getOutPositionAngleType() {
165         return outPositionAngleType;
166     }
167 
168     /** Get orbit interpolator.
169      * @return orbit interpolator.
170      */
171     public TimeInterpolator<Orbit> getOrbitInterpolator() {
172         return orbitInterpolator;
173     }
174 
175     /**
176      * Interpolate orbit at given interpolation date.
177      *
178      * @param interpolationDate interpolation date
179      * @param neighborList neighbor list
180      *
181      * @return interpolated orbit
182      */
183     protected Orbit interpolateOrbit(final AbsoluteDate interpolationDate,
184                                      final List<TimeStampedPair<Orbit, StateCovariance>> neighborList) {
185 
186         // Build orbit list from uncertain orbits
187         final List<Orbit> orbits = buildOrbitList(neighborList);
188 
189         return orbitInterpolator.interpolate(interpolationDate, orbits);
190     }
191 
192     /**
193      * Compute the interpolated covariance expressed in the interpolated orbit frame.
194      *
195      * @param uncertainStates list of orbits and associated covariances
196      * @param interpolatedOrbit interpolated orbit
197      *
198      * @return interpolated covariance expressed in the interpolated orbit frame
199      */
200     protected abstract StateCovariance computeInterpolatedCovarianceInOrbitFrame(
201             List<TimeStampedPair<Orbit, StateCovariance>> uncertainStates,
202             Orbit interpolatedOrbit);
203 
204     /**
205      * Express covariance in output configuration defined at this instance construction.
206      *
207      * @param interpolatedOrbit interpolated orbit
208      * @param covarianceInOrbitFrame covariance expressed in interpolated orbit frame
209      *
210      * @return covariance in desired output configuration
211      */
212     protected TimeStampedPair<Orbit, StateCovariance> expressCovarianceInDesiredOutput(final Orbit interpolatedOrbit,
213                                                                                        final StateCovariance covarianceInOrbitFrame) {
214 
215         final StateCovariance covarianceOutput;
216 
217         // Output frame is defined
218         if (outLOF == null) {
219 
220             // Output frame is pseudo inertial
221             if (outFrame.isPseudoInertial()) {
222                 final StateCovariance covarianceInOutputFrame =
223                         covarianceInOrbitFrame.changeCovarianceFrame(interpolatedOrbit, outFrame);
224 
225                 covarianceOutput =
226                         covarianceInOutputFrame.changeCovarianceType(interpolatedOrbit, outOrbitType, outPositionAngleType);
227             }
228             // Output frame is not pseudo inertial
229             else {
230                 covarianceOutput = covarianceInOrbitFrame.changeCovarianceFrame(interpolatedOrbit, outFrame);
231             }
232 
233         }
234         // Output local orbital frame is defined
235         else {
236             covarianceOutput = covarianceInOrbitFrame.changeCovarianceFrame(interpolatedOrbit, outLOF);
237         }
238 
239         return new TimeStampedPair<>(interpolatedOrbit, covarianceOutput);
240     }
241 
242     /**
243      * Build an orbit list from cached samples.
244      *
245      * @param neighborList neighbor list
246      *
247      * @return orbit list
248      */
249     private List<Orbit> buildOrbitList(final List<TimeStampedPair<Orbit, StateCovariance>> neighborList) {
250 
251         // Get samples stream
252         final Stream<TimeStampedPair<Orbit, StateCovariance>> uncertainStateStream = neighborList.stream();
253 
254         // Map to orbit
255         final Stream<Orbit> orbitStream = uncertainStateStream.map(TimeStampedPair::getFirst);
256 
257         // Convert to list
258         return orbitStream.collect(Collectors.toList());
259     }
260 }