GroundOptimizationProblemBuilder.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.List;
  21. import java.util.Map;

  22. import org.hipparchus.analysis.differentiation.Gradient;
  23. import org.hipparchus.linear.Array2DRowRealMatrix;
  24. import org.hipparchus.linear.ArrayRealVector;
  25. import org.hipparchus.linear.RealMatrix;
  26. import org.hipparchus.linear.RealVector;
  27. import org.hipparchus.optim.ConvergenceChecker;
  28. import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresBuilder;
  29. import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresProblem;
  30. import org.hipparchus.optim.nonlinear.vector.leastsquares.MultivariateJacobianFunction;
  31. import org.hipparchus.optim.nonlinear.vector.leastsquares.ParameterValidator;
  32. import org.hipparchus.util.FastMath;
  33. import org.hipparchus.util.Pair;
  34. import org.orekit.bodies.GeodeticPoint;
  35. import org.orekit.rugged.adjustment.measurements.Observables;
  36. import org.orekit.rugged.adjustment.measurements.SensorToGroundMapping;
  37. import org.orekit.rugged.api.Rugged;
  38. import org.orekit.rugged.errors.RuggedException;
  39. import org.orekit.rugged.errors.RuggedMessages;
  40. import org.orekit.rugged.linesensor.LineSensor;
  41. import org.orekit.rugged.linesensor.SensorPixel;
  42. import org.orekit.utils.ParameterDriver;

  43. /** Ground optimization problem builder.
  44.  * builds the optimization problem relying on ground measurements.
  45.  * @author Guylaine Prat
  46.  * @author Lucie Labat Allee
  47.  * @author Jonathan Guinet
  48.  * @author Luc Maisonobe
  49.  * @since 2.0
  50.  */
  51. public class GroundOptimizationProblemBuilder extends OptimizationProblemBuilder {

  52.     /** Key for target. */
  53.     private static final String TARGET = "Target";

  54.     /** Key for weight. */
  55.     private static final String WEIGHT = "Weight";

  56.     /** Rugged instance to refine.*/
  57.     private final Rugged rugged;

  58.     /** Sensor to ground mapping to generate target tab for optimization.*/
  59.     private List<SensorToGroundMapping> sensorToGroundMappings;

  60.     /** Minimum line for inverse location estimation.*/
  61.     private int minLine;

  62.     /** Maximum line for inverse location estimation.*/
  63.     private int maxLine;

  64.     /** Target and weight (the solution of the optimization problem).*/
  65.     private HashMap<String, double[] > targetAndWeight;


  66.     /** Build a new instance of the optimization problem.
  67.      * @param sensors list of sensors to refine
  68.      * @param measurements set of observables
  69.      * @param rugged name of rugged to refine
  70.      */
  71.     public GroundOptimizationProblemBuilder(final List<LineSensor> sensors,
  72.                                             final Observables measurements, final Rugged rugged) {

  73.         super(sensors, measurements);
  74.         this.rugged = rugged;
  75.         this.initMapping();
  76.     }

  77.     /** {@inheritDoc} */
  78.     @Override
  79.     protected void initMapping() {

  80.         final String ruggedName = rugged.getName();
  81.         this.sensorToGroundMappings = new ArrayList<>();
  82.         for (final LineSensor lineSensor : this.getSensors()) {
  83.             final SensorToGroundMapping mapping = this.getMeasurements().getGroundMapping(ruggedName, lineSensor.getName());
  84.             if (mapping != null) {
  85.                 this.sensorToGroundMappings.add(mapping);
  86.             }
  87.         }
  88.     }

  89.     /** {@inheritDoc} */
  90.     @Override
  91.     protected void createTargetAndWeight() {

  92.         int n = 0;
  93.         for (final SensorToGroundMapping reference : this.sensorToGroundMappings) {
  94.             n += reference.getMapping().size();
  95.         }

  96.         if (n == 0) {
  97.             throw new RuggedException(RuggedMessages.NO_REFERENCE_MAPPINGS);
  98.         }
  99.         final double[] target = new double[2 * n];
  100.         final double[] weight = new double[2 * n];

  101.         double min = Double.POSITIVE_INFINITY;
  102.         double max = Double.NEGATIVE_INFINITY;
  103.         int k = 0;

  104.         for (final SensorToGroundMapping reference : this.sensorToGroundMappings) {
  105.             for (final Map.Entry<SensorPixel, GeodeticPoint> mapping : reference.getMapping()) {
  106.                 final SensorPixel sp = mapping.getKey();
  107.                 weight[k] = 1.0;
  108.                 target[k++] = sp.getLineNumber();
  109.                 weight[k] = 1.0;
  110.                 target[k++] = sp.getPixelNumber();
  111.                 min = FastMath.min(min, sp.getLineNumber());
  112.                 max = FastMath.max(max, sp.getLineNumber());
  113.             }
  114.         }

  115.         this.minLine = (int) FastMath.floor(min - ESTIMATION_LINE_RANGE_MARGIN);
  116.         this.maxLine = (int) FastMath.ceil(max - ESTIMATION_LINE_RANGE_MARGIN);
  117.         this.targetAndWeight = new HashMap<String, double[]>();
  118.         this.targetAndWeight.put(TARGET, target);
  119.         this.targetAndWeight.put(WEIGHT, weight);
  120.     }

  121.     /** {@inheritDoc} */
  122.     @Override
  123.     protected MultivariateJacobianFunction createFunction() {

  124.         // model function
  125.         final MultivariateJacobianFunction model = point -> {

  126.             // set the current parameters values
  127.             int i = 0;
  128.             for (final ParameterDriver driver : this.getDrivers()) {
  129.                 driver.setNormalizedValue(point.getEntry(i++));
  130.             }

  131.             final double[] target = this.targetAndWeight.get(TARGET);

  132.             // compute inverse loc and its partial derivatives
  133.             final RealVector value = new ArrayRealVector(target.length);
  134.             final RealMatrix jacobian = new Array2DRowRealMatrix(target.length, this.getNbParams());
  135.             int l = 0;
  136.             for (final SensorToGroundMapping reference : this.sensorToGroundMappings) {
  137.                 for (final Map.Entry<SensorPixel, GeodeticPoint> mapping : reference.getMapping()) {
  138.                     final GeodeticPoint gp = mapping.getValue();
  139.                     final Gradient[] ilResult = this.rugged.inverseLocationDerivatives(reference.getSensorName(), gp, minLine, maxLine, this.getGenerator());

  140.                     if (ilResult == null) {
  141.                         value.setEntry(l, minLine - 100.0); // arbitrary
  142.                         // line far
  143.                         // away
  144.                         value.setEntry(l + 1, -100.0); // arbitrary
  145.                         // pixel far away
  146.                     } else {
  147.                         // extract the value
  148.                         value.setEntry(l, ilResult[0].getValue());
  149.                         value.setEntry(l + 1, ilResult[1].getValue());

  150.                         // extract the Jacobian
  151.                         final int[] orders = new int[this.getNbParams()];
  152.                         int m = 0;
  153.                         for (final ParameterDriver driver : this.getDrivers()) {
  154.                             final double scale = driver.getScale();
  155.                             orders[m] = 1;
  156.                             jacobian.setEntry(l, m,
  157.                                     ilResult[0]
  158.                                             .getPartialDerivative(orders) *
  159.                                             scale);
  160.                             jacobian.setEntry(l + 1, m,
  161.                                     ilResult[1]
  162.                                             .getPartialDerivative(orders) *
  163.                                             scale);
  164.                             orders[m] = 0;
  165.                             m++;
  166.                         }
  167.                     }

  168.                     l += 2;
  169.                 }
  170.             }

  171.             // inverse loc result with Jacobian for all reference points
  172.             return new Pair<RealVector, RealMatrix>(value, jacobian);
  173.         };

  174.         return model;
  175.     }


  176.     /** Least square problem builder.
  177.      * @param maxEvaluations maxIterations and evaluations
  178.      * @param convergenceThreshold parameter convergence threshold
  179.      * @return the least square problem
  180.      */
  181.     @Override
  182.     public final LeastSquaresProblem build(final int maxEvaluations, final double convergenceThreshold) {

  183.         this.createTargetAndWeight();
  184.         final double[] target = this.targetAndWeight.get(TARGET);
  185.         final double[] start = this.createStartTab();
  186.         final ParameterValidator validator = this.createParameterValidator();
  187.         final ConvergenceChecker<LeastSquaresProblem.Evaluation> checker = this.createChecker(convergenceThreshold);
  188.         final MultivariateJacobianFunction model = this.createFunction();
  189.         return new LeastSquaresBuilder()
  190.                         .lazyEvaluation(false).maxIterations(maxEvaluations)
  191.                         .maxEvaluations(maxEvaluations).weight(null).start(start)
  192.                         .target(target).parameterValidator(validator).checker(checker)
  193.                         .model(model).build();
  194.     }
  195. }