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

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


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

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

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

  55.     /** CR3BP System considered. */
  56.     private final CR3BPSystem syst;

  57.     /** orbitalPeriodApprox Orbital Period of the firstGuess. */
  58.     private final double orbitalPeriodApprox;

  59.     /** orbitalPeriod Orbital Period of the required orbit. */
  60.     private double orbitalPeriod;

  61.     /** Propagator. */
  62.     private final NumericalPropagator propagator;

  63.     /** UTC time scale. */
  64.     private final TimeScale utc;

  65.     /** Simple Constructor.
  66.      * <p> Standard constructor using DormandPrince853 integrator for the differential correction </p>
  67.      * @param firstguess first guess PVCoordinates of the point to start differential correction
  68.      * @param syst CR3BP System considered
  69.      * @param orbitalPeriod Orbital Period of the required orbit
  70.      */
  71.     @DefaultDataContext
  72.     public CR3BPDifferentialCorrection(final PVCoordinates firstguess,
  73.                                        final CR3BPSystem syst, final double orbitalPeriod) {
  74.         this(firstguess, syst, orbitalPeriod,
  75.                 Propagator.getDefaultLaw(DataContext.getDefault().getFrames()),
  76.                 DataContext.getDefault().getTimeScales().getUTC());
  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 numerocal propagator
  84.      * @param utc UTC time scale
  85.      */
  86.     public CR3BPDifferentialCorrection(final PVCoordinates firstguess,
  87.                                        final CR3BPSystem syst,
  88.                                        final double orbitalPeriod,
  89.                                        final AttitudeProvider attitudeProvider,
  90.                                        final TimeScale utc) {
  91.         this.firstGuess = firstguess;
  92.         this.syst = syst;
  93.         this.orbitalPeriodApprox = orbitalPeriod;
  94.         this.utc = utc;

  95.         // Adaptive stepsize boundaries
  96.         final double minStep = 1E-12;
  97.         final double maxstep = 0.001;

  98.         // Integrator tolerances
  99.         final double positionTolerance = 1E-5;
  100.         final double velocityTolerance = 1E-5;
  101.         final double massTolerance = 1.0e-6;
  102.         final double[] vecAbsoluteTolerances = {positionTolerance, positionTolerance, positionTolerance, velocityTolerance, velocityTolerance, velocityTolerance, massTolerance};
  103.         final double[] vecRelativeTolerances = new double[vecAbsoluteTolerances.length];

  104.         // Integrator definition
  105.         final AdaptiveStepsizeIntegrator integrator = new DormandPrince853Integrator(minStep, maxstep,
  106.                                                                                      vecAbsoluteTolerances,
  107.                                                                                      vecRelativeTolerances);

  108.         // Propagator definition
  109.         this.propagator = new NumericalPropagator(integrator, attitudeProvider);

  110.     }

  111.     /**
  112.      * Return the real starting PVCoordinates on the Libration orbit type
  113.      * after differential correction from a first guess.
  114.      * @param type libration orbit type
  115.      * @return pv Position-Velocity of the starting point on the Halo Orbit
  116.      */
  117.     public PVCoordinates compute(final LibrationOrbitType type) {
  118.         // Event detector settings
  119.         final double maxcheck = 10;
  120.         final double threshold = 1E-10;

  121.         // Event detector definition
  122.         final EventDetector XZPlaneCrossing =
  123.             new HaloXZPlaneCrossingDetector(maxcheck, threshold).withHandler(new PlaneCrossingHandler());

  124.         // Additional equations set in order to compute the State Transition Matrix along the propagation
  125.         final STMEquations stm = new STMEquations(syst);

  126.         // CR3BP has no defined orbit type
  127.         propagator.setOrbitType(null);

  128.         // CR3BP has central Attraction
  129.         propagator.setIgnoreCentralAttraction(true);

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

  132.         // Add previously set additional equations to the propagator
  133.         propagator.addAdditionalEquations(stm);

  134.         // Add previously set event detector to the propagator
  135.         propagator.addEventDetector(XZPlaneCrossing);

  136.         return type == LibrationOrbitType.HALO ? computeHalo(stm) : computeLyapunov(stm);
  137.     }

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

  144.         // number of iteration
  145.         double iHalo = 0;

  146.         // Time settings (this date has no effect on the result, this is only for code structure purpose)
  147.         final AbsoluteDate startDateHalo = new AbsoluteDate(1996, 06, 25, 0, 0, 00.000, utc);

  148.         // Initializing PVCoordinates with first guess
  149.         PVCoordinates pvHalo = firstGuess;

  150.         // Start a new differentially corrected propagation until it converges to a Halo Orbit
  151.         do {

  152.             // SpacecraftState initialization
  153.             final AbsolutePVCoordinates initialAbsPVHalo = new AbsolutePVCoordinates(syst.getRotatingFrame(), startDateHalo, pvHalo);
  154.             final SpacecraftState       initialStateHalo = new SpacecraftState(initialAbsPVHalo);

  155.             // Additional equations initialization
  156.             final SpacecraftState augmentedInitialStateHalo = stm.setInitialPhi(initialStateHalo);

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

  159.             // Propagator initialization
  160.             propagator.setInitialState(augmentedInitialStateHalo);

  161.             // Propagate until trajectory crosses XZ Plane
  162.             final SpacecraftState finalStateHalo =
  163.                 propagator.propagate(startDateHalo.shiftedBy(orbitalPeriodApprox));

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

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

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

  173.             orbitalPeriod = 2 * finalStateHalo.getDate().durationFrom(startDateHalo);

  174.             if (FastMath.abs(dvxf) > 1E-8 || FastMath.abs(dvzf) > 1E-8) {
  175.                 // Y axis velocity
  176.                 final double vy =
  177.                     finalStateHalo.getPVCoordinates().getVelocity().getY();

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

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

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

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

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

  195.                 pvHalo = new PVCoordinates(new Vector3D(newx,
  196.                                                         pvHalo.getPosition().getY(),
  197.                                                         pvHalo.getPosition().getZ()),
  198.                                            new Vector3D(pvHalo.getVelocity().getX(),
  199.                                                         newvy,
  200.                                                         pvHalo.getVelocity().getZ()));
  201.                 ++iHalo;
  202.             } else {
  203.                 break;
  204.             }

  205.         } while (iHalo < 30);  // Converge within 1E-8 tolerance and under 5 iterations

  206.         // Return
  207.         return pvHalo;
  208.     }

  209.     /** Return the real starting PVCoordinates on the Lyapunov orbit after
  210.      * differential correction from a first guess.
  211.      * @param stm additional equations
  212.      * @return pv Position-Velocity of the starting point on the Lyapunov Orbit
  213.      */
  214.     public PVCoordinates computeLyapunov(final STMEquations stm) {

  215.         // number of iteration
  216.         double iLyapunov = 0;

  217.         // Time settings (this date has no effect on the result, this is only for code structure purpose)
  218.         final AbsoluteDate startDateLyapunov = new AbsoluteDate(1996, 06, 25, 0, 0, 00.000, utc);

  219.         // Initializing PVCoordinates with first guess
  220.         PVCoordinates pvLyapunov = firstGuess;

  221.         // Start a new differentially corrected propagation until it converges to a Halo Orbit
  222.         do {

  223.             // SpacecraftState initialization
  224.             final AbsolutePVCoordinates initialAbsPVLyapunov = new AbsolutePVCoordinates(syst.getRotatingFrame(), startDateLyapunov, pvLyapunov);
  225.             final SpacecraftState       initialStateLyapunov = new SpacecraftState(initialAbsPVLyapunov);

  226.             // Additional equations initialization
  227.             final SpacecraftState augmentedInitialStateLyapunov = stm.setInitialPhi(initialStateLyapunov);

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

  230.             // Propagator initialization
  231.             propagator.setInitialState(augmentedInitialStateLyapunov);

  232.             // Propagate until trajectory crosses XZ Plane
  233.             final SpacecraftState finalStateLyapunov =
  234.                 propagator.propagate(startDateLyapunov.shiftedBy(orbitalPeriodApprox));

  235.             // Stops computation if trajectory did not cross XZ Plane after one full orbital period
  236.             if (cross == false) {
  237.                 throw new OrekitException(OrekitMessages.TRAJECTORY_NOT_CROSSING_XZPLANE);
  238.             }

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

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

  243.             orbitalPeriod = 2 * finalStateLyapunov.getDate().durationFrom(startDateLyapunov);

  244.             if (FastMath.abs(dvxf) > 1E-14) {
  245.                 // Y axis velocity
  246.                 final double vy = finalStateLyapunov.getPVCoordinates().getVelocity().getY();

  247.                 // Spacecraft acceleration
  248.                 final double accy = finalStateLyapunov.getPVCoordinates().getAcceleration().getY();

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

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

  253.                 pvLyapunov = new PVCoordinates(new Vector3D(pvLyapunov.getPosition().getX(),
  254.                                                             pvLyapunov.getPosition().getY(),
  255.                                                             0),
  256.                                                new Vector3D(pvLyapunov.getVelocity().getX(),
  257.                                                             newvy,
  258.                                                             0));

  259.                 ++iLyapunov;
  260.             } else {
  261.                 break;
  262.             }

  263.         } while (iLyapunov < 30); // Converge within 1E-8 tolerance and under 5 iterations

  264.         // Return
  265.         return pvLyapunov;
  266.     }

  267.     /** Get the orbital period of the required orbit.
  268.      * @return the orbitalPeriod
  269.      */
  270.     public double getOrbitalPeriod() {
  271.         return orbitalPeriod;
  272.     }

  273.     /**
  274.      * Static class for event detection.
  275.      */
  276.     private class PlaneCrossingHandler implements EventHandler<HaloXZPlaneCrossingDetector> {

  277.         /** {@inheritDoc} */
  278.         public Action eventOccurred(final SpacecraftState s,
  279.                                     final HaloXZPlaneCrossingDetector detector,
  280.                                     final boolean increasing) {
  281.             cross = true;
  282.             return Action.STOP;
  283.         }
  284.     }
  285. }