AbstractFixedBoundaryCartesianSingleShooting.java

  1. /* Copyright 2022-2025 Romain Serra
  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.control.indirect.shooting;

  18. import org.hipparchus.util.FastMath;
  19. import org.orekit.attitudes.Attitude;
  20. import org.orekit.control.indirect.shooting.boundary.CartesianBoundaryConditionChecker;
  21. import org.orekit.control.indirect.shooting.boundary.FixedTimeBoundaryOrbits;
  22. import org.orekit.control.indirect.shooting.boundary.FixedTimeCartesianBoundaryStates;
  23. import org.orekit.control.indirect.shooting.propagation.ShootingPropagationSettings;
  24. import org.orekit.frames.Frame;
  25. import org.orekit.orbits.CartesianOrbit;
  26. import org.orekit.orbits.Orbit;
  27. import org.orekit.propagation.SpacecraftState;
  28. import org.orekit.propagation.numerical.NumericalPropagator;
  29. import org.orekit.utils.AbsolutePVCoordinates;
  30. import org.orekit.utils.TimeStampedPVCoordinates;

  31. /**
  32.  * Abstract class for indirect single shooting methods with Cartesian coordinates for fixed time fixed boundary.
  33.  * Terminal mass is assumed to be free, thus corresponding adjoint must vanish at terminal time.
  34.  * On the other hand, other terminal adjoint variables are free because the Cartesian state is fixed.
  35.  *
  36.  * @author Romain Serra
  37.  * @since 12.2
  38.  * @see org.orekit.control.indirect.adjoint.CartesianAdjointDerivativesProvider
  39.  * @see org.orekit.control.indirect.adjoint.FieldCartesianAdjointDerivativesProvider
  40.  */
  41. public abstract class AbstractFixedBoundaryCartesianSingleShooting extends AbstractFixedInitialCartesianSingleShooting {

  42.     /** Default value for defects scaling. */
  43.     private static final double DEFAULT_SCALE = 1.;

  44.     /** Terminal Cartesian coordinates. */
  45.     private final TimeStampedPVCoordinates terminalCartesianState;

  46.     /** Condition checker. */
  47.     private final CartesianBoundaryConditionChecker conditionChecker;

  48.     /** Scale for velocity defects (m). */
  49.     private double scaleVelocityDefects;

  50.     /** Scale for position defects (m/s). */
  51.     private double scalePositionDefects;

  52.     /** Tolerance for convergence on terminal mass adjoint, if applicable to dynamics. */
  53.     private double toleranceMassAdjoint = DEFAULT_TOLERANCE_MASS_ADJOINT;

  54.     /**
  55.      * Constructor with boundary conditions as orbits.
  56.      * @param propagationSettings propagation settings
  57.      * @param boundaryConditions boundary conditions as {@link FixedTimeCartesianBoundaryStates}
  58.      * @param conditionChecker boundary condition checker
  59.      */
  60.     protected AbstractFixedBoundaryCartesianSingleShooting(final ShootingPropagationSettings propagationSettings,
  61.                                                            final FixedTimeCartesianBoundaryStates boundaryConditions,
  62.                                                            final CartesianBoundaryConditionChecker conditionChecker) {
  63.         super(propagationSettings, buildInitialStateTemplate(boundaryConditions.getInitialCartesianState(),
  64.                 propagationSettings));
  65.         this.conditionChecker = conditionChecker;
  66.         this.terminalCartesianState = boundaryConditions.getTerminalCartesianState()
  67.                 .getPVCoordinates(propagationSettings.getPropagationFrame());
  68.         this.scalePositionDefects = DEFAULT_SCALE;
  69.         this.scaleVelocityDefects = DEFAULT_SCALE;
  70.     }

  71.     /**
  72.      * Constructor with boundary conditions as orbits.
  73.      * @param propagationSettings propagation settings
  74.      * @param boundaryConditions boundary conditions as {@link FixedTimeBoundaryOrbits}
  75.      * @param conditionChecker boundary condition checker
  76.      */
  77.     protected AbstractFixedBoundaryCartesianSingleShooting(final ShootingPropagationSettings propagationSettings,
  78.                                                            final FixedTimeBoundaryOrbits boundaryConditions,
  79.                                                            final CartesianBoundaryConditionChecker conditionChecker) {
  80.         super(propagationSettings, buildInitialStateTemplate(boundaryConditions.getInitialOrbit(),
  81.                 propagationSettings));
  82.         this.conditionChecker = conditionChecker;
  83.         this.terminalCartesianState = boundaryConditions.getTerminalOrbit().getPVCoordinates(propagationSettings.getPropagationFrame());
  84.         this.scalePositionDefects = DEFAULT_SCALE;
  85.         this.scaleVelocityDefects = DEFAULT_SCALE;
  86.     }

  87.     /**
  88.      * Setter for scale of position defects.
  89.      * @param scalePositionDefects new scale
  90.      */
  91.     public void setScalePositionDefects(final double scalePositionDefects) {
  92.         this.scalePositionDefects = scalePositionDefects;
  93.     }

  94.     /**
  95.      * Getter for scale of position defects.
  96.      * @return scale
  97.      */
  98.     public double getScalePositionDefects() {
  99.         return scalePositionDefects;
  100.     }

  101.     /**
  102.      * Setter for scale of velocity defects.
  103.      * @param scaleVelocityDefects new scale
  104.      */
  105.     public void setScaleVelocityDefects(final double scaleVelocityDefects) {
  106.         this.scaleVelocityDefects = scaleVelocityDefects;
  107.     }

  108.     /**
  109.      * Getter for scale of velocity defects.
  110.      * @return scale
  111.      */
  112.     public double getScaleVelocityDefects() {
  113.         return scaleVelocityDefects;
  114.     }

  115.     /**
  116.      * Getter for the boundary condition checker.
  117.      * @return checker
  118.      */
  119.     protected CartesianBoundaryConditionChecker getConditionChecker() {
  120.         return conditionChecker;
  121.     }

  122.     /**
  123.      * Getter for the target terminal Cartesian state vector.
  124.      * @return expected terminal state
  125.      */
  126.     protected TimeStampedPVCoordinates getTerminalCartesianState() {
  127.         return terminalCartesianState;
  128.     }

  129.     /**
  130.      * Setter for mass adjoint tolerance.
  131.      * @param toleranceMassAdjoint new tolerance value
  132.      */
  133.     public void setToleranceMassAdjoint(final double toleranceMassAdjoint) {
  134.         this.toleranceMassAdjoint = FastMath.abs(toleranceMassAdjoint);
  135.     }

  136.     /**
  137.      * Create template initial state (without adjoint varialbles) for propagation from orbits.
  138.      * @param initialOrbit initial orbit
  139.      * @param propagationSettings propagation settings
  140.      * @return template propagation state
  141.      */
  142.     private static SpacecraftState buildInitialStateTemplate(final Orbit initialOrbit,
  143.                                                              final ShootingPropagationSettings propagationSettings) {
  144.         final Frame frame = propagationSettings.getPropagationFrame();
  145.         final CartesianOrbit cartesianOrbit = new CartesianOrbit(initialOrbit.getPVCoordinates(frame), frame,
  146.             initialOrbit.getDate(), initialOrbit.getMu());
  147.         final Attitude attitude = propagationSettings.getAttitudeProvider()
  148.                 .getAttitude(cartesianOrbit, cartesianOrbit.getDate(), cartesianOrbit.getFrame());
  149.         return new SpacecraftState(cartesianOrbit).withAttitude(attitude);
  150.     }

  151.     /**
  152.      * Create template initial state (without adjoint varialbles) for propagation.
  153.      * @param initialCartesianState initial Cartesian state
  154.      * @param propagationSettings propagation settings
  155.      * @return template propagation state
  156.      */
  157.     private static SpacecraftState buildInitialStateTemplate(final AbsolutePVCoordinates initialCartesianState,
  158.                                                              final ShootingPropagationSettings propagationSettings) {
  159.         final Frame frame = propagationSettings.getPropagationFrame();
  160.         final AbsolutePVCoordinates absolutePVCoordinates = new AbsolutePVCoordinates(frame,
  161.                 initialCartesianState.getPVCoordinates(frame));
  162.         final Attitude attitude = propagationSettings.getAttitudeProvider()
  163.                 .getAttitude(absolutePVCoordinates, absolutePVCoordinates.getDate(), absolutePVCoordinates.getFrame());
  164.         return new SpacecraftState(absolutePVCoordinates, attitude);
  165.     }

  166.     /** {@inheritDoc} */
  167.     @Override
  168.     public ShootingBoundaryOutput computeCandidateSolution(final SpacecraftState initialState,
  169.                                                            final int iterationCount) {
  170.         final NumericalPropagator propagator = buildPropagator(initialState);
  171.         final SpacecraftState actualTerminalState = propagator.propagate(getTerminalCartesianState().getDate());
  172.         final boolean converged = checkConvergence(actualTerminalState);
  173.         return new ShootingBoundaryOutput(converged, iterationCount, initialState, getPropagationSettings(),
  174.                 actualTerminalState);
  175.     }

  176.     /**
  177.      * Checks convergence.
  178.      * @param actualTerminalState achieved terminal state
  179.      * @return convergence flag
  180.      */
  181.     private boolean checkConvergence(final SpacecraftState actualTerminalState) {
  182.         final boolean isCartesianConverged = getConditionChecker().isConverged(getTerminalCartesianState(),
  183.                 actualTerminalState.getPVCoordinates());
  184.         if (isCartesianConverged) {
  185.             final String adjointName = getPropagationSettings().getAdjointDynamicsProvider().getAdjointName();
  186.             final double[] terminalAdjoint = actualTerminalState.getAdditionalState(adjointName);
  187.             if (terminalAdjoint.length == 7) {
  188.                 return FastMath.abs(terminalAdjoint[6]) < toleranceMassAdjoint;
  189.             } else {
  190.                 return true;
  191.             }
  192.         } else {
  193.             return false;
  194.         }
  195.     }

  196. }