1   /* Copyright 2022-2025 Romain Serra
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.util.Pair;
20  import org.orekit.orbits.Orbit;
21  import org.orekit.propagation.sampling.OrekitFixedStepHandler;
22  import org.orekit.propagation.sampling.OrekitStepHandler;
23  import org.orekit.propagation.sampling.OrekitStepInterpolator;
24  import org.orekit.time.AbsoluteDate;
25  
26  import java.util.ArrayList;
27  import java.util.List;
28  import java.util.stream.Collectors;
29  
30  /**
31   * Class implementing step handlers to propagate orbital covariance using linearized Keplerian motion, no matter the propagation model.
32   * Although less precise than using the same perturbations than the propagator, it is more computationally performant.
33   *
34   * @author Romain Serra
35   * @since 13.1
36   * @see StateCovarianceMatrixProvider
37   */
38  public class LinearKeplerianCovarianceHandler implements OrekitFixedStepHandler {
39  
40      /** Initial orbital covariance. */
41      private final StateCovariance initialCovariance;
42  
43      /** Logged states and covariances. */
44      private final List<Pair<SpacecraftState, StateCovariance>> statesWithCovariances = new ArrayList<>();
45  
46      /**
47       * Constructor.
48       * @param initialCovariance initial orbital covariance
49       */
50      public LinearKeplerianCovarianceHandler(final StateCovariance initialCovariance) {
51          this.initialCovariance = initialCovariance;
52      }
53  
54      /**
55       * Gets a copy of the covariances.
56       * @return state covariances
57       */
58      public List<StateCovariance> getStatesCovariances() {
59          return statesWithCovariances.stream().map(Pair::getValue).collect(Collectors.toList());
60      }
61  
62      @Override
63      public void init(final SpacecraftState s0, final AbsoluteDate t, final double dt) {
64          OrekitFixedStepHandler.super.init(s0, t, dt);
65          statesWithCovariances.clear();
66          statesWithCovariances.add(new Pair<>(s0, initialCovariance));
67      }
68  
69      @Override
70      public void handleStep(final SpacecraftState currentState) {
71          final Pair<SpacecraftState, StateCovariance> lastPair = statesWithCovariances.get(statesWithCovariances.size() - 1);
72          final Orbit lastOrbit = lastPair.getKey().getOrbit();
73          final LinearKeplerianCovarianceMapper covarianceHandler = new LinearKeplerianCovarianceMapper(lastOrbit,
74                  lastPair.getValue());
75          final StateCovariance currentCovariance = covarianceHandler.map(currentState.getOrbit());
76          statesWithCovariances.add(new Pair<>(currentState, currentCovariance));
77      }
78  
79      /**
80       * Convert into a non-fixed step handler, based on the instance (so do not use it elsewhere for something else).
81       * @return fixed-step handler
82       * @see OrekitStepHandler
83       */
84      public OrekitStepHandler toOrekitStepHandler() {
85          final LinearKeplerianCovarianceHandler handler = new LinearKeplerianCovarianceHandler(initialCovariance);
86  
87          return new OrekitStepHandler() {
88              @Override
89              public void init(final SpacecraftState s0, final AbsoluteDate t) {
90                  OrekitStepHandler.super.init(s0, t);
91                  handler.init(s0, t, 0.);
92                  statesWithCovariances.clear();
93              }
94  
95              @Override
96              public void handleStep(final OrekitStepInterpolator interpolator) {
97                  handler.handleStep(interpolator.getCurrentState());
98              }
99  
100             @Override
101             public void finish(final SpacecraftState finalState) {
102                 OrekitStepHandler.super.finish(finalState);
103                 statesWithCovariances.addAll(handler.statesWithCovariances);
104             }
105         };
106     }
107 }