CR3BPDifferentialCorrection.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.orbits;

  18. import org.hipparchus.geometry.euclidean.threed.Rotation;
  19. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  20. import org.hipparchus.linear.RealMatrix;
  21. import org.hipparchus.ode.events.Action;
  22. import org.hipparchus.ode.nonstiff.AdaptiveStepsizeIntegrator;
  23. import org.hipparchus.ode.nonstiff.DormandPrince853Integrator;
  24. import org.hipparchus.util.FastMath;
  25. import org.orekit.attitudes.AttitudeProvider;
  26. import org.orekit.attitudes.InertialProvider;
  27. import org.orekit.bodies.CR3BPSystem;
  28. import org.orekit.errors.OrekitException;
  29. import org.orekit.errors.OrekitMessages;
  30. import org.orekit.propagation.SpacecraftState;
  31. import org.orekit.propagation.events.HaloXZPlaneCrossingDetector;
  32. import org.orekit.propagation.numerical.NumericalPropagator;
  33. import org.orekit.propagation.numerical.cr3bp.CR3BPForceModel;
  34. import org.orekit.propagation.numerical.cr3bp.STMEquations;
  35. import org.orekit.time.AbsoluteDate;
  36. import org.orekit.time.TimeScale;
  37. import org.orekit.utils.AbsolutePVCoordinates;
  38. import org.orekit.utils.PVCoordinates;


  39. /**
  40.  * Class implementing the differential correction method for Halo or Lyapunov
  41.  * Orbits. It is not a simple differential correction, it uses higher order
  42.  * terms to be more accurate and meet orbits requirements.
  43.  * @see "Three-dimensional, periodic, Halo Orbits by Kathleen Connor Howell, Stanford University"
  44.  * @author Vincent Mouraux
  45.  * @since 10.2
  46.  */
  47. public class CR3BPDifferentialCorrection {

  48.     /** Maximum number of iterations. */
  49.     private static final int MAX_ITER = 30;

  50.     /** Max check interval for crossing plane. */
  51.     private static final double CROSSING_MAX_CHECK = 3600.0;

  52.     /** Convergence tolerance for plane crossing time. */
  53.     private static final double CROSSING_TOLERANCE = 1.0e-10;

  54.     /** Arbitrary start date. */
  55.     private static final AbsoluteDate START_DATE = AbsoluteDate.ARBITRARY_EPOCH;

  56.     /** Boolean return true if the propagated trajectory crosses the plane. */
  57.     private boolean cross;

  58.     /** first guess PVCoordinates of the point to start differential correction. */
  59.     private final PVCoordinates firstGuess;

  60.     /** CR3BP System considered. */
  61.     private final CR3BPSystem syst;

  62.     /** orbitalPeriodApprox Orbital Period of the firstGuess. */
  63.     private final double orbitalPeriodApprox;

  64.     /** orbitalPeriod Orbital Period of the required orbit. */
  65.     private double orbitalPeriod;

  66.     /** Simple Constructor.
  67.      * <p> Standard constructor using DormandPrince853 integrator for the differential correction </p>
  68.      * @param firstguess first guess PVCoordinates of the point to start differential correction
  69.      * @param syst CR3BP System considered
  70.      * @param orbitalPeriod Orbital Period of the required orbit
  71.      */
  72.     public CR3BPDifferentialCorrection(final PVCoordinates firstguess,
  73.                                        final CR3BPSystem syst, final double orbitalPeriod) {
  74.         this.firstGuess = firstguess;
  75.         this.syst = syst;
  76.         this.orbitalPeriodApprox = orbitalPeriod;

  77.     }

  78.     /** Simple Constructor.
  79.      * <p> Standard constructor using DormandPrince853 integrator for the differential correction </p>
  80.      * @param firstguess first guess PVCoordinates of the point to start differential correction
  81.      * @param syst CR3BP System considered
  82.      * @param orbitalPeriod Orbital Period of the required orbit
  83.      * @param attitudeProvider the attitude law for the numerical propagator
  84.      * @param utc UTC time scale
  85.      * @deprecated as of 11.1, replaced by {@link #CR3BPDifferentialCorrection(PVCoordinates, CR3BPSystem, double)}
  86.      */
  87.     @Deprecated
  88.     public CR3BPDifferentialCorrection(final PVCoordinates firstguess,
  89.                                        final CR3BPSystem syst,
  90.                                        final double orbitalPeriod,
  91.                                        final AttitudeProvider attitudeProvider,
  92.                                        final TimeScale utc) {
  93.         this(firstguess, syst, orbitalPeriod);
  94.     }

  95.     /** Build the propagator.
  96.      * @return propagator
  97.      * @since 11.1
  98.      */
  99.     private NumericalPropagator buildPropagator() {

  100.         // Adaptive stepsize boundaries
  101.         final double minStep = 1E-12;
  102.         final double maxstep = 0.001;

  103.         // Integrator tolerances
  104.         final double positionTolerance = 1E-5;
  105.         final double velocityTolerance = 1E-5;
  106.         final double massTolerance = 1.0e-6;
  107.         final double[] vecAbsoluteTolerances = {positionTolerance, positionTolerance, positionTolerance, velocityTolerance, velocityTolerance, velocityTolerance, massTolerance};
  108.         final double[] vecRelativeTolerances = new double[vecAbsoluteTolerances.length];

  109.         // Integrator definition
  110.         final AdaptiveStepsizeIntegrator integrator = new DormandPrince853Integrator(minStep, maxstep,
  111.                                                                                      vecAbsoluteTolerances,
  112.                                                                                      vecRelativeTolerances);

  113.         // Propagator definition
  114.         final NumericalPropagator propagator =
  115.                         new NumericalPropagator(integrator, new InertialProvider(Rotation.IDENTITY, syst.getRotatingFrame()));

  116.         // CR3BP has no defined orbit type
  117.         propagator.setOrbitType(null);

  118.         // CR3BP has central Attraction
  119.         propagator.setIgnoreCentralAttraction(true);

  120.         // Add CR3BP Force Model to the propagator
  121.         propagator.addForceModel(new CR3BPForceModel(syst));

  122.         // Add event detector for crossing plane
  123.         propagator.addEventDetector(new HaloXZPlaneCrossingDetector(CROSSING_MAX_CHECK, CROSSING_TOLERANCE).
  124.                                     withHandler((state, detector, increasing) -> {
  125.                                         cross = true;
  126.                                         return Action.STOP;
  127.                                     }));

  128.         return propagator;

  129.     }

  130.     /**
  131.      * Return the real starting PVCoordinates on the Libration orbit type
  132.      * after differential correction from a first guess.
  133.      * @param type libration orbit type
  134.      * @return pv Position-Velocity of the starting point on the Halo Orbit
  135.      */
  136.     public PVCoordinates compute(final LibrationOrbitType type) {
  137.         return type == LibrationOrbitType.HALO ? computeHalo() : computeLyapunov();
  138.     }

  139.     /** Return the real starting PVCoordinates on the Halo orbit after differential correction from a first guess.
  140.      * @return pv Position-Velocity of the starting point on the Halo Orbit
  141.      */
  142.     private PVCoordinates computeHalo() {

  143.         // Initializing PVCoordinates with first guess
  144.         PVCoordinates pvHalo = firstGuess;

  145.         // Start a new differentially corrected propagation until it converges to a Halo Orbit
  146.         // Converge within 1E-8 tolerance and under 5 iterations
  147.         for (int iHalo = 0; iHalo < MAX_ITER; ++iHalo) {

  148.             // SpacecraftState initialization
  149.             final AbsolutePVCoordinates initialAbsPVHalo = new AbsolutePVCoordinates(syst.getRotatingFrame(), START_DATE, pvHalo);
  150.             final SpacecraftState       initialStateHalo = new SpacecraftState(initialAbsPVHalo);

  151.             // setup propagator
  152.             final NumericalPropagator propagator = buildPropagator();
  153.             final STMEquations        stm        = new STMEquations(syst);
  154.             propagator.addAdditionalDerivativesProvider(stm);
  155.             propagator.setInitialState(stm.setInitialPhi(initialStateHalo));

  156.             // boolean changed to true by crossing XZ plane during propagation. Has to be true for the differential correction to converge
  157.             cross = false;

  158.             // Propagate until trajectory crosses XZ Plane
  159.             final SpacecraftState finalStateHalo =
  160.                 propagator.propagate(START_DATE.shiftedBy(orbitalPeriodApprox));

  161.             // Stops computation if trajectory did not cross XZ Plane after one full orbital period
  162.             if (cross == false) {
  163.                 throw new OrekitException(OrekitMessages.TRAJECTORY_NOT_CROSSING_XZPLANE);
  164.             }

  165.             // Get State Transition Matrix phi
  166.             final RealMatrix phiHalo = stm.getStateTransitionMatrix(finalStateHalo);

  167.             // Gap from desired X and Z axis velocity value ()
  168.             final double dvxf = -finalStateHalo.getPVCoordinates().getVelocity().getX();
  169.             final double dvzf = -finalStateHalo.getPVCoordinates().getVelocity().getZ();

  170.             orbitalPeriod = 2 * finalStateHalo.getDate().durationFrom(START_DATE);

  171.             if (FastMath.abs(dvxf) <= 1E-8 && FastMath.abs(dvzf) <= 1E-8) {
  172.                 break;
  173.             }

  174.             // Y axis velocity
  175.             final double vy = finalStateHalo.getPVCoordinates().getVelocity().getY();

  176.             // Spacecraft acceleration
  177.             final Vector3D acc  = finalStateHalo.getPVCoordinates().getAcceleration();
  178.             final double   accx = acc.getX();
  179.             final double   accz = acc.getZ();

  180.             // Compute A coefficients
  181.             final double a11 = phiHalo.getEntry(3, 0) - accx * phiHalo.getEntry(1, 0) / vy;
  182.             final double a12 = phiHalo.getEntry(3, 4) - accx * phiHalo.getEntry(1, 4) / vy;
  183.             final double a21 = phiHalo.getEntry(5, 0) - accz * phiHalo.getEntry(1, 0) / vy;
  184.             final double a22 = phiHalo.getEntry(5, 4) - accz * phiHalo.getEntry(1, 4) / vy;

  185.             // A determinant used for matrix inversion
  186.             final double aDet = a11 * a22 - a21 * a12;

  187.             // Correction to apply to initial conditions
  188.             final double deltax0  = (a22 * dvxf - a12 * dvzf) / aDet;
  189.             final double deltavy0 = (-a21 * dvxf + a11 * dvzf) / aDet;

  190.             // Computation of the corrected initial PVCoordinates
  191.             final double newx  = pvHalo.getPosition().getX() + deltax0;
  192.             final double newvy = pvHalo.getVelocity().getY() + deltavy0;

  193.             pvHalo = new PVCoordinates(new Vector3D(newx,
  194.                                                     pvHalo.getPosition().getY(),
  195.                                                     pvHalo.getPosition().getZ()),
  196.                                        new Vector3D(pvHalo.getVelocity().getX(),
  197.                                                     newvy,
  198.                                                     pvHalo.getVelocity().getZ()));
  199.         }

  200.         // Return
  201.         return pvHalo;
  202.     }

  203.     /** Return the real starting PVCoordinates on the Lyapunov orbit after differential correction from a first guess.
  204.      * @return pv Position-Velocity of the starting point on the Lyapunov Orbit
  205.      */
  206.     public PVCoordinates computeLyapunov() {

  207.         // Initializing PVCoordinates with first guess
  208.         PVCoordinates pvLyapunov = firstGuess;

  209.         // Start a new differentially corrected propagation until it converges to a Halo Orbit
  210.         // Converge within 1E-8 tolerance and under 5 iterations
  211.         for (int iLyapunov = 0; iLyapunov < MAX_ITER; ++iLyapunov) {

  212.             // SpacecraftState initialization
  213.             final AbsolutePVCoordinates initialAbsPVLyapunov = new AbsolutePVCoordinates(syst.getRotatingFrame(), START_DATE, pvLyapunov);
  214.             final SpacecraftState       initialStateLyapunov = new SpacecraftState(initialAbsPVLyapunov);

  215.             // setup propagator
  216.             final NumericalPropagator propagator = buildPropagator();
  217.             final STMEquations        stm        = new STMEquations(syst);
  218.             propagator.addAdditionalDerivativesProvider(stm);
  219.             propagator.setInitialState(stm.setInitialPhi(initialStateLyapunov));

  220.             // boolean changed to true by crossing XZ plane during propagation. Has to be true for the differential correction to converge
  221.             cross = false;

  222.             // Propagate until trajectory crosses XZ Plane
  223.             final SpacecraftState finalStateLyapunov =
  224.                 propagator.propagate(START_DATE.shiftedBy(orbitalPeriodApprox));

  225.             // Stops computation if trajectory did not cross XZ Plane after one full orbital period
  226.             if (cross == false) {
  227.                 throw new OrekitException(OrekitMessages.TRAJECTORY_NOT_CROSSING_XZPLANE);
  228.             }

  229.             // Get State Transition Matrix phi
  230.             final RealMatrix phi = stm.getStateTransitionMatrix(finalStateLyapunov);

  231.             // Gap from desired y position and x velocity value ()
  232.             final double dvxf = -finalStateLyapunov.getPVCoordinates().getVelocity().getX();

  233.             orbitalPeriod = 2 * finalStateLyapunov.getDate().durationFrom(START_DATE);

  234.             if (FastMath.abs(dvxf) <= 1E-14) {
  235.                 break;
  236.             }

  237.             // Y axis velocity
  238.             final double vy = finalStateLyapunov.getPVCoordinates().getVelocity().getY();

  239.             // Spacecraft acceleration
  240.             final double accy = finalStateLyapunov.getPVCoordinates().getAcceleration().getY();

  241.             // Compute A coefficients
  242.             final double deltavy0 = dvxf / (phi.getEntry(3, 4) - accy * phi.getEntry(1, 4) / vy);

  243.             // Computation of the corrected initial PVCoordinates
  244.             final double newvy = pvLyapunov.getVelocity().getY() + deltavy0;

  245.             pvLyapunov = new PVCoordinates(new Vector3D(pvLyapunov.getPosition().getX(),
  246.                                                         pvLyapunov.getPosition().getY(),
  247.                                                         0),
  248.                                            new Vector3D(pvLyapunov.getVelocity().getX(),
  249.                                                         newvy,
  250.                                                         0));

  251.         }

  252.         // Return
  253.         return pvLyapunov;
  254.     }

  255.     /** Get the orbital period of the required orbit.
  256.      * @return the orbitalPeriod
  257.      */
  258.     public double getOrbitalPeriod() {
  259.         return orbitalPeriod;
  260.     }

  261. }