AbstractSwitchingAttitudeProvider.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.attitudes;

  18. import org.hipparchus.CalculusFieldElement;
  19. import org.hipparchus.Field;
  20. import org.hipparchus.geometry.euclidean.threed.FieldRotation;
  21. import org.hipparchus.geometry.euclidean.threed.Rotation;
  22. import org.hipparchus.ode.events.Action;
  23. import org.orekit.frames.Frame;
  24. import org.orekit.propagation.FieldSpacecraftState;
  25. import org.orekit.propagation.SpacecraftState;
  26. import org.orekit.propagation.events.DetectorModifier;
  27. import org.orekit.propagation.events.EventDetector;
  28. import org.orekit.propagation.events.FieldEventDetector;
  29. import org.orekit.propagation.events.FieldEventDetectionSettings;
  30. import org.orekit.propagation.events.handlers.EventHandler;
  31. import org.orekit.propagation.events.handlers.FieldEventHandler;
  32. import org.orekit.time.AbsoluteDate;
  33. import org.orekit.time.FieldAbsoluteDate;
  34. import org.orekit.utils.FieldPVCoordinatesProvider;
  35. import org.orekit.utils.PVCoordinatesProvider;
  36. import org.orekit.utils.TimeSpanMap;

  37. /** This classes manages a sequence of different attitude providers that are activated
  38.  * in turn according to switching events.
  39.  * <p>Only one attitude provider in the sequence is in an active state. When one of
  40.  * the switch event associated with the active provider occurs, the active provider becomes
  41.  * the one specified with the event. A simple example is a provider for the sun lighted part
  42.  * of the orbit and another provider for the eclipse time. When the sun lighted provider is active,
  43.  * the eclipse entry event is checked and when it occurs the eclipse provider is activated.
  44.  * When the eclipse provider is active, the eclipse exit event is checked and when it occurs
  45.  * the sun lighted provider is activated again. This sequence is a simple loop.</p>
  46.  * <p>An active attitude provider may have several switch events and next provider settings, leading
  47.  * to different activation patterns depending on which events are triggered first. An example
  48.  * of this feature is handling switches to safe mode if some contingency condition is met, in
  49.  * addition to the nominal switches that correspond to proper operations. Another example
  50.  * is handling of maneuver mode.
  51.  * <p>
  52.  * Note that this attitude provider is stateful, it keeps in memory the sequence of active
  53.  * underlying providers with their switch dates and the transitions from one provider to
  54.  * the other. This implies that this provider should <em>not</em> be shared among different
  55.  * propagators at the same time, each propagator should use its own instance of this provider.
  56.  * <p>
  57.  * The sequence kept in memory is reset when {@link #resetActiveProvider(AttitudeProvider)}
  58.  * is called, and only the specify provider is kept. The sequence is also partially
  59.  * reset each time a propagation starts. If a new propagation is started after a first
  60.  * propagation has been run, all the already computed switches that occur after propagation
  61.  * start for forward propagation or before propagation start for backward propagation will
  62.  * be erased. New switches will be computed and applied properly according to the new
  63.  * propagation settings. The already computed switches that are not in covered are kept
  64.  * in memory. This implies that if a propagation is interrupted and restarted in the
  65.  * same direction, then attitude switches will remain in place, ensuring that even if the
  66.  * interruption occurred in the middle of an attitude transition the second propagation will
  67.  * properly complete the transition that was started by the first propagator.
  68.  * </p>
  69.  * @author Luc Maisonobe
  70.  * @author Romain Serra
  71.  * @since 13.0
  72.  */
  73. abstract class AbstractSwitchingAttitudeProvider implements AttitudeProvider {

  74.     /** Providers that have been activated. */
  75.     private TimeSpanMap<AttitudeProvider> activated;

  76.     /** Constructor for an initially empty sequence.
  77.      */
  78.     protected AbstractSwitchingAttitudeProvider() {
  79.         activated = null;
  80.     }

  81.     /** Reset the active provider.
  82.      * <p>
  83.      * Calling this method clears all already seen switch history,
  84.      * so it should <em>not</em> be used during the propagation itself,
  85.      * it is intended to be used only at start
  86.      * </p>
  87.      * @param provider provider to activate
  88.      */
  89.     public void resetActiveProvider(final AttitudeProvider provider) {
  90.         activated = new TimeSpanMap<>(provider);
  91.     }

  92.     /**
  93.      * Setter for map of activate attitude providers.
  94.      * @param activated new map
  95.      */
  96.     protected void setActivated(final TimeSpanMap<AttitudeProvider> activated) {
  97.         this.activated = activated;
  98.     }

  99.     /**
  100.      * Getter for map of activated attitude providers.
  101.      * @return map of providers
  102.      */
  103.     protected TimeSpanMap<AttitudeProvider> getActivated() {
  104.         return activated;
  105.     }

  106.     /** {@inheritDoc} */
  107.     @Override
  108.     public Attitude getAttitude(final PVCoordinatesProvider pvProv,
  109.                                 final AbsoluteDate date, final Frame frame) {
  110.         return activated.get(date).getAttitude(pvProv, date, frame);
  111.     }

  112.     /** {@inheritDoc} */
  113.     @Override
  114.     public <T extends CalculusFieldElement<T>> FieldAttitude<T> getAttitude(final FieldPVCoordinatesProvider<T> pvProv,
  115.                                                                             final FieldAbsoluteDate<T> date,
  116.                                                                             final Frame frame) {
  117.         return activated.get(date.toAbsoluteDate()).getAttitude(pvProv, date, frame);
  118.     }

  119.     /** {@inheritDoc} */
  120.     @Override
  121.     public Rotation getAttitudeRotation(final PVCoordinatesProvider pvProv, final AbsoluteDate date, final Frame frame) {
  122.         return activated.get(date).getAttitudeRotation(pvProv, date, frame);
  123.     }

  124.     @Override
  125.     public <T extends CalculusFieldElement<T>> FieldRotation<T> getAttitudeRotation(final FieldPVCoordinatesProvider<T> pvProv,
  126.                                                                                     final FieldAbsoluteDate<T> date,
  127.                                                                                     final Frame frame) {
  128.         return activated.get(date.toAbsoluteDate()).getAttitudeRotation(pvProv, date, frame);
  129.     }

  130.     /**
  131.      * Method creating a Field attitude switch from a non-Field one.
  132.      * @param field field
  133.      * @param attitudeSwitch attitude switch
  134.      * @return Field detector
  135.      * @param <T> field type
  136.      */
  137.     protected <T extends CalculusFieldElement<T>> FieldEventDetector<T> getFieldEventDetector(final Field<T> field,
  138.                                                                                               final AbstractAttitudeSwitch attitudeSwitch) {
  139.         return new FieldEventDetector<T>() {

  140.             /** {@inheritDoc} */
  141.             @Override
  142.             public void init(final FieldSpacecraftState<T> s0, final FieldAbsoluteDate<T> t) {
  143.                 attitudeSwitch.init(s0.toSpacecraftState(), t.toAbsoluteDate());
  144.             }

  145.             /** {@inheritDoc} */
  146.             @Override
  147.             public T g(final FieldSpacecraftState<T> s) {
  148.                 return field.getZero().newInstance(attitudeSwitch.g(s.toSpacecraftState()));
  149.             }

  150.             @Override
  151.             public FieldEventDetectionSettings<T> getDetectionSettings() {
  152.                 return new FieldEventDetectionSettings<>(field, attitudeSwitch.getDetectionSettings());
  153.             }

  154.             /** {@inheritDoc} */
  155.             @Override
  156.             public FieldEventHandler<T> getHandler() {
  157.                 return new FieldEventHandler<T>() {
  158.                     /** {@inheritDoc} */
  159.                     @Override
  160.                     public Action eventOccurred(final FieldSpacecraftState<T> s,
  161.                                                 final FieldEventDetector<T> detector,
  162.                                                 final boolean increasing) {
  163.                         return attitudeSwitch.eventOccurred(s.toSpacecraftState(), attitudeSwitch, increasing);
  164.                     }

  165.                     /** {@inheritDoc} */
  166.                     @Override
  167.                     public FieldSpacecraftState<T> resetState(final FieldEventDetector<T> detector,
  168.                                                               final FieldSpacecraftState<T> oldState) {
  169.                         return new FieldSpacecraftState<>(field, attitudeSwitch.resetState(attitudeSwitch, oldState.toSpacecraftState()));
  170.                     }
  171.                 };
  172.             }

  173.         };
  174.     }

  175.     /** Abstract class to manage attitude switches.
  176.      * @since 13.0
  177.      */
  178.     abstract static class AbstractAttitudeSwitch implements DetectorModifier, EventHandler {

  179.         /**
  180.          * Event direction triggering the switch.
  181.          */
  182.         private final boolean switchOnIncrease;

  183.         /**
  184.          * Event direction triggering the switch.
  185.          */
  186.         private final boolean switchOnDecrease;

  187.         /**
  188.          * Attitude provider applicable for times in the switch event occurrence past.
  189.          */
  190.         private final AttitudeProvider past;

  191.         /**
  192.          * Attitude provider applicable for times in the switch event occurrence future.
  193.          */
  194.         private final AttitudeProvider future;

  195.         /**
  196.          * Handler to call for notifying when switch occurs (may be null).
  197.          */
  198.         private final AttitudeSwitchHandler switchHandler;

  199.         /** Wrapped event detector. */
  200.         private final EventDetector event;

  201.         /**
  202.          * Simple constructor.
  203.          *
  204.          * @param event            event
  205.          * @param switchOnIncrease if true, switch is triggered on increasing event
  206.          * @param switchOnDecrease if true, switch is triggered on decreasing event otherwise switch is triggered on
  207.          *                         decreasing event
  208.          * @param past             attitude provider applicable for times in the switch event occurrence past
  209.          * @param future           attitude provider applicable for times in the switch event occurrence future
  210.          * @param switchHandler    handler to call for notifying when switch occurs (may be null)
  211.          */
  212.         protected AbstractAttitudeSwitch(final EventDetector event, final boolean switchOnIncrease,
  213.                                          final boolean switchOnDecrease, final AttitudeProvider past,
  214.                                          final AttitudeProvider future, final AttitudeSwitchHandler switchHandler) {
  215.             this.event = event;
  216.             this.switchOnIncrease = switchOnIncrease;
  217.             this.switchOnDecrease = switchOnDecrease;
  218.             this.past = past;
  219.             this.future = future;
  220.             this.switchHandler = switchHandler;
  221.         }

  222.         /** {@inheritDoc} */
  223.         @Override
  224.         public EventDetector getDetector() {
  225.             return event;
  226.         }

  227.         /**
  228.          * Protected getter for switch handle.
  229.          * @return switch handler
  230.          */
  231.         protected AttitudeSwitchHandler getSwitchHandler() {
  232.             return switchHandler;
  233.         }

  234.         /**
  235.          * Protected getter for future attitude provider.
  236.          * @return future provider
  237.          */
  238.         protected AttitudeProvider getFuture() {
  239.             return future;
  240.         }

  241.         /**
  242.          * Protected getter for past attitude provider.
  243.          * @return pas provider
  244.          */
  245.         protected AttitudeProvider getPast() {
  246.             return past;
  247.         }

  248.         /**
  249.          * Protected getter for switch-on-decrease flag.
  250.          * @return flag
  251.          */
  252.         protected boolean isSwitchOnDecrease() {
  253.             return switchOnDecrease;
  254.         }

  255.         /**
  256.          * Protected getter for switch-on-increase flag.
  257.          * @return flag
  258.          */
  259.         protected boolean isSwitchOnIncrease() {
  260.             return switchOnIncrease;
  261.         }

  262.         /**
  263.          * {@inheritDoc}
  264.          */
  265.         @Override
  266.         public EventHandler getHandler() {
  267.             return this;
  268.         }

  269.         /**
  270.          * {@inheritDoc}
  271.          */
  272.         @Override
  273.         public SpacecraftState resetState(final EventDetector detector, final SpacecraftState oldState) {
  274.             // delegate to underlying event
  275.             return getDetector().getHandler().resetState(getDetector(), oldState);
  276.         }

  277.     }

  278. }