AbstractMultipleShooting.java

  1. /* Copyright 2002-2020 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.utils;

  18. import java.util.ArrayList;
  19. import java.util.HashMap;
  20. import java.util.List;
  21. import java.util.Map;

  22. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  23. import org.hipparchus.linear.MatrixUtils;
  24. import org.hipparchus.linear.RealMatrix;
  25. import org.hipparchus.linear.RealVector;
  26. import org.orekit.attitudes.Attitude;
  27. import org.orekit.attitudes.AttitudeProvider;
  28. import org.orekit.errors.OrekitException;
  29. import org.orekit.errors.OrekitMessages;
  30. import org.orekit.propagation.SpacecraftState;
  31. import org.orekit.propagation.integration.AdditionalEquations;
  32. import org.orekit.propagation.numerical.NumericalPropagator;
  33. import org.orekit.time.AbsoluteDate;

  34. /**
  35.  * Multiple shooting method using only constraints on state vectors of patch points (and possibly on epoch and integration time).
  36.  * @see "TRAJECTORY DESIGN AND ORBIT MAINTENANCE STRATEGIES IN MULTI-BODY DYNAMICAL REGIMES by Thomas A. Pavlak, Purdue University"
  37.  * @author William Desprats
  38.  * @since 10.2
  39.  */
  40. public abstract class AbstractMultipleShooting implements MultipleShooting {

  41.     /** Patch points along the trajectory. */
  42.     private List<SpacecraftState> patchedSpacecraftStates;

  43.     /** Derivatives linked to the Propagators. */
  44.     private final List<AdditionalEquations> additionalEquations;

  45.     /** List of Propagators. */
  46.     private final List<NumericalPropagator> propagatorList;

  47.     /** Duration of propagation along each arcs. */
  48.     private double[] propagationTime;

  49.     /** Free components of patch points. */
  50.     private boolean[] freePatchPointMap;

  51.     /** Free epoch of patch points. */
  52.     private boolean[] freeEpochMap;

  53.     /** Number of free variables. */
  54.     private int nFree;

  55.     /** Number of free epoch. */
  56.     private int nEpoch;

  57.     /** Number of constraints. */
  58.     private int nConstraints;

  59.     /** Patch points components which are constrained. */
  60.     private Map<Integer, Double> mapConstraints;

  61.     /** True if orbit is closed. */
  62.     private boolean isClosedOrbit;

  63.     /** Tolerance on the constraint vector. */
  64.     private double tolerance;

  65.     /** Expected name of the additional equations. */
  66.     private final String additionalName;

  67.     /** Simple Constructor.
  68.      * <p> Standard constructor for multiple shooting </p>
  69.      * @param initialGuessList initial patch points to be corrected.
  70.      * @param propagatorList list of propagators associated to each patch point.
  71.      * @param additionalEquations list of additional equations linked to propagatorList.
  72.      * @param arcDuration initial guess of the duration of each arc.
  73.      * @param tolerance convergence tolerance on the constraint vector.
  74.      * @param additionalName name of the additional equations
  75.      */
  76.     protected AbstractMultipleShooting(final List<SpacecraftState> initialGuessList, final List<NumericalPropagator> propagatorList,
  77.                                        final List<AdditionalEquations> additionalEquations, final double arcDuration,
  78.                                        final double tolerance, final String additionalName) {
  79.         this.patchedSpacecraftStates = initialGuessList;
  80.         this.propagatorList = propagatorList;
  81.         this.additionalEquations = additionalEquations;
  82.         this.additionalName = additionalName;
  83.         // Should check if propagatorList.size() = initialGuessList.size() - 1
  84.         final int propagationNumber = initialGuessList.size() - 1;
  85.         this.propagationTime = new double[propagationNumber];
  86.         for (int i = 0; i < propagationNumber; i++ ) {
  87.             this.propagationTime[i] = arcDuration;
  88.         }

  89.         // All the patch points are set initially as free variables
  90.         this.freePatchPointMap = new boolean[6 * initialGuessList.size()]; // epoch
  91.         for (int i = 0; i < freePatchPointMap.length; i++) {
  92.             freePatchPointMap[i] = true;
  93.         }

  94.         //Except the first one, the epochs of the patch points are set free.
  95.         this.freeEpochMap = new boolean[initialGuessList.size()];
  96.         freeEpochMap[0] = false;
  97.         for (int i = 1; i < freeEpochMap.length; i++) {
  98.             freeEpochMap[i] = true;
  99.         }
  100.         this.nEpoch = initialGuessList.size() - 1;

  101.         this.nConstraints = 6 * propagationNumber;
  102.         this.nFree = 6 * initialGuessList.size() + 1;

  103.         this.tolerance = tolerance;

  104.         // All the additional constraints must be set afterward
  105.         this.mapConstraints = new HashMap<>();
  106.     }

  107.     /** Set a component of a patch point to free or not.
  108.      * @param patchNumber Patch point with constraint
  109.      * @param componentIndex Component of the patch points which are constrained.
  110.      * @param isFree constraint value
  111.      */
  112.     public void setPatchPointComponentFreedom(final int patchNumber, final int componentIndex, final boolean isFree) {
  113.         if (freePatchPointMap[6 * (patchNumber - 1) +  componentIndex] != isFree ) {
  114.             final int eps = isFree ? 1 : -1;
  115.             nFree = nFree + eps;
  116.             freePatchPointMap[6 * (patchNumber - 1) +  componentIndex] = isFree;
  117.         }
  118.     }

  119.     /** Add a constraint on one component of one patch point.
  120.      * @param patchNumber Patch point with constraint
  121.      * @param componentIndex Component of the patch points which are constrained.
  122.      * @param constraintValue constraint value
  123.      */
  124.     public void addConstraint(final int patchNumber, final int componentIndex, final double constraintValue) {
  125.         final int contraintIndex = (patchNumber - 1) * 6 + componentIndex;
  126.         if (!mapConstraints.containsKey(contraintIndex)) {
  127.             nConstraints++;
  128.         }
  129.         mapConstraints.put(contraintIndex, constraintValue);
  130.     }

  131.     /** Set the epoch a patch point to free or not.
  132.      * @param patchNumber Patch point
  133.      * @param isFree constraint value
  134.      */
  135.     public void setEpochFreedom(final int patchNumber, final boolean isFree) {
  136.         if (freeEpochMap[patchNumber - 1] != isFree) {
  137.             freeEpochMap[patchNumber - 1] = isFree;
  138.             final int eps = isFree ? 1 : -1;
  139.             nEpoch = nEpoch + eps;
  140.         }
  141.     }

  142.     /** {@inheritDoc} */
  143.     @Override
  144.     public List<SpacecraftState> compute() {

  145.         if (nFree > nConstraints) {
  146.             throw new OrekitException(OrekitMessages.MULTIPLE_SHOOTING_UNDERCONSTRAINED, nFree, nConstraints);
  147.         }

  148.         int iter = 0; // number of iteration

  149.         double fxNorm = 0;

  150.         do {

  151.             final List<SpacecraftState> propagatedSP = propagatePatchedSpacecraftState(); // multi threading see PropagatorsParallelizer
  152.             final RealMatrix M = computeJacobianMatrix(propagatedSP);
  153.             final RealVector fx = MatrixUtils.createRealVector(computeConstraint(propagatedSP));

  154.             // Solve linear system
  155.             final RealMatrix MMt = M.multiply(M.transpose());
  156.             final RealVector dx  = M.transpose().multiply(MatrixUtils.inverse(MMt)).operate(fx);

  157.             // Apply correction from the free variable vector to all the variables (propagation time, pacthSpaceraftState)
  158.             updateTrajectory(dx);

  159.             fxNorm = fx.getNorm() / fx.getDimension();

  160.             iter++;

  161.         } while (fxNorm > tolerance && iter < 1); // Converge within tolerance and under 10 iterations

  162.         return patchedSpacecraftStates;
  163.     }

  164.     /** Compute the Jacobian matrix of the problem.
  165.      *  @param propagatedSP List of propagated SpacecraftStates (patch points)
  166.      *  @return jacobianMatrix Jacobian matrix
  167.      */
  168.     private RealMatrix computeJacobianMatrix(final List<SpacecraftState> propagatedSP) {

  169.         final int npoints         = patchedSpacecraftStates.size();
  170.         final int epochConstraint = nEpoch == 0 ? 0 : npoints - 1;
  171.         final int nrows    = getNumberOfConstraints() + epochConstraint;
  172.         final int ncolumns = getNumberOfFreeVariables() + nEpoch;

  173.         final RealMatrix M = MatrixUtils.createRealMatrix(nrows, ncolumns);

  174.         int index = 0;
  175.         int indexEpoch = nFree;
  176.         for (int i = 0; i < npoints - 1; i++) {

  177.             final SpacecraftState finalState = propagatedSP.get(i);
  178.             // The Jacobian matrix has the following form:

  179.             //          [     |     |     ]
  180.             //          [  A  |  B  |  C  ]
  181.             // DF(X) =  [     |     |     ]
  182.             //          [-----------------]
  183.             //          [  0  |  D  |  E  ]
  184.             //          [-----------------]
  185.             //          [  F  |  0  |  0  ]

  186.             //          [     |     ]
  187.             //          [  A  |  B  ]
  188.             // DF(X) =  [     |     ]
  189.             //          [-----------]
  190.             //          [  C  |  0  ]
  191.             //
  192.             // For a problem with all the components of each patch points is free, A is detailed below :
  193.             //      [ phi1     -I                                   ]
  194.             //      [         phi2     -I                           ]
  195.             // A =  [                 ....    ....                  ]   6(n-1)x6n
  196.             //      [                         ....     ....         ]
  197.             //      [                                 phin-1    -I  ]

  198.             // D is computing according to additional constraints
  199.             // (for now, closed orbit, or a component of a patch point equals to a specified value)
  200.             //

  201.             // If the duration of the propagation of each arc is the same :
  202.             //      [ xdot1f ]
  203.             //      [ xdot2f ]                      [  -1 ]
  204.             // B =  [  ....  ]   6(n-1)x1   and D = [ ... ]
  205.             //      [  ....  ]                      [  -1 ]
  206.             //      [xdotn-1f]

  207.             // Otherwise :
  208.             //      [ xdot1f                                ]
  209.             //      [        xdot2f                         ]
  210.             // B =  [                 ....                  ]   6(n-1)x(n-1) and D = -I
  211.             //      [                        ....           ]
  212.             //      [                             xdotn-1f  ]
  213.             //
  214.             // If the problem is not dependant of the epoch (e.g. CR3BP), the C and E matrices are not computed.
  215.             // Otherwise :
  216.             //      [ -dx1f/dtau1                                           0 ]
  217.             //      [          -dx2f/dtau2                                  0 ]
  218.             // C =  [                       ....                            0 ]   6(n-1)xn
  219.             //      [                               ....                    0 ]
  220.             //      [                                     -dxn-1f/dtaun-1   0 ]
  221.             //
  222.             //      [ -1   1  0                 ]
  223.             //      [     -1   1  0             ]
  224.             // E =  [          ..   ..          ] n-1xn
  225.             //      [               ..   ..     ]
  226.             //      [                    -1   1 ]

  227.             final PVCoordinates pvf = finalState.getPVCoordinates();

  228.             // Get State Transition Matrix phi
  229.             final double[][] phi = getStateTransitionMatrix(finalState);

  230.             // Matrix A
  231.             for (int j = 0; j < 6; j++) { // Loop on 6 component of the patch point
  232.                 if (freePatchPointMap[6 * i + j]) { // If this component is free
  233.                     for (int k = 0; k < 6; k++) { // Loop on the 6 component of the patch point constraint
  234.                         M.setEntry(6 * i + k, index, phi[k][j]);
  235.                     }
  236.                     if (i > 0) {
  237.                         M.setEntry(6 * (i - 1) + j, index, -1);
  238.                     }
  239.                     index++;
  240.                 }
  241.             }

  242.             // Matrix B
  243.             final double[][] pvfArray = new double[][] {
  244.                 {pvf.getVelocity().getX()},
  245.                 {pvf.getVelocity().getY()},
  246.                 {pvf.getVelocity().getZ()},
  247.                 {pvf.getAcceleration().getX()},
  248.                 {pvf.getAcceleration().getY()},
  249.                 {pvf.getAcceleration().getZ()}};

  250.             M.setSubMatrix(pvfArray, 6 * i, nFree - 1);

  251.             // Matrix C
  252.             if (freeEpochMap[i]) { // If this component is free
  253.                 final double[] derivatives = finalState.getAdditionalState("derivatives");
  254.                 final double[][] subC = new double[6][1];
  255.                 for (int j = 0; j < 6; j++) { // Loop on 6 component of the patch point
  256.                     subC[j][0] = -derivatives[derivatives.length - 6 + j];
  257.                 }
  258.                 M.setSubMatrix(subC, 6 * i, indexEpoch);
  259.                 indexEpoch++;
  260.             }
  261.         }

  262.         for (int j = 0; j < 6; j++) { // Loop on 6 component of the patch point
  263.             if (freePatchPointMap[6 * (npoints - 1) + j]) { // If this component is free
  264.                 M.setEntry(6 * (npoints - 2) + j, index, -1);
  265.                 index++;
  266.             }
  267.         }


  268.         // Matrices D and E.
  269.         if (nEpoch > 0) {
  270.             final double[][] subDE = computeEpochJacobianMatrix(propagatedSP);
  271.             M.setSubMatrix(subDE, 6 * (npoints - 1), nFree - 1);
  272.         }

  273.         // Matrices F.
  274.         final double[][] subF = computeAdditionalJacobianMatrix(propagatedSP);
  275.         if (subF.length > 0) {
  276.             M.setSubMatrix(subF, 6 * (npoints - 1) + epochConstraint, 0);
  277.         }

  278.         return M;
  279.     }

  280.     /** Compute the constraint vector of the problem.
  281.      *  @param propagatedSP propagated SpacecraftState
  282.      *  @return constraint vector
  283.      */
  284.     private double[] computeConstraint(final List<SpacecraftState> propagatedSP) {

  285.         // The Constraint vector has the following form :

  286.         //         [ x1f - x2i ]---
  287.         //         [ x2f - x3i ]   |
  288.         // F(X) =  [    ...    ] vectors' equality for a continuous trajectory
  289.         //         [    ...    ]   |
  290.         //         [xn-1f - xni]---
  291.         //         [ d2-(d1+T) ]   continuity between epoch
  292.         //         [    ...    ]   and integration time
  293.         //         [dn-(dn-1+T)]---
  294.         //         [    ...    ] additional
  295.         //         [    ...    ] constraints

  296.         final int npoints = patchedSpacecraftStates.size();

  297.         final double[] additionalConstraints = computeAdditionalConstraints(propagatedSP);
  298.         final boolean epoch = getNumberOfFreeEpoch() > 0;

  299.         final int nrows = epoch ? getNumberOfConstraints() + npoints - 1 : getNumberOfConstraints();

  300.         final double[] fx = new double[nrows];
  301.         for (int i = 0; i < npoints - 1; i++) {
  302.             final AbsolutePVCoordinates absPvi = patchedSpacecraftStates.get(i + 1).getAbsPVA();
  303.             final AbsolutePVCoordinates absPvf = propagatedSP.get(i).getAbsPVA();
  304.             final double[] ecartPos = absPvf.getPosition().subtract(absPvi.getPosition()).toArray();
  305.             final double[] ecartVel = absPvf.getVelocity().subtract(absPvi.getVelocity()).toArray();
  306.             for (int j = 0; j < 3; j++) {
  307.                 fx[6 * i + j] = ecartPos[j];
  308.                 fx[6 * i + 3 + j] = ecartVel[j];
  309.             }
  310.         }

  311.         int index = 6 * (npoints - 1);

  312.         if (epoch) {
  313.             for (int i = 0; i < npoints - 1; i++) {
  314.                 final double deltaEpoch = patchedSpacecraftStates.get(i + 1).getDate().durationFrom(patchedSpacecraftStates.get(i).getDate());
  315.                 fx[index] = deltaEpoch - propagationTime[i];
  316.                 index++;
  317.             }
  318.         }

  319.         for (int i = 0; i < additionalConstraints.length; i++) {
  320.             fx[index] = additionalConstraints[i];
  321.             index++;
  322.         }

  323.         return fx;
  324.     }


  325.     /** Update the trajectory, and the propagation time.
  326.      *  @param dx correction on the initial vector
  327.      */
  328.     private void updateTrajectory(final RealVector dx) {
  329.         // X = [x1, ..., xn, T1, ..., Tn, d1, ..., dn]
  330.         // X = [x1, ..., xn, T, d2, ..., dn]

  331.         final int n = getNumberOfFreeVariables();

  332.         final boolean epochFree = getNumberOfFreeEpoch() > 0;

  333.         // Update propagation time
  334.         //------------------------------------------------------
  335.         final double deltaT = dx.getEntry(n - 1);
  336.         for (int i = 0; i < propagationTime.length; i++) {
  337.             propagationTime[i] = propagationTime[i] - deltaT;
  338.         }

  339.         // Update patch points through SpacecrafStates
  340.         //--------------------------------------------------------------------------------

  341.         int index = 0;
  342.         int indexEpoch = 0;

  343.         for (int i = 0; i < patchedSpacecraftStates.size(); i++) {
  344.             // Get delta in position and velocity
  345.             final double[] deltaPV = new double[6];
  346.             for (int j = 0; j < 6; j++) { // Loop on 6 component of the patch point
  347.                 if (freePatchPointMap[6 * i + j]) { // If this component is free (is to be updated)
  348.                     deltaPV[j] = dx.getEntry(index);
  349.                     index++;
  350.                 }
  351.             }
  352.             final Vector3D deltaP = new Vector3D(deltaPV[0], deltaPV[1], deltaPV[2]);
  353.             final Vector3D deltaV = new Vector3D(deltaPV[3], deltaPV[4], deltaPV[5]);

  354.             // Update the PVCoordinates of the patch point
  355.             final AbsolutePVCoordinates currentAPV = patchedSpacecraftStates.get(i).getAbsPVA();
  356.             final Vector3D position = currentAPV.getPosition().subtract(deltaP);
  357.             final Vector3D velocity = currentAPV.getVelocity().subtract(deltaV);
  358.             final PVCoordinates pv = new PVCoordinates(position, velocity);

  359.             //Update epoch in the AbsolutePVCoordinates
  360.             AbsoluteDate epoch = currentAPV.getDate();
  361.             if (epochFree) {
  362.                 if (freeEpochMap[i]) {
  363.                     final double deltaEpoch = dx.getEntry(n + indexEpoch);
  364.                     epoch = epoch.shiftedBy(-deltaEpoch);
  365.                     indexEpoch++;
  366.                 }
  367.             } else {
  368.                 if (i > 0) {
  369.                     epoch = patchedSpacecraftStates.get(i - 1).getDate().shiftedBy(propagationTime[i - 1]);
  370.                 }
  371.             }
  372.             final AbsolutePVCoordinates updatedAPV = new AbsolutePVCoordinates(currentAPV.getFrame(), epoch, pv);

  373.             //Update attitude epoch
  374.             // Last point does not have an associated propagator. The previous one is then selected.
  375.             final int iAttitude = i < getPropagatorList().size() ? i : getPropagatorList().size() - 1;
  376.             final AttitudeProvider attitudeProvider = getPropagatorList().get(iAttitude).getAttitudeProvider();
  377.             final Attitude attitude = attitudeProvider.getAttitude(updatedAPV, epoch, currentAPV.getFrame());

  378.             //Update the SpacecraftState using previously updated attitude and AbsolutePVCoordinates
  379.             patchedSpacecraftStates.set(i, new SpacecraftState(updatedAPV, attitude));
  380.         }

  381.     }

  382.     /** Compute the Jacobian matrix of the problem.
  383.      *  @return propagatedSP propagated SpacecraftStates
  384.      */
  385.     private List<SpacecraftState> propagatePatchedSpacecraftState() {

  386.         final int n = patchedSpacecraftStates.size() - 1;

  387.         final ArrayList<SpacecraftState> propagatedSP = new ArrayList<>(n);

  388.         for (int i = 0; i < n; i++) {

  389.             // SpacecraftState initialization
  390.             final SpacecraftState initialState = patchedSpacecraftStates.get(i);

  391.             final SpacecraftState augmentedInitialState = getAugmentedInitialState(initialState, additionalEquations.get(i));

  392.             // Propagator initialization
  393.             propagatorList.get(i).setInitialState(augmentedInitialState);

  394.             final double integrationTime = propagationTime[i];

  395.             // Propagate trajectory
  396.             final SpacecraftState finalState = propagatorList.get(i).propagate(initialState.getDate().shiftedBy(integrationTime));

  397.             propagatedSP.add(finalState);
  398.         }

  399.         return propagatedSP;
  400.     }

  401.     /** Get the state transition matrix.
  402.      * @param s current spacecraft state
  403.      * @return the state transition matrix
  404.      */
  405.     private double[][] getStateTransitionMatrix(final SpacecraftState s) {
  406.         // Additional states
  407.         final Map<String, double[]> map = s.getAdditionalStates();
  408.         // Initialize state transition matrix
  409.         final int        dim  = 6;
  410.         final double[][] phiM = new double[dim][dim];

  411.         // Loop on entry set
  412.         for (final Map.Entry<String, double[]> entry : map.entrySet()) {
  413.             // Extract entry name
  414.             final String name = entry.getKey();
  415.             if (additionalName.equals(name)) {
  416.                 final double[] stm = entry.getValue();
  417.                 for (int i = 0; i < dim; i++) {
  418.                     for (int j = 0; j < 6; j++) {
  419.                         phiM[i][j] = stm[dim * i + j];
  420.                     }
  421.                 }
  422.             }
  423.         }

  424.         // Return state transition matrix
  425.         return phiM;
  426.     }

  427.     /** Compute a part of the Jacobian matrix with derivatives from epoch.
  428.      * The CR3BP is a time invariant problem. The derivatives w.r.t. epoch are zero.
  429.      *  @param propagatedSP propagatedSP
  430.      *  @return jacobianMatrix Jacobian sub-matrix
  431.      */
  432.     protected double[][] computeEpochJacobianMatrix(final List<SpacecraftState> propagatedSP) {

  433.         final boolean[] map = getFreeEpochMap();

  434.         final int nFreeEpoch = getNumberOfFreeEpoch();
  435.         final int ncolumns = 1 + nFreeEpoch;
  436.         final int nrows = patchedSpacecraftStates.size() - 1;

  437.         final double[][] M = new double[nrows][ncolumns];

  438.         // The Jacobian matrix has the following form:

  439.         //      [-1 -1   1  0                 ]
  440.         //      [-1     -1   1  0             ]
  441.         // F =  [..          ..   ..          ]
  442.         //      [..               ..   ..   0 ]
  443.         //      [-1                    -1   1 ]

  444.         int index = 1;
  445.         for (int i = 0; i < nrows; i++) {
  446.             M[i][0] = -1;
  447.             if (map[i]) {
  448.                 M[i][index] = -1;
  449.                 index++;
  450.             }
  451.             if (map[i + 1]) {
  452.                 M[i][index] =  1;
  453.             }
  454.         }

  455.         return M;
  456.     }

  457.     /** Update the array of additional constraints.
  458.      * @param startIndex start index
  459.      * @param fxAdditional array of additional constraints
  460.      */
  461.     protected void updateAdditionalConstraints(final int startIndex, final double[] fxAdditional) {
  462.         int iter = startIndex;
  463.         for (final Map.Entry<Integer, Double> entry : getConstraintsMap().entrySet()) {
  464.             // Extract entry values
  465.             final int    key   = entry.getKey();
  466.             final double value = entry.getValue();
  467.             final int np = key / 6;
  468.             final int nc = key % 6;
  469.             final AbsolutePVCoordinates absPv = getPatchedSpacecraftState().get(np).getAbsPVA();
  470.             if (nc < 3) {
  471.                 fxAdditional[iter] = absPv.getPosition().toArray()[nc] - value;
  472.             } else {
  473.                 fxAdditional[iter] = absPv.getVelocity().toArray()[nc - 3] -  value;
  474.             }
  475.             iter++;
  476.         }
  477.     }

  478.     /** Compute the additional constraints.
  479.      *  @param propagatedSP propagated SpacecraftState
  480.      *  @return fxAdditionnal additional constraints
  481.      */
  482.     protected abstract double[] computeAdditionalConstraints(List<SpacecraftState> propagatedSP);

  483.     /** Compute a part of the Jacobian matrix from additional constraints.
  484.      *  @param propagatedSP propagatedSP
  485.      *  @return jacobianMatrix Jacobian sub-matrix
  486.      */
  487.     protected abstract double[][] computeAdditionalJacobianMatrix(List<SpacecraftState> propagatedSP);


  488.     /** Compute the additional state from the additionalEquations.
  489.      *  @param initialState SpacecraftState without the additional state
  490.      *  @param additionalEquations2 Additional Equations.
  491.      *  @return augmentedSP SpacecraftState with the additional state within.
  492.      */
  493.     protected abstract SpacecraftState getAugmentedInitialState(SpacecraftState initialState,
  494.                                                                 AdditionalEquations additionalEquations2);



  495.     /** Set the constraint of a closed orbit or not.
  496.      *  @param isClosed true if orbit should be closed
  497.      */
  498.     public void setClosedOrbitConstraint(final boolean isClosed) {
  499.         if (this.isClosedOrbit != isClosed) {
  500.             nConstraints = nConstraints + (isClosed ? 6 : -6);
  501.             this.isClosedOrbit = isClosed;
  502.         }
  503.     }

  504.     /** Get the number of free variables.
  505.      * @return the number of free variables
  506.      */
  507.     protected int getNumberOfFreeVariables() {
  508.         return nFree;
  509.     }

  510.     /** Get the number of free epoch.
  511.      * @return the number of free epoch
  512.      */
  513.     protected int getNumberOfFreeEpoch() {
  514.         return nEpoch;
  515.     }

  516.     /** Get the number of constraints.
  517.      * @return the number of constraints
  518.      */
  519.     protected int getNumberOfConstraints() {
  520.         return nConstraints;
  521.     }

  522.     /** Get the flags representing the free components of patch points.
  523.      * @return an array of flags representing the free components of patch points
  524.      */
  525.     protected boolean[] getFreePatchPointMap() {
  526.         return freePatchPointMap;
  527.     }

  528.     /** Get the flags representing the free epoch of patch points.
  529.      * @return an array of flags representing the free epoch of patch points
  530.      */
  531.     protected boolean[] getFreeEpochMap() {
  532.         return freeEpochMap;
  533.     }

  534.     /** Get the map of patch points components which are constrained.
  535.      * @return a map of patch points components which are constrained
  536.      */
  537.     protected Map<Integer, Double> getConstraintsMap() {
  538.         return mapConstraints;
  539.     }

  540.     /** Get the list of patched spacecraft states.
  541.      * @return a list of patched spacecraft states
  542.      */
  543.     protected List<SpacecraftState> getPatchedSpacecraftState() {
  544.         return patchedSpacecraftStates;
  545.     }

  546.     /** Get the list of propagators.
  547.      * @return a list of propagators
  548.      */
  549.     protected List<NumericalPropagator> getPropagatorList() {
  550.         return propagatorList;
  551.     }

  552.     /** Get he flag representing if the orbit is closed.
  553.      * @return true if orbit is closed
  554.      */
  555.     protected boolean isClosedOrbit() {
  556.         return isClosedOrbit;
  557.     }

  558. }