From e1a350d743bb80d3adc0c415fc19c9038fde60aa Mon Sep 17 00:00:00 2001
From: Jonathan Guinet <jonathan.guinet@c-s.fr>
Date: Wed, 22 Feb 2017 09:48:01 -0500
Subject: [PATCH] refactoring

---
 .../rugged/adjustment/AdjustmentContext.java  |  47 +--
 .../GroundOptimizationProblemBuilder.java     |  20 +-
 ...nterSensorsOptimizationProblemBuilder.java | 273 ++++++++++++++++++
 .../OptimizationProblemBuilder.java           |   5 +-
 .../java/org/orekit/rugged/api/Rugged.java    |   2 +-
 .../orekit/rugged/errors/RuggedMessages.java  |   3 +-
 .../generators/GroundMeasureGenerator.java    | 203 +++++++------
 .../generators/InterMeasureGenerator.java     | 200 +++++++------
 .../rugged/refining/measures/Observables.java |  78 +++--
 .../refining/measures/SensorMapping.java      |  25 +-
 .../measures/SensorToGroundMapping.java       |  23 +-
 .../measures/SensorToSensorMapping.java       |  95 ++++--
 .../java/AffinagePleiades/GroundRefining.java |   2 +-
 .../java/AffinagePleiades/InterRefining.java  | 260 +++++++++--------
 .../java/AffinagePleiades/Refining.java       |  49 ++--
 15 files changed, 873 insertions(+), 412 deletions(-)
 create mode 100644 src/main/java/org/orekit/rugged/adjustment/InterSensorsOptimizationProblemBuilder.java

diff --git a/src/main/java/org/orekit/rugged/adjustment/AdjustmentContext.java b/src/main/java/org/orekit/rugged/adjustment/AdjustmentContext.java
index 10deaa25..3ab99a86 100644
--- a/src/main/java/org/orekit/rugged/adjustment/AdjustmentContext.java
+++ b/src/main/java/org/orekit/rugged/adjustment/AdjustmentContext.java
@@ -18,11 +18,13 @@ 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.errors.OrekitException;
 import org.orekit.errors.OrekitExceptionWrapper;
 import org.orekit.rugged.api.Rugged;
@@ -55,7 +57,7 @@ public class AdjustmentContext {
      * @param viewingModel viewingModel
      * @param measures control and tie points
      */
-    public AdjustmentContext(final List<Rugged> viewingModel, final Observables measures) {
+    public AdjustmentContext(final Collection<Rugged> viewingModel, final Observables measures) {
         this.viewingModel = new HashMap<String, Rugged>();
         for (final Rugged r : viewingModel) {
             this.viewingModel.put(r.getName(), r);
@@ -110,9 +112,6 @@ public class AdjustmentContext {
      * already aware of the updated parameters.
      * </p>
      *
-     * @param references reference mappings between sensors pixels and ground
-     *        point that should ultimately be reached by adjusting selected
-     *        viewing models parameters
      * @param maxEvaluations maximum number of evaluations
      * @param parametersConvergenceThreshold convergence threshold on normalized
      *        parameters (dimensionless, related to parameters scales)
@@ -122,24 +121,40 @@ public class AdjustmentContext {
      *            if parameters cannot be estimated (too few measurements,
      *            ill-conditioned problem ...)
      */
-    public Optimum estimateFreeParameters(final String ruggedName, final int maxEvaluations, final double parametersConvergenceThreshold)
+    public Optimum estimateFreeParameters(final Collection<String> ruggedNameList, final int maxEvaluations, final double parametersConvergenceThreshold)
                     throws RuggedException {
         try {
 
-            final Rugged rugged = this.viewingModel.get(ruggedName);
-            if (rugged == null) {
-                throw new RuggedException(RuggedMessages.INVALID_RUGGED_NAME);
-            }
-
-            final List<LineSensor> selectedSensors = new ArrayList<LineSensor>(rugged.getLineSensors());
+            List<Rugged> ruggedList = new ArrayList<Rugged>();
+            List<LineSensor> selectedSensors = new ArrayList<LineSensor>();
+            for (String ruggedName : ruggedNameList){
+                final Rugged rugged = this.viewingModel.get(ruggedName);
+                if (rugged == null) {
+                    throw new RuggedException(RuggedMessages.INVALID_RUGGED_NAME);
+                }
 
-            /** builder */
-            final GroundOptimizationProblemBuilder optimizationProblem = new GroundOptimizationProblemBuilder(selectedSensors, measures, rugged);
+                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, measures, rugged);
+                    theProblem = groundOptimizationProblem.build(maxEvaluations, parametersConvergenceThreshold);
+                    break;
+                case 2:
+                    final InterSensorsOptimizationProblemBuilder interSensorsOptimizationProblem = new InterSensorsOptimizationProblemBuilder(selectedSensors, measures, ruggedList);
+                    theProblem = interSensorsOptimizationProblem.build(maxEvaluations, parametersConvergenceThreshold);
+                    break;
+                default :
+                    throw new RuggedException(RuggedMessages.UNSUPPORTED_REFINING_CONTEXT,ruggedList.size());
+            }
 
-            return adjuster.optimize(optimizationProblem.build(maxEvaluations, parametersConvergenceThreshold));
-
+            return adjuster.optimize(theProblem);
 
         } catch (RuggedExceptionWrapper rew) {
             throw rew.getException();
@@ -149,6 +164,4 @@ public class AdjustmentContext {
         }
     }
 
-    /*public Optimum estimateFreeParameters(final String RuggedNameA, final String RuggedNameB, final int maxEvaluations, final float parametersConvergenceThreshold)*/
-
 }
diff --git a/src/main/java/org/orekit/rugged/adjustment/GroundOptimizationProblemBuilder.java b/src/main/java/org/orekit/rugged/adjustment/GroundOptimizationProblemBuilder.java
index a116bd55..4b5d763c 100644
--- a/src/main/java/org/orekit/rugged/adjustment/GroundOptimizationProblemBuilder.java
+++ b/src/main/java/org/orekit/rugged/adjustment/GroundOptimizationProblemBuilder.java
@@ -47,6 +47,7 @@ extends OptimizationProblemBuilder {
     /** maximum line for inverse location estimation.*/
     private int maxLine;
 
+    /** target and weight (the solution of the optimization problem) */
     private HashMap<String, double[] > targetAndWeight;
 
     /**
@@ -60,14 +61,25 @@ extends OptimizationProblemBuilder {
                                                             throws RuggedException {
         super(sensors, measures);
         this.rugged = rugged;
+        this.initMapping();
+    }
+
+    /* (non-Javadoc)
+     * @see org.orekit.rugged.adjustment.OptimizationProblemBuilder#initMapping()
+     */
+    @Override
+    protected void initMapping()
+    {
+        final String ruggedName = rugged.getName();
         this.sensorToGroundMappings = new ArrayList<SensorToGroundMapping>();
-        for (Map.Entry<String, SensorToGroundMapping> entry : this.measures.getGroundMappings()) {
-            this.sensorToGroundMappings.add(entry.getValue());
+        for (final LineSensor lineSensor : sensors)
+        {
+            final SensorToGroundMapping mapping = this.measures.getGroundMapping(ruggedName, lineSensor.getName());
+            if(mapping != null)
+                this.sensorToGroundMappings.add(mapping);
         }
-
     }
 
-
     @Override
     protected void createTargetAndWeight()
                     throws RuggedException {
diff --git a/src/main/java/org/orekit/rugged/adjustment/InterSensorsOptimizationProblemBuilder.java b/src/main/java/org/orekit/rugged/adjustment/InterSensorsOptimizationProblemBuilder.java
new file mode 100644
index 00000000..bff043b0
--- /dev/null
+++ b/src/main/java/org/orekit/rugged/adjustment/InterSensorsOptimizationProblemBuilder.java
@@ -0,0 +1,273 @@
+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.DerivativeStructure;
+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.errors.OrekitException;
+import org.orekit.errors.OrekitExceptionWrapper;
+import org.orekit.rugged.api.Rugged;
+import org.orekit.rugged.errors.RuggedException;
+import org.orekit.rugged.errors.RuggedExceptionWrapper;
+import org.orekit.rugged.errors.RuggedMessages;
+import org.orekit.rugged.linesensor.LineSensor;
+import org.orekit.rugged.linesensor.SensorPixel;
+import org.orekit.rugged.refining.measures.Observables;
+import org.orekit.rugged.refining.measures.SensorToSensorMapping;
+import org.orekit.rugged.utils.SpacecraftToObservedBody;
+import org.orekit.time.AbsoluteDate;
+import org.orekit.utils.ParameterDriver;
+
+
+
+public class InterSensorsOptimizationProblemBuilder
+extends OptimizationProblemBuilder {
+
+    /** list of rugged instance to refine.*/
+    private Map<String, Rugged> ruggedMap;
+
+    /** sensorToGround mapping to generate target tab for optimization.*/
+    private List<SensorToSensorMapping> sensorToSensorMappings;
+
+
+    private HashMap<String, double[] > targetAndWeight;
+
+    /**
+     * @param sensors list of sensors to refine
+     * @param measures set of observables
+     * @param rugged name of rugged to refine
+     * @throws RuggedException an exception is generated if no parameters has been selected for refining
+     */
+    public InterSensorsOptimizationProblemBuilder(final List<LineSensor> sensors,
+                                                  final Observables measures, final Collection<Rugged> ruggedList)
+                                                                  throws RuggedException {
+        super(sensors, measures);
+
+        this.ruggedMap = new LinkedHashMap<String, Rugged>();
+
+        for(final Rugged rugged : ruggedList)
+        {
+            this.ruggedMap.put(rugged.getName(),rugged);
+        }
+        this.initMapping();
+    }
+
+    /* (non-Javadoc)
+     * @see org.orekit.rugged.adjustment.OptimizationProblemBuilder#initMapping()
+     */
+    @Override
+    protected void initMapping()
+    {
+        this.sensorToSensorMappings = new ArrayList<SensorToSensorMapping>();
+        for (final String ruggedNameA : this.ruggedMap.keySet()){
+            for (final String ruggedNameB : this.ruggedMap.keySet()){
+                for (final LineSensor sensorA : this.sensors){
+                    for (final LineSensor sensorB : this.sensors){
+                        final String sensorNameA = sensorA.getName();
+                        final String sensorNameB = sensorB.getName();
+                        final SensorToSensorMapping mapping = this.measures.getInterMapping(ruggedNameA, sensorNameA, ruggedNameB, sensorNameB);
+                        if (mapping != null)
+                        {
+
+                            this.sensorToSensorMappings.add(mapping);
+                        }
+                    }
+                }
+
+            }
+
+        }
+
+    }
+
+    @Override
+    protected void createTargetAndWeight()
+                    throws RuggedException {
+        try {
+            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 Earth constraint weight
+                final double earthConstraintWeight = reference.getEarthConstraintWeight();
+                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
+                    Double losDistance  = reference.getLosDistance(i);
+
+                    weight[k] = 1.0 - earthConstraintWeight;
+                    target[k++] = losDistance.doubleValue();
+
+                    // Get Earth distance (constraint)
+                    Double earthDistance  = reference.getEarthDistance(i);
+                    weight[k] = earthConstraintWeight;
+                    target[k++] = earthDistance.doubleValue();
+                }
+            }
+
+            this.targetAndWeight = new HashMap<String, double[]>();
+            this.targetAndWeight.put("Target", target);
+            this.targetAndWeight.put("Weight", weight);
+
+        } catch  (RuggedExceptionWrapper rew) {
+            throw rew.getException();
+        }
+    }
+
+    @Override
+    protected MultivariateJacobianFunction createFunction()
+    {
+        // model function
+        final MultivariateJacobianFunction model = point -> {
+
+            try {
+
+                // set the current parameters values
+                int i = 0;
+                for (final ParameterDriver driver : this.drivers.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.nbParams);
+
+                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();
+
+                        LineSensor lineSensorB = ruggedB.getLineSensor(reference.getSensorNameB());
+                        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 DerivativeStructure[] ilResult = ruggedB.distanceBetweenLOSDerivatives(lineSensorA,
+                                                                                                     dateA,
+                                                                                                     pixelA,
+                                                                                                     scToBodyA,
+                                                                                                     lineSensorB,
+                                                                                                     dateB,
+                                                                                                     pixelB,
+                                                                                                     generator);
+
+                        if (ilResult == null) {
+                            // TODO
+                        } 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.nbParams];
+                            int m = 0;
+
+                            for (final ParameterDriver driver : this.drivers.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);
+
+            } catch (RuggedException re) {
+                throw new RuggedExceptionWrapper(re);
+            } catch (OrekitException oe) {
+                throw new OrekitExceptionWrapper(oe);
+            }
+        };
+
+        return model;
+    }
+
+
+    /** leastsquare problem builder.
+     * @param maxEvaluations maxIterations and evaluations
+     * @param convergenceThreshold parameter convergence threshold
+     * @throws RuggedException if sensor is not found
+     * @return
+     */
+    @Override
+    public final LeastSquaresProblem build(final int maxEvaluations, final double convergenceThreshold) throws RuggedException {
+
+        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();
+    }
+
+}
diff --git a/src/main/java/org/orekit/rugged/adjustment/OptimizationProblemBuilder.java b/src/main/java/org/orekit/rugged/adjustment/OptimizationProblemBuilder.java
index bab37eff..7669c75d 100644
--- a/src/main/java/org/orekit/rugged/adjustment/OptimizationProblemBuilder.java
+++ b/src/main/java/org/orekit/rugged/adjustment/OptimizationProblemBuilder.java
@@ -57,6 +57,7 @@ abstract class OptimizationProblemBuilder {
     /** measures .*/
     protected Observables measures;
 
+    protected final List<LineSensor> sensors;
 
     /**  OptimizationProblemBuilder constructor
      * @param sensors
@@ -78,6 +79,7 @@ abstract class OptimizationProblemBuilder {
         }
 
         this.measures = measures;
+        this.sensors = sensors;
     }
 
     /**  nbParams getter.
@@ -151,7 +153,8 @@ abstract class OptimizationProblemBuilder {
 
     protected abstract MultivariateJacobianFunction createFunction();
 
-
+    /** parse the observables to select mapping .*/
+    protected abstract void initMapping();
 
     /**
      * create parameter validator.
diff --git a/src/main/java/org/orekit/rugged/api/Rugged.java b/src/main/java/org/orekit/rugged/api/Rugged.java
index df4fa506..019451c7 100644
--- a/src/main/java/org/orekit/rugged/api/Rugged.java
+++ b/src/main/java/org/orekit/rugged/api/Rugged.java
@@ -849,7 +849,7 @@ public class Rugged {
      * @see #distanceBetweenLOS(String, AbsoluteDate, int, String, AbsoluteDate,
      *      int)
      */
-    private DerivativeStructure[]
+    public DerivativeStructure[]
                     distanceBetweenLOSDerivatives(final LineSensor sensorA,
                                                   final AbsoluteDate dateA,
                                                   final double pixelA,
diff --git a/src/main/java/org/orekit/rugged/errors/RuggedMessages.java b/src/main/java/org/orekit/rugged/errors/RuggedMessages.java
index e4687f4f..10bf1b9a 100644
--- a/src/main/java/org/orekit/rugged/errors/RuggedMessages.java
+++ b/src/main/java/org/orekit/rugged/errors/RuggedMessages.java
@@ -80,7 +80,8 @@ public enum RuggedMessages implements Localizable {
     NO_PARAMETERS_SELECTED("no parameters have been selected for estimation"),
     NO_REFERENCE_MAPPINGS("no reference mappings for parameters estimation"),
     DUPLICATED_PARAMETER_NAME("a different parameter with name {0} already exists"),
-    INVALID_RUGGED_NAME("invalid rugged name.");
+    INVALID_RUGGED_NAME("invalid rugged name."),
+    UNSUPPORTED_REFINING_CONTEXT("refining using {0} rugged instance is not handled.");
 
     // CHECKSTYLE: resume JavadocVariable check
 
diff --git a/src/main/java/org/orekit/rugged/refining/generators/GroundMeasureGenerator.java b/src/main/java/org/orekit/rugged/refining/generators/GroundMeasureGenerator.java
index a673df2d..deef2691 100644
--- a/src/main/java/org/orekit/rugged/refining/generators/GroundMeasureGenerator.java
+++ b/src/main/java/org/orekit/rugged/refining/generators/GroundMeasureGenerator.java
@@ -16,23 +16,22 @@
  */
 package org.orekit.rugged.refining.generators;
 
+import org.hipparchus.geometry.euclidean.threed.Vector3D;
+import org.hipparchus.random.GaussianRandomGenerator;
+import org.hipparchus.random.UncorrelatedRandomVectorGenerator;
+import org.hipparchus.random.Well19937a;
+import org.hipparchus.util.FastMath;
 import org.orekit.bodies.GeodeticPoint;
 import org.orekit.rugged.api.Rugged;
 import org.orekit.rugged.errors.RuggedException;
 import org.orekit.rugged.linesensor.LineSensor;
 import org.orekit.rugged.linesensor.SensorPixel;
 import org.orekit.rugged.refining.measures.Noise;
+import org.orekit.rugged.refining.measures.Observables;
 import org.orekit.rugged.refining.measures.SensorToGroundMapping;
 import org.orekit.rugged.refining.metrics.DistanceTools;
-
 import org.orekit.time.AbsoluteDate;
 
-import org.hipparchus.geometry.euclidean.threed.Vector3D;
-import org.hipparchus.random.UncorrelatedRandomVectorGenerator;
-import org.hipparchus.random.GaussianRandomGenerator;
-import org.hipparchus.random.Well19937a;
-import org.hipparchus.util.FastMath;
-
 
 
 /** Ground measures generator (sensor to ground mapping).
@@ -45,14 +44,17 @@ public class GroundMeasureGenerator implements Measurable {
     /** mapping */
     private SensorToGroundMapping groundMapping;
 
+    /** observables which contains ground mapping.*/
+    private Observables observables;
+
     private Rugged rugged;
-    
+
     private LineSensor sensor;
 
     private int measureCount;
-    
+
     private int dimension;
-    
+
     /** Simple constructor.
      * <p>
      *
@@ -60,112 +62,129 @@ public class GroundMeasureGenerator implements Measurable {
      */
     public GroundMeasureGenerator(final Rugged rugged, final String sensorName, final int dimension) throws RuggedException
     {
-	
-    // generate reference mapping
-    groundMapping = new SensorToGroundMapping(sensorName);
-    this.rugged = rugged;
-    sensor = rugged.getLineSensor(groundMapping.getSensorName());
-    measureCount = 0;
-    this.dimension = dimension;
-    
+
+        // generate reference mapping
+        groundMapping = new SensorToGroundMapping(rugged.getName(), sensorName);
+
+        //create observables for one model
+        this.observables = new Observables(1);
+
+        this.rugged = rugged;
+        sensor = rugged.getLineSensor(groundMapping.getSensorName());
+        measureCount = 0;
+        this.dimension = dimension;
+
     }
 
     public SensorToGroundMapping getGroundMapping() {
-    	return groundMapping;
+        return groundMapping;
     }
 
+
+    /**  getter for observables.
+     * @return the observables
+     */
+    public Observables getObservables() {
+        return observables;
+    }
+
+    @Override
     public int  getMeasureCount() {
-    	return measureCount;
-    }    
+        return measureCount;
+    }
 
+    @Override
     public void createMeasure(final int lineSampling,final int pixelSampling)  throws RuggedException
     {
         for (double line = 0; line < dimension; line += lineSampling) {
 
-        	final AbsoluteDate date = sensor.getDate(line);
-        	for (int pixel = 0; pixel < sensor.getNbPixels(); pixel += pixelSampling) {
+            final AbsoluteDate date = sensor.getDate(line);
+            for (int pixel = 0; pixel < sensor.getNbPixels(); pixel += pixelSampling) {
 
-        		final GeodeticPoint gp2 = rugged.directLocation(date, sensor.getPosition(),
-                                                      sensor.getLOS(date, pixel));
+                final GeodeticPoint gp2 = rugged.directLocation(date, sensor.getPosition(),
+                                                                sensor.getLOS(date, pixel));
 
-        		groundMapping.addMapping(new SensorPixel(line, pixel), gp2);
-        		measureCount++;
-        	}
+                groundMapping.addMapping(new SensorPixel(line, pixel), gp2);
+                measureCount++;
+            }
         }
+        this.observables.addGroundMapping(groundMapping);
     }
+    @Override
     public void createNoisyMeasure(final int lineSampling,final int pixelSampling, final Noise noise)  throws RuggedException
     {
         /* Estimate latitude and longitude errors estimation */
-    	final Vector3D latLongError = estimateLatLongError();
-
-    	/* Get noise features */
-    	final double[] mean = noise.getMean(); /* [latitude, longitude, altitude] mean */
-    	final double[] std = noise.getStandardDeviation(); /* [latitude, longitude, altitude] standard deviation */
-
-    	final double latErrorMean = mean[0] * latLongError.getX(); // in line: -0.000002 deg
-    	final double lonErrorMean = mean[1] * latLongError.getY(); // in line: 0.000012 deg
-    	final double latErrorStd = std[0] * latLongError.getX(); // in line: -0.000002 deg
-    	final double lonErrorStd = std[1] * latLongError.getY(); // in line: 0.000012 deg
-
-    	// Gaussian random generator
-    	// Build a null mean random uncorrelated vector generator with standard deviation corresponding to the estimated error on ground
-    	final double meanGenerator[] =  {latErrorMean, lonErrorMean, mean[2]};
-    	final double stdGenerator[] = {latErrorStd, lonErrorStd, std[2]};
-    	System.out.format("Corresponding error estimation on ground {Latitude, Longitude, Altitude}:%n");
+        final Vector3D latLongError = estimateLatLongError();
+
+        /* Get noise features */
+        final double[] mean = noise.getMean(); /* [latitude, longitude, altitude] mean */
+        final double[] std = noise.getStandardDeviation(); /* [latitude, longitude, altitude] standard deviation */
+
+        final double latErrorMean = mean[0] * latLongError.getX(); // in line: -0.000002 deg
+        final double lonErrorMean = mean[1] * latLongError.getY(); // in line: 0.000012 deg
+        final double latErrorStd = std[0] * latLongError.getX(); // in line: -0.000002 deg
+        final double lonErrorStd = std[1] * latLongError.getY(); // in line: 0.000012 deg
+
+        // Gaussian random generator
+        // Build a null mean random uncorrelated vector generator with standard deviation corresponding to the estimated error on ground
+        final double meanGenerator[] =  {latErrorMean, lonErrorMean, mean[2]};
+        final double stdGenerator[] = {latErrorStd, lonErrorStd, std[2]};
+        System.out.format("Corresponding error estimation on ground {Latitude, Longitude, Altitude}:%n");
         System.out.format("\tMean: {%1.10f rad, %1.10f rad, %1.10f m} %n", meanGenerator[0], meanGenerator[1], meanGenerator[2]);
         System.out.format("\tStd : {%1.10f rad, %1.10f rad, %1.10f m} %n", stdGenerator[0], stdGenerator[1], stdGenerator[2]);
 
-    	final GaussianRandomGenerator rng = new GaussianRandomGenerator(new Well19937a(0xefac03d9be4d24b9l));
-    	final UncorrelatedRandomVectorGenerator rvg = new UncorrelatedRandomVectorGenerator(meanGenerator, stdGenerator, rng);
-        
-    	System.out.format("Add a gaussian noise to measures without biais (null mean) and standard deviation%n corresponding to the estimated error on ground.%n");
-    	for (double line = 0; line < dimension; line += lineSampling) {
-        	
-        	final AbsoluteDate date = sensor.getDate(line);
-        	for (int pixel = 0; pixel < sensor.getNbPixels(); pixel += pixelSampling) {
-
-        		// Components of generated vector follow (independent) Gaussian distribution
-            	final Vector3D vecRandom = new Vector3D(rvg.nextVector());
-            	
-        		final GeodeticPoint gp2 = rugged.directLocation(date, sensor.getPosition(),
-                                                      sensor.getLOS(date, pixel));
-        		          		
-        		
-        		final GeodeticPoint gpNoisy = new GeodeticPoint(gp2.getLatitude()+vecRandom.getX(), 
-                        gp2.getLongitude()+vecRandom.getY(),
-                        gp2.getAltitude()+vecRandom.getZ()); 
-
-        		//if(line == 0) {
-        		//	System.out.format("Init  gp: (%f,%d): %s %n",line,pixel,gp2.toString());
-        		//	System.out.format("Random:   (%f,%d): %s %n",line,pixel,vecRandom.toString());
-        		//	System.out.format("Final gp: (%f,%d): %s %n",line,pixel,gpNoisy.toString());
-        		//}
-   
-        		groundMapping.addMapping(new SensorPixel(line, pixel), gpNoisy);
-        		measureCount++;
-        	}
+        final GaussianRandomGenerator rng = new GaussianRandomGenerator(new Well19937a(0xefac03d9be4d24b9l));
+        final UncorrelatedRandomVectorGenerator rvg = new UncorrelatedRandomVectorGenerator(meanGenerator, stdGenerator, rng);
+
+        System.out.format("Add a gaussian noise to measures without biais (null mean) and standard deviation%n corresponding to the estimated error on ground.%n");
+        for (double line = 0; line < dimension; line += lineSampling) {
+
+            final AbsoluteDate date = sensor.getDate(line);
+            for (int pixel = 0; pixel < sensor.getNbPixels(); pixel += pixelSampling) {
+
+                // Components of generated vector follow (independent) Gaussian distribution
+                final Vector3D vecRandom = new Vector3D(rvg.nextVector());
+
+                final GeodeticPoint gp2 = rugged.directLocation(date, sensor.getPosition(),
+                                                                sensor.getLOS(date, pixel));
+
+
+                final GeodeticPoint gpNoisy = new GeodeticPoint(gp2.getLatitude()+vecRandom.getX(),
+                                                                gp2.getLongitude()+vecRandom.getY(),
+                                                                gp2.getAltitude()+vecRandom.getZ());
+
+                //if(line == 0) {
+                //	System.out.format("Init  gp: (%f,%d): %s %n",line,pixel,gp2.toString());
+                //	System.out.format("Random:   (%f,%d): %s %n",line,pixel,vecRandom.toString());
+                //	System.out.format("Final gp: (%f,%d): %s %n",line,pixel,gpNoisy.toString());
+                //}
+
+                groundMapping.addMapping(new SensorPixel(line, pixel), gpNoisy);
+                measureCount++;
+            }
         }
+        this.observables.addGroundMapping(groundMapping);
     }
     private Vector3D estimateLatLongError() throws RuggedException {
-    
-    	System.out.format("Uncertainty in pixel (in line) for a real geometric refining: 1 pixel (assumption)%n");
-    	final int pix =sensor.getNbPixels()/2;
-    	final int line= (int) FastMath.floor(pix); // assumption : same number of line and pixels;
-    	System.out.format("Pixel size estimated at position  pix: %d line: %d %n", pix, line);
-    	final AbsoluteDate date = sensor.getDate(line);
-    	final GeodeticPoint gp_pix0 = rugged.directLocation(date, sensor.getPosition(), sensor.getLOS(date, pix));
-    	final AbsoluteDate date1 = sensor.getDate(line+1);
-    	final GeodeticPoint gp_pix1 = rugged.directLocation(date1, sensor.getPosition(), sensor.getLOS(date1, pix+1));
-    	final double latErr = FastMath.abs(gp_pix0.getLatitude() - gp_pix1.getLatitude());
-    	final double lonErr = FastMath.abs(gp_pix0.getLongitude() - gp_pix1.getLongitude());
-    	//double dist = FastMath.sqrt(lonErr*lonErr + latErr*latErr)/FastMath.sqrt(2);
-    	final double distanceX =  DistanceTools.computeDistanceInMeter(gp_pix0.getLongitude(), gp_pix0.getLatitude(),gp_pix1.getLongitude(), gp_pix0.getLatitude());
-    	final double distanceY =  DistanceTools.computeDistanceInMeter(gp_pix0.getLongitude(), gp_pix0.getLatitude(),gp_pix0.getLongitude(), gp_pix1.getLatitude());
-    	
-    	System.out.format("Estimated distance: X %3.3f Y %3.3f %n",distanceX, distanceY);
-    	
-    	//System.out.format(" lat  : %1.10f %1.10f %n",  latErr, lonErr);
-    	return new Vector3D(latErr, lonErr, 0.0);
+
+        System.out.format("Uncertainty in pixel (in line) for a real geometric refining: 1 pixel (assumption)%n");
+        final int pix =sensor.getNbPixels()/2;
+        final int line= (int) FastMath.floor(pix); // assumption : same number of line and pixels;
+        System.out.format("Pixel size estimated at position  pix: %d line: %d %n", pix, line);
+        final AbsoluteDate date = sensor.getDate(line);
+        final GeodeticPoint gp_pix0 = rugged.directLocation(date, sensor.getPosition(), sensor.getLOS(date, pix));
+        final AbsoluteDate date1 = sensor.getDate(line+1);
+        final GeodeticPoint gp_pix1 = rugged.directLocation(date1, sensor.getPosition(), sensor.getLOS(date1, pix+1));
+        final double latErr = FastMath.abs(gp_pix0.getLatitude() - gp_pix1.getLatitude());
+        final double lonErr = FastMath.abs(gp_pix0.getLongitude() - gp_pix1.getLongitude());
+        //double dist = FastMath.sqrt(lonErr*lonErr + latErr*latErr)/FastMath.sqrt(2);
+        final double distanceX =  DistanceTools.computeDistanceInMeter(gp_pix0.getLongitude(), gp_pix0.getLatitude(),gp_pix1.getLongitude(), gp_pix0.getLatitude());
+        final double distanceY =  DistanceTools.computeDistanceInMeter(gp_pix0.getLongitude(), gp_pix0.getLatitude(),gp_pix0.getLongitude(), gp_pix1.getLatitude());
+
+        System.out.format("Estimated distance: X %3.3f Y %3.3f %n",distanceX, distanceY);
+
+        //System.out.format(" lat  : %1.10f %1.10f %n",  latErr, lonErr);
+        return new Vector3D(latErr, lonErr, 0.0);
     }
 }
 
diff --git a/src/main/java/org/orekit/rugged/refining/generators/InterMeasureGenerator.java b/src/main/java/org/orekit/rugged/refining/generators/InterMeasureGenerator.java
index f366c5eb..f6ee7b8c 100644
--- a/src/main/java/org/orekit/rugged/refining/generators/InterMeasureGenerator.java
+++ b/src/main/java/org/orekit/rugged/refining/generators/InterMeasureGenerator.java
@@ -13,6 +13,9 @@
  */
 package org.orekit.rugged.refining.generators;
 
+import org.hipparchus.random.GaussianRandomGenerator;
+import org.hipparchus.random.UncorrelatedRandomVectorGenerator;
+import org.hipparchus.random.Well19937a;
 import org.orekit.bodies.GeodeticPoint;
 import org.orekit.rugged.api.Rugged;
 import org.orekit.rugged.errors.RuggedException;
@@ -21,16 +24,12 @@ import org.orekit.rugged.errors.RuggedMessages;
 import org.orekit.rugged.linesensor.LineSensor;
 import org.orekit.rugged.linesensor.SensorPixel;
 import org.orekit.rugged.refining.measures.Noise;
+import org.orekit.rugged.refining.measures.Observables;
 import org.orekit.rugged.refining.measures.SensorToSensorMapping;
 import org.orekit.rugged.refining.metrics.DistanceTools;
 import org.orekit.rugged.utils.SpacecraftToObservedBody;
-
 import org.orekit.time.AbsoluteDate;
 
-import org.hipparchus.random.UncorrelatedRandomVectorGenerator;
-import org.hipparchus.random.GaussianRandomGenerator;
-import org.hipparchus.random.Well19937a;
-
 /**
  * Inter-measures generator (sensor to sensor mapping).
  * @author Jonathan Guinet
@@ -41,6 +40,9 @@ public class InterMeasureGenerator implements Measurable {
     /** mapping. */
     private SensorToSensorMapping interMapping;
 
+    /** observables which contains sensor to sensor mapping.*/
+    private Observables observables;
+
     private Rugged ruggedA;
 
     private Rugged ruggedB;
@@ -54,15 +56,15 @@ public class InterMeasureGenerator implements Measurable {
     private String sensorNameA;
 
     private String sensorNameB;
-    
+
     private int dimensionA;
-    
+
     private int dimensionB;
-    
+
     private double outlier=0.0;
-    
 
-    /** Default constructor: measures generation without outlier points control 
+
+    /** Default constructor: measures generation without outlier points control
      * and without Earth distance constraint.
      * @param viewingModelA
      * @param ruggedA
@@ -70,9 +72,9 @@ public class InterMeasureGenerator implements Measurable {
      * @param ruggedB
      * @throws RuggedException
      */
-    public InterMeasureGenerator(Rugged ruggedA, String sensorNameA, int dimensionA, 
+    public InterMeasureGenerator(Rugged ruggedA, String sensorNameA, int dimensionA,
                                  Rugged ruggedB, String sensorNameB, int dimensionB)
-        throws RuggedException {
+                                                 throws RuggedException {
 
         // Initialize parameters
         this.initParams(ruggedA, sensorNameA, dimensionA, ruggedB, sensorNameB, dimensionB);
@@ -80,11 +82,13 @@ public class InterMeasureGenerator implements Measurable {
         // generate reference mapping, without Earth distance constraint
         interMapping = new SensorToSensorMapping(sensorNameA, sensorNameB);
 
+        //create observables for two models
+        this.observables = new Observables(2);
     }
-    
-    
+
+
     /** Constructor for measures generation taking into account outlier points control,
-     * without Earth distance constraint. 
+     * without Earth distance constraint.
      * @param viewingModelA viewing model A
      * @param ruggedA Rugged instance corresponding to the viewing model A
      * @param viewingModelB viewing model B
@@ -92,143 +96,154 @@ public class InterMeasureGenerator implements Measurable {
      * @param outlier limit value of outlier points
      * @throws RuggedException
      */
-    public InterMeasureGenerator(Rugged ruggedA, String sensorNameA, int dimensionA, 
+    public InterMeasureGenerator(Rugged ruggedA, String sensorNameA, int dimensionA,
                                  Rugged ruggedB, String sensorNameB, int dimensionB, double outlier)
-        throws RuggedException {
+                                                 throws RuggedException {
 
         this(ruggedA, sensorNameA, dimensionA, ruggedB, sensorNameB, dimensionB);
         this.outlier = outlier;
 
     }
 
-    
+
     /** Constructor for measures generation taking into account outlier points control,
-     * and Earth distance constraint. 
+     * and Earth distance constraint.
      * @param viewingModelA viewing model A
      * @param ruggedA Rugged instance corresponding to the viewing model A
      * @param viewingModelB viewing model B
      * @param ruggedB Rugged instance corresponding to the viewing model B
      * @param outlier limit value of outlier points
-     * @param earthConstraintWeight weight given to the Earth distance constraint 
+     * @param earthConstraintWeight weight given to the Earth distance constraint
      * with respect to the LOS distance (between 0 and 1).
      * @throws RuggedException
      * @see Rugged#estimateFreeParams2Models
      */
-    public InterMeasureGenerator(Rugged ruggedA, String sensorNameA, int dimensionA, 
-                                 Rugged ruggedB, String sensorNameB, int dimensionB, 
+    public InterMeasureGenerator(Rugged ruggedA, String sensorNameA, int dimensionA,
+                                 Rugged ruggedB, String sensorNameB, int dimensionB,
                                  double outlier, final double earthConstraintWeight)
-        throws RuggedException {
+                                                 throws RuggedException {
 
-     // Initialize parameters
+        // Initialize parameters
         this.initParams(ruggedA, sensorNameA, dimensionA, ruggedB, sensorNameB, dimensionB);
 
         // generate reference mapping, with Earth distance constraints
         // Weighting will be applied as follow :
         // (1-earthConstraintWeight) for losDistance weighting
         // earthConstraintWeight for earthDistance weighting
-        interMapping = new SensorToSensorMapping(sensorNameA, sensorNameB, earthConstraintWeight);
+        interMapping = new SensorToSensorMapping(sensorNameA, ruggedA.getName(), sensorNameB, ruggedB.getName(), earthConstraintWeight);
 
         // outlier points control
         this.outlier = outlier;
 
+        this.observables = new Observables(2);
+
     }
 
     public SensorToSensorMapping getInterMapping() {
         return interMapping;
     }
 
+
+    /**  getter for observables.
+     * @return the observables
+     */
+    public Observables getObservables() {
+        return observables;
+    }
+
+    @Override
     public int getMeasureCount() {
         return measureCount;
     }
 
+    @Override
     public void createMeasure(final int lineSampling, final int pixelSampling) throws RuggedException {
-        // Get outlier
-        double outlier = this.outlier;
-                    
+
         // Search the sensor pixel seeing point
         final int minLine = 0;
         final int maxLine = dimensionB - 1;
-                    
+
         for (double line = 0; line < dimensionA; line += lineSampling) {
 
-            AbsoluteDate dateA = sensorA.getDate(line);
-            
+            final AbsoluteDate dateA = sensorA.getDate(line);
+
             for (double pixelA = 0; pixelA < sensorA.getNbPixels(); pixelA += pixelSampling) {
 
-                GeodeticPoint gpA = ruggedA.directLocation(dateA, sensorA.getPosition(),
-                                                           sensorA.getLOS(dateA, pixelA));
+                final GeodeticPoint gpA = ruggedA.directLocation(dateA, sensorA.getPosition(),
+                                                                 sensorA.getLOS(dateA, pixelA));
 
-                SensorPixel sensorPixelB = ruggedB.inverseLocation(sensorNameB, gpA, minLine, maxLine);
+                final SensorPixel sensorPixelB = ruggedB.inverseLocation(sensorNameB, gpA, minLine, maxLine);
                 // we need to test if the sensor pixel is found in the
                 // prescribed lines otherwise the sensor pixel is null
                 if (sensorPixelB != null) {
                     final AbsoluteDate dateB = sensorB.getDate(sensorPixelB.getLineNumber());
-                    double pixelB = sensorPixelB.getPixelNumber();
+                    final double pixelB = sensorPixelB.getPixelNumber();
                     final SpacecraftToObservedBody scToBodyA = ruggedA.getScToBody();
-                               
-                    GeodeticPoint gpB = ruggedB.directLocation(dateB, sensorB.getPosition(),
-                                                               sensorB.getLOS(dateB, pixelB));
-                                
-                    double GEOdistance = DistanceTools.computeDistanceInMeter(gpA.getLongitude(), gpA.getLatitude(),
-                                                                          gpB.getLongitude(), gpB.getLatitude());
 
-                    if(GEOdistance < outlier)
+                    final GeodeticPoint gpB = ruggedB.directLocation(dateB, sensorB.getPosition(),
+                                                                     sensorB.getLOS(dateB, pixelB));
+
+                    final double GEOdistance = DistanceTools.computeDistanceInMeter(gpA.getLongitude(), gpA.getLatitude(),
+                                                                                    gpB.getLongitude(), gpB.getLatitude());
+
+                    if (GEOdistance < this.outlier)
                     {
-                    /*System.out.format("A line %2.3f pixel %2.3f %n", line, pixelA);*/
-
-                    SensorPixel RealPixelA = new SensorPixel(line, pixelA);
-
-                    SensorPixel RealPixelB = new SensorPixel(sensorPixelB.getLineNumber(), 
-                                                             sensorPixelB.getPixelNumber());
-
-                    AbsoluteDate RealDateA = sensorA.getDate(RealPixelA.getLineNumber());
-                    AbsoluteDate RealDateB = sensorB.getDate(RealPixelB.getLineNumber());
-                    double[] distanceLOSB = ruggedB.distanceBetweenLOS(sensorA, RealDateA, RealPixelA.getPixelNumber(), scToBodyA,
-                                                                       sensorB, RealDateB, RealPixelB.getPixelNumber());
-                    
-                    final double losDistance = distanceLOSB[1];
-                    final double earthDistance = 0.0;
-                    
-                    interMapping.addMapping(RealPixelA, RealPixelB, losDistance, earthDistance);
-                    measureCount++;
+                        /*System.out.format("A line %2.3f pixel %2.3f %n", line, pixelA);*/
+
+                        final SensorPixel RealPixelA = new SensorPixel(line, pixelA);
+
+                        final SensorPixel RealPixelB = new SensorPixel(sensorPixelB.getLineNumber(),
+                                                                       sensorPixelB.getPixelNumber());
+
+                        final AbsoluteDate RealDateA = sensorA.getDate(RealPixelA.getLineNumber());
+                        final AbsoluteDate RealDateB = sensorB.getDate(RealPixelB.getLineNumber());
+                        final double[] distanceLOSB = ruggedB.distanceBetweenLOS(sensorA, RealDateA, RealPixelA.getPixelNumber(), scToBodyA,
+                                                                                 sensorB, RealDateB, RealPixelB.getPixelNumber());
+
+
+                        final double losDistance = 0.0;
+                        final double earthDistance = distanceLOSB[1];
+
+                        interMapping.addMapping(RealPixelA, RealPixelB, losDistance, earthDistance);
+                        measureCount++;
                     }
                     else
                     {
                         /*System.out.format("A line %2.3f pixel %2.3f %n rejected ", line, pixelA);*/
                     }
-                } 
+                }
             }
         }
+        this.observables.addInterMapping(interMapping);
     }
 
 
-    /**
-     * tie point creation from directLocation with RuggedA and inverse location
+    /** tie point creation from directLocation with RuggedA and inverse location.
      * with RuggedB
      * @param lineSampling sampling along lines
      * @param pixelSampling sampling along columns
      * @param noise error tabulation
      * @throws RuggedException
      */
+    @Override
     public void createNoisyMeasure(final int lineSampling, final int pixelSampling, final Noise noise)
-        throws RuggedException {
-        
+                    throws RuggedException {
+
         // Get outlier
         double outlier = this.outlier;
-        
+
         /* Get noise features (errors) */
         final double[] mean = noise.getMean(); /* [pixelA, pixelB] mean */
         final double[] std = noise.getStandardDeviation(); /* [pixelA, pixelB] standard deviation */
-        
-        
+
         // Search the sensor pixel seeing point
         final int minLine = 0;
         final int maxLine = dimensionB - 1;
-        
+
         double meanA[] =  {mean[0],mean[0]};
         double stdA[] = {std[0],std[0]};
         double meanB[] =  {mean[1],mean[1]};
-        double stdB[] = {std[1],std[1]};  
+        double stdB[] = {std[1],std[1]};
 
         GaussianRandomGenerator rngA = new GaussianRandomGenerator(new Well19937a(0xefac03d9be4d24b9l));
         UncorrelatedRandomVectorGenerator rvgA = new UncorrelatedRandomVectorGenerator(meanA, stdA, rngA);
@@ -240,20 +255,20 @@ public class InterMeasureGenerator implements Measurable {
 
             AbsoluteDate dateA = sensorA.getDate(line);
             for (double pixelA = 0; pixelA < sensorA
-                .getNbPixels(); pixelA += pixelSampling) {
+                            .getNbPixels(); pixelA += pixelSampling) {
 
                 GeodeticPoint gpA = ruggedA
-                    .directLocation(dateA, sensorA.getPosition(),
-                                    sensorA.getLOS(dateA, pixelA));
+                                .directLocation(dateA, sensorA.getPosition(),
+                                                sensorA.getLOS(dateA, pixelA));
 
                 SensorPixel sensorPixelB = ruggedB
-                    .inverseLocation(sensorNameB, gpA, minLine, maxLine);
+                                .inverseLocation(sensorNameB, gpA, minLine, maxLine);
                 // we need to test if the sensor pixel is found in the
                 // prescribed lines otherwise the sensor pixel is null
                 if (sensorPixelB != null) {
                     //System.out.format("  %n");
                     final AbsoluteDate dateB = sensorB
-                        .getDate(sensorPixelB.getLineNumber());
+                                    .getDate(sensorPixelB.getLineNumber());
                     double pixelB = sensorPixelB.getPixelNumber();
                     final SpacecraftToObservedBody scToBodyA = ruggedA
                                     .getScToBody();
@@ -271,17 +286,17 @@ public class InterMeasureGenerator implements Measurable {
                     double distanceLOSA = ruggedA
                                     .distanceBetweenLOS(sensorB, dateB, pixelB, scToBodyB,
                                                         sensorA, dateA, pixelA);*/
-                    
+
                     //System.out.format("distance LOS %1.8e %1.8e %n",distanceLOSB,distanceLOSA);
-                    
-                    
-                    
+
+
+
                     GeodeticPoint gpB = ruggedB
                                     .directLocation(dateB, sensorB.getPosition(),
                                                     sensorB.getLOS(dateB, pixelB));
-                    
+
                     double GEOdistance = DistanceTools.computeDistanceInMeter(gpA.getLongitude(), gpA.getLatitude(),
-                                                                gpB.getLongitude(), gpB.getLatitude());
+                                                                              gpB.getLongitude(), gpB.getLatitude());
 
                     if(GEOdistance < outlier)
                     {
@@ -295,9 +310,9 @@ public class InterMeasureGenerator implements Measurable {
                                                                  vecRandomA[0],
                                                                  pixelA + vecRandomA[1]);
                         SensorPixel RealPixelB = new SensorPixel(sensorPixelB
-                            .getLineNumber() + vecRandomB[0], sensorPixelB
-                                .getPixelNumber() + vecRandomB[1]);
-                         /*System.out.format("pix A %f %f Real %f %f %n", line,
+                                                                 .getLineNumber() + vecRandomB[0], sensorPixelB
+                                                                 .getPixelNumber() + vecRandomB[1]);
+                        /*System.out.format("pix A %f %f Real %f %f %n", line,
                          pixelA, RealPixelA.getLineNumber(),
                          RealPixelA.getPixelNumber());
                          System.out.format("pix B %f %f Real %f %f %n",
@@ -309,10 +324,10 @@ public class InterMeasureGenerator implements Measurable {
                         AbsoluteDate RealDateB = sensorB.getDate(RealPixelB.getLineNumber());
                         double[] distanceLOSB = ruggedB
                                         .distanceBetweenLOS(sensorA, RealDateA, RealPixelA.getPixelNumber(), scToBodyA,
-                                                            sensorB, RealDateB, RealPixelB.getPixelNumber());                        
+                                                            sensorB, RealDateB, RealPixelB.getPixelNumber());
                         final Double losDistance = 0.0;
                         final Double earthDistance = distanceLOSB[1];
-                        
+
                         interMapping.addMapping(RealPixelA, RealPixelB, losDistance, earthDistance);
                         measureCount++;
                     }
@@ -321,13 +336,14 @@ public class InterMeasureGenerator implements Measurable {
                         /*System.out.format("A line %2.3f pixel %2.3f %n rejected ", line,
                                           pixelA);*/
                     }
-                } 
+                }
 
             }
         }
+        this.observables.addInterMapping(interMapping);
     }
-    
-    /** Default constructor: measures generation without outlier points control 
+
+    /** Default constructor: measures generation without outlier points control
      * and Earth distances constraint.
      * @param viewingModelA
      * @param ruggedA
@@ -337,14 +353,14 @@ public class InterMeasureGenerator implements Measurable {
      */
     private void initParams(Rugged ruggedA, String sensorNameA, int dimensionA,
                             Rugged ruggedB, String sensorNameB, int dimensionB) throws RuggedException {
-        
+
         // generate reference mapping
         this.sensorNameA = sensorNameA;
         this.sensorNameB = sensorNameB;
         // check that sensors's name is different
         if (sensorNameA.contains(sensorNameB)) {
             throw new RuggedExceptionWrapper(new RuggedException(RuggedMessages.DUPLICATED_PARAMETER_NAME,
-                                                        sensorNameA));
+                                                                 sensorNameA));
         }
 
         this.ruggedA = ruggedA;
@@ -352,10 +368,10 @@ public class InterMeasureGenerator implements Measurable {
 
         sensorA = ruggedA.getLineSensor(sensorNameA);
         sensorB = ruggedB.getLineSensor(sensorNameB);
-        
+
         this.dimensionA = dimensionA;
         this.dimensionB = dimensionB;
-        
+
         measureCount = 0;
 
     }
diff --git a/src/main/java/org/orekit/rugged/refining/measures/Observables.java b/src/main/java/org/orekit/rugged/refining/measures/Observables.java
index 79bf1312..4e2318b4 100644
--- a/src/main/java/org/orekit/rugged/refining/measures/Observables.java
+++ b/src/main/java/org/orekit/rugged/refining/measures/Observables.java
@@ -16,15 +16,9 @@
  */
 package org.orekit.rugged.refining.measures;
 
-import java.util.ArrayList;
-import java.util.Collections;
+import java.util.Collection;
 import java.util.LinkedHashMap;
-import java.util.List;
 import java.util.Map;
-import java.util.Set;
-
-import org.orekit.rugged.errors.RuggedException;
-import org.orekit.rugged.errors.RuggedMessages;
 
 /** Class for measures generation.
  * @author Lucie Labat-Allee
@@ -38,7 +32,7 @@ public class Observables {
     private final Map<String, SensorToGroundMapping> groundMappings;
 
     /** Sensor to sensor mappings structure (liaison points). */
-    private final List<SensorToSensorMapping> interMappings;
+    private final Map<String, SensorToSensorMapping> interMappings;
 
     /** Number of viewing models to map */
     private final int nbModels;
@@ -50,7 +44,7 @@ public class Observables {
      */
     public Observables(final int nbModels) {
         this.groundMappings = new LinkedHashMap<String, SensorToGroundMapping>();
-        this.interMappings = new ArrayList<SensorToSensorMapping>();
+        this.interMappings = new LinkedHashMap<String, SensorToSensorMapping>();
         this.nbModels = nbModels;
     }
 
@@ -58,22 +52,23 @@ public class Observables {
      * @param SensorToSensorMapping sensor to sensor mapping
      */
     public void addInterMapping(final SensorToSensorMapping interMapping) {
-        interMappings.add(interMapping);
+        final String key = this.createKey(interMapping);
+        interMappings.put(this.createKey(interMapping),interMapping);
     }
 
     /** Add a  ground mapping between
      * @param SensorToGroundMapping sensor to ground mapping
      */
     public void addGroundMapping(final SensorToGroundMapping groundMapping) {
-        groundMappings.put(groundMapping.getSensorName(), groundMapping);
+        groundMappings.put(this.createKey(groundMapping), groundMapping);
     }
 
 
     /** Get all the ground mapping entries.
      * @return an unmodifiable view of all mapping entries
      */
-    public Set<Map.Entry<String, SensorToGroundMapping>> getGroundMappings() {
-        return  Collections.unmodifiableSet(groundMappings.entrySet());
+    public Collection<SensorToGroundMapping> getGroundMappings() {
+        return  groundMappings.values();
     }
 
 
@@ -81,26 +76,38 @@ public class Observables {
      * Get a ground Mapping for a sensor.
      *
      * @param sensorName sensor name
-     * @return selected ground mapping
-     * @exception RuggedException if sensor is not known
+     * @return selected ground mapping or null of sensorName is not found
      */
-    public SensorToGroundMapping getGroundMapping(final String sensorName)
-                    throws RuggedException {
-        final SensorToGroundMapping mapping = this.groundMappings.get(sensorName);
-        if (mapping == null) {
-            throw new RuggedException(RuggedMessages.UNKNOWN_SENSOR,
-                                      sensorName);
-        }
+    public SensorToGroundMapping getGroundMapping(final String ruggedName, final String sensorName) {
+        final SensorToGroundMapping mapping = this.groundMappings.get(ruggedName + "_" + sensorName);
         return mapping;
     }
 
     /**
      * @return the interMappings
      */
-    public List<SensorToSensorMapping> getInterMappings() {
-        return interMappings;
+    public Collection<SensorToSensorMapping> getInterMappings() {
+        return interMappings.values();
     }
 
+    /**
+     * Get a sensor  Mapping for a sensor.
+     *
+     * @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 of sensorName is not found
+     */
+    public SensorToSensorMapping getInterMapping(final String ruggedNameA, final String sensorNameA, final String ruggedNameB, final String sensorNameB) {
+
+        final String keyA = ruggedNameA + "_" + sensorNameA;
+        final String keyB = ruggedNameB + "_" + sensorNameB;
+        final SensorToSensorMapping mapping = this.interMappings.get(keyA + "__" + keyB);
+        return mapping;
+    }
+
+
     /**
      * @return the nbModels
      */
@@ -108,4 +115,27 @@ public class Observables {
         return nbModels;
     }
 
+
+    /** create key for GroudMapping map.
+     * @param groundMapping the groundMapping
+     * @return the key
+     */
+    private String createKey(final SensorToGroundMapping groundMapping)
+    {
+        final String key = groundMapping.getRuggedName() + "_" + groundMapping.getSensorName();
+        return key;
+    }
+
+    /** create key for SensorToSensorMapping map.
+     * @param groundMapping the groundMapping
+     * @return the key
+     */
+    private String createKey(final SensorToSensorMapping sensorMapping)
+    {
+        final String keyA = sensorMapping.getRuggedNameA() + "_" + sensorMapping.getSensorNameA();
+        final String keyB = sensorMapping.getRuggedNameB() + "_" + sensorMapping.getSensorNameB();
+        return keyA + "__" + keyB;
+    }
+
+
 }
diff --git a/src/main/java/org/orekit/rugged/refining/measures/SensorMapping.java b/src/main/java/org/orekit/rugged/refining/measures/SensorMapping.java
index 0784bc5d..b6d1d007 100644
--- a/src/main/java/org/orekit/rugged/refining/measures/SensorMapping.java
+++ b/src/main/java/org/orekit/rugged/refining/measures/SensorMapping.java
@@ -20,6 +20,7 @@ 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.
@@ -31,6 +32,10 @@ public class SensorMapping<T> {
     /** 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;
 
@@ -39,10 +44,20 @@ public class SensorMapping<T> {
      * @param sensorName name of the sensor to which mapping applies
      */
     public SensorMapping(final String sensorName) {
+        this(sensorName, "Rugged");
+    }
+
+    /** Build a new instance.
+     * @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.mapping = new LinkedHashMap<SensorPixel,T>();
+        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
      */
@@ -50,6 +65,14 @@ public class SensorMapping<T> {
         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 / ground point corresponding to the sensor pixel
diff --git a/src/main/java/org/orekit/rugged/refining/measures/SensorToGroundMapping.java b/src/main/java/org/orekit/rugged/refining/measures/SensorToGroundMapping.java
index 2fe172ed..f9410bc8 100644
--- a/src/main/java/org/orekit/rugged/refining/measures/SensorToGroundMapping.java
+++ b/src/main/java/org/orekit/rugged/refining/measures/SensorToGroundMapping.java
@@ -38,11 +38,20 @@ public class SensorToGroundMapping {
     private final SensorMapping<GeodeticPoint> groundMapping;
 
     /** Build a new instance.
+     * @param ruggedName name of the rugged to which mapping applies
      * @param sensorName name of the sensor to which mapping applies
      */
-    public SensorToGroundMapping(final String sensorName) {
+    public SensorToGroundMapping(final String ruggedName, final String sensorName) {
         this.sensorName     = sensorName;
-        this.groundMapping = new SensorMapping<GeodeticPoint>(sensorName);
+        this.groundMapping = new SensorMapping<GeodeticPoint>(sensorName, ruggedName);
+    }
+
+
+    /** Build a new instance.
+     * @param sensorName name of the sensor to which mapping applies
+     */
+    public SensorToGroundMapping(final String sensorName) {
+        this(sensorName, "Rugged");
     }
 
     /** Get the name of the sensor to which mapping applies.
@@ -52,6 +61,13 @@ 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
@@ -67,4 +83,7 @@ public class SensorToGroundMapping {
         return Collections.unmodifiableSet(groundMapping.getMapping());
     }
 
+
+    //public Boolean Match(final String SensorName,final String )
+
 }
diff --git a/src/main/java/org/orekit/rugged/refining/measures/SensorToSensorMapping.java b/src/main/java/org/orekit/rugged/refining/measures/SensorToSensorMapping.java
index 37b47a51..22d01216 100644
--- a/src/main/java/org/orekit/rugged/refining/measures/SensorToSensorMapping.java
+++ b/src/main/java/org/orekit/rugged/refining/measures/SensorToSensorMapping.java
@@ -21,12 +21,13 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.orekit.rugged.api.Rugged;
 import org.orekit.rugged.linesensor.SensorPixel;
 
-/** Container for mapping sensors pixels of two viewing models.  
+/** Container for mapping sensors pixels of two viewing models.
  * Store the distance between both lines of sight computed with @link {@link Rugged#distanceBetweenLOS(
  * String, org.orekit.time.AbsoluteDate, int, String, org.orekit.time.AbsoluteDate, int)}
- * Constraints in relation to Earth distance can be added. 
+ * Constraints in relation to Earth distance can be added.
  * @author Lucie LabatAllee
  * @see SensorMapping
  * @since 2.0
@@ -36,48 +37,68 @@ public class SensorToSensorMapping {
     /** 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;
 
     /** Distance between two LOS */
     private final List<Double> losDistances;
-    
+
     /** Earth distance associated with pixel A */
     private final List<Double> earthDistances;
-    
+
     /** Earth constraint weight */
     private double earthConstraintWeight;
-    
-    
+
+
     /** Build a new instance without Earth constraints
      * @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.interMapping = new SensorMapping<SensorPixel>(sensorNameA);
+        this(sensorNameA, "Rugged", sensorNameB, "Rugged", 0.0);
+    }
+
+    /** Build a new instance without Earth constraints
+     * @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 ruggedNameA , final String sensorNameB, final String ruggedNameB, final double constraintWeight) {
+        this.interMapping = new SensorMapping<SensorPixel>(sensorNameA, ruggedNameA);
         this.sensorNameB = sensorNameB;
+        this.ruggedNameB = ruggedNameB;
         this.losDistances = new ArrayList<Double>();
         this.earthDistances = new ArrayList<Double>();
-        this.earthConstraintWeight = 0.0;
-        
+        this.earthConstraintWeight = constraintWeight;
+
     }
 
-    
-    /** Build a new instance with Earth constraints: we want to minimize the distance between pixelA and Earth 
+    /** Build a new instance without Earth constraints
      * @param sensorNameA name of the sensor A to which mapping applies
      * @param sensorNameB name of the sensor B to which mapping applies
-     * @param constraintWeight weight given to the Earth distance constraint 
+     */
+    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 Earth constraints: we want to minimize the distance between pixelA and Earth
+     * @param sensorNameA name of the sensor A to which mapping applies
+     * @param sensorNameB name of the sensor B to which mapping applies
+     * @param constraintWeight weight given to the Earth distance constraint
      * with respect to the LOS distance (between 0 and 1). Weighting will be applied as follow :
      * (1-earthConstraintWeight) for losDistance weighting
      * earthConstraintWeight for earthDistance weighting
      */
-    public SensorToSensorMapping(final String sensorNameA, final String sensorNameB, 
+    public SensorToSensorMapping(final String sensorNameA, final String sensorNameB,
                                  final double constraintWeight) {
-        this(sensorNameA, sensorNameB);
-        this.earthConstraintWeight = constraintWeight;
+        this(sensorNameA, "Rugged", sensorNameB, "Rugged", constraintWeight);
     }
 
-    
+
     /** Get the name of the sensor B to which mapping applies.
      * @return name of the sensor B to which mapping applies
      */
@@ -91,22 +112,40 @@ public class SensorToSensorMapping {
     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 losDistances
      */
     public  List<Double> getLosDistances() {
         return losDistances;
-    } 
-    
+    }
+
 
     /** Get distances between Earth and pixel A (mapping with constraints)
      * @return the earthDistances
@@ -115,7 +154,7 @@ public class SensorToSensorMapping {
         return earthDistances;
     }
 
-    
+
     /** Get the weight given to the Earth distance constraint with respect to the LOS distance
      * @return the earthConstraintWeight
      */
@@ -123,7 +162,7 @@ public class SensorToSensorMapping {
         return earthConstraintWeight;
     }
 
-    
+
     /** Get distance between Earth and pixel A, corresponding to the inter mapping index
      * @param idx inter mapping index
      * @return the earthDistances
@@ -131,8 +170,8 @@ public class SensorToSensorMapping {
     public Double getEarthDistance(final int idx) {
         return getEarthDistances().get(idx);
     }
-    
-    
+
+
     /** Get distance between LOS, corresponding to the inter mapping index
      * @param idx inter mapping index
      * @return the losDistance
@@ -140,7 +179,7 @@ public class SensorToSensorMapping {
     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
@@ -153,19 +192,19 @@ public class SensorToSensorMapping {
     }
 
     /** Add a mapping between two sensor pixels (A and B) and corresponding distance between the LOS
-     *  and the earth distance constraint associated with pixel A 
+     *  and the earth distance constraint associated with pixel A
      * @param pixelA sensor pixel A
      * @param pixelB sensor pixel B corresponding to the sensor pixel A
      * @param losDistance distance between both line of sight
      * @param earthDistance distance between Earth and pixel A
      */
-    public void addMapping(final SensorPixel pixelA, final SensorPixel pixelB, 
+    public void addMapping(final SensorPixel pixelA, final SensorPixel pixelB,
                            final Double losDistance, final Double earthDistance) {
         interMapping.addMapping(pixelA, pixelB);
         losDistances.add(losDistance);
         earthDistances.add(earthDistance);
     }
-    
+
     /** Set the Earth constraint weight
      * @param earthConstraintWeight the Earth constraint weight to set
      */
diff --git a/src/tutorials/java/AffinagePleiades/GroundRefining.java b/src/tutorials/java/AffinagePleiades/GroundRefining.java
index 20c56158..f52dffb0 100644
--- a/src/tutorials/java/AffinagePleiades/GroundRefining.java
+++ b/src/tutorials/java/AffinagePleiades/GroundRefining.java
@@ -238,7 +238,7 @@ public class GroundRefining extends Refining {
             int maxIterations = 100;
             double convergenceThreshold =  1e-14;
 
-            refining.optimization(maxIterations, convergenceThreshold, measures.getGroundMapping(), refining.getRugged());
+            refining.optimization(maxIterations, convergenceThreshold, measures.getObservables(), refining.getRugged());
 
 
             // Check estimated values
diff --git a/src/tutorials/java/AffinagePleiades/InterRefining.java b/src/tutorials/java/AffinagePleiades/InterRefining.java
index 100f0364..2412255c 100644
--- a/src/tutorials/java/AffinagePleiades/InterRefining.java
+++ b/src/tutorials/java/AffinagePleiades/InterRefining.java
@@ -17,19 +17,20 @@
 package AffinagePleiades;
 
 
-import org.hipparchus.util.FastMath;
-import org.hipparchus.geometry.euclidean.threed.Vector3D;
 import java.io.File;
-import java.util.Locale;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
+import java.util.Locale;
 
+import org.hipparchus.geometry.euclidean.threed.Vector3D;
+import org.hipparchus.util.FastMath;
 import org.orekit.bodies.BodyShape;
 import org.orekit.bodies.GeodeticPoint;
 import org.orekit.data.DataProvidersManager;
 import org.orekit.data.DirectoryCrawler;
 import org.orekit.errors.OrekitException;
 import org.orekit.forces.gravity.potential.NormalizedSphericalHarmonicsProvider;
-
 import org.orekit.orbits.Orbit;
 import org.orekit.rugged.api.AlgorithmId;
 import org.orekit.rugged.api.BodyRotatingFrameId;
@@ -37,7 +38,6 @@ import org.orekit.rugged.api.EllipsoidId;
 import org.orekit.rugged.api.InertialFrameId;
 import org.orekit.rugged.api.Rugged;
 import org.orekit.rugged.api.RuggedBuilder;
-
 import org.orekit.rugged.errors.RuggedException;
 import org.orekit.rugged.linesensor.LineSensor;
 import org.orekit.rugged.refining.generators.GroundMeasureGenerator;
@@ -58,7 +58,7 @@ import org.orekit.utils.TimeStampedPVCoordinates;
 
 /**
  * Class for testing refining (liaison points study)
- * with or without noisy measurements 
+ * with or without noisy measurements
  * @author Jonathan Guinet
  * @author Lucie Labat-Allee
  * @see SensorToGroundMapping
@@ -68,54 +68,54 @@ public class InterRefining extends Refining {
 
     /** Pleiades viewing model A */
     PleiadesViewingModel pleiadesViewingModelA;
-    
+
     /** Pleiades viewing model B */
     PleiadesViewingModel pleiadesViewingModelB;
 
     /** Orbit model corresponding to viewing model A */
     OrbitModel orbitmodelA;
-    
+
     /** Orbit model corresponding to viewing model B */
     OrbitModel orbitmodelB;
-    
+
     /** Sensor name A corresponding to viewing model A */
     String sensorNameA;
-    
+
     /** Sensor name A corresponding to viewing model B */
     String sensorNameB;
-    
+
     /** RuggedA 's instance */
     Rugged ruggedA;
-    
+
     /** RuggedB 's instance */
     Rugged ruggedB;
 
     /** Inter-measurements (between both viewing models) */
     InterMeasureGenerator measures;
- 
-    
+
+
     /**
      * Constructor
      */
     public InterRefining() throws RuggedException, OrekitException {
-    
+
         sensorNameA = "SensorA";
         final double incidenceAngleA = -5.0;
         final String dateA = "2016-01-01T11:59:50.0";
-        
+
         pleiadesViewingModelA = new PleiadesViewingModel(sensorNameA, incidenceAngleA, dateA);
-       
+
         sensorNameB = "SensorB";
         final double incidenceAngleB = 0.0;
         final String dateB = "2016-01-01T12:02:50.0";
 
         pleiadesViewingModelB = new PleiadesViewingModel(sensorNameB, incidenceAngleB, dateB);
-        
+
         orbitmodelA =  new OrbitModel();
         orbitmodelB =  new OrbitModel();
     }
-    
-    
+
+
     /** Main functions
      * @param args
      */
@@ -129,71 +129,71 @@ public class InterRefining extends Refining {
             File orekitData = new File(home, "COTS/orekit-data");
             DataProvidersManager.getInstance().addProvider(new DirectoryCrawler(orekitData));
 
-            
+
             // Initialize refining context
             // ---------------------------
             InterRefining refining = new InterRefining();
 
-            
+
             // Sensors's definition: create 2 Pleiades viewing models
             // ------------------------------------------------------
             System.out.format("**** Build Pleiades viewing model A and its orbit definition **** %n");
-            
+
             // 1/- Create First Pleiades Viewing Model
             PleiadesViewingModel pleiadesViewingModelA = refining.getPleiadesViewingModelA();
             final AbsoluteDate minDateA =  pleiadesViewingModelA.getMinDate();
             final AbsoluteDate maxDateA =  pleiadesViewingModelA.getMaxDate();
             final AbsoluteDate refDateA = pleiadesViewingModelA.getDatationReference();
-            LineSensor lineSensorA =  pleiadesViewingModelA.getLineSensor(); 
-            System.out.format(Locale.US, "Viewing model A - date min: %s max: %s ref: %s %n", minDateA, maxDateA, refDateA);        
+            LineSensor lineSensorA =  pleiadesViewingModelA.getLineSensor();
+            System.out.format(Locale.US, "Viewing model A - date min: %s max: %s ref: %s %n", minDateA, maxDateA, refDateA);
 
             // ----Satellite position, velocity and attitude: create orbit model A
             OrbitModel orbitmodelA = refining.getOrbitmodelA();
             BodyShape earthA = orbitmodelA.createEarth();
             NormalizedSphericalHarmonicsProvider gravityFieldA = orbitmodelA.createGravityField();
             Orbit orbitA  = orbitmodelA.createOrbit(gravityFieldA.getMu(), refDateA);
-            
+
             // ----If no LOF Transform Attitude Provider is Nadir Pointing Yaw Compensation
             final double [] rollPoly = {0.0,0.0,0.0};
             double[] pitchPoly = {0.025,0.0};
             double[] yawPoly = {0.0,0.0,0.0};
             orbitmodelA.setLOFTransform(rollPoly, pitchPoly, yawPoly, minDateA);
-            
+
             // ----Satellite attitude
             List<TimeStampedAngularCoordinates> satelliteQListA = orbitmodelA.orbitToQ(orbitA, earthA, minDateA.shiftedBy(-0.0), maxDateA.shiftedBy(+0.0), 0.25);
             int nbQPoints = 2;
-            
+
             // ----Position and velocities
             PVCoordinates PVA = orbitA.getPVCoordinates(earthA.getBodyFrame());
             List<TimeStampedPVCoordinates> satellitePVListA = orbitmodelA.orbitToPV(orbitA, earthA, minDateA.shiftedBy(-0.0), maxDateA.shiftedBy(+0.0), 0.25);
             int nbPVPoints = 8;
-            
+
             // ----Convert frame and coordinates type in one call
             GeodeticPoint gpA = earthA.transform(PVA.getPosition(), earthA.getBodyFrame(), orbitA.getDate());
-            
+
             System.out.format(Locale.US, "(A) Geodetic Point at date %s : φ = %8.10f °, λ = %8.10f %n",
                               orbitA.getDate().toString(),
                               FastMath.toDegrees(gpA.getLatitude()),
-                              FastMath.toDegrees(gpA.getLongitude()));                       
-            
-            
+                              FastMath.toDegrees(gpA.getLongitude()));
+
+
             // Rugged A initialization
             // ---------------------
             System.out.format("**** Rugged A initialization **** %n");
             RuggedBuilder ruggedBuilderA = new RuggedBuilder();
-    
+
             ruggedBuilderA.addLineSensor(lineSensorA);
             ruggedBuilderA.setAlgorithm(AlgorithmId.IGNORE_DEM_USE_ELLIPSOID);
             ruggedBuilderA.setEllipsoid(EllipsoidId.WGS84, BodyRotatingFrameId.ITRF);
             ruggedBuilderA.setTimeSpan(minDateA,maxDateA, 0.001, 5.0).
-                    setTrajectory(InertialFrameId.EME2000, satellitePVListA, nbPVPoints, CartesianDerivativesFilter.USE_PV, 
-                                                           satelliteQListA, nbQPoints, AngularDerivativesFilter.USE_R)
-                    .setLightTimeCorrection(false)
-                    .setAberrationOfLightCorrection(false); 
-            
+            setTrajectory(InertialFrameId.EME2000, satellitePVListA, nbPVPoints, CartesianDerivativesFilter.USE_PV,
+                          satelliteQListA, nbQPoints, AngularDerivativesFilter.USE_R)
+            .setLightTimeCorrection(false)
+            .setAberrationOfLightCorrection(false);
+            ruggedBuilderA.setName("RuggedA");
             refining.setRuggedA(ruggedBuilderA.build());
 
-            
+
             System.out.format("\n**** Build Pleiades viewing model B and its orbit definition **** %n");
             // 2/- Create Second Pleiades Viewing Model
             PleiadesViewingModel pleiadesViewingModelB = refining.getPleiadesViewingModelB();
@@ -201,7 +201,7 @@ public class InterRefining extends Refining {
             final AbsoluteDate maxDateB =  pleiadesViewingModelB.getMaxDate();
             final AbsoluteDate refDateB = pleiadesViewingModelB.getDatationReference();
             LineSensor lineSensorB =  pleiadesViewingModelB.getLineSensor();
-            System.out.format(Locale.US, "Viewing model B - date min: %s max: %s ref: %s  %n", minDateB, maxDateB, refDateB);        
+            System.out.format(Locale.US, "Viewing model B - date min: %s max: %s ref: %s  %n", minDateB, maxDateB, refDateB);
 
             // ----Satellite position, velocity and attitude: create orbit model B
             OrbitModel orbitmodelB =  new OrbitModel();
@@ -209,49 +209,49 @@ public class InterRefining extends Refining {
             NormalizedSphericalHarmonicsProvider gravityFieldB = orbitmodelB.createGravityField();
             Orbit orbitB  = orbitmodelB.createOrbit(gravityFieldB.getMu(), refDateB);
             //orbitmodelB.setLOFTransform(rollPoly, pitchPoly, yawPoly, minDateB);
-            
+
             // ----Satellite attitude
             List<TimeStampedAngularCoordinates> satelliteQListB = orbitmodelB.orbitToQ(orbitB, earthB, minDateB.shiftedBy(-0.0), maxDateB.shiftedBy(+0.0), 0.25);
-            
+
             // ----Position and velocities
             PVCoordinates PVB = orbitB.getPVCoordinates(earthB.getBodyFrame());
             List<TimeStampedPVCoordinates> satellitePVListB = orbitmodelB.orbitToPV(orbitB, earthB, minDateB.shiftedBy(-0.0), maxDateB.shiftedBy(+0.0), 0.25);
             GeodeticPoint gpB = earthB.transform(PVB.getPosition(), earthB.getBodyFrame(), orbitB.getDate());
-            
+
             System.out.format(Locale.US, "(B) Geodetic Point at date %s : φ = %8.10f °, λ = %8.10f %n",orbitA.getDate().toString(),
                               FastMath.toDegrees(gpB.getLatitude()),
-                              FastMath.toDegrees(gpB.getLongitude()));                       
-            
+                              FastMath.toDegrees(gpB.getLongitude()));
+
 
             // Rugged B initialization
             // ---------------------
             System.out.format("**** Rugged B initialization **** %n");
             RuggedBuilder ruggedBuilderB = new RuggedBuilder();
-            
+
             ruggedBuilderB.addLineSensor(lineSensorB);
             ruggedBuilderB.setAlgorithm(AlgorithmId.IGNORE_DEM_USE_ELLIPSOID);
             ruggedBuilderB.setEllipsoid(EllipsoidId.WGS84, BodyRotatingFrameId.ITRF);
             ruggedBuilderB.setTimeSpan(minDateB,maxDateB, 0.001, 5.0).
-                    setTrajectory(InertialFrameId.EME2000, satellitePVListB, nbPVPoints, CartesianDerivativesFilter.USE_PV, 
-                                                           satelliteQListB, nbQPoints, AngularDerivativesFilter.USE_R)
-                    .setLightTimeCorrection(false)
-                    .setAberrationOfLightCorrection(false);                  
-            
+            setTrajectory(InertialFrameId.EME2000, satellitePVListB, nbPVPoints, CartesianDerivativesFilter.USE_PV,
+                          satelliteQListB, nbQPoints, AngularDerivativesFilter.USE_R)
+            .setLightTimeCorrection(false)
+            .setAberrationOfLightCorrection(false);
+            ruggedBuilderB.setName("RuggedB");
             refining.setRuggedB(ruggedBuilderB.build());
-          
-            
-            
+
+
+
             // Compute distance between LOS
             // -----------------------------
             double distance = refining.computeDistance(lineSensorA, lineSensorB);
             System.out.format("distance %f meters %n",distance);
-            
-            
-            // Initialize disruptions: 
+
+
+            // Initialize disruptions:
             // -----------------------
-            
+
             // Introduce rotations around instrument axes (roll and pitch translations, scale factor)
-            System.out.format("\n**** Add disruptions on both acquisitions (A,B): roll and pitch rotations, scale factor **** %n");       
+            System.out.format("\n**** Add disruptions on both acquisitions (A,B): roll and pitch rotations, scale factor **** %n");
             double rollValueA =  FastMath.toRadians(0.004);
             double pitchValueA = FastMath.toRadians(0.0008);
             double rollValueB =  FastMath.toRadians(-0.004);
@@ -259,23 +259,23 @@ public class InterRefining extends Refining {
             double factorValue = 1.0;
             System.out.format("Acquisition A roll: %3.5f \tpitch: %3.5f \tfactor: %3.5f \n",rollValueA,pitchValueA,factorValue);
             System.out.format("Acquisition B roll: %3.5f \tpitch: %3.5f \tfactor: %3.5f \n",rollValueB,pitchValueB,factorValue);
-                        
+
             // Apply disruptions on physical model (acquisition A)
             refining.applyDisruptions(refining.getRuggedA(),refining.getSensorNameA(),
                                       rollValueA, pitchValueA, factorValue);
-            
+
             // Apply disruptions on physical model (acquisition B)
             refining.applyDisruptions(refining.getRuggedB(),refining.getSensorNameB(),
                                       rollValueB, pitchValueB, factorValue);
-            
-            
-            
+
+
+
             // Generate measures (observations) from physical model disrupted
             // --------------------------------------------------------------
-            
+
             int lineSampling = 1000;
-            int pixelSampling = 1000;       
- 
+            int pixelSampling = 1000;
+
             // Noise definition
             final Noise noise = new Noise(0,2); /* distribution: gaussian(0), vector dimension:3 */
             final double[] mean = {5.0,0.0};    /* {pixelA mean, pixelB mean} */
@@ -286,54 +286,54 @@ public class InterRefining extends Refining {
             System.out.format("\tSensor A mean: %f std %f %n",mean[0],standardDeviation[0]);
             System.out.format("\tSensor B mean: %f std %f %n",mean[1],standardDeviation[1]);
 
-            InterMeasureGenerator measures = refining.generateNoisyPoints(lineSampling, pixelSampling, 
+            InterMeasureGenerator measures = refining.generateNoisyPoints(lineSampling, pixelSampling,
                                                                           refining.getRuggedA(), refining.getSensorNameA(),
                                                                           refining.getPleiadesViewingModelA().getDimension(),
                                                                           refining.getRuggedB(), refining.getSensorNameB(),
                                                                           refining.getPleiadesViewingModelB().getDimension(),
                                                                           noise);
-            
-//            // To test with measures without noise
-//            InterMeasureGenerator measures = refining.generatePoints(lineSampling, pixelSampling, 
-//                                                                     refining.getRuggedA(), refining.getSensorNameA(),
-//                                                                     refining.getPleiadesViewingModelA().getDimension(),
-//                                                                     refining.getRuggedB(), refining.getSensorNameB(),
-//                                                                     refining.getPleiadesViewingModelB().getDimension());
-            
+
+            //            // To test with measures without noise
+            //            InterMeasureGenerator measures = refining.generatePoints(lineSampling, pixelSampling,
+            //                                                                     refining.getRuggedA(), refining.getSensorNameA(),
+            //                                                                     refining.getPleiadesViewingModelA().getDimension(),
+            //                                                                     refining.getRuggedB(), refining.getSensorNameB(),
+            //                                                                     refining.getPleiadesViewingModelB().getDimension());
+
             refining.setMeasures(measures);
-            
-            
+
+
             // Compute ground truth residues
             // -----------------------------
             System.out.format("\n**** Ground truth residuals **** %n");
             refining.computeMetrics(measures.getInterMapping(), refining.getRuggedA(), refining.getRuggedB(), false);
-            
+
 
             // Initialize physical models without disruptions
             // -----------------------------------------------
             System.out.format("\n**** Initialize physical models (A,B) without disruptions: reset Roll/Pitch/Factor **** %n");
             refining.resetModel(refining.getRuggedA(), refining.getSensorNameA(), false);
             refining.resetModel(refining.getRuggedB(), refining.getSensorNameB(), false);
-            
-            
+
+
             // Compute initial residues
             // ------------------------
             System.out.format("\n**** Initial Residuals  **** %n");
             refining.computeMetrics(measures.getInterMapping(), refining.getRuggedA(), refining.getRuggedB(), false);
-            
-               
+
+
             // Start optimization
             // ------------------
             System.out.format("\n**** Start optimization  **** %n");
-            
+
             int maxIterations = 100;
             double convergenceThreshold =  1e-10;
-            
-            refining.optimization(maxIterations, convergenceThreshold, 
-                                  measures.getInterMapping(), 
-                                  refining.getRuggedA(), refining.getRuggedB());
-            
-            
+
+            refining.optimization(maxIterations, convergenceThreshold,
+                                  measures.getObservables(),
+                                  refining.getRuggeds());
+
+
             // Check estimated values
             // ----------------------
             System.out.format("\n**** Check parameters ajustement **** %n");
@@ -344,15 +344,15 @@ public class InterRefining extends Refining {
             refining.paramsEstimation(refining.getRuggedB(), refining.getSensorNameB(),
                                       rollValueB, pitchValueB, factorValue);
             //refining.paramsEstimation(rollValueA, pitchValueA, factorValue, rollValueB, pitchValueB);
-             
-            
+
+
             // Compute statistics
             // ------------------
             System.out.format("\n**** Compute Statistics **** %n");
             refining.computeMetrics(measures.getInterMapping(), refining.getRuggedA(), refining.getRuggedB(), false);
-            
-                         
-                 
+
+
+
         } catch (OrekitException oe) {
             System.err.println(oe.getLocalizedMessage());
             System.exit(1);
@@ -364,7 +364,7 @@ public class InterRefining extends Refining {
     }
 
 
-    
+
     /**
      * @return the pleiadesViewingModelA
      */
@@ -373,17 +373,17 @@ public class InterRefining extends Refining {
     }
 
 
-    
+
     /**
      * @param pleiadesViewingModelA the pleiadesViewingModelA to set
      */
     public void
-        setPleiadesViewingModelA(PleiadesViewingModel pleiadesViewingModelA) {
+    setPleiadesViewingModelA(PleiadesViewingModel pleiadesViewingModelA) {
         this.pleiadesViewingModelA = pleiadesViewingModelA;
     }
 
 
-    
+
     /**
      * @return the pleiadesViewingModelB
      */
@@ -392,17 +392,17 @@ public class InterRefining extends Refining {
     }
 
 
-    
+
     /**
      * @param pleiadesViewingModelB the pleiadesViewingModelB to set
      */
     public void
-        setPleiadesViewingModelB(PleiadesViewingModel pleiadesViewingModelB) {
+    setPleiadesViewingModelB(PleiadesViewingModel pleiadesViewingModelB) {
         this.pleiadesViewingModelB = pleiadesViewingModelB;
     }
 
 
-    
+
     /**
      * @return the orbitmodelA
      */
@@ -411,7 +411,7 @@ public class InterRefining extends Refining {
     }
 
 
-    
+
     /**
      * @param orbitmodelA the orbitmodelA to set
      */
@@ -420,7 +420,7 @@ public class InterRefining extends Refining {
     }
 
 
-    
+
     /**
      * @return the orbitmodelB
      */
@@ -429,7 +429,7 @@ public class InterRefining extends Refining {
     }
 
 
-    
+
     /**
      * @param orbitmodelB the orbitmodelB to set
      */
@@ -438,8 +438,8 @@ public class InterRefining extends Refining {
     }
 
 
-    
-    
+
+
     /**
      * @return the sensorNameA
      */
@@ -448,7 +448,7 @@ public class InterRefining extends Refining {
     }
 
 
-    
+
     /**
      * @return the sensorNameB
      */
@@ -465,7 +465,7 @@ public class InterRefining extends Refining {
     }
 
 
-    
+
     /**
      * @param ruggedA the ruggedA to set
      */
@@ -481,8 +481,16 @@ public class InterRefining extends Refining {
         return ruggedB;
     }
 
+    /**
+     * @return the ruggedList
+     */
+    public  Collection<Rugged> getRuggeds() {
+        List<Rugged> ruggedList = Arrays.asList(this.ruggedA, this.ruggedB);
+        return ruggedList;
+    }
+
+
 
-    
     /**
      * @param ruggedB the ruggedB to set
      */
@@ -505,47 +513,47 @@ public class InterRefining extends Refining {
      * @return GSD
      */
     private double computeDistance(final LineSensor lineSensorA, final LineSensor lineSensorB) throws RuggedException {
-        
+
         Vector3D positionA = lineSensorA.getPosition(); // This returns a zero vector since we set the relative position of the sensor w.r.T the satellite to 0.
-        
+
         AbsoluteDate lineDateA = lineSensorA.getDate(pleiadesViewingModelA.dimension/2);
         Vector3D losA = lineSensorA.getLOS(lineDateA,pleiadesViewingModelA.dimension/2);
         GeodeticPoint centerPointA = ruggedA.directLocation(lineDateA, positionA, losA);
         System.out.format(Locale.US, "\ncenter geodetic position A : φ = %8.10f °, λ = %8.10f °, h = %8.3f m%n",
                           FastMath.toDegrees(centerPointA.getLatitude()),
-                          FastMath.toDegrees(centerPointA.getLongitude()),centerPointA.getAltitude());      
-        
-        
+                          FastMath.toDegrees(centerPointA.getLongitude()),centerPointA.getAltitude());
+
+
         Vector3D positionB = lineSensorB.getPosition(); // This returns a zero vector since we set the relative position of the sensor w.r.T the satellite to 0.
-        
+
         AbsoluteDate lineDateB = lineSensorB.getDate(pleiadesViewingModelB.dimension/2);
         Vector3D losB = lineSensorB.getLOS(lineDateB,pleiadesViewingModelB.dimension/2);
         GeodeticPoint centerPointB = ruggedB.directLocation(lineDateB, positionB, losB);
         System.out.format(Locale.US, "center geodetic position B : φ = %8.10f °, λ = %8.10f °, h = %8.3f m%n",
                           FastMath.toDegrees(centerPointB.getLatitude()),
-                          FastMath.toDegrees(centerPointB.getLongitude()),centerPointB.getAltitude());      
-        
+                          FastMath.toDegrees(centerPointB.getLongitude()),centerPointB.getAltitude());
+
 
         lineDateB = lineSensorB.getDate(0);
         losB = lineSensorB.getLOS(lineDateB,0);
         GeodeticPoint firstPointB = ruggedB.directLocation(lineDateB, positionB, losB);
         System.out.format(Locale.US, "first geodetic position B : φ = %8.10f °, λ = %8.10f °, h = %8.3f m%n",
                           FastMath.toDegrees(firstPointB.getLatitude()),
-                          FastMath.toDegrees(firstPointB.getLongitude()),firstPointB.getAltitude());      
-        
+                          FastMath.toDegrees(firstPointB.getLongitude()),firstPointB.getAltitude());
+
         lineDateB = lineSensorB.getDate(pleiadesViewingModelB.dimension-1);
         losB = lineSensorB.getLOS(lineDateB,pleiadesViewingModelB.dimension-1);
         GeodeticPoint lastPointB = ruggedB.directLocation(lineDateB, positionB, losB);
         System.out.format(Locale.US, "last geodetic position  B : φ = %8.10f °, λ = %8.10f °, h = %8.3f m%n",
                           FastMath.toDegrees(lastPointB.getLatitude()),
-                          FastMath.toDegrees(lastPointB.getLongitude()),lastPointB.getAltitude());      
-        
+                          FastMath.toDegrees(lastPointB.getLongitude()),lastPointB.getAltitude());
+
         double distance = DistanceTools.computeDistanceInMeter(centerPointA.getLongitude(), centerPointA.getLatitude(),
-                                                           centerPointB.getLongitude(), centerPointB.getLatitude());
-        
+                                                               centerPointB.getLongitude(), centerPointB.getLatitude());
+
         return distance;
     }
- 
+
 
 
 
diff --git a/src/tutorials/java/AffinagePleiades/Refining.java b/src/tutorials/java/AffinagePleiades/Refining.java
index 7f93ae89..e7ede512 100644
--- a/src/tutorials/java/AffinagePleiades/Refining.java
+++ b/src/tutorials/java/AffinagePleiades/Refining.java
@@ -17,6 +17,7 @@
 package AffinagePleiades;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 
@@ -26,6 +27,7 @@ import org.orekit.errors.OrekitExceptionWrapper;
 import org.orekit.rugged.adjustment.AdjustmentContext;
 import org.orekit.rugged.api.Rugged;
 import org.orekit.rugged.errors.RuggedException;
+import org.orekit.rugged.errors.RuggedMessages;
 import org.orekit.rugged.refining.generators.GroundMeasureGenerator;
 import org.orekit.rugged.refining.generators.InterMeasureGenerator;
 import org.orekit.rugged.refining.measures.Noise;
@@ -316,24 +318,19 @@ public class Refining {
      * @throws RuggedException
      */
     public void optimization(int maxIterations, double convergenceThreshold,
-                             SensorToGroundMapping measures,
+                             Observables measures,
                              Rugged rugged) throws OrekitException, RuggedException {
 
 
-        System.out.format("Iterations max: %d\tconvergence threshold: %3.6e \n",maxIterations, convergenceThreshold);
-        List<Rugged> viewingModel = new ArrayList<Rugged>();
-        viewingModel.add(rugged);
+        System.out.format("Iterations max: %d\tconvergence threshold: %3.6e \n", maxIterations, convergenceThreshold);
 
-        Observables observables =  new  Observables(1);
-        observables.addGroundMapping(measures);
-
-        AdjustmentContext adjustmentContext = new AdjustmentContext(viewingModel, observables);
-        Optimum optimum = adjustmentContext.estimateFreeParameters("Rugged_refining",maxIterations,convergenceThreshold);
+        AdjustmentContext adjustmentContext = new AdjustmentContext(Collections.singletonList(rugged), measures);
+        Optimum optimum = adjustmentContext.estimateFreeParameters(Collections.singletonList(rugged.getName()), maxIterations, convergenceThreshold);
 
         // Print statistics
-        System.out.format("Max value: %3.6e %n",optimum.getResiduals().getMaxValue());
-        System.out.format("Optimization performed in %d iterations \n",optimum.getEvaluations());
-        System.out.format("RMSE: %f \n",optimum.getRMS());
+        System.out.format("Max value: %3.6e %n", optimum.getResiduals().getMaxValue());
+        System.out.format("Optimization performed in %d iterations \n", optimum.getEvaluations());
+        System.out.format("RMSE: %f \n", optimum.getRMS());
     }
 
 
@@ -347,22 +344,30 @@ public class Refining {
      * @throws RuggedException
      */
     public void optimization(int maxIterations, double convergenceThreshold,
-                             SensorToSensorMapping interMapping,
-                             Rugged ruggedA, Rugged ruggedB) throws OrekitException, RuggedException {
+                             Observables measures,
+                             Collection<Rugged> ruggeds) throws OrekitException, RuggedException {
+
+
+        System.out.format("Iterations max: %d\tconvergence threshold: %3.6e \n", maxIterations, convergenceThreshold);
+        if(ruggeds.size()!= 2 )
+        {
+            throw new RuggedException(RuggedMessages.UNSUPPORTED_REFINING_CONTEXT,ruggeds.size());
+        }
 
+        AdjustmentContext adjustmentContext = new AdjustmentContext(ruggeds, measures);
 
-        System.out.format("Iterations max: %d\tconvergence threshold: %3.6e \n",maxIterations, convergenceThreshold);
+        List<String> ruggedNameList = new ArrayList<String>();
+        for(Rugged rugged : ruggeds) {
+            ruggedNameList.add(rugged.getName());
+        }
 
-        // Note: estimateFreeParams2Models() is supposed to be applying on ruggedB, not on ruggedA (to be compliant with notations)
 
-        // Adapt parameters
-        Optimum optimum = ruggedB.estimateFreeParams2Models(Collections.singletonList(interMapping),
-                                                            maxIterations,convergenceThreshold, ruggedA);
+        Optimum optimum = adjustmentContext.estimateFreeParameters(ruggedNameList, maxIterations, convergenceThreshold);
 
         // Print statistics
-        System.out.format("Max value: %3.6e %n",optimum.getResiduals().getMaxValue());
-        System.out.format("Optimization performed in %d iterations \n",optimum.getEvaluations());
-        System.out.format("RMSE: %f \n",optimum.getRMS());
+        System.out.format("Max value: %3.6e %n", optimum.getResiduals().getMaxValue());
+        System.out.format("Optimization performed in %d iterations \n", optimum.getEvaluations());
+        System.out.format("RMSE: %f \n", optimum.getRMS());
     }
 
 
-- 
GitLab