1   /* Copyright 2002-2021 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.estimation.measurements;
18  
19  import java.util.IdentityHashMap;
20  import java.util.Map;
21  import java.util.stream.Stream;
22  
23  import org.orekit.errors.OrekitIllegalArgumentException;
24  import org.orekit.errors.OrekitMessages;
25  import org.orekit.propagation.SpacecraftState;
26  import org.orekit.time.AbsoluteDate;
27  import org.orekit.utils.ParameterDriver;
28  import org.orekit.utils.TimeStampedPVCoordinates;
29  
30  /** Class holding an estimated theoretical value associated to an {@link ObservedMeasurement observed measurement}.
31   * @param <T> the type of the measurement
32   * @author Luc Maisonobe
33   * @since 8.0
34   */
35  public class EstimatedMeasurement<T extends ObservedMeasurement<T>> implements ComparableMeasurement {
36  
37      /** Associated observed measurement. */
38      private final T observedMeasurement;
39  
40      /** Iteration number. */
41      private final int iteration;
42  
43      /** Evaluations counter. */
44      private final int count;
45  
46      /** States of the spacecrafts. */
47      private final SpacecraftState[] states;
48  
49      /** Coordinates of the participants in signal travel order. */
50      private final TimeStampedPVCoordinates[] participants;
51  
52      /** Estimated value. */
53      private double[] estimatedValue;
54  
55      /** Measurement status. */
56      private Status status;
57  
58      /** Partial derivatives with respect to states. */
59      private double[][][] stateDerivatives;
60  
61      /** Partial derivatives with respect to parameters. */
62      private final Map<ParameterDriver, double[]> parametersDerivatives;
63  
64      /** Simple constructor.
65       * @param observedMeasurement associated observed measurement
66       * @param iteration iteration number
67       * @param count evaluations counter
68       * @param states states of the spacecrafts
69       * @param participants coordinates of the participants in signal travel order
70       * in inertial frame
71       */
72      public EstimatedMeasurement(final T observedMeasurement,
73                                  final int iteration, final int count,
74                                  final SpacecraftState[] states,
75                                  final TimeStampedPVCoordinates[] participants) {
76          this.observedMeasurement   = observedMeasurement;
77          this.iteration             = iteration;
78          this.count                 = count;
79          this.states                = states.clone();
80          this.participants          = participants.clone();
81          this.status                = Status.PROCESSED;
82          this.stateDerivatives      = new double[states.length][][];
83          this.parametersDerivatives = new IdentityHashMap<ParameterDriver, double[]>();
84      }
85  
86      /** Get the associated observed measurement.
87       * @return associated observed measurement
88       */
89      public T getObservedMeasurement() {
90          return observedMeasurement;
91      }
92  
93      /** {@inheritDoc} */
94      @Override
95      public AbsoluteDate getDate() {
96          return observedMeasurement.getDate();
97      }
98  
99      /** Get the iteration number.
100      * @return iteration number
101      */
102     public int getIteration() {
103         return iteration;
104     }
105 
106     /** Get the evaluations counter.
107      * @return evaluations counter
108      */
109     public int getCount() {
110         return count;
111     }
112 
113     /** Get the states of the spacecrafts.
114      * @return states of the spacecrafts
115      */
116     public SpacecraftState[] getStates() {
117         return states.clone();
118     }
119 
120     /** Get the coordinates of the measurements participants in signal travel order.
121      * <p>
122      * First participant (at index 0) emits the signal (it is for example a ground
123      * station for two-way range measurement). Last participant receives the signal
124      * (it is also the ground station for two-way range measurement, but a few
125      * milliseconds later). Intermediate participants relfect the signal (it is the
126      * spacecraft for two-way range measurement).
127      * </p>
128      * @return coordinates of the measurements participants in signal travel order
129      * in inertial frame
130      */
131     public TimeStampedPVCoordinates[] getParticipants() {
132         return participants.clone();
133     }
134 
135     /** Get the time offset from first state date to measurement date.
136      * @return time offset from first state date to measurement date
137      */
138     public double getTimeOffset() {
139         return observedMeasurement.getDate().durationFrom(states[0].getDate());
140     }
141 
142     /** {@inheritDoc} */
143     @Override
144     public double[] getObservedValue() {
145         return observedMeasurement.getObservedValue();
146     }
147 
148     /** Get the estimated value.
149      * @return estimated value
150      */
151     public double[] getEstimatedValue() {
152         return estimatedValue.clone();
153     }
154 
155     /** Set the estimated value.
156      * @param estimatedValue estimated value
157      */
158     public void setEstimatedValue(final double... estimatedValue) {
159         this.estimatedValue = estimatedValue.clone();
160     }
161 
162     /** Get the status.
163      * <p>
164      * The status is set to {@link Status#PROCESSED PROCESSED} at construction, and
165      * can be reset to {@link Status#REJECTED REJECTED} later on, typically by
166      * {@link org.orekit.estimation.measurements.modifiers.OutlierFilter OutlierFilter}
167      * or {@link org.orekit.estimation.measurements.modifiers.DynamicOutlierFilter DynamicOutlierFilter}
168      * </p>
169      * @return status
170      */
171     public Status getStatus() {
172         return status;
173     }
174 
175     /** Set the status.
176      * @param status status to set
177      */
178     public void setStatus(final Status status) {
179         this.status = status;
180     }
181 
182     /** Get state size.
183      * <p>
184      * Warning, the {@link #setStateDerivatives(int, double[][])}
185      * method must have been called before this method is called.
186      * </p>
187      * @return state size
188      * @since 10.1
189      */
190     public int getStateSize() {
191         return stateDerivatives[0][0].length;
192     }
193 
194     /** Get the partial derivatives of the {@link #getEstimatedValue()
195      * simulated measurement} with respect to state Cartesian coordinates.
196      * @param index index of the state, according to the {@code states}
197      * passed at construction
198      * @return partial derivatives of the simulated value (array of size
199      * {@link ObservedMeasurement#getDimension() dimension} x 6)
200      */
201     public double[][] getStateDerivatives(final int index) {
202         final double[][] sd = new double[observedMeasurement.getDimension()][];
203         for (int i = 0; i < observedMeasurement.getDimension(); ++i) {
204             sd[i] = stateDerivatives[index][i].clone();
205         }
206         return sd;
207     }
208 
209     /** Set the partial derivatives of the {@link #getEstimatedValue()
210      * simulated measurement} with respect to state Cartesian coordinates.
211      * @param index index of the state, according to the {@code states}
212      * passed at construction
213      * @param derivatives partial derivatives with respect to state
214      */
215     public void setStateDerivatives(final int index, final double[]... derivatives) {
216         this.stateDerivatives[index] = new double[observedMeasurement.getDimension()][];
217         for (int i = 0; i < observedMeasurement.getDimension(); ++i) {
218             this.stateDerivatives[index][i] = derivatives[i].clone();
219         }
220     }
221 
222     /** Get all the drivers with set derivatives.
223      * @return all the drivers with set derivatives
224      * @since 9.0
225      */
226     public Stream<ParameterDriver> getDerivativesDrivers() {
227         return parametersDerivatives.entrySet().stream().map(entry -> entry.getKey());
228     }
229 
230     /** Get the partial derivatives of the {@link #getEstimatedValue()
231      * simulated measurement} with respect to a parameter.
232      * @param driver driver for the parameter
233      * @return partial derivatives of the simulated value
234      * @exception OrekitIllegalArgumentException if parameter is unknown
235      */
236     public double[] getParameterDerivatives(final ParameterDriver driver)
237         throws OrekitIllegalArgumentException {
238         final double[] p = parametersDerivatives.get(driver);
239         if (p == null) {
240             final StringBuilder builder = new StringBuilder();
241             for (final Map.Entry<ParameterDriver, double[]> entry : parametersDerivatives.entrySet()) {
242                 if (builder.length() > 0) {
243                     builder.append(", ");
244                 }
245                 builder.append(entry.getKey().getName());
246             }
247             throw new OrekitIllegalArgumentException(OrekitMessages.UNSUPPORTED_PARAMETER_NAME,
248                                                      driver.getName(),
249                                                      builder.length() > 0 ? builder.toString() : "<none>");
250         }
251         return p;
252     }
253 
254     /** Set the partial derivatives of the {@link #getEstimatedValue()
255      * simulated measurement} with respect to parameter.
256      * @param driver driver for the parameter
257      * @param parameterDerivatives partial derivatives with respect to parameter
258      */
259     public void setParameterDerivatives(final ParameterDriver driver, final double... parameterDerivatives) {
260         parametersDerivatives.put(driver, parameterDerivatives);
261     }
262 
263     /** Enumerate for the status of the measurement. */
264     public enum Status {
265 
266         /** Status for processed measurements. */
267         PROCESSED,
268 
269         /** Status for rejected measurements. */
270         REJECTED;
271 
272     }
273 
274 }