1   /* Copyright 2002-2022 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.integration;
18  
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import org.hipparchus.analysis.differentiation.Gradient;
23  import org.hipparchus.geometry.euclidean.threed.FieldRotation;
24  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
25  import org.orekit.attitudes.FieldAttitude;
26  import org.orekit.orbits.FieldCartesianOrbit;
27  import org.orekit.orbits.FieldOrbit;
28  import org.orekit.propagation.FieldSpacecraftState;
29  import org.orekit.utils.FieldAngularCoordinates;
30  import org.orekit.utils.FieldPVCoordinates;
31  import org.orekit.utils.ParameterDriver;
32  import org.orekit.utils.ParametersDriversProvider;
33  import org.orekit.utils.TimeStampedFieldAngularCoordinates;
34  import org.orekit.utils.TimeStampedFieldPVCoordinates;
35  
36  /** Converter for states and parameters arrays.
37   *  @author Luc Maisonobe
38   *  @author Bryan Cazabonne
39   *  @since 10.2
40   */
41  public abstract class AbstractGradientConverter {
42  
43      /** Dimension of the state. */
44      private final int freeStateParameters;
45  
46      /** States with various number of additional parameters. */
47      private final List<FieldSpacecraftState<Gradient>> gStates;
48  
49      /** Simple constructor.
50       * @param freeStateParameters number of free parameters
51       */
52      protected AbstractGradientConverter(final int freeStateParameters) {
53          this.freeStateParameters = freeStateParameters;
54          this.gStates             = new ArrayList<>();
55      }
56  
57      /** Get the number of free state parameters.
58       * @return number of free state parameters
59       */
60      public int getFreeStateParameters() {
61          return freeStateParameters;
62      }
63  
64      /** Initialize first state with 0 parameters.
65       * @param zeroParametersState state with zero parameters
66       * @since 11.2
67       */
68      protected void initStates(final FieldSpacecraftState<Gradient> zeroParametersState) {
69          gStates.clear();
70          gStates.add(zeroParametersState);
71      }
72  
73      /** Add zero derivatives.
74       * @param original original scalar
75       * @param freeParameters total number of free parameters in the gradient
76       * @return extended scalar
77       */
78      protected Gradient extend(final Gradient original, final int freeParameters) {
79          final double[] originalDerivatives = original.getGradient();
80          final double[] extendedDerivatives = new double[freeParameters];
81          System.arraycopy(originalDerivatives, 0, extendedDerivatives, 0, originalDerivatives.length);
82          return new Gradient(original.getValue(), extendedDerivatives);
83      }
84  
85      /** Add zero derivatives.
86       * @param original original vector
87       * @param freeParameters total number of free parameters in the gradient
88       * @return extended vector
89       */
90      protected FieldVector3D<Gradient> extend(final FieldVector3D<Gradient> original, final int freeParameters) {
91          return new FieldVector3D<>(extend(original.getX(), freeParameters),
92                                     extend(original.getY(), freeParameters),
93                                     extend(original.getZ(), freeParameters));
94      }
95  
96      /** Add zero derivatives.
97       * @param original original rotation
98       * @param freeParameters total number of free parameters in the gradient
99       * @return extended rotation
100      */
101     protected FieldRotation<Gradient> extend(final FieldRotation<Gradient> original, final int freeParameters) {
102         return new FieldRotation<>(extend(original.getQ0(), freeParameters),
103                                    extend(original.getQ1(), freeParameters),
104                                    extend(original.getQ2(), freeParameters),
105                                    extend(original.getQ3(), freeParameters),
106                                    false);
107     }
108     /**
109      * Get the state with the number of parameters consistent with parametric model.
110      * @param parametricModel parametric model
111      * @return state with the number of parameters consistent with parametric model
112      */
113     public FieldSpacecraftState<Gradient> getState(final ParametersDriversProvider parametricModel) {
114 
115         // count the required number of parameters
116         int nbParams = 0;
117         for (final ParameterDriver driver : parametricModel.getParametersDrivers()) {
118             if (driver.isSelected()) {
119                 ++nbParams;
120             }
121         }
122 
123         // fill in intermediate slots
124         while (gStates.size() < nbParams + 1) {
125             gStates.add(null);
126         }
127 
128         if (gStates.get(nbParams) == null) {
129             // it is the first time we need this number of parameters
130             // we need to create the state
131             final int freeParameters = freeStateParameters + nbParams;
132             final FieldSpacecraftState<Gradient> s0 = gStates.get(0);
133 
134             // orbit
135             final FieldPVCoordinates<Gradient> pv0 = s0.getPVCoordinates();
136             final FieldOrbit<Gradient> gOrbit =
137                             new FieldCartesianOrbit<>(new TimeStampedFieldPVCoordinates<>(s0.getDate().toAbsoluteDate(),
138                                                                                           extend(pv0.getPosition(),     freeParameters),
139                                                                                           extend(pv0.getVelocity(),     freeParameters),
140                                                                                           extend(pv0.getAcceleration(), freeParameters)),
141                                                       s0.getFrame(), extend(s0.getMu(), freeParameters));
142 
143             // attitude
144             final FieldAngularCoordinates<Gradient> ac0 = s0.getAttitude().getOrientation();
145             final FieldAttitude<Gradient> gAttitude =
146                             new FieldAttitude<>(s0.getAttitude().getReferenceFrame(),
147                                                 new TimeStampedFieldAngularCoordinates<>(gOrbit.getDate(),
148                                                                                          extend(ac0.getRotation(), freeParameters),
149                                                                                          extend(ac0.getRotationRate(), freeParameters),
150                                                                                          extend(ac0.getRotationAcceleration(), freeParameters)));
151 
152             // mass
153             final Gradient gM = extend(s0.getMass(), freeParameters);
154 
155             gStates.set(nbParams, new FieldSpacecraftState<>(gOrbit, gAttitude, gM));
156 
157         }
158 
159         return gStates.get(nbParams);
160 
161     }
162 
163     /** Get the parametric model parameters.
164      * @param state state as returned by {@link #getState(ParametersDriversProvider) getState(parametricModel)}
165      * @param parametricModel parametric model associated with the parameters
166      * @return parametric model parameters
167      */
168     public Gradient[] getParameters(final FieldSpacecraftState<Gradient> state,
169                                     final ParametersDriversProvider parametricModel) {
170         final int freeParameters = state.getMass().getFreeParameters();
171         final List<ParameterDriver> drivers = parametricModel.getParametersDrivers();
172         final Gradient[] parameters = new Gradient[drivers.size()];
173         int index = freeStateParameters;
174         int i = 0;
175         for (ParameterDriver driver : drivers) {
176             parameters[i++] = driver.isSelected() ?
177                               Gradient.variable(freeParameters, index++, driver.getValue()) :
178                               Gradient.constant(freeParameters, driver.getValue());
179         }
180         return parameters;
181     }
182 
183 }