1   /* Copyright 2002-2026 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.covariance;
18  
19  import org.hipparchus.linear.RealMatrix;
20  import org.orekit.frames.Frame;
21  import org.orekit.orbits.Orbit;
22  import org.orekit.orbits.OrbitType;
23  import org.orekit.orbits.PositionAngleType;
24  import org.orekit.propagation.AdditionalDataProvider;
25  import org.orekit.propagation.MatricesHarvester;
26  import org.orekit.propagation.Propagator;
27  import org.orekit.propagation.SpacecraftState;
28  import org.orekit.time.AbsoluteDate;
29  
30  /**
31   * Additional state provider for state covariance matrix.
32   * <p>
33   * This additional state provider allows computing a propagated covariance matrix based on a user defined input state
34   * covariance matrix. The computation of the propagated covariance matrix uses the State Transition Matrix between the
35   * propagated spacecraft state and the initial state. As a result, the user must define the name
36   * {@link #stmName of the provider for the State Transition Matrix}. The STM is assumed to be the identity at the
37   * covariance epoch, if it is not, results will not be consistent.
38   * <p>
39   * The State Transition Matrix and the input state covariance matrix can be expressed in different orbit types,
40   * which is defined in the {@link MatricesHarvester matrix harvester} specified at construction time.
41   * <p>
42   * In order to add this additional state provider to an orbit propagator, user must use the
43   * {@link Propagator#addAdditionalDataProvider(AdditionalDataProvider)} method.
44   * <p>
45   * For a given propagated spacecraft {@code state}, the propagated state covariance matrix is accessible through the
46   * method {@link #getStateCovariance(SpacecraftState)}
47   * <p>
48   * The provider must be initialized with the same epoch as the reference covariance. This means either that the very first
49   * propagation must start from this date or the {@link #init(SpacecraftState, AbsoluteDate)} (SpacecraftState)
50   * must be called manually once before use. Failure to do so will result in an {@link NullPointerException}.
51   *
52   * @author Bryan Cazabonne
53   * @author Vincent Cucchietti
54   * @since 11.3
55   */
56  public class StateCovarianceMatrixProvider implements AdditionalDataProvider<RealMatrix> {
57  
58      /** Dimension of the state. */
59      private static final int ORBITAL_STATE_DIMENSION = 6;
60  
61      /** Name of the state for State Transition Matrix. */
62      private final String stmName;
63  
64      /** Matrix harvester to access the State Transition Matrix. */
65      private final MatricesHarvester harvester;
66  
67      /** Name of the additional state. */
68      private final String additionalName;
69  
70      /** Orbit type used for the State Transition Matrix. */
71      private final OrbitType stmOrbitType;
72  
73      /** Position angle used for State Transition Matrix. */
74      private final PositionAngleType stmAngleType;
75  
76      /** Orbit type for the covariance matrix. */
77      private final OrbitType covOrbitType;
78  
79      /** Position angle used for the covariance matrix. */
80      private final PositionAngleType covAngleType;
81  
82      /** Reference state covariance. */
83      private final StateCovariance covRef;
84  
85      /** State covariance matrix adapted for STM. */
86      private RealMatrix covMatrixRef;
87  
88      /**
89       * Constructor.
90       *
91       * @param additionalName name of the additional state
92       * @param stmName name of the state for State Transition Matrix
93       * @param harvester matrix harvester as returned by
94       * {@code propagator.setupMatricesComputation(stmName, null, null)}
95       * @param covRef reference state covariance
96       */
97      public StateCovarianceMatrixProvider(final String additionalName, final String stmName,
98                                           final MatricesHarvester harvester, final StateCovariance covRef) {
99          // Initialize fields
100         this.additionalName = additionalName;
101         this.stmName        = stmName;
102         this.harvester      = harvester;
103         this.covRef         = covRef;
104         this.covOrbitType   = covRef.getOrbitType();
105         this.covAngleType   = covRef.getPositionAngleType();
106         this.stmOrbitType   = harvester.getOrbitType();
107         this.stmAngleType   = harvester.getPositionAngleType();
108     }
109 
110     /** {@inheritDoc} */
111     @Override
112     public String getName() {
113         return additionalName;
114     }
115 
116     /** {@inheritDoc} */
117     @Override
118     public void init(final SpacecraftState initialState, final AbsoluteDate target) {
119         if (initialState.getDate().isEqualTo(covRef.getDate())) {
120             // Convert the initial state covariance in the same orbit type and frame as the STM
121             final Orbit initialOrbit = initialState.getOrbit();
122             StateCovariance covariance = covRef.changeCovarianceFrame(initialOrbit, initialState.getFrame());
123             covariance = covariance.changeCovarianceType(initialOrbit, stmOrbitType, stmAngleType);
124             covMatrixRef = covariance.getMatrix();
125         }
126     }
127 
128     /**
129      * {@inheritDoc}
130      * <p>
131      * The covariance matrix can be computed only if the State Transition Matrix state is available.
132      * </p>
133      */
134     @Override
135     public boolean yields(final SpacecraftState state) {
136         return !state.hasAdditionalData(stmName);
137     }
138 
139     /** {@inheritDoc} */
140     @Override
141     public RealMatrix getAdditionalData(final SpacecraftState state) {
142 
143         // State transition matrix for the input state
144         final int inclusiveSize = ORBITAL_STATE_DIMENSION - 1;
145         final RealMatrix dYdY0 = harvester.getStateTransitionMatrix(state).getSubMatrix(0, inclusiveSize, 0, inclusiveSize);
146 
147         // Compute the propagated covariance matrix
148         RealMatrix propCov = dYdY0.multiply(covMatrixRef.multiplyTransposed(dYdY0));
149         final StateCovariance propagated = new StateCovariance(propCov, state.getDate(), state.getFrame(), stmOrbitType, stmAngleType);
150 
151         // Update to the user defined type
152         propCov = propagated.changeCovarianceType(state.getOrbit(), covOrbitType, covAngleType).getMatrix();
153 
154         // Return the propagated covariance matrix
155         return propCov;
156 
157     }
158 
159     /**
160      * Get the orbit type in which the covariance matrix is expressed.
161      *
162      * @return the orbit type
163      */
164     public OrbitType getCovarianceOrbitType() {
165         return covOrbitType;
166     }
167 
168     /**
169      * Get the state covariance in the same frame/local orbital frame, orbit type and position angle as the reference
170      * covariance.
171      *
172      * @param state spacecraft state to which the covariance matrix should correspond
173      * @return the state covariance
174      * @see #getStateCovariance(SpacecraftState, Frame)
175      * @see #getStateCovariance(SpacecraftState, OrbitType, PositionAngleType)
176      */
177     public StateCovariance getStateCovariance(final SpacecraftState state) {
178 
179         // Get the current propagated covariance
180         final RealMatrix covarianceMatrix = getAdditionalData(state);
181 
182         // Create associated state covariance
183         final StateCovariance covariance =
184                 new StateCovariance(covarianceMatrix, state.getDate(), state.getFrame(), covOrbitType, covAngleType);
185 
186         // Return the state covariance in same frame/lof as reference covariance
187         if (covRef.getLOF() == null) {
188             return covariance;
189         }
190         else {
191             return covariance.changeCovarianceFrame(state.getOrbit(), covRef.getLOF());
192         }
193 
194     }
195 
196     /**
197      * Get the state covariance expressed in a given frame.
198      * <p>
199      * The output covariance matrix is expressed in the same orbit type as {@link #getCovarianceOrbitType()}.
200      *
201      * @param state spacecraft state to which the covariance matrix should correspond
202      * @param frame output frame for which the output covariance matrix must be expressed (must be inertial)
203      * @return the state covariance expressed in <code>frame</code>
204      * @see #getStateCovariance(SpacecraftState)
205      * @see #getStateCovariance(SpacecraftState, OrbitType, PositionAngleType)
206      */
207     public StateCovariance getStateCovariance(final SpacecraftState state, final Frame frame) {
208         // Return the converted covariance
209         return getStateCovariance(state).changeCovarianceFrame(state.getOrbit(), frame);
210     }
211 
212     /**
213      * Get the state covariance expressed in a given orbit type.
214      *
215      * @param state spacecraft state to which the covariance matrix should correspond
216      * @param orbitType output orbit type
217      * @param angleType output position angle (not used if orbitType equals {@code CARTESIAN})
218      * @return the state covariance in <code>orbitType</code> and <code>angleType</code>
219      * @see #getStateCovariance(SpacecraftState)
220      * @see #getStateCovariance(SpacecraftState, Frame)
221      */
222     public StateCovariance getStateCovariance(final SpacecraftState state, final OrbitType orbitType,
223                                               final PositionAngleType angleType) {
224         // Return the converted covariance
225         return getStateCovariance(state).changeCovarianceType(state.getOrbit(), orbitType, angleType);
226     }
227 }