OptimizationProblemBuilder.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.HashMap;
  20. import java.util.HashSet;
  21. import java.util.List;
  22. import java.util.Map;
  23. import java.util.Set;

  24. import org.hipparchus.Field;
  25. import org.hipparchus.analysis.differentiation.Gradient;
  26. import org.hipparchus.analysis.differentiation.GradientField;
  27. import org.hipparchus.optim.ConvergenceChecker;
  28. import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresProblem;
  29. import org.hipparchus.optim.nonlinear.vector.leastsquares.MultivariateJacobianFunction;
  30. import org.hipparchus.optim.nonlinear.vector.leastsquares.ParameterValidator;
  31. import org.orekit.rugged.adjustment.measurements.Observables;
  32. import org.orekit.rugged.errors.RuggedException;
  33. import org.orekit.rugged.errors.RuggedMessages;
  34. import org.orekit.rugged.linesensor.LineSensor;
  35. import org.orekit.rugged.utils.DerivativeGenerator;
  36. import org.orekit.utils.ParameterDriver;

  37. /**
  38.  * Builder for optimization problem.
  39.  * <p>
  40.  * Constructs the optimization problem defined by a set of measurement and sensors.
  41.  * </p>
  42.  * @author Jonathan Guinet
  43.  * @author Guylaine Prat
  44.  * @since 2.0
  45.  */
  46. abstract class OptimizationProblemBuilder {

  47.     /** Margin used in parameters estimation for the inverse location lines range. */
  48.     protected static final int ESTIMATION_LINE_RANGE_MARGIN = 100;

  49.     /** Gradient generator.*/
  50.     private final DerivativeGenerator<Gradient> generator;

  51.     /** Parameter drivers list. */
  52.     private final List<ParameterDriver> drivers;

  53.     /** Number of parameters to refine. */
  54.     private final int nbParams;

  55.     /** Measurements. */
  56.     private Observables measurements;

  57.     /** Sensors list. */
  58.     private final List<LineSensor> sensors;

  59.     /** Constructor.
  60.      * @param sensors list of sensors to refine
  61.      * @param measurements set of observables
  62.      */
  63.     OptimizationProblemBuilder(final List<LineSensor> sensors, final Observables measurements) {

  64.         this.generator = this.createGenerator(sensors);
  65.         this.drivers = this.generator.getSelected();
  66.         this.nbParams = this.drivers.size();
  67.         if (this.nbParams == 0) {
  68.             throw new RuggedException(RuggedMessages.NO_PARAMETERS_SELECTED);
  69.         }
  70.         this.measurements = measurements;
  71.         this.sensors = sensors;
  72.     }

  73.     /** Least squares problem builder.
  74.      * @param maxEvaluations maximum number of evaluations
  75.      * @param convergenceThreshold convergence threshold
  76.      * @return the least squares problem
  77.      */

  78.     public abstract LeastSquaresProblem build(int maxEvaluations, double convergenceThreshold);

  79.     /** Create the convergence check.
  80.      * <p>
  81.      * check LInf distance of parameters variation between previous and current iteration
  82.      * </p>
  83.      * @param parametersConvergenceThreshold convergence threshold
  84.      * @return the checker
  85.      */
  86.     final ConvergenceChecker<LeastSquaresProblem.Evaluation>
  87.                             createChecker(final double parametersConvergenceThreshold) {

  88.         final ConvergenceChecker<LeastSquaresProblem.Evaluation> checker = (iteration, previous, current)
  89.             -> current.getPoint().getLInfDistance(previous.getPoint()) <= parametersConvergenceThreshold;

  90.         return checker;
  91.     }

  92.     /** Create start points for optimization algorithm.
  93.      * @return start parameters values (normalized)
  94.      */
  95.     final double[] createStartTab() {

  96.         // Get start points (as a normalized value)
  97.         final double[] start = new double[this.nbParams];
  98.         int iStart = 0;
  99.         for (final ParameterDriver driver : this.drivers) {
  100.             start[iStart++] = driver.getNormalizedValue();
  101.         }
  102.         return start;
  103.     }

  104.     /** Create targets and weights of optimization problem. */
  105.     protected abstract void createTargetAndWeight();

  106.     /** Create the model function value and its Jacobian.
  107.      * @return the model function value and its Jacobian
  108.      */
  109.     protected abstract MultivariateJacobianFunction createFunction();

  110.     /** Parse the observables to select mapping .*/
  111.     protected abstract void initMapping();

  112.     /** Create parameter validator.
  113.      * @return parameter validator
  114.      */
  115.     final ParameterValidator createParameterValidator() {

  116.         // Prevent parameters to exceed their prescribed bounds
  117.         final ParameterValidator validator = params -> {
  118.             int i = 0;
  119.             for (final ParameterDriver driver : this.drivers) {

  120.                 // let the parameter handle min/max clipping
  121.                 driver.setNormalizedValue(params.getEntry(i));
  122.                 params.setEntry(i++, driver.getNormalizedValue());
  123.             }
  124.             return params;
  125.         };

  126.         return validator;
  127.     }

  128.     /** Create the generator for {@link Gradient} instances.
  129.      * @param selectedSensors list of sensors referencing the parameters drivers
  130.      * @return a new generator
  131.      */
  132.     private DerivativeGenerator<Gradient> createGenerator(final List<LineSensor> selectedSensors) {

  133.         // Initialize set of drivers name
  134.         final Set<String> names = new HashSet<>();

  135.         // Get the drivers name
  136.         for (final LineSensor sensor : selectedSensors) {

  137.             // Get the drivers name for the sensor
  138.             sensor.getParametersDrivers().forEach(driver -> {

  139.                 // Add the name of the driver to the set of drivers name
  140.                 if (names.contains(driver.getName()) == false) {
  141.                     names.add(driver.getName());
  142.                 }
  143.             });
  144.         }

  145.         // Set up generator list and map
  146.         final List<ParameterDriver> selected = new ArrayList<>();
  147.         final Map<String, Integer> map = new HashMap<>();

  148.         // Get the list of selected drivers
  149.         for (final LineSensor sensor : selectedSensors) {

  150.             sensor.getParametersDrivers().filter(driver -> driver.isSelected()).forEach(driver -> {
  151.                 if (map.get(driver.getName()) == null) {
  152.                     map.put(driver.getName(), map.size());
  153.                     selected.add(driver);
  154.                 }
  155.             });
  156.         }

  157.         // gradient Generator
  158.         final GradientField field = GradientField.getField(map.size());
  159.         return new DerivativeGenerator<Gradient>() {

  160.             /** {@inheritDoc} */
  161.             @Override
  162.             public List<ParameterDriver> getSelected() {
  163.                 return selected;
  164.             }

  165.             /** {@inheritDoc} */
  166.             @Override
  167.             public Gradient constant(final double value) {
  168.                 return Gradient.constant(map.size(), value);
  169.             }

  170.             /** {@inheritDoc} */
  171.             @Override
  172.             public Gradient variable(final ParameterDriver driver) {
  173.                 final Integer index = map.get(driver.getName());
  174.                 if (index == null) {
  175.                     return constant(driver.getValue());
  176.                 } else {
  177.                     return Gradient.variable(map.size(), index.intValue(), driver.getValue());
  178.                 }
  179.             }

  180.             /** {@inheritDoc} */
  181.             @Override
  182.             public Field<Gradient> getField() {
  183.                 return field;
  184.             }

  185.         };
  186.     }

  187.     /** Get the sensors list.
  188.      * @return the sensors list
  189.      */
  190.     protected List<LineSensor> getSensors() {
  191.         return sensors;
  192.     }

  193.     /** Get the number of parameters to refine.
  194.      * @return the number of parameters to refine
  195.      */
  196.     protected final int getNbParams() {
  197.         return this.nbParams;
  198.     }

  199.     /**
  200.      * Get the parameters drivers list.
  201.      * @return the selected list of parameters driver
  202.      */
  203.     protected final List<ParameterDriver> getDrivers() {
  204.         return this.drivers;
  205.     }

  206.     /**
  207.      * Get the derivative structure generator.
  208.      * @return the derivative structure generator.
  209.      */
  210.     protected final DerivativeGenerator<Gradient> getGenerator() {
  211.         return this.generator;
  212.     }

  213.     /** Get the measurements.
  214.      * @return the measurements
  215.      */
  216.     protected Observables getMeasurements() {
  217.         return measurements;
  218.     }
  219. }