1 /* Copyright 2013-2019 CS Systèmes d'Information
2 * Licensed to CS Systèmes d'Information (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.rugged.adjustment;
18
19
20 import java.util.ArrayList;
21 import java.util.Collection;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25
26 import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresOptimizer.Optimum;
27 import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresProblem;
28 import org.orekit.rugged.adjustment.measurements.Observables;
29 import org.orekit.rugged.api.Rugged;
30 import org.orekit.rugged.errors.RuggedException;
31 import org.orekit.rugged.errors.RuggedMessages;
32 import org.orekit.rugged.linesensor.LineSensor;
33
34 /** Create adjustment context for viewing model refining.
35 * @author Lucie LabatAllee
36 * @author Jonathan Guinet
37 * @author Luc Maisonobe
38 * @author Guylaine Prat
39 * @since 2.0
40 */
41 public class AdjustmentContext {
42
43 /** List of Rugged instances to optimize. */
44 private final Map<String, Rugged> viewingModel;
45
46 /** Set of measurements. */
47 private final Observables measurements;
48
49 /** Least square optimizer choice.*/
50 private OptimizerId optimizerID;
51
52
53 /** Build a new instance.
54 * The default optimizer is Gauss Newton with QR decomposition.
55 * @param viewingModel viewing model
56 * @param measurements control and tie points
57 */
58 public AdjustmentContext(final Collection<Rugged> viewingModel, final Observables measurements) {
59
60 this.viewingModel = new HashMap<String, Rugged>();
61 for (final Rugged r : viewingModel) {
62 this.viewingModel.put(r.getName(), r);
63 }
64 this.measurements = measurements;
65 this.optimizerID = OptimizerId.GAUSS_NEWTON_QR;
66 }
67
68 /** Setter for optimizer algorithm.
69 * @param optimizerId the chosen algorithm
70 */
71 public void setOptimizer(final OptimizerId optimizerId)
72 {
73 this.optimizerID = optimizerId;
74 }
75
76 /**
77 * Estimate the free parameters in viewing model to match specified sensor
78 * to ground mappings.
79 * <p>
80 * This method is typically used for calibration of on-board sensor
81 * parameters, like rotation angles polynomial coefficients.
82 * </p>
83 * <p>
84 * Before using this method, the {@link org.orekit.utils.ParameterDriver viewing model
85 * parameters} retrieved by calling the
86 * {@link LineSensor#getParametersDrivers() getParametersDrivers()} method
87 * on the desired sensors must be configured. The parameters that should be
88 * estimated must have their {@link org.orekit.utils.ParameterDriver#setSelected(boolean)
89 * selection status} set to {@code true} whereas the parameters that should
90 * retain their current value must have their
91 * {@link org.orekit.utils.ParameterDriver#setSelected(boolean) selection status} set to
92 * {@code false}. If needed, the {@link org.orekit.utils.ParameterDriver#setValue(double)
93 * value} of the estimated/selected parameters can also be changed before
94 * calling the method, as this value will serve as the initial value in the
95 * estimation process.
96 * </p>
97 * <p>
98 * The method solves a least-squares problem to minimize the residuals
99 * between test locations and the reference mappings by adjusting the
100 * selected viewing models parameters.
101 * </p>
102 * <p>
103 * The estimated parameters can be retrieved after the method completes by
104 * calling again the {@link LineSensor#getParametersDrivers()
105 * getParametersDrivers()} method on the desired sensors and checking the
106 * updated values of the parameters. In fact, as the values of the
107 * parameters are already updated by this method, if users want to use the
108 * updated values immediately to perform new direct/inverse locations, they
109 * can do so without looking at the parameters: the viewing models are
110 * already aware of the updated parameters.
111 * </p>
112 *
113 * @param ruggedNameList list of rugged to refine
114 * @param maxEvaluations maximum number of evaluations
115 * @param parametersConvergenceThreshold convergence threshold on normalized
116 * parameters (dimensionless, related to parameters scales)
117 * @return optimum of the least squares problem
118 */
119 public Optimum estimateFreeParameters(final Collection<String> ruggedNameList, final int maxEvaluations,
120 final double parametersConvergenceThreshold) {
121
122 final List<Rugged> ruggedList = new ArrayList<Rugged>();
123 final List<LineSensor> selectedSensors = new ArrayList<LineSensor>();
124 for (String ruggedName : ruggedNameList) {
125 final Rugged rugged = this.viewingModel.get(ruggedName);
126 if (rugged == null) {
127 throw new RuggedException(RuggedMessages.INVALID_RUGGED_NAME);
128 }
129
130 ruggedList.add(rugged);
131 selectedSensors.addAll(rugged.getLineSensors());
132 }
133
134 final LeastSquareAdjusteruster.html#LeastSquareAdjuster">LeastSquareAdjuster adjuster = new LeastSquareAdjuster(this.optimizerID);
135 LeastSquaresProblem theProblem = null;
136
137 // builder
138 switch (ruggedList.size()) {
139 case 1:
140 final Rugged rugged = ruggedList.get(0);
141 final GroundOptimizationProblemBuilderOptimizationProblemBuilder">GroundOptimizationProblemBuilder groundOptimizationProblem = new GroundOptimizationProblemBuilder(selectedSensors, measurements, rugged);
142 theProblem = groundOptimizationProblem.build(maxEvaluations, parametersConvergenceThreshold);
143 break;
144 case 2:
145 final InterSensorsOptimizationProblemBuilderOptimizationProblemBuilder">InterSensorsOptimizationProblemBuilder interSensorsOptimizationProblem = new InterSensorsOptimizationProblemBuilder(selectedSensors, measurements, ruggedList);
146 theProblem = interSensorsOptimizationProblem.build(maxEvaluations, parametersConvergenceThreshold);
147 break;
148 default :
149 throw new RuggedException(RuggedMessages.UNSUPPORTED_REFINING_CONTEXT, ruggedList.size());
150 }
151
152 return adjuster.optimize(theProblem);
153 }
154 }