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