1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.estimation.leastsquares;
18
19 import org.hipparchus.linear.Array2DRowRealMatrix;
20 import org.hipparchus.linear.ArrayRealVector;
21 import org.hipparchus.linear.MatrixUtils;
22 import org.hipparchus.linear.RealMatrix;
23 import org.hipparchus.linear.RealVector;
24 import org.hipparchus.optim.nonlinear.vector.leastsquares.MultivariateJacobianFunction;
25 import org.hipparchus.util.FastMath;
26 import org.hipparchus.util.Incrementor;
27 import org.hipparchus.util.Pair;
28 import org.orekit.estimation.measurements.EstimatedMeasurement;
29 import org.orekit.estimation.measurements.ObservedMeasurement;
30 import org.orekit.orbits.Orbit;
31 import org.orekit.propagation.MatricesHarvester;
32 import org.orekit.propagation.Propagator;
33 import org.orekit.propagation.PropagatorsParallelizer;
34 import org.orekit.propagation.SpacecraftState;
35 import org.orekit.propagation.conversion.PropagatorBuilder;
36 import org.orekit.propagation.sampling.MultiSatStepHandler;
37 import org.orekit.time.AbsoluteDate;
38 import org.orekit.time.ChronologicalComparator;
39 import org.orekit.utils.ParameterDriver;
40 import org.orekit.utils.ParameterDriversList;
41 import org.orekit.utils.ParameterDriversList.DelegatingDriver;
42 import org.orekit.utils.TimeSpanMap;
43 import org.orekit.utils.TimeSpanMap.Span;
44
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.Collections;
48 import java.util.HashMap;
49 import java.util.IdentityHashMap;
50 import java.util.List;
51 import java.util.Map;
52
53
54
55
56
57
58
59
60
61
62 public abstract class AbstractBatchLSModel implements MultivariateJacobianFunction {
63
64
65 private final PropagatorBuilder[] builders;
66
67
68
69
70
71 private final ParameterDriversList[] estimatedOrbitalParameters;
72
73
74 private final ParameterDriversList[] estimatedPropagationParameters;
75
76
77 private final ParameterDriversList estimatedMeasurementsParameters;
78
79
80 private final List<ObservedMeasurement<?>> measurements;
81
82
83 private final int[] orbitsStartColumns;
84
85
86 private final int[] orbitsEndColumns;
87
88
89
90
91 private final int[] orbitsJacobianColumns;
92
93
94 private final Map<String, Integer> propagationParameterColumns;
95
96
97 private final Map<String, Integer> measurementParameterColumns;
98
99
100 private final Map<ObservedMeasurement<?>, EstimatedMeasurement<?>> evaluations;
101
102
103 private final ModelObserver observer;
104
105
106 private Incrementor evaluationsCounter;
107
108
109 private Incrementor iterationsCounter;
110
111
112 private AbsoluteDate firstDate;
113
114
115 private AbsoluteDate lastDate;
116
117
118 private final boolean forwardPropagation;
119
120
121 private RealVector value;
122
123
124
125
126 private final MatricesHarvester[] harvesters;
127
128
129 private RealMatrix jacobian;
130
131
132
133
134
135
136
137
138 public AbstractBatchLSModel(final PropagatorBuilder[] propagatorBuilders,
139 final List<ObservedMeasurement<?>> measurements,
140 final ParameterDriversList estimatedMeasurementsParameters,
141 final ModelObserver observer) {
142
143 this.builders = propagatorBuilders.clone();
144 this.measurements = measurements;
145 this.estimatedMeasurementsParameters = estimatedMeasurementsParameters;
146 this.measurementParameterColumns = new HashMap<>(estimatedMeasurementsParameters.getNbValuesToEstimate());
147 this.estimatedOrbitalParameters = new ParameterDriversList[builders.length];
148 this.estimatedPropagationParameters = new ParameterDriversList[builders.length];
149 this.evaluations = new IdentityHashMap<>(measurements.size());
150 this.observer = observer;
151 this.harvesters = new MatricesHarvester[builders.length];
152
153
154 int rows = 0;
155 for (final ObservedMeasurement<?> measurement : measurements) {
156 rows += measurement.getDimension();
157 }
158
159 this.orbitsStartColumns = new int[builders.length];
160 this.orbitsEndColumns = new int[builders.length];
161 this.orbitsJacobianColumns = new int[builders.length * 6];
162 Arrays.fill(orbitsJacobianColumns, -1);
163 int columns = 0;
164 for (int i = 0; i < builders.length; ++i) {
165 this.orbitsStartColumns[i] = columns;
166 final List<ParameterDriversList.DelegatingDriver> orbitalParametersDrivers =
167 builders[i].getOrbitalParametersDrivers().getDrivers();
168 for (int j = 0; j < orbitalParametersDrivers.size(); ++j) {
169 if (orbitalParametersDrivers.get(j).isSelected()) {
170 orbitsJacobianColumns[columns] = j;
171 ++columns;
172 }
173 }
174 this.orbitsEndColumns[i] = columns;
175 }
176
177
178 final List<String> estimatedPropagationParametersNames = new ArrayList<>();
179 for (int i = 0; i < builders.length; ++i) {
180
181
182 for (final DelegatingDriver delegating : getSelectedPropagationDriversForBuilder(i).getDrivers()) {
183
184 final TimeSpanMap<String> delegatingNameSpanMap = delegating.getNamesSpanMap();
185
186 Span<String> currentNameSpan = delegatingNameSpanMap.getFirstSpan();
187
188 if (!estimatedPropagationParametersNames.contains(currentNameSpan.getData())) {
189 estimatedPropagationParametersNames.add(currentNameSpan.getData());
190 }
191 for (int spanNumber = 1; spanNumber < delegatingNameSpanMap.getSpansNumber(); ++spanNumber) {
192 currentNameSpan = delegatingNameSpanMap.getSpan(currentNameSpan.getEnd());
193
194 if (!estimatedPropagationParametersNames.contains(currentNameSpan.getData())) {
195 estimatedPropagationParametersNames.add(currentNameSpan.getData());
196 }
197 }
198 }
199 }
200
201
202 propagationParameterColumns = new HashMap<>(estimatedPropagationParametersNames.size());
203 for (final String driverName : estimatedPropagationParametersNames) {
204 propagationParameterColumns.put(driverName, columns);
205 ++columns;
206 }
207
208 for (final ParameterDriver parameter : estimatedMeasurementsParameters.getDrivers()) {
209 for (Span<String> span = parameter.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) {
210 measurementParameterColumns.put(span.getData(), columns);
211 columns++;
212 }
213 }
214
215
216 value = new ArrayRealVector(rows);
217 jacobian = MatrixUtils.createRealMatrix(rows, columns);
218
219
220
221
222 final AbsoluteDate refDate = builders[0].getInitialOrbitDate();
223
224
225 measurements.sort(new ChronologicalComparator());
226 firstDate = measurements.get(0).getDate();
227 lastDate = measurements.get(measurements.size() - 1).getDate();
228
229
230 forwardPropagation = FastMath.abs(refDate.durationFrom(firstDate)) <= FastMath.abs(refDate.durationFrom(lastDate));
231 }
232
233
234
235
236 public void setEvaluationsCounter(final Incrementor evaluationsCounter) {
237 this.evaluationsCounter = evaluationsCounter;
238 }
239
240
241
242
243 public void setIterationsCounter(final Incrementor iterationsCounter) {
244 this.iterationsCounter = iterationsCounter;
245 }
246
247
248
249
250 public boolean isForwardPropagation() {
251 return forwardPropagation;
252 }
253
254
255
256
257
258 protected abstract MatricesHarvester configureHarvester(Propagator propagator);
259
260
261
262
263
264
265
266
267
268 protected abstract Orbit configureOrbits(MatricesHarvester harvester, Propagator propagator);
269
270
271 @Override
272 public Pair<RealVector, RealMatrix> value(final RealVector point) {
273
274
275 final Propagator[] propagators = createPropagators(point);
276 final Orbit[] orbits = new Orbit[propagators.length];
277 for (int i = 0; i < propagators.length; ++i) {
278 harvesters[i] = configureHarvester(propagators[i]);
279 orbits[i] = configureOrbits(harvesters[i], propagators[i]);
280 }
281 final PropagatorsParallelizer parallelizer =
282 new PropagatorsParallelizer(Arrays.asList(propagators), configureMeasurements(point));
283
284
285 evaluations.clear();
286 value.set(0.0);
287 for (int i = 0; i < jacobian.getRowDimension(); ++i) {
288 for (int j = 0; j < jacobian.getColumnDimension(); ++j) {
289 jacobian.setEntry(i, j, 0.0);
290 }
291 }
292
293
294 if (isForwardPropagation()) {
295
296 parallelizer.propagate(firstDate.shiftedBy(-1.0), lastDate.shiftedBy(+1.0));
297 } else {
298
299 parallelizer.propagate(lastDate.shiftedBy(+1.0), firstDate.shiftedBy(-1.0));
300 }
301
302 observer.modelCalled(orbits, evaluations);
303
304 return new Pair<>(value, jacobian);
305
306 }
307
308
309
310
311
312
313 public ParameterDriversList getSelectedOrbitalParametersDriversForBuilder(final int iBuilder) {
314
315
316 if (estimatedOrbitalParameters[iBuilder] == null) {
317
318
319 final ParameterDriversList selectedOrbitalDrivers = new ParameterDriversList();
320 for (final DelegatingDriver delegating : builders[iBuilder].getOrbitalParametersDrivers().getDrivers()) {
321 if (delegating.isSelected()) {
322 for (final ParameterDriver driver : delegating.getRawDrivers()) {
323 selectedOrbitalDrivers.add(driver);
324 }
325 }
326 }
327
328
329 estimatedOrbitalParameters[iBuilder] = selectedOrbitalDrivers;
330 }
331 return estimatedOrbitalParameters[iBuilder];
332 }
333
334
335
336
337
338 public ParameterDriversList getSelectedPropagationDriversForBuilder(final int iBuilder) {
339
340
341 if (estimatedPropagationParameters[iBuilder] == null) {
342
343
344 final ParameterDriversList selectedPropagationDrivers = new ParameterDriversList();
345 for (final DelegatingDriver delegating : builders[iBuilder].getPropagationParametersDrivers().getDrivers()) {
346 if (delegating.isSelected()) {
347 for (final ParameterDriver driver : delegating.getRawDrivers()) {
348 selectedPropagationDrivers.add(driver);
349 }
350 }
351 }
352
353
354
355 selectedPropagationDrivers.sort();
356
357
358 estimatedPropagationParameters[iBuilder] = selectedPropagationDrivers;
359 }
360 return estimatedPropagationParameters[iBuilder];
361 }
362
363
364
365
366
367 public Propagator[] createPropagators(final RealVector point) {
368
369 final Propagator[] propagators = new Propagator[builders.length];
370
371
372
373 for (int i = 0; i < builders.length; ++i) {
374
375 int element = 0;
376
377 final int nbOrb = orbitsEndColumns[i] - orbitsStartColumns[i];
378
379
380 final ParameterDriversList selectedPropagationDrivers = getSelectedPropagationDriversForBuilder(i);
381 final int nbParams = selectedPropagationDrivers.getNbParams();
382 final int nbValuesToEstimate = selectedPropagationDrivers.getNbValuesToEstimate();
383
384
385 final double[] propagatorArray = new double[nbOrb + nbValuesToEstimate];
386
387
388 for (int j = 0; j < nbOrb; ++j) {
389 propagatorArray[element++] = point.getEntry(orbitsStartColumns[i] + j);
390 }
391
392
393 for (int j = 0; j < nbParams; ++j) {
394 final DelegatingDriver driver = selectedPropagationDrivers.getDrivers().get(j);
395 final TimeSpanMap<String> delegatingNameSpanMap = driver.getNamesSpanMap();
396
397
398
399 Span<String> currentNameSpan = delegatingNameSpanMap.getFirstSpan();
400 propagatorArray[element++] = point.getEntry(propagationParameterColumns.get(currentNameSpan.getData()));
401
402 for (int spanNumber = 1; spanNumber < delegatingNameSpanMap.getSpansNumber(); ++spanNumber) {
403 currentNameSpan = delegatingNameSpanMap.getSpan(currentNameSpan.getEnd());
404 propagatorArray[element++] = point.getEntry(propagationParameterColumns.get(currentNameSpan.getData()));
405
406 }
407 }
408
409
410 propagators[i] = builders[i].buildPropagator(propagatorArray);
411 }
412
413 return propagators;
414
415 }
416
417
418
419
420
421 public void fetchEvaluatedMeasurement(final int index, final EstimatedMeasurement<?> evaluation) {
422
423
424 final SpacecraftState[] evaluationStates = evaluation.getStates();
425 final ObservedMeasurement<?> observedMeasurement = evaluation.getObservedMeasurement();
426
427
428 evaluations.put(observedMeasurement, evaluation);
429 if (evaluation.getStatus() == EstimatedMeasurement.Status.REJECTED) {
430 return;
431 }
432
433 final double[] evaluated = evaluation.getEstimatedValue();
434 final double[] observed = observedMeasurement.getObservedValue();
435 final double[] sigma = observedMeasurement.getTheoreticalStandardDeviation();
436 final double[] weight = evaluation.getObservedMeasurement().getBaseWeight();
437 for (int i = 0; i < evaluated.length; ++i) {
438 value.setEntry(index + i, weight[i] * (evaluated[i] - observed[i]) / sigma[i]);
439 }
440
441 for (int k = 0; k < evaluationStates.length; ++k) {
442
443 final int p = observedMeasurement.getSatellites().get(k).getPropagatorIndex();
444
445
446 final double[][] aCY = new double[6][6];
447 final Orbit currentOrbit = evaluationStates[k].getOrbit();
448 currentOrbit.getJacobianWrtParameters(builders[p].getPositionAngleType(), aCY);
449 final RealMatrix dCdY = new Array2DRowRealMatrix(aCY, false);
450
451
452 final RealMatrix dMdC = new Array2DRowRealMatrix(evaluation.getStateDerivatives(k), false);
453 final RealMatrix dMdY = dMdC.multiply(dCdY);
454
455
456 final ParameterDriversList selectedOrbitalDrivers = getSelectedOrbitalParametersDriversForBuilder(p);
457 final int nbOrbParams = selectedOrbitalDrivers.getNbParams();
458 if (nbOrbParams > 0) {
459 final RealMatrix dYdY0 = harvesters[p].getStateTransitionMatrix(evaluationStates[k]);
460 final RealMatrix dMdY0 = dMdY.multiply(dYdY0);
461 for (int i = 0; i < dMdY0.getRowDimension(); ++i) {
462 for (int j = orbitsStartColumns[p]; j < orbitsEndColumns[p]; ++j) {
463 final ParameterDriver driver =
464 selectedOrbitalDrivers.getDrivers().get(j - orbitsStartColumns[p]);
465 final double partial = dMdY0.getEntry(i, orbitsJacobianColumns[j]);
466 jacobian.setEntry(index + i, j,
467 weight[i] * partial / sigma[i] * driver.getScale());
468 }
469 }
470 }
471
472
473 final ParameterDriversList selectedPropagationDrivers = getSelectedPropagationDriversForBuilder(p);
474 final int nbParams = selectedPropagationDrivers.getNbParams();
475 if (nbParams > 0) {
476 final RealMatrix dYdPp = harvesters[p].getParametersJacobian(evaluationStates[k]);
477 final RealMatrix dMdPp = dMdY.multiply(dYdPp);
478
479 for (int i = 0; i < dMdPp.getRowDimension(); ++i) {
480 int col = 0;
481
482
483 for (int j = 0; j < nbParams; ++j) {
484 final ParameterDriver delegating = selectedPropagationDrivers.getDrivers().get(j);
485 final TimeSpanMap<String> delegatingNameSpanMap = delegating.getNamesSpanMap();
486
487 for (Span<String> currentNameSpan = delegatingNameSpanMap.getFirstSpan(); currentNameSpan != null; currentNameSpan = currentNameSpan.next()) {
488 jacobian.addToEntry(index + i, propagationParameterColumns.get(currentNameSpan.getData()),
489 weight[i] * dMdPp.getEntry(i, col++) / sigma[i] * delegating.getScale());
490 }
491 }
492 }
493 }
494 }
495
496 for (final ParameterDriver driver : observedMeasurement.getParametersDrivers()) {
497 if (driver.isSelected()) {
498 for (Span<String> span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) {
499 final double[] aMPm = evaluation.getParameterDerivatives(driver, span.getStart());
500 for (int i = 0; i < aMPm.length; ++i) {
501 jacobian.setEntry(index + i, measurementParameterColumns.get(span.getData()),
502 weight[i] * aMPm[i] / sigma[i] * driver.getScale());
503 }
504 }
505 }
506 }
507
508 }
509
510
511
512
513
514 private MultiSatStepHandler configureMeasurements(final RealVector point) {
515
516
517 int index = orbitsEndColumns[builders.length - 1] + propagationParameterColumns.size();
518 for (final ParameterDriver parameter : estimatedMeasurementsParameters.getDrivers()) {
519
520 for (Span<Double> span = parameter.getValueSpanMap().getFirstSpan(); span != null; span = span.next()) {
521 parameter.setNormalizedValue(point.getEntry(index++), span.getStart());
522 }
523 }
524
525
526 final List<PreCompensation> precompensated = new ArrayList<>();
527 for (final ObservedMeasurement<?> measurement : measurements) {
528 if (measurement.isEnabled()) {
529 precompensated.add(new PreCompensation(measurement, evaluations.get(measurement)));
530 }
531 }
532 precompensated.sort(new ChronologicalComparator());
533
534
535 firstDate = precompensated.get(0).getDate();
536 lastDate = precompensated.get(precompensated.size() - 1).getDate();
537
538
539 if (!forwardPropagation) {
540 Collections.reverse(precompensated);
541 }
542
543 return new MeasurementHandler(this, precompensated);
544
545 }
546
547
548
549
550 public int getIterationsCount() {
551 return iterationsCounter.getCount();
552 }
553
554
555
556
557 public int getEvaluationsCount() {
558 return evaluationsCounter.getCount();
559 }
560
561 }