Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • orekit/rugged
  • sdinot/rugged
  • yzokras/rugged
  • youngcle/rugged-mod
4 results
Show changes
Showing
with 1602 additions and 51 deletions
' Copyright 2013-2015 CS Systèmes d'Information
' Licensed to CS Systèmes d'Information (CS) under one or more
' Copyright 2013-2022 CS GROUP
' Licensed to CS GROUP (CS) under one or more
' contributor license agreements. See the NOTICE file distributed with
' this work for additional information regarding copyright ownership.
' CS licenses this file to You under the Apache License, Version 2.0
......
' Copyright 2013-2015 CS Systèmes d'Information
' Licensed to CS Systèmes d'Information (CS) under one or more
' Copyright 2013-2022 CS GROUP
' Licensed to CS GROUP (CS) under one or more
' contributor license agreements. See the NOTICE file distributed with
' this work for additional information regarding copyright ownership.
' CS licenses this file to You under the Apache License, Version 2.0
......
' Copyright 2013-2015 CS Systèmes d'Information
' Licensed to CS Systèmes d'Information (CS) under one or more
' Copyright 2013-2022 CS GROUP
' Licensed to CS GROUP (CS) under one or more
' contributor license agreements. See the NOTICE file distributed with
' this work for additional information regarding copyright ownership.
' CS licenses this file to You under the Apache License, Version 2.0
......
' Copyright 2013-2015 CS Systèmes d'Information
' Licensed to CS Systèmes d'Information (CS) under one or more
' Copyright 2013-2022 CS GROUP
' Licensed to CS GROUP (CS) under one or more
' contributor license agreements. See the NOTICE file distributed with
' this work for additional information regarding copyright ownership.
' CS licenses this file to You under the Apache License, Version 2.0
......
File moved
' Copyright 2013-2015 CS Systèmes d'Information
' Licensed to CS Systèmes d'Information (CS) under one or more
' Copyright 2013-2022 CS GROUP
' Licensed to CS GROUP (CS) under one or more
' contributor license agreements. See the NOTICE file distributed with
' this work for additional information regarding copyright ownership.
' CS licenses this file to You under the Apache License, Version 2.0
......
/* Copyright 2013-2022 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.rugged.adjustment;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresOptimizer.Optimum;
import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresProblem;
import org.orekit.rugged.adjustment.measurements.Observables;
import org.orekit.rugged.api.Rugged;
import org.orekit.rugged.errors.RuggedException;
import org.orekit.rugged.errors.RuggedMessages;
import org.orekit.rugged.linesensor.LineSensor;
/** Create adjustment context for viewing model refining.
* @author Lucie LabatAllee
* @author Jonathan Guinet
* @author Luc Maisonobe
* @author Guylaine Prat
* @since 2.0
*/
public class AdjustmentContext {
/** List of Rugged instances to optimize. */
private final Map<String, Rugged> viewingModel;
/** Set of measurements. */
private final Observables measurements;
/** Least square optimizer choice.*/
private OptimizerId optimizerID;
/** Build a new instance.
* The default optimizer is Gauss Newton with QR decomposition.
* @param viewingModel viewing model
* @param measurements control and tie points
*/
public AdjustmentContext(final Collection<Rugged> viewingModel, final Observables measurements) {
this.viewingModel = new HashMap<String, Rugged>();
for (final Rugged r : viewingModel) {
this.viewingModel.put(r.getName(), r);
}
this.measurements = measurements;
this.optimizerID = OptimizerId.GAUSS_NEWTON_QR;
}
/** Setter for optimizer algorithm.
* @param optimizerId the chosen algorithm
*/
public void setOptimizer(final OptimizerId optimizerId)
{
this.optimizerID = optimizerId;
}
/**
* Estimate the free parameters in viewing model to match specified sensor
* to ground mappings.
* <p>
* This method is typically used for calibration of on-board sensor
* parameters, like rotation angles polynomial coefficients.
* </p>
* <p>
* Before using this method, the {@link org.orekit.utils.ParameterDriver viewing model
* parameters} retrieved by calling the
* {@link LineSensor#getParametersDrivers() getParametersDrivers()} method
* on the desired sensors must be configured. The parameters that should be
* estimated must have their {@link org.orekit.utils.ParameterDriver#setSelected(boolean)
* selection status} set to {@code true} whereas the parameters that should
* retain their current value must have their
* {@link org.orekit.utils.ParameterDriver#setSelected(boolean) selection status} set to
* {@code false}. If needed, the {@link org.orekit.utils.ParameterDriver#setValue(double)
* value} of the estimated/selected parameters can also be changed before
* calling the method, as this value will serve as the initial value in the
* estimation process.
* </p>
* <p>
* The method solves a least-squares problem to minimize the residuals
* between test locations and the reference mappings by adjusting the
* selected viewing models parameters.
* </p>
* <p>
* The estimated parameters can be retrieved after the method completes by
* calling again the {@link LineSensor#getParametersDrivers()
* getParametersDrivers()} method on the desired sensors and checking the
* updated values of the parameters. In fact, as the values of the
* parameters are already updated by this method, if users want to use the
* updated values immediately to perform new direct/inverse locations, they
* can do so without looking at the parameters: the viewing models are
* already aware of the updated parameters.
* </p>
*
* @param ruggedNameList list of rugged to refine
* @param maxEvaluations maximum number of evaluations
* @param parametersConvergenceThreshold convergence threshold on normalized
* parameters (dimensionless, related to parameters scales)
* @return optimum of the least squares problem
*/
public Optimum estimateFreeParameters(final Collection<String> ruggedNameList, final int maxEvaluations,
final double parametersConvergenceThreshold) {
final List<Rugged> ruggedList = new ArrayList<>();
final List<LineSensor> selectedSensors = new ArrayList<>();
for (String ruggedName : ruggedNameList) {
final Rugged rugged = this.viewingModel.get(ruggedName);
if (rugged == null) {
throw new RuggedException(RuggedMessages.INVALID_RUGGED_NAME);
}
ruggedList.add(rugged);
selectedSensors.addAll(rugged.getLineSensors());
}
final LeastSquareAdjuster adjuster = new LeastSquareAdjuster(this.optimizerID);
LeastSquaresProblem theProblem = null;
// builder
switch (ruggedList.size()) {
case 1:
final Rugged rugged = ruggedList.get(0);
final GroundOptimizationProblemBuilder groundOptimizationProblem = new GroundOptimizationProblemBuilder(selectedSensors, measurements, rugged);
theProblem = groundOptimizationProblem.build(maxEvaluations, parametersConvergenceThreshold);
break;
case 2:
final InterSensorsOptimizationProblemBuilder interSensorsOptimizationProblem = new InterSensorsOptimizationProblemBuilder(selectedSensors, measurements, ruggedList);
theProblem = interSensorsOptimizationProblem.build(maxEvaluations, parametersConvergenceThreshold);
break;
default :
throw new RuggedException(RuggedMessages.UNSUPPORTED_REFINING_CONTEXT, ruggedList.size());
}
return adjuster.optimize(theProblem);
}
}
/* Copyright 2013-2022 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.rugged.adjustment;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hipparchus.analysis.differentiation.Gradient;
import org.hipparchus.linear.Array2DRowRealMatrix;
import org.hipparchus.linear.ArrayRealVector;
import org.hipparchus.linear.RealMatrix;
import org.hipparchus.linear.RealVector;
import org.hipparchus.optim.ConvergenceChecker;
import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresBuilder;
import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresProblem;
import org.hipparchus.optim.nonlinear.vector.leastsquares.MultivariateJacobianFunction;
import org.hipparchus.optim.nonlinear.vector.leastsquares.ParameterValidator;
import org.hipparchus.util.FastMath;
import org.hipparchus.util.Pair;
import org.orekit.bodies.GeodeticPoint;
import org.orekit.rugged.adjustment.measurements.Observables;
import org.orekit.rugged.adjustment.measurements.SensorToGroundMapping;
import org.orekit.rugged.api.Rugged;
import org.orekit.rugged.errors.RuggedException;
import org.orekit.rugged.errors.RuggedMessages;
import org.orekit.rugged.linesensor.LineSensor;
import org.orekit.rugged.linesensor.SensorPixel;
import org.orekit.utils.ParameterDriver;
/** Ground optimization problem builder.
* builds the optimization problem relying on ground measurements.
* @author Guylaine Prat
* @author Lucie Labat Allee
* @author Jonathan Guinet
* @author Luc Maisonobe
* @since 2.0
*/
public class GroundOptimizationProblemBuilder extends OptimizationProblemBuilder {
/** Key for target. */
private static final String TARGET = "Target";
/** Key for weight. */
private static final String WEIGHT = "Weight";
/** Rugged instance to refine.*/
private final Rugged rugged;
/** Sensor to ground mapping to generate target tab for optimization.*/
private List<SensorToGroundMapping> sensorToGroundMappings;
/** Minimum line for inverse location estimation.*/
private int minLine;
/** Maximum line for inverse location estimation.*/
private int maxLine;
/** Target and weight (the solution of the optimization problem).*/
private HashMap<String, double[] > targetAndWeight;
/** Build a new instance of the optimization problem.
* @param sensors list of sensors to refine
* @param measurements set of observables
* @param rugged name of rugged to refine
*/
public GroundOptimizationProblemBuilder(final List<LineSensor> sensors,
final Observables measurements, final Rugged rugged) {
super(sensors, measurements);
this.rugged = rugged;
this.initMapping();
}
/** {@inheritDoc} */
@Override
protected void initMapping() {
final String ruggedName = rugged.getName();
this.sensorToGroundMappings = new ArrayList<>();
for (final LineSensor lineSensor : this.getSensors()) {
final SensorToGroundMapping mapping = this.getMeasurements().getGroundMapping(ruggedName, lineSensor.getName());
if (mapping != null) {
this.sensorToGroundMappings.add(mapping);
}
}
}
/** {@inheritDoc} */
@Override
protected void createTargetAndWeight() {
int n = 0;
for (final SensorToGroundMapping reference : this.sensorToGroundMappings) {
n += reference.getMapping().size();
}
if (n == 0) {
throw new RuggedException(RuggedMessages.NO_REFERENCE_MAPPINGS);
}
final double[] target = new double[2 * n];
final double[] weight = new double[2 * n];
double min = Double.POSITIVE_INFINITY;
double max = Double.NEGATIVE_INFINITY;
int k = 0;
for (final SensorToGroundMapping reference : this.sensorToGroundMappings) {
for (final Map.Entry<SensorPixel, GeodeticPoint> mapping : reference.getMapping()) {
final SensorPixel sp = mapping.getKey();
weight[k] = 1.0;
target[k++] = sp.getLineNumber();
weight[k] = 1.0;
target[k++] = sp.getPixelNumber();
min = FastMath.min(min, sp.getLineNumber());
max = FastMath.max(max, sp.getLineNumber());
}
}
this.minLine = (int) FastMath.floor(min - ESTIMATION_LINE_RANGE_MARGIN);
this.maxLine = (int) FastMath.ceil(max - ESTIMATION_LINE_RANGE_MARGIN);
this.targetAndWeight = new HashMap<String, double[]>();
this.targetAndWeight.put(TARGET, target);
this.targetAndWeight.put(WEIGHT, weight);
}
/** {@inheritDoc} */
@Override
protected MultivariateJacobianFunction createFunction() {
// model function
final MultivariateJacobianFunction model = point -> {
// set the current parameters values
int i = 0;
for (final ParameterDriver driver : this.getDrivers()) {
driver.setNormalizedValue(point.getEntry(i++));
}
final double[] target = this.targetAndWeight.get(TARGET);
// compute inverse loc and its partial derivatives
final RealVector value = new ArrayRealVector(target.length);
final RealMatrix jacobian = new Array2DRowRealMatrix(target.length, this.getNbParams());
int l = 0;
for (final SensorToGroundMapping reference : this.sensorToGroundMappings) {
for (final Map.Entry<SensorPixel, GeodeticPoint> mapping : reference.getMapping()) {
final GeodeticPoint gp = mapping.getValue();
final Gradient[] ilResult = this.rugged.inverseLocationDerivatives(reference.getSensorName(), gp, minLine, maxLine, this.getGenerator());
if (ilResult == null) {
value.setEntry(l, minLine - 100.0); // arbitrary
// line far
// away
value.setEntry(l + 1, -100.0); // arbitrary
// pixel far away
} else {
// extract the value
value.setEntry(l, ilResult[0].getValue());
value.setEntry(l + 1, ilResult[1].getValue());
// extract the Jacobian
final int[] orders = new int[this.getNbParams()];
int m = 0;
for (final ParameterDriver driver : this.getDrivers()) {
final double scale = driver.getScale();
orders[m] = 1;
jacobian.setEntry(l, m,
ilResult[0]
.getPartialDerivative(orders) *
scale);
jacobian.setEntry(l + 1, m,
ilResult[1]
.getPartialDerivative(orders) *
scale);
orders[m] = 0;
m++;
}
}
l += 2;
}
}
// inverse loc result with Jacobian for all reference points
return new Pair<RealVector, RealMatrix>(value, jacobian);
};
return model;
}
/** Least square problem builder.
* @param maxEvaluations maxIterations and evaluations
* @param convergenceThreshold parameter convergence threshold
* @return the least square problem
*/
@Override
public final LeastSquaresProblem build(final int maxEvaluations, final double convergenceThreshold) {
this.createTargetAndWeight();
final double[] target = this.targetAndWeight.get(TARGET);
final double[] start = this.createStartTab();
final ParameterValidator validator = this.createParameterValidator();
final ConvergenceChecker<LeastSquaresProblem.Evaluation> checker = this.createChecker(convergenceThreshold);
final MultivariateJacobianFunction model = this.createFunction();
return new LeastSquaresBuilder()
.lazyEvaluation(false).maxIterations(maxEvaluations)
.maxEvaluations(maxEvaluations).weight(null).start(start)
.target(target).parameterValidator(validator).checker(checker)
.model(model).build();
}
}
/* Copyright 2013-2022 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.rugged.adjustment;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.hipparchus.analysis.differentiation.Gradient;
import org.hipparchus.linear.Array2DRowRealMatrix;
import org.hipparchus.linear.ArrayRealVector;
import org.hipparchus.linear.RealMatrix;
import org.hipparchus.linear.RealVector;
import org.hipparchus.optim.ConvergenceChecker;
import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresBuilder;
import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresProblem;
import org.hipparchus.optim.nonlinear.vector.leastsquares.MultivariateJacobianFunction;
import org.hipparchus.optim.nonlinear.vector.leastsquares.ParameterValidator;
import org.hipparchus.util.Pair;
import org.orekit.rugged.adjustment.measurements.Observables;
import org.orekit.rugged.adjustment.measurements.SensorToSensorMapping;
import org.orekit.rugged.api.Rugged;
import org.orekit.rugged.errors.RuggedException;
import org.orekit.rugged.errors.RuggedMessages;
import org.orekit.rugged.linesensor.LineSensor;
import org.orekit.rugged.linesensor.SensorPixel;
import org.orekit.rugged.utils.SpacecraftToObservedBody;
import org.orekit.time.AbsoluteDate;
import org.orekit.utils.ParameterDriver;
/** Constructs the optimization problem for a list of tie points.
* @author Guylaine Prat
* @author Lucie Labat Allee
* @author Jonathan Guinet
* @author Luc Maisonobe
* @since 2.0
*/
public class InterSensorsOptimizationProblemBuilder extends OptimizationProblemBuilder {
/** Key for target. */
private static final String TARGET = "Target";
/** Key for weight. */
private static final String WEIGHT = "Weight";
/** List of rugged instance to refine.*/
private Map<String, Rugged> ruggedMap;
/** Sensor to ground mapping to generate target tab for optimization.*/
private List<SensorToSensorMapping> sensorToSensorMappings;
/** Targets and weights of optimization problem. */
private HashMap<String, double[] > targetAndWeight;
/** Constructor.
* @param sensors list of sensors to refine
* @param measurements set of observables
* @param ruggedList names of rugged to refine
*/
public InterSensorsOptimizationProblemBuilder(final List<LineSensor> sensors,
final Observables measurements, final Collection<Rugged> ruggedList) {
super(sensors, measurements);
this.ruggedMap = new LinkedHashMap<String, Rugged>();
for (final Rugged rugged : ruggedList) {
this.ruggedMap.put(rugged.getName(), rugged);
}
this.initMapping();
}
/** {@inheritDoc} */
@Override
protected void initMapping() {
this.sensorToSensorMappings = new ArrayList<>();
for (final String ruggedNameA : this.ruggedMap.keySet()) {
for (final String ruggedNameB : this.ruggedMap.keySet()) {
for (final LineSensor sensorA : this.getSensors()) {
for (final LineSensor sensorB : this.getSensors()) {
final String sensorNameA = sensorA.getName();
final String sensorNameB = sensorB.getName();
final SensorToSensorMapping mapping = this.getMeasurements().getInterMapping(ruggedNameA, sensorNameA, ruggedNameB, sensorNameB);
if (mapping != null) {
this.sensorToSensorMappings.add(mapping);
}
}
}
}
}
}
/** {@inheritDoc} */
@Override
protected void createTargetAndWeight() {
int n = 0;
for (final SensorToSensorMapping reference : this.sensorToSensorMappings) {
n += reference.getMapping().size();
}
if (n == 0) {
throw new RuggedException(RuggedMessages.NO_REFERENCE_MAPPINGS);
}
n = 2 * n;
final double[] target = new double[n];
final double[] weight = new double[n];
int k = 0;
for (final SensorToSensorMapping reference : this.sensorToSensorMappings) {
// Get central body constraint weight
final double bodyConstraintWeight = reference.getBodyConstraintWeight();
int i = 0;
for (Iterator<Map.Entry<SensorPixel, SensorPixel>> gtIt = reference.getMapping().iterator(); gtIt.hasNext(); i++) {
if (i == reference.getMapping().size()) break;
// Get LOS distance
final Double losDistance = reference.getLosDistance(i);
weight[k] = 1.0 - bodyConstraintWeight;
target[k++] = losDistance.doubleValue();
// Get central body distance (constraint)
final Double bodyDistance = reference.getBodyDistance(i);
weight[k] = bodyConstraintWeight;
target[k++] = bodyDistance.doubleValue();
}
}
this.targetAndWeight = new HashMap<String, double[]>();
this.targetAndWeight.put(TARGET, target);
this.targetAndWeight.put(WEIGHT, weight);
}
/** {@inheritDoc} */
@Override
protected MultivariateJacobianFunction createFunction() {
// model function
final MultivariateJacobianFunction model = point -> {
// set the current parameters values
int i = 0;
for (final ParameterDriver driver : this.getDrivers()) {
driver.setNormalizedValue(point.getEntry(i++));
}
final double[] target = this.targetAndWeight.get(TARGET);
// compute distance and its partial derivatives
final RealVector value = new ArrayRealVector(target.length);
final RealMatrix jacobian = new Array2DRowRealMatrix(target.length, this.getNbParams());
int l = 0;
for (final SensorToSensorMapping reference : this.sensorToSensorMappings) {
final String ruggedNameA = reference.getRuggedNameA();
final String ruggedNameB = reference.getRuggedNameB();
final Rugged ruggedA = this.ruggedMap.get(ruggedNameA);
if (ruggedA == null) {
throw new RuggedException(RuggedMessages.INVALID_RUGGED_NAME);
}
final Rugged ruggedB = this.ruggedMap.get(ruggedNameB);
if (ruggedB == null) {
throw new RuggedException(RuggedMessages.INVALID_RUGGED_NAME);
}
for (final Map.Entry<SensorPixel, SensorPixel> mapping : reference.getMapping()) {
final SensorPixel spA = mapping.getKey();
final SensorPixel spB = mapping.getValue();
final LineSensor lineSensorB = ruggedB.getLineSensor(reference.getSensorNameB());
final LineSensor lineSensorA = ruggedA.getLineSensor(reference.getSensorNameA());
final AbsoluteDate dateA = lineSensorA.getDate(spA.getLineNumber());
final AbsoluteDate dateB = lineSensorB.getDate(spB.getLineNumber());
final double pixelA = spA.getPixelNumber();
final double pixelB = spB.getPixelNumber();
final SpacecraftToObservedBody scToBodyA = ruggedA.getScToBody();
final Gradient[] ilResult =
ruggedB.distanceBetweenLOSderivatives(lineSensorA, dateA, pixelA, scToBodyA,
lineSensorB, dateB, pixelB, this.getGenerator());
// extract the value
value.setEntry(l, ilResult[0].getValue());
value.setEntry(l + 1, ilResult[1].getValue());
// extract the Jacobian
final int[] orders = new int[this.getNbParams()];
int m = 0;
for (final ParameterDriver driver : this.getDrivers()) {
final double scale = driver.getScale();
orders[m] = 1;
jacobian.setEntry(l, m, ilResult[0].getPartialDerivative(orders) * scale);
jacobian.setEntry(l + 1, m, ilResult[1].getPartialDerivative(orders) * scale);
orders[m] = 0;
m++;
}
l += 2; // pass to the next evaluation
}
}
// distance result with Jacobian for all reference points
return new Pair<RealVector, RealMatrix>(value, jacobian);
};
return model;
}
/** Least square problem builder.
* @param maxEvaluations maxIterations and evaluations
* @param convergenceThreshold parameter convergence threshold
* @return the least square problem
*/
@Override
public final LeastSquaresProblem build(final int maxEvaluations, final double convergenceThreshold) {
this.createTargetAndWeight();
final double[] target = this.targetAndWeight.get(TARGET);
final double[] start = this.createStartTab();
final ParameterValidator validator = this.createParameterValidator();
final ConvergenceChecker<LeastSquaresProblem.Evaluation> checker = this.createChecker(convergenceThreshold);
final MultivariateJacobianFunction model = this.createFunction();
return new LeastSquaresBuilder()
.lazyEvaluation(false).maxIterations(maxEvaluations)
.maxEvaluations(maxEvaluations).weight(null).start(start)
.target(target).parameterValidator(validator).checker(checker)
.model(model).build();
}
}
/* Copyright 2013-2022 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.rugged.adjustment;
import org.hipparchus.linear.LUDecomposer;
import org.hipparchus.linear.QRDecomposer;
import org.hipparchus.optim.nonlinear.vector.leastsquares.GaussNewtonOptimizer;
import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresOptimizer;
import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresOptimizer.Optimum;
import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresProblem;
import org.hipparchus.optim.nonlinear.vector.leastsquares.LevenbergMarquardtOptimizer;
import org.orekit.rugged.errors.RuggedInternalError;
/** LeastSquareAdjuster
* Class for setting least square algorithm chosen for solving optimization problem.
* @author Jonathan Guinet
* @author Lucie Labat-Allee
* @author Guylaine Prat
* @since 2.0
*/
public class LeastSquareAdjuster {
/** Least square optimizer.*/
private final LeastSquaresOptimizer adjuster;
/** Least square optimizer choice.*/
private final OptimizerId optimizerID;
/** Constructor.
* @param optimizerID optimizer choice
*/
public LeastSquareAdjuster(final OptimizerId optimizerID) {
this.optimizerID = optimizerID;
this.adjuster = this.selectOptimizer();
}
/** Default constructor with Gauss Newton with QR decomposition algorithm.*/
public LeastSquareAdjuster() {
this.optimizerID = OptimizerId.GAUSS_NEWTON_QR;
this.adjuster = this.selectOptimizer();
}
/** Solve the least square problem.
* @param problem the least square problem
* @return the solution
*/
public Optimum optimize(final LeastSquaresProblem problem) {
return this.adjuster.optimize(problem);
}
/** Create the optimizer.
* @return the least square optimizer
*/
private LeastSquaresOptimizer selectOptimizer() {
// Set up the optimizer
switch (this.optimizerID) {
case LEVENBERG_MARQUADT:
return new LevenbergMarquardtOptimizer();
case GAUSS_NEWTON_LU :
return new GaussNewtonOptimizer(new LUDecomposer(1e-11), true);
case GAUSS_NEWTON_QR :
return new GaussNewtonOptimizer(new QRDecomposer(1e-11), false);
default :
// this should never happen
throw new RuggedInternalError(null);
}
}
}
/* Copyright 2013-2022 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.rugged.adjustment;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hipparchus.Field;
import org.hipparchus.analysis.differentiation.Gradient;
import org.hipparchus.analysis.differentiation.GradientField;
import org.hipparchus.optim.ConvergenceChecker;
import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresProblem;
import org.hipparchus.optim.nonlinear.vector.leastsquares.MultivariateJacobianFunction;
import org.hipparchus.optim.nonlinear.vector.leastsquares.ParameterValidator;
import org.orekit.rugged.adjustment.measurements.Observables;
import org.orekit.rugged.errors.RuggedException;
import org.orekit.rugged.errors.RuggedMessages;
import org.orekit.rugged.linesensor.LineSensor;
import org.orekit.rugged.utils.DerivativeGenerator;
import org.orekit.utils.ParameterDriver;
/**
* Builder for optimization problem.
* <p>
* Constructs the optimization problem defined by a set of measurement and sensors.
* </p>
* @author Jonathan Guinet
* @author Guylaine Prat
* @since 2.0
*/
abstract class OptimizationProblemBuilder {
/** Margin used in parameters estimation for the inverse location lines range. */
protected static final int ESTIMATION_LINE_RANGE_MARGIN = 100;
/** Gradient generator.*/
private final DerivativeGenerator<Gradient> generator;
/** Parameter drivers list. */
private final List<ParameterDriver> drivers;
/** Number of parameters to refine. */
private final int nbParams;
/** Measurements. */
private Observables measurements;
/** Sensors list. */
private final List<LineSensor> sensors;
/** Constructor.
* @param sensors list of sensors to refine
* @param measurements set of observables
*/
OptimizationProblemBuilder(final List<LineSensor> sensors, final Observables measurements) {
this.generator = this.createGenerator(sensors);
this.drivers = this.generator.getSelected();
this.nbParams = this.drivers.size();
if (this.nbParams == 0) {
throw new RuggedException(RuggedMessages.NO_PARAMETERS_SELECTED);
}
this.measurements = measurements;
this.sensors = sensors;
}
/** Least squares problem builder.
* @param maxEvaluations maximum number of evaluations
* @param convergenceThreshold convergence threshold
* @return the least squares problem
*/
public abstract LeastSquaresProblem build(int maxEvaluations, double convergenceThreshold);
/** Create the convergence check.
* <p>
* check LInf distance of parameters variation between previous and current iteration
* </p>
* @param parametersConvergenceThreshold convergence threshold
* @return the checker
*/
final ConvergenceChecker<LeastSquaresProblem.Evaluation>
createChecker(final double parametersConvergenceThreshold) {
final ConvergenceChecker<LeastSquaresProblem.Evaluation> checker = (iteration, previous, current)
-> current.getPoint().getLInfDistance(previous.getPoint()) <= parametersConvergenceThreshold;
return checker;
}
/** Create start points for optimization algorithm.
* @return start parameters values (normalized)
*/
final double[] createStartTab() {
// Get start points (as a normalized value)
final double[] start = new double[this.nbParams];
int iStart = 0;
for (final ParameterDriver driver : this.drivers) {
start[iStart++] = driver.getNormalizedValue();
}
return start;
}
/** Create targets and weights of optimization problem. */
protected abstract void createTargetAndWeight();
/** Create the model function value and its Jacobian.
* @return the model function value and its Jacobian
*/
protected abstract MultivariateJacobianFunction createFunction();
/** Parse the observables to select mapping .*/
protected abstract void initMapping();
/** Create parameter validator.
* @return parameter validator
*/
final ParameterValidator createParameterValidator() {
// Prevent parameters to exceed their prescribed bounds
final ParameterValidator validator = params -> {
int i = 0;
for (final ParameterDriver driver : this.drivers) {
// let the parameter handle min/max clipping
driver.setNormalizedValue(params.getEntry(i));
params.setEntry(i++, driver.getNormalizedValue());
}
return params;
};
return validator;
}
/** Create the generator for {@link Gradient} instances.
* @param selectedSensors list of sensors referencing the parameters drivers
* @return a new generator
*/
private DerivativeGenerator<Gradient> createGenerator(final List<LineSensor> selectedSensors) {
// Initialize set of drivers name
final Set<String> names = new HashSet<>();
// Get the drivers name
for (final LineSensor sensor : selectedSensors) {
// Get the drivers name for the sensor
sensor.getParametersDrivers().forEach(driver -> {
// Add the name of the driver to the set of drivers name
if (names.contains(driver.getName()) == false) {
names.add(driver.getName());
}
});
}
// Set up generator list and map
final List<ParameterDriver> selected = new ArrayList<>();
final Map<String, Integer> map = new HashMap<>();
// Get the list of selected drivers
for (final LineSensor sensor : selectedSensors) {
sensor.getParametersDrivers().filter(driver -> driver.isSelected()).forEach(driver -> {
if (map.get(driver.getName()) == null) {
map.put(driver.getName(), map.size());
selected.add(driver);
}
});
}
// gradient Generator
final GradientField field = GradientField.getField(map.size());
return new DerivativeGenerator<Gradient>() {
/** {@inheritDoc} */
@Override
public List<ParameterDriver> getSelected() {
return selected;
}
/** {@inheritDoc} */
@Override
public Gradient constant(final double value) {
return Gradient.constant(map.size(), value);
}
/** {@inheritDoc} */
@Override
public Gradient variable(final ParameterDriver driver) {
final Integer index = map.get(driver.getName());
if (index == null) {
return constant(driver.getValue());
} else {
return Gradient.variable(map.size(), index.intValue(), driver.getValue());
}
}
/** {@inheritDoc} */
@Override
public Field<Gradient> getField() {
return field;
}
};
}
/** Get the sensors list.
* @return the sensors list
*/
protected List<LineSensor> getSensors() {
return sensors;
}
/** Get the number of parameters to refine.
* @return the number of parameters to refine
*/
protected final int getNbParams() {
return this.nbParams;
}
/**
* Get the parameters drivers list.
* @return the selected list of parameters driver
*/
protected final List<ParameterDriver> getDrivers() {
return this.drivers;
}
/**
* Get the derivative structure generator.
* @return the derivative structure generator.
*/
protected final DerivativeGenerator<Gradient> getGenerator() {
return this.generator;
}
/** Get the measurements.
* @return the measurements
*/
protected Observables getMeasurements() {
return measurements;
}
}
/* Copyright 2013-2022 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.rugged.adjustment;
/** Enumerate for Optimizer used in Least square optimization.
* @author Jonathan Guinet
* @since 2.0
*/
public enum OptimizerId {
/** Levenberg Marquadt. */
LEVENBERG_MARQUADT,
/** Gauss Newton with LU decomposition. */
GAUSS_NEWTON_LU,
/** Gauss Newton with QR decomposition. */
GAUSS_NEWTON_QR
}
/* Copyright 2013-2022 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.rugged.adjustment.measurements;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
/** Class for measurements generation.
* @see SensorToSensorMapping
* @see SensorToGroundMapping
* @author Lucie Labat-Allee
* @author Guylaine Prat
* @since 2.0
*/
public class Observables {
/** Separator between Rugged name and sensor name. */
private static final String RUGGED_SENSOR_SEPARATOR = "_";
/** Separator between sensors. */
private static final String SENSORS_SEPARATOR = "__";
/** Sensor to ground mapping structure (example: for Ground Control Points GCP points).*/
private final Map<String, SensorToGroundMapping> groundMappings;
/** Sensor to sensor mappings structure (Tie points). */
private final Map<String, SensorToSensorMapping> interMappings;
/** Number of viewing models to map.*/
private final int nbModels;
/** Build a new instance.
* @param nbModels number of viewing models to map
*/
public Observables(final int nbModels) {
this.groundMappings = new LinkedHashMap<String, SensorToGroundMapping>();
this.interMappings = new LinkedHashMap<String, SensorToSensorMapping>();
this.nbModels = nbModels;
}
/** Add a mapping between two viewing models.
* @param interMapping sensor to sensor mapping
*/
public void addInterMapping(final SensorToSensorMapping interMapping) {
interMappings.put(this.createKey(interMapping), interMapping);
}
/** Add a ground mapping.
* <p>
* A ground mapping is defined by a set of GCPs.
* </p>
* @param groundMapping sensor to ground mapping
*/
public void addGroundMapping(final SensorToGroundMapping groundMapping) {
groundMappings.put(this.createKey(groundMapping), groundMapping);
}
/** Get all the ground mapping entries.
* @return an unmodifiable view of all mapping entries
*/
public Collection<SensorToGroundMapping> getGroundMappings() {
return groundMappings.values();
}
/**
* Get a ground Mapping for a sensor.
* @param ruggedName Rugged name
* @param sensorName sensor name
* @return selected ground mapping or null if sensor is not found
*/
public SensorToGroundMapping getGroundMapping(final String ruggedName, final String sensorName) {
final SensorToGroundMapping mapping = this.groundMappings.get(ruggedName + RUGGED_SENSOR_SEPARATOR + sensorName);
return mapping;
}
/** Get the sensor to sensor values.
* @return the inter-mappings
*/
public Collection<SensorToSensorMapping> getInterMappings() {
return interMappings.values();
}
/** Get the number of viewing models to map.
* @return the number of viewing models to map
*/
public int getNbModels() {
return nbModels;
}
/**
* Get a sensor mapping for a sensor.
* <p>
* returns sensor to sensor mapping associated with specific sensors and related rugged instance.
* </p>
* @param ruggedNameA Rugged name A
* @param sensorNameA sensor name A
* @param ruggedNameB Rugged name B
* @param sensorNameB sensor name B
* @return selected ground mapping or null if a sensor is not found
*/
public SensorToSensorMapping getInterMapping(final String ruggedNameA, final String sensorNameA,
final String ruggedNameB, final String sensorNameB) {
final String keyA = ruggedNameA + RUGGED_SENSOR_SEPARATOR + sensorNameA;
final String keyB = ruggedNameB + RUGGED_SENSOR_SEPARATOR + sensorNameB;
final SensorToSensorMapping mapping = interMappings.get(keyA + SENSORS_SEPARATOR + keyB);
return mapping;
}
/** Create key for SensorToGroundMapping map.
* @param groundMapping the ground mapping
* @return the key
*/
private String createKey(final SensorToGroundMapping groundMapping)
{
final String key = groundMapping.getRuggedName() + RUGGED_SENSOR_SEPARATOR + groundMapping.getSensorName();
return key;
}
/** Create key for SensorToSensorMapping map.
* @param sensorMapping the inter mapping
* @return the key
*/
private String createKey(final SensorToSensorMapping sensorMapping)
{
final String keyA = sensorMapping.getRuggedNameA() + RUGGED_SENSOR_SEPARATOR + sensorMapping.getSensorNameA();
final String keyB = sensorMapping.getRuggedNameB() + RUGGED_SENSOR_SEPARATOR + sensorMapping.getSensorNameB();
return keyA + SENSORS_SEPARATOR + keyB;
}
}
/* Copyright 2013-2022 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.rugged.adjustment.measurements;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.orekit.rugged.linesensor.SensorPixel;
/** Container for mapping sensor pixels with sensor pixels or ground points.
* @author Lucie Labat-Allee
* @author Guylaine Prat
* @since 2.0
*/
public class SensorMapping<T> {
/** Default name for Rugged. */
private static final String RUGGED = "Rugged";
/** Name of the sensor to which mapping applies. */
private final String sensorName;
/** Name of the Rugged to which mapping applies. */
private final String ruggedName;
/** Mapping from sensor to other (sensor or ground). */
private final Map<SensorPixel, T> mapping;
/** Build a new instance (with default Rugged name).
* @param sensorName name of the sensor to which mapping applies
*/
public SensorMapping(final String sensorName) {
this(sensorName, RUGGED);
}
/** Build a new instance with a specific Rugged name.
* @param sensorName name of the sensor to which mapping applies
* @param ruggedName name of the Rugged to which mapping applies
*/
public SensorMapping(final String sensorName, final String ruggedName) {
this.sensorName = sensorName;
this.ruggedName = ruggedName;
this.mapping = new LinkedHashMap<SensorPixel, T>();
}
/** Get the name of the sensor to which mapping applies.
* @return name of the sensor to which mapping applies
*/
public String getSensorName() {
return sensorName;
}
/** Get the name of the Rugged to which mapping applies.
* @return name of the Rugged to which mapping applies
*/
public String getRuggedName() {
return ruggedName;
}
/** Add a mapping between a sensor pixel and another point (sensor pixel or ground point).
* @param pixel sensor pixel
* @param point sensor pixel or ground point corresponding to the sensor pixel
*/
public void addMapping(final SensorPixel pixel, final T point) {
mapping.put(pixel, point);
}
/** Get all the mapping entries.
* @return an unmodifiable view of all mapping entries
*/
public Set<Map.Entry<SensorPixel, T>> getMapping() {
return Collections.unmodifiableSet(mapping.entrySet());
}
}
/* Copyright 2013-2016 CS Systèmes d'Information
* Licensed to CS Systèmes d'Information (CS) under one or more
/* Copyright 2013-2022 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
......@@ -14,10 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.rugged.api;
package org.orekit.rugged.adjustment.measurements;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
......@@ -25,27 +24,39 @@ import org.orekit.bodies.GeodeticPoint;
import org.orekit.rugged.linesensor.SensorPixel;
/** Container for mapping between sensor pixels and ground points.
* @see SensorMapping
* @author Luc Maisonobe
* @author Lucie Labat-Allee
* @author Guylaine Prat
* @since 2.0
*/
public class SensorToGroundMapping {
/** Default name for Rugged. */
private static final String RUGGED = "Rugged";
/** Name of the sensor to which mapping applies. */
private final String sensorName;
/** Mapping from sensor to ground. */
private final Map<SensorPixel, GeodeticPoint> sensorToGround;
private final SensorMapping<GeodeticPoint> groundMapping;
/** Mapping from ground to sensor. */
private final Map<GeodeticPoint, SensorPixel> groundToSensor;
/** Build a new instance.
/** Build a new instance (with default Rugged name).
* @param sensorName name of the sensor to which mapping applies
*/
public SensorToGroundMapping(final String sensorName) {
this(RUGGED, sensorName);
}
/** Build a new instance with a specific Rugged name.
* @param ruggedName name of the Rugged to which mapping applies
* @param sensorName name of the sensor to which mapping applies
*/
public SensorToGroundMapping(final String ruggedName, final String sensorName) {
this.sensorName = sensorName;
this.sensorToGround = new IdentityHashMap<>();
this.groundToSensor = new IdentityHashMap<>();
this.groundMapping = new SensorMapping<>(sensorName, ruggedName);
}
/** Get the name of the sensor to which mapping applies.
......@@ -55,42 +66,25 @@ public class SensorToGroundMapping {
return sensorName;
}
/** Get the name of the Rugged to which mapping applies.
* @return name of the Rugged to which mapping applies
*/
public String getRuggedName() {
return this.groundMapping.getRuggedName();
}
/** Add a mapping between one sensor pixel and one ground point.
* @param pixel sensor pixel
* @param groundPoint ground point corresponding to the sensor pixel
*/
public void addMapping(final SensorPixel pixel, final GeodeticPoint groundPoint) {
sensorToGround.put(pixel, groundPoint);
groundToSensor.put(groundPoint, pixel);
}
/** Get the ground point corresponding to a pixel.
* @param pixel sensor pixel (it must one of the instances
* passed to {@link #addMapping(SensorPixel, GeodeticPoint)},
* not a pixel at the same location)
* @return corresponding ground point, or null if the pixel was
* not passed to {@link #addMapping(SensorPixel, GeodeticPoint)}
*/
public GeodeticPoint getGroundPoint(final SensorPixel pixel) {
return sensorToGround.get(pixel);
}
/** Get the sensor pixel corresponding to a ground point.
* @param groundPoint ground point (it must one of the instances
* passed to {@link #addMapping(SensorPixel, GeodeticPoint)},
* not a ground point at the same location)
* @return corresponding sensor pixel, or null if the ground point
* was not passed to {@link #addMapping(SensorPixel, GeodeticPoint)}
*/
public SensorPixel getPixel(final GeodeticPoint groundPoint) {
return groundToSensor.get(groundPoint);
groundMapping.addMapping(pixel, groundPoint);
}
/** Get all the mapping entries.
* @return an unmodifiable view of all mapping entries
*/
public Set<Map.Entry<SensorPixel, GeodeticPoint>> getMappings() {
return Collections.unmodifiableSet(sensorToGround.entrySet());
public Set<Map.Entry<SensorPixel, GeodeticPoint>> getMapping() {
return Collections.unmodifiableSet(groundMapping.getMapping());
}
}
/* Copyright 2013-2022 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.rugged.adjustment.measurements;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.orekit.rugged.linesensor.SensorPixel;
/** Container for mapping sensors pixels of two viewing models.
* Store the distance between both lines of sight computed with
* {@link org.orekit.rugged.api.Rugged#distanceBetweenLOS(org.orekit.rugged.linesensor.LineSensor, org.orekit.time.AbsoluteDate, double, org.orekit.rugged.utils.SpacecraftToObservedBody, org.orekit.rugged.linesensor.LineSensor, org.orekit.time.AbsoluteDate, double)}
* <p> Constraints in relation to central body distance can be added.
* @see SensorMapping
* @author Lucie LabatAllee
* @author Guylaine Prat
* @since 2.0
*/
public class SensorToSensorMapping {
/** Default name for Rugged. */
private static final String RUGGED = "Rugged";
/** Name of the sensor B to which mapping applies. */
private final String sensorNameB;
/** Name of the Rugged B to which mapping applies. */
private final String ruggedNameB;
/** Mapping from sensor A to sensor B. */
private final SensorMapping<SensorPixel> interMapping;
/** Distances between two LOS. */
private final List<Double> losDistances;
/** Central body distances associated with pixel A. */
private final List<Double> bodyDistances;
/** Body constraint weight. */
private double bodyConstraintWeight;
/** Build a new instance without central body constraint (with default Rugged names).
* @param sensorNameA name of the sensor A to which mapping applies
* @param sensorNameB name of the sensor B to which mapping applies
*/
public SensorToSensorMapping(final String sensorNameA, final String sensorNameB) {
this(sensorNameA, RUGGED, sensorNameB, RUGGED, 0.0);
}
/** Build a new instance with central body constraint.
* @param sensorNameA name of the sensor A to which mapping applies
* @param ruggedNameA name of the Rugged A to which mapping applies
* @param sensorNameB name of the sensor B to which mapping applies
* @param ruggedNameB name of the Rugged B to which mapping applies
* @param bodyConstraintWeight weight given to the central body distance constraint
* with respect to the LOS distance (between 0 and 1).
* <br>Weighting will be applied as follow :
* <ul>
* <li>(1 - bodyConstraintWeight) for LOS distance weighting</li>
* <li>bodyConstraintWeight for central body distance weighting</li>
* </ul>
*/
public SensorToSensorMapping(final String sensorNameA, final String ruggedNameA,
final String sensorNameB, final String ruggedNameB,
final double bodyConstraintWeight) {
this.interMapping = new SensorMapping<>(sensorNameA, ruggedNameA);
this.sensorNameB = sensorNameB;
this.ruggedNameB = ruggedNameB;
this.losDistances = new ArrayList<>();
this.bodyDistances = new ArrayList<>();
this.bodyConstraintWeight = bodyConstraintWeight;
}
/** Build a new instance without central body constraints.
* @param sensorNameA name of the sensor A to which mapping applies
* @param ruggedNameA name of the Rugged A to which mapping applies
* @param sensorNameB name of the sensor B to which mapping applies
* @param ruggedNameB name of the Rugged B to which mapping applies
*/
public SensorToSensorMapping(final String sensorNameA, final String ruggedNameA,
final String sensorNameB, final String ruggedNameB) {
this(sensorNameA, ruggedNameA, sensorNameB, ruggedNameB, 0.0);
}
/** Build a new instance with central body constraints (with default Rugged names):
* we want to minimize the distance between pixel A and central body.
* @param sensorNameA name of the sensor A to which mapping applies
* @param sensorNameB name of the sensor B to which mapping applies
* @param bodyConstraintWeight weight given to the central body distance constraint
* with respect to the LOS distance (between 0 and 1).
* <br>Weighting will be applied as follow :
* <ul>
* <li>(1 - bodyConstraintWeight) for LOS distance weighting</li>
* <li>bodyConstraintWeight for central body distance weighting</li>
* </ul>
*/
public SensorToSensorMapping(final String sensorNameA, final String sensorNameB,
final double bodyConstraintWeight) {
this(sensorNameA, RUGGED, sensorNameB, RUGGED, bodyConstraintWeight);
}
/** Get the name of the sensor B to which mapping applies.
* @return name of the sensor B to which mapping applies
*/
public String getSensorNameB() {
return sensorNameB;
}
/** Get the name of the sensor A to which mapping applies.
* @return name of the sensor A to which mapping applies
*/
public String getSensorNameA() {
return interMapping.getSensorName();
}
/** Get the name of the Rugged B to which mapping applies.
* @return name of the Rugged B to which mapping applies
*/
public String getRuggedNameB() {
return ruggedNameB;
}
/** Get the name of the Rugged A to which mapping applies.
* @return name of the Rugged A to which mapping applies
*/
public String getRuggedNameA() {
return interMapping.getRuggedName();
}
/** Get all the inter-mapping entries.
* @return an unmodifiable view of all mapping entries
*/
public Set<Map.Entry<SensorPixel, SensorPixel>> getMapping() {
return interMapping.getMapping();
}
/** Get distances between lines of sight (from both view).
* @return the LOS distances
*/
public List<Double> getLosDistances() {
return losDistances;
}
/** Get distances between central body and pixel A (mapping with constraints).
* @return the central body distances
*/
public List<Double> getBodyDistances() {
return bodyDistances;
}
/** Get the weight given to the central body distance constraint with respect to the LOS distance.
* @return the central body constraint weight
*/
public double getBodyConstraintWeight() {
return bodyConstraintWeight;
}
/** Get distance between central body and pixel A, corresponding to the inter-mapping index.
* @param idx inter-mapping index
* @return the central body distances at index idx
*/
public Double getBodyDistance(final int idx) {
return getBodyDistances().get(idx);
}
/** Get distance between LOS, corresponding to the inter-mapping index.
* @param idx inter-mapping index
* @return the LOS distance at index idx
*/
public Double getLosDistance(final int idx) {
return getLosDistances().get(idx);
}
/** Add a mapping between two sensor pixels (A and B) and corresponding distance between the LOS.
* @param pixelA sensor pixel A
* @param pixelB sensor pixel B corresponding to the sensor pixel A (by direct then inverse location)
* @param losDistance distance between the two lines of sight
*/
public void addMapping(final SensorPixel pixelA, final SensorPixel pixelB, final Double losDistance) {
interMapping.addMapping(pixelA, pixelB);
losDistances.add(losDistance);
}
/** Add a mapping between two sensor pixels (A and B) and corresponding distance between the LOS
* and the central body distance constraint associated with pixel A.
* @param pixelA sensor pixel A
* @param pixelB sensor pixel B corresponding to the sensor pixel A (by direct then inverse location)
* @param losDistance distance between the two lines of sight
* @param bodyDistance elevation to central body
*/
public void addMapping(final SensorPixel pixelA, final SensorPixel pixelB,
final Double losDistance, final Double bodyDistance) {
interMapping.addMapping(pixelA, pixelB);
losDistances.add(losDistance);
bodyDistances.add(bodyDistance);
}
/** Set the central body constraint weight.
* @param bodyConstraintWeight the central body constraint weight to set
*/
public void setBodyConstraintWeight(final double bodyConstraintWeight) {
this.bodyConstraintWeight = bodyConstraintWeight;
}
}
/* Copyright 2013-2022 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* This package provides tools for measurements generation.
*
* @author Luc Maisonobe
* @author Guylaine Prat
* @author Jonathan Guinet
* @author Lucie Labat-Allee
*
*/
package org.orekit.rugged.adjustment.measurements;
/* Copyright 2013-2022 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* This package provides tools to deal with viewing model refining.
*
* @author Luc Maisonobe
* @author Guylaine Prat
* @author Jonathan Guinet
*
*/
package org.orekit.rugged.adjustment;
/* Copyright 2013-2016 CS Systèmes d'Information
* Licensed to CS Systèmes d'Information (CS) under one or more
/* Copyright 2013-2022 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
......
/* Copyright 2013-2016 CS Systèmes d'Information
* Licensed to CS Systèmes d'Information (CS) under one or more
/* Copyright 2013-2022 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
......