AbstractKalmanModel.java

  1. /* Copyright 2002-2022 CS GROUP
  2.  * Licensed to CS GROUP (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.orekit.estimation.sequential;

  18. import java.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.Comparator;
  21. import java.util.HashMap;
  22. import java.util.List;
  23. import java.util.Map;

  24. import org.hipparchus.filtering.kalman.ProcessEstimate;
  25. import org.hipparchus.filtering.kalman.extended.NonLinearEvolution;
  26. import org.hipparchus.filtering.kalman.extended.NonLinearProcess;
  27. import org.hipparchus.linear.Array2DRowRealMatrix;
  28. import org.hipparchus.linear.ArrayRealVector;
  29. import org.hipparchus.linear.MatrixUtils;
  30. import org.hipparchus.linear.RealMatrix;
  31. import org.hipparchus.linear.RealVector;
  32. import org.orekit.estimation.measurements.EstimatedMeasurement;
  33. import org.orekit.estimation.measurements.ObservedMeasurement;
  34. import org.orekit.orbits.Orbit;
  35. import org.orekit.propagation.MatricesHarvester;
  36. import org.orekit.propagation.PropagationType;
  37. import org.orekit.propagation.Propagator;
  38. import org.orekit.propagation.SpacecraftState;
  39. import org.orekit.propagation.conversion.OrbitDeterminationPropagatorBuilder;
  40. import org.orekit.propagation.integration.AbstractJacobiansMapper;
  41. import org.orekit.time.AbsoluteDate;
  42. import org.orekit.utils.ParameterDriver;
  43. import org.orekit.utils.ParameterDriversList;
  44. import org.orekit.utils.ParameterDriversList.DelegatingDriver;

  45. /** Abstract class defining the process model dynamics to use with a {@link KalmanEstimator}.
  46.  * @author Romain Gerbaud
  47.  * @author Maxime Journot
  48.  * @author Bryan Cazabonne
  49.  * @author Thomas Paulet
  50.  * @since 11.0
  51.  */
  52. public abstract class AbstractKalmanModel implements KalmanEstimation, NonLinearProcess<MeasurementDecorator> {

  53.     /** Builders for propagators. */
  54.     private final List<OrbitDeterminationPropagatorBuilder> builders;

  55.     /** Estimated orbital parameters. */
  56.     private final ParameterDriversList allEstimatedOrbitalParameters;

  57.     /** Estimated propagation drivers. */
  58.     private final ParameterDriversList allEstimatedPropagationParameters;

  59.     /** Per-builder estimated orbita parameters drivers.
  60.      * @since 11.1
  61.      */
  62.     private final ParameterDriversList[] estimatedOrbitalParameters;

  63.     /** Per-builder estimated propagation drivers. */
  64.     private final ParameterDriversList[] estimatedPropagationParameters;

  65.     /** Estimated measurements parameters. */
  66.     private final ParameterDriversList estimatedMeasurementsParameters;

  67.     /** Start columns for each estimated orbit. */
  68.     private final int[] orbitsStartColumns;

  69.     /** End columns for each estimated orbit. */
  70.     private final int[] orbitsEndColumns;

  71.     /** Map for propagation parameters columns. */
  72.     private final Map<String, Integer> propagationParameterColumns;

  73.     /** Map for measurements parameters columns. */
  74.     private final Map<String, Integer> measurementParameterColumns;

  75.     /** Providers for covariance matrices. */
  76.     private final List<CovarianceMatrixProvider> covarianceMatricesProviders;

  77.     /** Process noise matrix provider for measurement parameters. */
  78.     private final CovarianceMatrixProvider measurementProcessNoiseMatrix;

  79.     /** Indirection arrays to extract the noise components for estimated parameters. */
  80.     private final int[][] covarianceIndirection;

  81.     /** Scaling factors. */
  82.     private final double[] scale;

  83.     /** Harvesters for extracting Jacobians from integrated states. */
  84.     private MatricesHarvester[] harvesters;

  85.     /** Propagators for the reference trajectories, up to current date. */
  86.     private Propagator[] referenceTrajectories;

  87.     /** Current corrected estimate. */
  88.     private ProcessEstimate correctedEstimate;

  89.     /** Current number of measurement. */
  90.     private int currentMeasurementNumber;

  91.     /** Reference date. */
  92.     private AbsoluteDate referenceDate;

  93.     /** Current date. */
  94.     private AbsoluteDate currentDate;

  95.     /** Predicted spacecraft states. */
  96.     private SpacecraftState[] predictedSpacecraftStates;

  97.     /** Corrected spacecraft states. */
  98.     private SpacecraftState[] correctedSpacecraftStates;

  99.     /** Predicted measurement. */
  100.     private EstimatedMeasurement<?> predictedMeasurement;

  101.     /** Corrected measurement. */
  102.     private EstimatedMeasurement<?> correctedMeasurement;

  103.     /** Type of the orbit used for the propagation.*/
  104.     private PropagationType propagationType;

  105.     /** Type of the elements used to define the orbital state.*/
  106.     private PropagationType stateType;

  107.     /** Kalman process model constructor (package private).
  108.      * This constructor is used whenever state type and propagation type do not matter.
  109.      * It is used for {@link KalmanModel} and {@link TLEKalmanModel}.
  110.      * @param propagatorBuilders propagators builders used to evaluate the orbits.
  111.      * @param covarianceMatricesProviders providers for covariance matrices
  112.      * @param estimatedMeasurementParameters measurement parameters to estimate
  113.      * @param measurementProcessNoiseMatrix provider for measurement process noise matrix
  114.      * @param harvesters harvesters for extracting Jacobians from integrated states
  115.      */
  116.     protected AbstractKalmanModel(final List<OrbitDeterminationPropagatorBuilder> propagatorBuilders,
  117.                                   final List<CovarianceMatrixProvider> covarianceMatricesProviders,
  118.                                   final ParameterDriversList estimatedMeasurementParameters,
  119.                                   final CovarianceMatrixProvider measurementProcessNoiseMatrix,
  120.                                   final MatricesHarvester[] harvesters) {
  121.         this(propagatorBuilders, covarianceMatricesProviders, estimatedMeasurementParameters,
  122.              measurementProcessNoiseMatrix, harvesters, PropagationType.MEAN, PropagationType.MEAN);
  123.     }

  124.     /** Kalman process model constructor (package private).
  125.      * This constructor is used whenever propagation type and/or state type are to be specified.
  126.      * It is used for {@link DSSTKalmanModel}.
  127.      * @param propagatorBuilders propagators builders used to evaluate the orbits.
  128.      * @param covarianceMatricesProviders providers for covariance matrices
  129.      * @param estimatedMeasurementParameters measurement parameters to estimate
  130.      * @param measurementProcessNoiseMatrix provider for measurement process noise matrix
  131.      * @param harvesters harvesters for extracting Jacobians from integrated states
  132.      * @param propagationType type of the orbit used for the propagation (mean or osculating), applicable only for DSST
  133.      * @param stateType type of the elements used to define the orbital state (mean or osculating), applicable only for DSST
  134.      */
  135.     protected AbstractKalmanModel(final List<OrbitDeterminationPropagatorBuilder> propagatorBuilders,
  136.                                   final List<CovarianceMatrixProvider> covarianceMatricesProviders,
  137.                                   final ParameterDriversList estimatedMeasurementParameters,
  138.                                   final CovarianceMatrixProvider measurementProcessNoiseMatrix,
  139.                                   final MatricesHarvester[] harvesters,
  140.                                   final PropagationType propagationType,
  141.                                   final PropagationType stateType) {

  142.         this.builders                        = propagatorBuilders;
  143.         this.estimatedMeasurementsParameters = estimatedMeasurementParameters;
  144.         this.measurementParameterColumns     = new HashMap<>(estimatedMeasurementsParameters.getDrivers().size());
  145.         this.currentMeasurementNumber        = 0;
  146.         this.referenceDate                   = propagatorBuilders.get(0).getInitialOrbitDate();
  147.         this.currentDate                     = referenceDate;
  148.         this.propagationType                 = propagationType;
  149.         this.stateType                       = stateType;

  150.         final Map<String, Integer> orbitalParameterColumns = new HashMap<>(6 * builders.size());
  151.         orbitsStartColumns      = new int[builders.size()];
  152.         orbitsEndColumns        = new int[builders.size()];
  153.         int columns = 0;
  154.         allEstimatedOrbitalParameters = new ParameterDriversList();
  155.         estimatedOrbitalParameters    = new ParameterDriversList[builders.size()];
  156.         for (int k = 0; k < builders.size(); ++k) {
  157.             estimatedOrbitalParameters[k] = new ParameterDriversList();
  158.             orbitsStartColumns[k] = columns;
  159.             final String suffix = propagatorBuilders.size() > 1 ? "[" + k + "]" : null;
  160.             for (final ParameterDriver driver : builders.get(k).getOrbitalParametersDrivers().getDrivers()) {
  161.                 if (driver.getReferenceDate() == null) {
  162.                     driver.setReferenceDate(currentDate);
  163.                 }
  164.                 if (suffix != null && !driver.getName().endsWith(suffix)) {
  165.                     // we add suffix only conditionally because the method may already have been called
  166.                     // and suffixes may have already been appended
  167.                     driver.setName(driver.getName() + suffix);
  168.                 }
  169.                 if (driver.isSelected()) {
  170.                     allEstimatedOrbitalParameters.add(driver);
  171.                     estimatedOrbitalParameters[k].add(driver);
  172.                     orbitalParameterColumns.put(driver.getName(), columns++);
  173.                 }
  174.             }
  175.             orbitsEndColumns[k] = columns;
  176.         }

  177.         // Gather all the propagation drivers names in a list
  178.         allEstimatedPropagationParameters = new ParameterDriversList();
  179.         estimatedPropagationParameters    = new ParameterDriversList[builders.size()];
  180.         final List<String> estimatedPropagationParametersNames = new ArrayList<>();
  181.         for (int k = 0; k < builders.size(); ++k) {
  182.             estimatedPropagationParameters[k] = new ParameterDriversList();
  183.             for (final ParameterDriver driver : builders.get(k).getPropagationParametersDrivers().getDrivers()) {
  184.                 if (driver.getReferenceDate() == null) {
  185.                     driver.setReferenceDate(currentDate);
  186.                 }
  187.                 if (driver.isSelected()) {
  188.                     allEstimatedPropagationParameters.add(driver);
  189.                     estimatedPropagationParameters[k].add(driver);
  190.                     final String driverName = driver.getName();
  191.                     // Add the driver name if it has not been added yet
  192.                     if (!estimatedPropagationParametersNames.contains(driverName)) {
  193.                         estimatedPropagationParametersNames.add(driverName);
  194.                     }
  195.                 }
  196.             }
  197.         }
  198.         estimatedPropagationParametersNames.sort(Comparator.naturalOrder());

  199.         // Populate the map of propagation drivers' columns and update the total number of columns
  200.         propagationParameterColumns = new HashMap<>(estimatedPropagationParametersNames.size());
  201.         for (final String driverName : estimatedPropagationParametersNames) {
  202.             propagationParameterColumns.put(driverName, columns);
  203.             ++columns;
  204.         }

  205.         // Populate the map of measurement drivers' columns and update the total number of columns
  206.         for (final ParameterDriver parameter : estimatedMeasurementsParameters.getDrivers()) {
  207.             if (parameter.getReferenceDate() == null) {
  208.                 parameter.setReferenceDate(currentDate);
  209.             }
  210.             measurementParameterColumns.put(parameter.getName(), columns);
  211.             ++columns;
  212.         }

  213.         // Store providers for process noise matrices
  214.         this.covarianceMatricesProviders = covarianceMatricesProviders;
  215.         this.measurementProcessNoiseMatrix = measurementProcessNoiseMatrix;
  216.         this.covarianceIndirection       = new int[builders.size()][columns];
  217.         for (int k = 0; k < covarianceIndirection.length; ++k) {
  218.             final ParameterDriversList orbitDrivers      = builders.get(k).getOrbitalParametersDrivers();
  219.             final ParameterDriversList parametersDrivers = builders.get(k).getPropagationParametersDrivers();
  220.             Arrays.fill(covarianceIndirection[k], -1);
  221.             int i = 0;
  222.             for (final ParameterDriver driver : orbitDrivers.getDrivers()) {
  223.                 final Integer c = orbitalParameterColumns.get(driver.getName());
  224.                 if (c != null) {
  225.                     covarianceIndirection[k][i++] = c.intValue();
  226.                 }
  227.             }
  228.             for (final ParameterDriver driver : parametersDrivers.getDrivers()) {
  229.                 final Integer c = propagationParameterColumns.get(driver.getName());
  230.                 if (c != null) {
  231.                     covarianceIndirection[k][i++] = c.intValue();
  232.                 }
  233.             }
  234.             for (final ParameterDriver driver : estimatedMeasurementParameters.getDrivers()) {
  235.                 final Integer c = measurementParameterColumns.get(driver.getName());
  236.                 if (c != null) {
  237.                     covarianceIndirection[k][i++] = c.intValue();
  238.                 }
  239.             }
  240.         }

  241.         // Compute the scale factors
  242.         this.scale = new double[columns];
  243.         int index = 0;
  244.         for (final ParameterDriver driver : allEstimatedOrbitalParameters.getDrivers()) {
  245.             scale[index++] = driver.getScale();
  246.         }
  247.         for (final ParameterDriver driver : allEstimatedPropagationParameters.getDrivers()) {
  248.             scale[index++] = driver.getScale();
  249.         }
  250.         for (final ParameterDriver driver : estimatedMeasurementsParameters.getDrivers()) {
  251.             scale[index++] = driver.getScale();
  252.         }

  253.         // Build the reference propagators and add their partial derivatives equations implementation
  254.         this.harvesters = harvesters.clone();
  255.         updateReferenceTrajectories(getEstimatedPropagators(), propagationType, stateType);
  256.         this.predictedSpacecraftStates = new SpacecraftState[referenceTrajectories.length];
  257.         for (int i = 0; i < predictedSpacecraftStates.length; ++i) {
  258.             predictedSpacecraftStates[i] = referenceTrajectories[i].getInitialState();
  259.         };
  260.         this.correctedSpacecraftStates = predictedSpacecraftStates.clone();

  261.         // Initialize the estimated normalized state and fill its values
  262.         final RealVector correctedState      = MatrixUtils.createRealVector(columns);

  263.         int p = 0;
  264.         for (final ParameterDriver driver : allEstimatedOrbitalParameters.getDrivers()) {
  265.             correctedState.setEntry(p++, driver.getNormalizedValue());
  266.         }
  267.         for (final ParameterDriver driver : allEstimatedPropagationParameters.getDrivers()) {
  268.             correctedState.setEntry(p++, driver.getNormalizedValue());
  269.         }
  270.         for (final ParameterDriver driver : estimatedMeasurementsParameters.getDrivers()) {
  271.             correctedState.setEntry(p++, driver.getNormalizedValue());
  272.         }

  273.         // Set up initial covariance
  274.         final RealMatrix physicalProcessNoise = MatrixUtils.createRealMatrix(columns, columns);
  275.         for (int k = 0; k < covarianceMatricesProviders.size(); ++k) {

  276.             // Number of estimated measurement parameters
  277.             final int nbMeas = estimatedMeasurementParameters.getNbParams();

  278.             // Number of estimated dynamic parameters (orbital + propagation)
  279.             final int nbDyn  = orbitsEndColumns[k] - orbitsStartColumns[k] +
  280.                                estimatedPropagationParameters[k].getNbParams();

  281.             // Covariance matrix
  282.             final RealMatrix noiseK = MatrixUtils.createRealMatrix(nbDyn + nbMeas, nbDyn + nbMeas);
  283.             if (nbDyn > 0) {
  284.                 final RealMatrix noiseP = covarianceMatricesProviders.get(k).
  285.                         getInitialCovarianceMatrix(correctedSpacecraftStates[k]);
  286.                 noiseK.setSubMatrix(noiseP.getData(), 0, 0);
  287.             }
  288.             if (measurementProcessNoiseMatrix != null) {
  289.                 final RealMatrix noiseM = measurementProcessNoiseMatrix.
  290.                                           getInitialCovarianceMatrix(correctedSpacecraftStates[k]);
  291.                 noiseK.setSubMatrix(noiseM.getData(), nbDyn, nbDyn);
  292.             }

  293.             KalmanEstimatorUtil.checkDimension(noiseK.getRowDimension(),
  294.                                                builders.get(k).getOrbitalParametersDrivers(),
  295.                                                builders.get(k).getPropagationParametersDrivers(),
  296.                                                estimatedMeasurementsParameters);

  297.             final int[] indK = covarianceIndirection[k];
  298.             for (int i = 0; i < indK.length; ++i) {
  299.                 if (indK[i] >= 0) {
  300.                     for (int j = 0; j < indK.length; ++j) {
  301.                         if (indK[j] >= 0) {
  302.                             physicalProcessNoise.setEntry(indK[i], indK[j], noiseK.getEntry(i, j));
  303.                         }
  304.                     }
  305.                 }
  306.             }

  307.         }
  308.         final RealMatrix correctedCovariance = normalizeCovarianceMatrix(physicalProcessNoise);

  309.         correctedEstimate = new ProcessEstimate(0.0, correctedState, correctedCovariance);

  310.     }

  311.     /** Update the reference trajectories using the propagators as input.
  312.      * @param propagators The new propagators to use
  313.      * @param pType propagationType type of the orbit used for the propagation (mean or osculating)
  314.      * @param sType type of the elements used to define the orbital state (mean or osculating)
  315.      */
  316.     protected abstract void updateReferenceTrajectories(Propagator[] propagators,
  317.                                                         PropagationType pType,
  318.                                                         PropagationType sType);

  319.     /** Not used anymore.
  320.      * @param mapper Jacobian mapper to calculate short period perturbations
  321.      * @param state state used to calculate short period perturbations
  322.      * @deprecated as of 11.1, not used anymore
  323.      */
  324.     protected void analyticalDerivativeComputations(final AbstractJacobiansMapper mapper, final SpacecraftState state) {
  325.         // nothing by default
  326.     }

  327.     /** {@inheritDoc} */
  328.     @Override
  329.     public RealMatrix getPhysicalStateTransitionMatrix() {
  330.         //  Un-normalize the state transition matrix (φ) from Hipparchus and return it.
  331.         // φ is an mxm matrix where m = nbOrb + nbPropag + nbMeas
  332.         // For each element [i,j] of normalized φ (φn), the corresponding physical value is:
  333.         // φ[i,j] = φn[i,j] * scale[i] / scale[j]

  334.         // Normalized matrix
  335.         final RealMatrix normalizedSTM = correctedEstimate.getStateTransitionMatrix();

  336.         if (normalizedSTM == null) {
  337.             return null;
  338.         } else {
  339.             // Initialize physical matrix
  340.             final int nbParams = normalizedSTM.getRowDimension();
  341.             final RealMatrix physicalSTM = MatrixUtils.createRealMatrix(nbParams, nbParams);

  342.             // Un-normalize the matrix
  343.             for (int i = 0; i < nbParams; ++i) {
  344.                 for (int j = 0; j < nbParams; ++j) {
  345.                     physicalSTM.setEntry(i, j,
  346.                                          normalizedSTM.getEntry(i, j) * scale[i] / scale[j]);
  347.                 }
  348.             }
  349.             return physicalSTM;
  350.         }
  351.     }

  352.     /** {@inheritDoc} */
  353.     @Override
  354.     public RealMatrix getPhysicalMeasurementJacobian() {
  355.         // Un-normalize the measurement matrix (H) from Hipparchus and return it.
  356.         // H is an nxm matrix where:
  357.         //  - m = nbOrb + nbPropag + nbMeas is the number of estimated parameters
  358.         //  - n is the size of the measurement being processed by the filter
  359.         // For each element [i,j] of normalized H (Hn) the corresponding physical value is:
  360.         // H[i,j] = Hn[i,j] * σ[i] / scale[j]

  361.         // Normalized matrix
  362.         final RealMatrix normalizedH = correctedEstimate.getMeasurementJacobian();

  363.         if (normalizedH == null) {
  364.             return null;
  365.         } else {
  366.             // Get current measurement sigmas
  367.             final double[] sigmas = correctedMeasurement.getObservedMeasurement().getTheoreticalStandardDeviation();

  368.             // Initialize physical matrix
  369.             final int nbLine = normalizedH.getRowDimension();
  370.             final int nbCol  = normalizedH.getColumnDimension();
  371.             final RealMatrix physicalH = MatrixUtils.createRealMatrix(nbLine, nbCol);

  372.             // Un-normalize the matrix
  373.             for (int i = 0; i < nbLine; ++i) {
  374.                 for (int j = 0; j < nbCol; ++j) {
  375.                     physicalH.setEntry(i, j, normalizedH.getEntry(i, j) * sigmas[i] / scale[j]);
  376.                 }
  377.             }
  378.             return physicalH;
  379.         }
  380.     }

  381.     /** {@inheritDoc} */
  382.     @Override
  383.     public RealMatrix getPhysicalInnovationCovarianceMatrix() {
  384.         // Un-normalize the innovation covariance matrix (S) from Hipparchus and return it.
  385.         // S is an nxn matrix where n is the size of the measurement being processed by the filter
  386.         // For each element [i,j] of normalized S (Sn) the corresponding physical value is:
  387.         // S[i,j] = Sn[i,j] * σ[i] * σ[j]

  388.         // Normalized matrix
  389.         final RealMatrix normalizedS = correctedEstimate.getInnovationCovariance();

  390.         if (normalizedS == null) {
  391.             return null;
  392.         } else {
  393.             // Get current measurement sigmas
  394.             final double[] sigmas = correctedMeasurement.getObservedMeasurement().getTheoreticalStandardDeviation();

  395.             // Initialize physical matrix
  396.             final int nbMeas = sigmas.length;
  397.             final RealMatrix physicalS = MatrixUtils.createRealMatrix(nbMeas, nbMeas);

  398.             // Un-normalize the matrix
  399.             for (int i = 0; i < nbMeas; ++i) {
  400.                 for (int j = 0; j < nbMeas; ++j) {
  401.                     physicalS.setEntry(i, j, normalizedS.getEntry(i, j) * sigmas[i] *   sigmas[j]);
  402.                 }
  403.             }
  404.             return physicalS;
  405.         }
  406.     }

  407.     /** {@inheritDoc} */
  408.     @Override
  409.     public RealMatrix getPhysicalKalmanGain() {
  410.         // Un-normalize the Kalman gain (K) from Hipparchus and return it.
  411.         // K is an mxn matrix where:
  412.         //  - m = nbOrb + nbPropag + nbMeas is the number of estimated parameters
  413.         //  - n is the size of the measurement being processed by the filter
  414.         // For each element [i,j] of normalized K (Kn) the corresponding physical value is:
  415.         // K[i,j] = Kn[i,j] * scale[i] / σ[j]

  416.         // Normalized matrix
  417.         final RealMatrix normalizedK = correctedEstimate.getKalmanGain();

  418.         if (normalizedK == null) {
  419.             return null;
  420.         } else {
  421.             // Get current measurement sigmas
  422.             final double[] sigmas = correctedMeasurement.getObservedMeasurement().getTheoreticalStandardDeviation();

  423.             // Initialize physical matrix
  424.             final int nbLine = normalizedK.getRowDimension();
  425.             final int nbCol  = normalizedK.getColumnDimension();
  426.             final RealMatrix physicalK = MatrixUtils.createRealMatrix(nbLine, nbCol);

  427.             // Un-normalize the matrix
  428.             for (int i = 0; i < nbLine; ++i) {
  429.                 for (int j = 0; j < nbCol; ++j) {
  430.                     physicalK.setEntry(i, j, normalizedK.getEntry(i, j) * scale[i] / sigmas[j]);
  431.                 }
  432.             }
  433.             return physicalK;
  434.         }
  435.     }

  436.     /** {@inheritDoc} */
  437.     @Override
  438.     public SpacecraftState[] getPredictedSpacecraftStates() {
  439.         return predictedSpacecraftStates.clone();
  440.     }

  441.     /** {@inheritDoc} */
  442.     @Override
  443.     public SpacecraftState[] getCorrectedSpacecraftStates() {
  444.         return correctedSpacecraftStates.clone();
  445.     }

  446.     /** {@inheritDoc} */
  447.     @Override
  448.     public int getCurrentMeasurementNumber() {
  449.         return currentMeasurementNumber;
  450.     }

  451.     /** {@inheritDoc} */
  452.     @Override
  453.     public AbsoluteDate getCurrentDate() {
  454.         return currentDate;
  455.     }

  456.     /** {@inheritDoc} */
  457.     @Override
  458.     public EstimatedMeasurement<?> getPredictedMeasurement() {
  459.         return predictedMeasurement;
  460.     }

  461.     /** {@inheritDoc} */
  462.     @Override
  463.     public EstimatedMeasurement<?> getCorrectedMeasurement() {
  464.         return correctedMeasurement;
  465.     }

  466.     /** {@inheritDoc} */
  467.     @Override
  468.     public RealVector getPhysicalEstimatedState() {
  469.         // Method {@link ParameterDriver#getValue()} is used to get
  470.         // the physical values of the state.
  471.         // The scales'array is used to get the size of the state vector
  472.         final RealVector physicalEstimatedState = new ArrayRealVector(scale.length);
  473.         int i = 0;
  474.         for (final DelegatingDriver driver : getEstimatedOrbitalParameters().getDrivers()) {
  475.             physicalEstimatedState.setEntry(i++, driver.getValue());
  476.         }
  477.         for (final DelegatingDriver driver : getEstimatedPropagationParameters().getDrivers()) {
  478.             physicalEstimatedState.setEntry(i++, driver.getValue());
  479.         }
  480.         for (final DelegatingDriver driver : getEstimatedMeasurementsParameters().getDrivers()) {
  481.             physicalEstimatedState.setEntry(i++, driver.getValue());
  482.         }

  483.         return physicalEstimatedState;
  484.     }

  485.     /** {@inheritDoc} */
  486.     @Override
  487.     public RealMatrix getPhysicalEstimatedCovarianceMatrix() {
  488.         // Un-normalize the estimated covariance matrix (P) from Hipparchus and return it.
  489.         // The covariance P is an mxm matrix where m = nbOrb + nbPropag + nbMeas
  490.         // For each element [i,j] of P the corresponding normalized value is:
  491.         // Pn[i,j] = P[i,j] / (scale[i]*scale[j])
  492.         // Consequently: P[i,j] = Pn[i,j] * scale[i] * scale[j]

  493.         // Normalized covariance matrix
  494.         final RealMatrix normalizedP = correctedEstimate.getCovariance();

  495.         // Initialize physical covariance matrix
  496.         final int nbParams = normalizedP.getRowDimension();
  497.         final RealMatrix physicalP = MatrixUtils.createRealMatrix(nbParams, nbParams);

  498.         // Un-normalize the covairance matrix
  499.         for (int i = 0; i < nbParams; ++i) {
  500.             for (int j = 0; j < nbParams; ++j) {
  501.                 physicalP.setEntry(i, j, normalizedP.getEntry(i, j) * scale[i] * scale[j]);
  502.             }
  503.         }
  504.         return physicalP;
  505.     }

  506.     /** {@inheritDoc} */
  507.     @Override
  508.     public ParameterDriversList getEstimatedOrbitalParameters() {
  509.         return allEstimatedOrbitalParameters;
  510.     }

  511.     /** {@inheritDoc} */
  512.     @Override
  513.     public ParameterDriversList getEstimatedPropagationParameters() {
  514.         return allEstimatedPropagationParameters;
  515.     }

  516.     /** {@inheritDoc} */
  517.     @Override
  518.     public ParameterDriversList getEstimatedMeasurementsParameters() {
  519.         return estimatedMeasurementsParameters;
  520.     }

  521.     /** Get the current corrected estimate.
  522.      * @return current corrected estimate
  523.      */
  524.     public ProcessEstimate getEstimate() {
  525.         return correctedEstimate;
  526.     }

  527.     /** Get the normalized error state transition matrix (STM) from previous point to current point.
  528.      * The STM contains the partial derivatives of current state with respect to previous state.
  529.      * The  STM is an mxm matrix where m is the size of the state vector.
  530.      * m = nbOrb + nbPropag + nbMeas
  531.      * @return the normalized error state transition matrix
  532.      */
  533.     private RealMatrix getErrorStateTransitionMatrix() {

  534.         /* The state transition matrix is obtained as follows, with:
  535.          *  - Y  : Current state vector
  536.          *  - Y0 : Initial state vector
  537.          *  - Pp : Current propagation parameter
  538.          *  - Pp0: Initial propagation parameter
  539.          *  - Mp : Current measurement parameter
  540.          *  - Mp0: Initial measurement parameter
  541.          *
  542.          *       |        |         |         |   |        |        |   .    |
  543.          *       | dY/dY0 | dY/dPp  | dY/dMp  |   | dY/dY0 | dY/dPp | ..0..  |
  544.          *       |        |         |         |   |        |        |   .    |
  545.          *       |--------|---------|---------|   |--------|--------|--------|
  546.          *       |        |         |         |   |   .    | 1 0 0..|   .    |
  547.          * STM = | dP/dY0 | dP/dPp0 | dP/dMp  | = | ..0..  | 0 1 0..| ..0..  |
  548.          *       |        |         |         |   |   .    | 0 0 1..|   .    |
  549.          *       |--------|---------|---------|   |--------|--------|--------|
  550.          *       |        |         |         |   |   .    |   .    | 1 0 0..|
  551.          *       | dM/dY0 | dM/dPp0 | dM/dMp0 |   | ..0..  | ..0..  | 0 1 0..|
  552.          *       |        |         |         |   |   .    |   .    | 0 0 1..|
  553.          */

  554.         // Initialize to the proper size identity matrix
  555.         final RealMatrix stm = MatrixUtils.createRealIdentityMatrix(correctedEstimate.getState().getDimension());

  556.         // loop over all orbits
  557.         for (int k = 0; k < predictedSpacecraftStates.length; ++k) {

  558.             // Indexes
  559.             final int[] indK = covarianceIndirection[k];

  560.             // Derivatives of the state vector with respect to initial state vector
  561.             final int nbOrbParams = estimatedOrbitalParameters[k].getNbParams();
  562.             if (nbOrbParams > 0) {

  563.                 // Reset reference (for example compute short periodic terms in DSST)
  564.                 harvesters[k].setReferenceState(predictedSpacecraftStates[k]);

  565.                 final RealMatrix dYdY0 = harvesters[k].getStateTransitionMatrix(predictedSpacecraftStates[k]);

  566.                 // Fill upper left corner (dY/dY0)
  567.                 for (int i = 0; i < dYdY0.getRowDimension(); ++i) {
  568.                     for (int j = 0; j < nbOrbParams; ++j) {
  569.                         stm.setEntry(indK[i], indK[j], dYdY0.getEntry(i, j));
  570.                     }
  571.                 }
  572.             }

  573.             // Derivatives of the state vector with respect to propagation parameters
  574.             final int nbParams = estimatedPropagationParameters[k].getNbParams();
  575.             if (nbParams > 0) {
  576.                 final RealMatrix dYdPp = harvesters[k].getParametersJacobian(predictedSpacecraftStates[k]);

  577.                 // Fill 1st row, 2nd column (dY/dPp)
  578.                 for (int i = 0; i < dYdPp.getRowDimension(); ++i) {
  579.                     for (int j = 0; j < nbParams; ++j) {
  580.                         stm.setEntry(indK[i], indK[j + 6], dYdPp.getEntry(i, j));
  581.                     }
  582.                 }

  583.             }

  584.         }

  585.         // Normalization of the STM
  586.         // normalized(STM)ij = STMij*Sj/Si
  587.         for (int i = 0; i < scale.length; i++) {
  588.             for (int j = 0; j < scale.length; j++ ) {
  589.                 stm.setEntry(i, j, stm.getEntry(i, j) * scale[j] / scale[i]);
  590.             }
  591.         }

  592.         // Return the error state transition matrix
  593.         return stm;

  594.     }

  595.     /** Get the normalized measurement matrix H.
  596.      * H contains the partial derivatives of the measurement with respect to the state.
  597.      * H is an nxm matrix where n is the size of the measurement vector and m the size of the state vector.
  598.      * @return the normalized measurement matrix H
  599.      */
  600.     private RealMatrix getMeasurementMatrix() {

  601.         // Observed measurement characteristics
  602.         final SpacecraftState[]      evaluationStates    = predictedMeasurement.getStates();
  603.         final ObservedMeasurement<?> observedMeasurement = predictedMeasurement.getObservedMeasurement();
  604.         final double[] sigma  = observedMeasurement.getTheoreticalStandardDeviation();

  605.         // Initialize measurement matrix H: nxm
  606.         // n: Number of measurements in current measurement
  607.         // m: State vector size
  608.         final RealMatrix measurementMatrix = MatrixUtils.
  609.                         createRealMatrix(observedMeasurement.getDimension(),
  610.                                          correctedEstimate.getState().getDimension());

  611.         // loop over all orbits involved in the measurement
  612.         for (int k = 0; k < evaluationStates.length; ++k) {
  613.             final int p = observedMeasurement.getSatellites().get(k).getPropagatorIndex();

  614.             // Predicted orbit
  615.             final Orbit predictedOrbit = evaluationStates[k].getOrbit();

  616.             // Measurement matrix's columns related to orbital parameters
  617.             // ----------------------------------------------------------

  618.             // Partial derivatives of the current Cartesian coordinates with respect to current orbital state
  619.             final double[][] aCY = new double[6][6];
  620.             predictedOrbit.getJacobianWrtParameters(builders.get(p).getPositionAngle(), aCY);   //dC/dY
  621.             final RealMatrix dCdY = new Array2DRowRealMatrix(aCY, false);

  622.             // Jacobian of the measurement with respect to current Cartesian coordinates
  623.             final RealMatrix dMdC = new Array2DRowRealMatrix(predictedMeasurement.getStateDerivatives(k), false);

  624.             // Jacobian of the measurement with respect to current orbital state
  625.             final RealMatrix dMdY = dMdC.multiply(dCdY);

  626.             // Fill the normalized measurement matrix's columns related to estimated orbital parameters
  627.             for (int i = 0; i < dMdY.getRowDimension(); ++i) {
  628.                 int jOrb = orbitsStartColumns[p];
  629.                 for (int j = 0; j < dMdY.getColumnDimension(); ++j) {
  630.                     final ParameterDriver driver = builders.get(p).getOrbitalParametersDrivers().getDrivers().get(j);
  631.                     if (driver.isSelected()) {
  632.                         measurementMatrix.setEntry(i, jOrb++,
  633.                                                    dMdY.getEntry(i, j) / sigma[i] * driver.getScale());
  634.                     }
  635.                 }
  636.             }

  637.             // Normalized measurement matrix's columns related to propagation parameters
  638.             // --------------------------------------------------------------

  639.             // Jacobian of the measurement with respect to propagation parameters
  640.             final int nbParams = estimatedPropagationParameters[p].getNbParams();
  641.             if (nbParams > 0) {
  642.                 final RealMatrix dYdPp = harvesters[p].getParametersJacobian(evaluationStates[k]);
  643.                 final RealMatrix dMdPp = dMdY.multiply(dYdPp);
  644.                 for (int i = 0; i < dMdPp.getRowDimension(); ++i) {
  645.                     for (int j = 0; j < nbParams; ++j) {
  646.                         final ParameterDriver delegating = estimatedPropagationParameters[p].getDrivers().get(j);
  647.                         measurementMatrix.setEntry(i, propagationParameterColumns.get(delegating.getName()),
  648.                                                    dMdPp.getEntry(i, j) / sigma[i] * delegating.getScale());
  649.                     }
  650.                 }
  651.             }

  652.             // Normalized measurement matrix's columns related to measurement parameters
  653.             // --------------------------------------------------------------

  654.             // Jacobian of the measurement with respect to measurement parameters
  655.             // Gather the measurement parameters linked to current measurement
  656.             for (final ParameterDriver driver : observedMeasurement.getParametersDrivers()) {
  657.                 if (driver.isSelected()) {
  658.                     // Derivatives of current measurement w/r to selected measurement parameter
  659.                     final double[] aMPm = predictedMeasurement.getParameterDerivatives(driver);

  660.                     // Check that the measurement parameter is managed by the filter
  661.                     if (measurementParameterColumns.get(driver.getName()) != null) {
  662.                         // Column of the driver in the measurement matrix
  663.                         final int driverColumn = measurementParameterColumns.get(driver.getName());

  664.                         // Fill the corresponding indexes of the measurement matrix
  665.                         for (int i = 0; i < aMPm.length; ++i) {
  666.                             measurementMatrix.setEntry(i, driverColumn,
  667.                                                        aMPm[i] / sigma[i] * driver.getScale());
  668.                         }
  669.                     }
  670.                 }
  671.             }
  672.         }

  673.         // Return the normalized measurement matrix
  674.         return measurementMatrix;

  675.     }

  676.     /** Normalize a covariance matrix.
  677.      * The covariance P is an mxm matrix where m = nbOrb + nbPropag + nbMeas
  678.      * For each element [i,j] of P the corresponding normalized value is:
  679.      * Pn[i,j] = P[i,j] / (scale[i]*scale[j])
  680.      * @param physicalCovarianceMatrix The "physical" covariance matrix in input
  681.      * @return the normalized covariance matrix
  682.      */
  683.     private RealMatrix normalizeCovarianceMatrix(final RealMatrix physicalCovarianceMatrix) {

  684.         // Initialize output matrix
  685.         final int nbParams = physicalCovarianceMatrix.getRowDimension();
  686.         final RealMatrix normalizedCovarianceMatrix = MatrixUtils.createRealMatrix(nbParams, nbParams);

  687.         // Normalize the state matrix
  688.         for (int i = 0; i < nbParams; ++i) {
  689.             for (int j = 0; j < nbParams; ++j) {
  690.                 normalizedCovarianceMatrix.setEntry(i, j,
  691.                                                     physicalCovarianceMatrix.getEntry(i, j) /
  692.                                                     (scale[i] * scale[j]));
  693.             }
  694.         }
  695.         return normalizedCovarianceMatrix;
  696.     }

  697.     /** {@inheritDoc} */
  698.     @Override
  699.     public NonLinearEvolution getEvolution(final double previousTime, final RealVector previousState,
  700.                                            final MeasurementDecorator measurement) {

  701.         // Set a reference date for all measurements parameters that lack one (including the not estimated ones)
  702.         final ObservedMeasurement<?> observedMeasurement = measurement.getObservedMeasurement();
  703.         for (final ParameterDriver driver : observedMeasurement.getParametersDrivers()) {
  704.             if (driver.getReferenceDate() == null) {
  705.                 driver.setReferenceDate(builders.get(0).getInitialOrbitDate());
  706.             }
  707.         }

  708.         ++currentMeasurementNumber;
  709.         currentDate = measurement.getObservedMeasurement().getDate();

  710.         // Note:
  711.         // - n = size of the current measurement
  712.         //  Example:
  713.         //   * 1 for Range, RangeRate and TurnAroundRange
  714.         //   * 2 for Angular (Azimuth/Elevation or Right-ascension/Declination)
  715.         //   * 6 for Position/Velocity
  716.         // - m = size of the state vector. n = nbOrb + nbPropag + nbMeas

  717.         // Predict the state vector (mx1)
  718.         final RealVector predictedState = predictState(observedMeasurement.getDate());

  719.         // Get the error state transition matrix (mxm)
  720.         final RealMatrix stateTransitionMatrix = getErrorStateTransitionMatrix();

  721.         // Predict the measurement based on predicted spacecraft state
  722.         // Compute the innovations (i.e. residuals of the predicted measurement)
  723.         // ------------------------------------------------------------

  724.         // Predicted measurement
  725.         // Note: here the "iteration/evaluation" formalism from the batch LS method
  726.         // is twisted to fit the need of the Kalman filter.
  727.         // The number of "iterations" is actually the number of measurements processed by the filter
  728.         // so far. We use this to be able to apply the OutlierFilter modifiers on the predicted measurement.
  729.         predictedMeasurement = observedMeasurement.estimate(currentMeasurementNumber,
  730.                                                             currentMeasurementNumber,
  731.                                                             KalmanEstimatorUtil.filterRelevant(observedMeasurement, predictedSpacecraftStates));

  732.         // Normalized measurement matrix (nxm)
  733.         final RealMatrix measurementMatrix = getMeasurementMatrix();

  734.         // compute process noise matrix
  735.         final RealMatrix physicalProcessNoise = MatrixUtils.createRealMatrix(previousState.getDimension(),
  736.                                                                              previousState.getDimension());
  737.         for (int k = 0; k < covarianceMatricesProviders.size(); ++k) {

  738.             // Number of estimated measurement parameters
  739.             final int nbMeas = estimatedMeasurementsParameters.getNbParams();

  740.             // Number of estimated dynamic parameters (orbital + propagation)
  741.             final int nbDyn  = orbitsEndColumns[k] - orbitsStartColumns[k] +
  742.                                estimatedPropagationParameters[k].getNbParams();

  743.             // Covariance matrix
  744.             final RealMatrix noiseK = MatrixUtils.createRealMatrix(nbDyn + nbMeas, nbDyn + nbMeas);
  745.             if (nbDyn > 0) {
  746.                 final RealMatrix noiseP = covarianceMatricesProviders.get(k).
  747.                                           getProcessNoiseMatrix(correctedSpacecraftStates[k],
  748.                                                                 predictedSpacecraftStates[k]);
  749.                 noiseK.setSubMatrix(noiseP.getData(), 0, 0);
  750.             }
  751.             if (measurementProcessNoiseMatrix != null) {
  752.                 final RealMatrix noiseM = measurementProcessNoiseMatrix.
  753.                                           getProcessNoiseMatrix(correctedSpacecraftStates[k],
  754.                                                                 predictedSpacecraftStates[k]);
  755.                 noiseK.setSubMatrix(noiseM.getData(), nbDyn, nbDyn);
  756.             }

  757.             KalmanEstimatorUtil.checkDimension(noiseK.getRowDimension(),
  758.                                                builders.get(k).getOrbitalParametersDrivers(),
  759.                                                builders.get(k).getPropagationParametersDrivers(),
  760.                                                estimatedMeasurementsParameters);

  761.             final int[] indK = covarianceIndirection[k];
  762.             for (int i = 0; i < indK.length; ++i) {
  763.                 if (indK[i] >= 0) {
  764.                     for (int j = 0; j < indK.length; ++j) {
  765.                         if (indK[j] >= 0) {
  766.                             physicalProcessNoise.setEntry(indK[i], indK[j], noiseK.getEntry(i, j));
  767.                         }
  768.                     }
  769.                 }
  770.             }

  771.         }
  772.         final RealMatrix normalizedProcessNoise = normalizeCovarianceMatrix(physicalProcessNoise);

  773.         return new NonLinearEvolution(measurement.getTime(), predictedState,
  774.                                       stateTransitionMatrix, normalizedProcessNoise, measurementMatrix);

  775.     }


  776.     /** {@inheritDoc} */
  777.     @Override
  778.     public RealVector getInnovation(final MeasurementDecorator measurement, final NonLinearEvolution evolution,
  779.                                     final RealMatrix innovationCovarianceMatrix) {

  780.         // Apply the dynamic outlier filter, if it exists
  781.         KalmanEstimatorUtil.applyDynamicOutlierFilter(predictedMeasurement, innovationCovarianceMatrix);
  782.         // Compute the innovation vector
  783.         return KalmanEstimatorUtil.computeInnovationVector(predictedMeasurement, predictedMeasurement.getObservedMeasurement().getTheoreticalStandardDeviation());
  784.     }

  785.     /** Finalize estimation.
  786.      * @param observedMeasurement measurement that has just been processed
  787.      * @param estimate corrected estimate
  788.      */
  789.     public void finalizeEstimation(final ObservedMeasurement<?> observedMeasurement,
  790.                                    final ProcessEstimate estimate) {
  791.         // Update the parameters with the estimated state
  792.         // The min/max values of the parameters are handled by the ParameterDriver implementation
  793.         correctedEstimate = estimate;
  794.         updateParameters();

  795.         // Get the estimated propagator (mirroring parameter update in the builder)
  796.         // and the estimated spacecraft state
  797.         final Propagator[] estimatedPropagators = getEstimatedPropagators();
  798.         for (int k = 0; k < estimatedPropagators.length; ++k) {
  799.             correctedSpacecraftStates[k] = estimatedPropagators[k].getInitialState();
  800.         }

  801.         // Compute the estimated measurement using estimated spacecraft state
  802.         correctedMeasurement = observedMeasurement.estimate(currentMeasurementNumber,
  803.                                                             currentMeasurementNumber,
  804.                                                             KalmanEstimatorUtil.filterRelevant(observedMeasurement, correctedSpacecraftStates));
  805.         // Update the trajectory
  806.         // ---------------------
  807.         updateReferenceTrajectories(estimatedPropagators, propagationType, stateType);

  808.     }

  809.     /** Set the predicted normalized state vector.
  810.      * The predicted/propagated orbit is used to update the state vector
  811.      * @param date prediction date
  812.      * @return predicted state
  813.      */
  814.     private RealVector predictState(final AbsoluteDate date) {

  815.         // Predicted state is initialized to previous estimated state
  816.         final RealVector predictedState = correctedEstimate.getState().copy();

  817.         // Orbital parameters counter
  818.         int jOrb = 0;

  819.         for (int k = 0; k < predictedSpacecraftStates.length; ++k) {

  820.             // Propagate the reference trajectory to measurement date
  821.             predictedSpacecraftStates[k] = referenceTrajectories[k].propagate(date);

  822.             // Update the builder with the predicted orbit
  823.             // This updates the orbital drivers with the values of the predicted orbit
  824.             builders.get(k).resetOrbit(predictedSpacecraftStates[k].getOrbit());

  825.             // The orbital parameters in the state vector are replaced with their predicted values
  826.             // The propagation & measurement parameters are not changed by the prediction (i.e. the propagation)
  827.             // As the propagator builder was previously updated with the predicted orbit,
  828.             // the selected orbital drivers are already up to date with the prediction
  829.             for (DelegatingDriver orbitalDriver : builders.get(k).getOrbitalParametersDrivers().getDrivers()) {
  830.                 if (orbitalDriver.isSelected()) {
  831.                     predictedState.setEntry(jOrb++, orbitalDriver.getNormalizedValue());
  832.                 }
  833.             }

  834.         }

  835.         return predictedState;

  836.     }

  837.     /** Update the estimated parameters after the correction phase of the filter.
  838.      * The min/max allowed values are handled by the parameter themselves.
  839.      */
  840.     private void updateParameters() {
  841.         final RealVector correctedState = correctedEstimate.getState();
  842.         int i = 0;
  843.         for (final DelegatingDriver driver : getEstimatedOrbitalParameters().getDrivers()) {
  844.             // let the parameter handle min/max clipping
  845.             driver.setNormalizedValue(correctedState.getEntry(i));
  846.             correctedState.setEntry(i++, driver.getNormalizedValue());
  847.         }
  848.         for (final DelegatingDriver driver : getEstimatedPropagationParameters().getDrivers()) {
  849.             // let the parameter handle min/max clipping
  850.             driver.setNormalizedValue(correctedState.getEntry(i));
  851.             correctedState.setEntry(i++, driver.getNormalizedValue());
  852.         }
  853.         for (final DelegatingDriver driver : getEstimatedMeasurementsParameters().getDrivers()) {
  854.             // let the parameter handle min/max clipping
  855.             driver.setNormalizedValue(correctedState.getEntry(i));
  856.             correctedState.setEntry(i++, driver.getNormalizedValue());
  857.         }
  858.     }

  859.     /** Getter for the propagators.
  860.      * @return the propagators
  861.      */
  862.     public List<OrbitDeterminationPropagatorBuilder> getBuilders() {
  863.         return builders;
  864.     }

  865.     /** Getter for the reference trajectories.
  866.      * @return the referencetrajectories
  867.      */
  868.     public Propagator[] getReferenceTrajectories() {
  869.         return referenceTrajectories.clone();
  870.     }

  871.     /** Setter for the reference trajectories.
  872.      * @param referenceTrajectories the reference trajectories to be setted
  873.      */
  874.     public void setReferenceTrajectories(final Propagator[] referenceTrajectories) {
  875.         this.referenceTrajectories = referenceTrajectories.clone();
  876.     }

  877.     /** Getter for the jacobian mappers.
  878.      * @return the jacobian mappers
  879.      * @deprecated as of 11.1, not used anymore
  880.      */
  881.     @Deprecated
  882.     public AbstractJacobiansMapper[] getMappers() {
  883.         return null;
  884.     }

  885.     /** Setter for the jacobian mappers.
  886.      * @param mappers the jacobian mappers to set
  887.      * @deprecated as of 11.1, replaced by {@link #setHarvesters(MatricesHarvester[])}
  888.      */
  889.     @Deprecated
  890.     public void setMappers(final AbstractJacobiansMapper[] mappers) {
  891.         setHarvesters(mappers);
  892.     }

  893.     /** Setter for the jacobian harvesters.
  894.      * @param harvesters the jacobian harvesters to set
  895.      * @since 11.1
  896.      */
  897.     public void setHarvesters(final MatricesHarvester[] harvesters) {
  898.         this.harvesters = harvesters.clone();
  899.     }

  900.     /** Get the propagators estimated with the values set in the propagators builders.
  901.      * @return propagators based on the current values in the builder
  902.      */
  903.     public Propagator[] getEstimatedPropagators() {
  904.         // Return propagators built with current instantiation of the propagator builders
  905.         final Propagator[] propagators = new Propagator[getBuilders().size()];
  906.         for (int k = 0; k < getBuilders().size(); ++k) {
  907.             propagators[k] = getBuilders().get(k).buildPropagator(getBuilders().get(k).getSelectedNormalizedParameters());
  908.         }
  909.         return propagators;
  910.     }

  911. }