AdjustmentContext.java

  1. /* Copyright 2013-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.rugged.adjustment;


  18. import java.util.ArrayList;
  19. import java.util.Collection;
  20. import java.util.HashMap;
  21. import java.util.List;
  22. import java.util.Map;

  23. import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresOptimizer.Optimum;
  24. import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresProblem;
  25. import org.orekit.rugged.adjustment.measurements.Observables;
  26. import org.orekit.rugged.api.Rugged;
  27. import org.orekit.rugged.errors.RuggedException;
  28. import org.orekit.rugged.errors.RuggedMessages;
  29. import org.orekit.rugged.linesensor.LineSensor;

  30. /** Create adjustment context for viewing model refining.
  31.  * @author Lucie LabatAllee
  32.  * @author Jonathan Guinet
  33.  * @author Luc Maisonobe
  34.  * @author Guylaine Prat
  35.  * @since 2.0
  36.  */
  37. public class AdjustmentContext {

  38.     /** List of Rugged instances to optimize. */
  39.     private final Map<String, Rugged> viewingModel;

  40.     /** Set of measurements. */
  41.     private final Observables measurements;

  42.     /** Least square optimizer choice.*/
  43.     private OptimizerId optimizerID;


  44.     /** Build a new instance.
  45.      * The default optimizer is Gauss Newton with QR decomposition.
  46.      * @param viewingModel viewing model
  47.      * @param measurements control and tie points
  48.      */
  49.     public AdjustmentContext(final Collection<Rugged> viewingModel, final Observables measurements) {

  50.         this.viewingModel = new HashMap<String, Rugged>();
  51.         for (final Rugged r : viewingModel) {
  52.             this.viewingModel.put(r.getName(), r);
  53.         }
  54.         this.measurements = measurements;
  55.         this.optimizerID = OptimizerId.GAUSS_NEWTON_QR;
  56.     }

  57.     /** Setter for optimizer algorithm.
  58.      * @param optimizerId the chosen algorithm
  59.      */
  60.     public void setOptimizer(final OptimizerId optimizerId)
  61.     {
  62.         this.optimizerID = optimizerId;
  63.     }

  64.     /**
  65.      * Estimate the free parameters in viewing model to match specified sensor
  66.      * to ground mappings.
  67.      * <p>
  68.      * This method is typically used for calibration of on-board sensor
  69.      * parameters, like rotation angles polynomial coefficients.
  70.      * </p>
  71.      * <p>
  72.      * Before using this method, the {@link org.orekit.utils.ParameterDriver viewing model
  73.      * parameters} retrieved by calling the
  74.      * {@link LineSensor#getParametersDrivers() getParametersDrivers()} method
  75.      * on the desired sensors must be configured. The parameters that should be
  76.      * estimated must have their {@link org.orekit.utils.ParameterDriver#setSelected(boolean)
  77.      * selection status} set to {@code true} whereas the parameters that should
  78.      * retain their current value must have their
  79.      * {@link org.orekit.utils.ParameterDriver#setSelected(boolean) selection status} set to
  80.      * {@code false}. If needed, the {@link org.orekit.utils.ParameterDriver#setValue(double)
  81.      * value} of the estimated/selected parameters can also be changed before
  82.      * calling the method, as this value will serve as the initial value in the
  83.      * estimation process.
  84.      * </p>
  85.      * <p>
  86.      * The method solves a least-squares problem to minimize the residuals
  87.      * between test locations and the reference mappings by adjusting the
  88.      * selected viewing models parameters.
  89.      * </p>
  90.      * <p>
  91.      * The estimated parameters can be retrieved after the method completes by
  92.      * calling again the {@link LineSensor#getParametersDrivers()
  93.      * getParametersDrivers()} method on the desired sensors and checking the
  94.      * updated values of the parameters. In fact, as the values of the
  95.      * parameters are already updated by this method, if users want to use the
  96.      * updated values immediately to perform new direct/inverse locations, they
  97.      * can do so without looking at the parameters: the viewing models are
  98.      * already aware of the updated parameters.
  99.      * </p>
  100.      *
  101.      * @param ruggedNameList list of rugged to refine
  102.      * @param maxEvaluations maximum number of evaluations
  103.      * @param parametersConvergenceThreshold convergence threshold on normalized
  104.      *                                       parameters (dimensionless, related to parameters scales)
  105.      * @return optimum of the least squares problem
  106.      */
  107.     public Optimum estimateFreeParameters(final Collection<String> ruggedNameList, final int maxEvaluations,
  108.                                           final double parametersConvergenceThreshold) {

  109.         final List<Rugged> ruggedList = new ArrayList<>();
  110.         final List<LineSensor> selectedSensors = new ArrayList<>();
  111.         for (String ruggedName : ruggedNameList) {
  112.             final Rugged rugged = this.viewingModel.get(ruggedName);
  113.             if (rugged == null) {
  114.                 throw new RuggedException(RuggedMessages.INVALID_RUGGED_NAME);
  115.             }

  116.             ruggedList.add(rugged);
  117.             selectedSensors.addAll(rugged.getLineSensors());
  118.         }

  119.         final LeastSquareAdjuster adjuster = new LeastSquareAdjuster(this.optimizerID);
  120.         LeastSquaresProblem theProblem = null;

  121.         // builder
  122.         switch (ruggedList.size()) {
  123.             case 1:
  124.                 final Rugged rugged = ruggedList.get(0);
  125.                 final GroundOptimizationProblemBuilder groundOptimizationProblem = new GroundOptimizationProblemBuilder(selectedSensors, measurements, rugged);
  126.                 theProblem = groundOptimizationProblem.build(maxEvaluations, parametersConvergenceThreshold);
  127.                 break;
  128.             case 2:
  129.                 final InterSensorsOptimizationProblemBuilder interSensorsOptimizationProblem = new InterSensorsOptimizationProblemBuilder(selectedSensors, measurements, ruggedList);
  130.                 theProblem = interSensorsOptimizationProblem.build(maxEvaluations, parametersConvergenceThreshold);
  131.                 break;
  132.             default :
  133.                 throw new RuggedException(RuggedMessages.UNSUPPORTED_REFINING_CONTEXT, ruggedList.size());
  134.         }

  135.         return adjuster.optimize(theProblem);
  136.     }
  137. }