AbstractSwitchingAttitudeProvider.java
- /* Copyright 2022-2025 Romain Serra
- * Licensed to CS GROUP (CS) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * CS licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.orekit.attitudes;
- import org.hipparchus.CalculusFieldElement;
- import org.hipparchus.Field;
- import org.hipparchus.geometry.euclidean.threed.FieldRotation;
- import org.hipparchus.geometry.euclidean.threed.Rotation;
- import org.hipparchus.ode.events.Action;
- import org.orekit.frames.Frame;
- import org.orekit.propagation.FieldSpacecraftState;
- import org.orekit.propagation.SpacecraftState;
- import org.orekit.propagation.events.DetectorModifier;
- import org.orekit.propagation.events.EventDetector;
- import org.orekit.propagation.events.FieldEventDetector;
- import org.orekit.propagation.events.FieldEventDetectionSettings;
- import org.orekit.propagation.events.handlers.EventHandler;
- import org.orekit.propagation.events.handlers.FieldEventHandler;
- import org.orekit.time.AbsoluteDate;
- import org.orekit.time.FieldAbsoluteDate;
- import org.orekit.utils.FieldPVCoordinatesProvider;
- import org.orekit.utils.PVCoordinatesProvider;
- import org.orekit.utils.TimeSpanMap;
- /** This classes manages a sequence of different attitude providers that are activated
- * in turn according to switching events.
- * <p>Only one attitude provider in the sequence is in an active state. When one of
- * the switch event associated with the active provider occurs, the active provider becomes
- * the one specified with the event. A simple example is a provider for the sun lighted part
- * of the orbit and another provider for the eclipse time. When the sun lighted provider is active,
- * the eclipse entry event is checked and when it occurs the eclipse provider is activated.
- * When the eclipse provider is active, the eclipse exit event is checked and when it occurs
- * the sun lighted provider is activated again. This sequence is a simple loop.</p>
- * <p>An active attitude provider may have several switch events and next provider settings, leading
- * to different activation patterns depending on which events are triggered first. An example
- * of this feature is handling switches to safe mode if some contingency condition is met, in
- * addition to the nominal switches that correspond to proper operations. Another example
- * is handling of maneuver mode.
- * <p>
- * Note that this attitude provider is stateful, it keeps in memory the sequence of active
- * underlying providers with their switch dates and the transitions from one provider to
- * the other. This implies that this provider should <em>not</em> be shared among different
- * propagators at the same time, each propagator should use its own instance of this provider.
- * <p>
- * The sequence kept in memory is reset when {@link #resetActiveProvider(AttitudeProvider)}
- * is called, and only the specify provider is kept. The sequence is also partially
- * reset each time a propagation starts. If a new propagation is started after a first
- * propagation has been run, all the already computed switches that occur after propagation
- * start for forward propagation or before propagation start for backward propagation will
- * be erased. New switches will be computed and applied properly according to the new
- * propagation settings. The already computed switches that are not in covered are kept
- * in memory. This implies that if a propagation is interrupted and restarted in the
- * same direction, then attitude switches will remain in place, ensuring that even if the
- * interruption occurred in the middle of an attitude transition the second propagation will
- * properly complete the transition that was started by the first propagator.
- * </p>
- * @author Luc Maisonobe
- * @author Romain Serra
- * @since 13.0
- */
- abstract class AbstractSwitchingAttitudeProvider implements AttitudeProvider {
- /** Providers that have been activated. */
- private TimeSpanMap<AttitudeProvider> activated;
- /** Constructor for an initially empty sequence.
- */
- protected AbstractSwitchingAttitudeProvider() {
- activated = null;
- }
- /** Reset the active provider.
- * <p>
- * Calling this method clears all already seen switch history,
- * so it should <em>not</em> be used during the propagation itself,
- * it is intended to be used only at start
- * </p>
- * @param provider provider to activate
- */
- public void resetActiveProvider(final AttitudeProvider provider) {
- activated = new TimeSpanMap<>(provider);
- }
- /**
- * Setter for map of activate attitude providers.
- * @param activated new map
- */
- protected void setActivated(final TimeSpanMap<AttitudeProvider> activated) {
- this.activated = activated;
- }
- /**
- * Getter for map of activated attitude providers.
- * @return map of providers
- */
- protected TimeSpanMap<AttitudeProvider> getActivated() {
- return activated;
- }
- /** {@inheritDoc} */
- @Override
- public Attitude getAttitude(final PVCoordinatesProvider pvProv,
- final AbsoluteDate date, final Frame frame) {
- return activated.get(date).getAttitude(pvProv, date, frame);
- }
- /** {@inheritDoc} */
- @Override
- public <T extends CalculusFieldElement<T>> FieldAttitude<T> getAttitude(final FieldPVCoordinatesProvider<T> pvProv,
- final FieldAbsoluteDate<T> date,
- final Frame frame) {
- return activated.get(date.toAbsoluteDate()).getAttitude(pvProv, date, frame);
- }
- /** {@inheritDoc} */
- @Override
- public Rotation getAttitudeRotation(final PVCoordinatesProvider pvProv, final AbsoluteDate date, final Frame frame) {
- return activated.get(date).getAttitudeRotation(pvProv, date, frame);
- }
- @Override
- public <T extends CalculusFieldElement<T>> FieldRotation<T> getAttitudeRotation(final FieldPVCoordinatesProvider<T> pvProv,
- final FieldAbsoluteDate<T> date,
- final Frame frame) {
- return activated.get(date.toAbsoluteDate()).getAttitudeRotation(pvProv, date, frame);
- }
- /**
- * Method creating a Field attitude switch from a non-Field one.
- * @param field field
- * @param attitudeSwitch attitude switch
- * @return Field detector
- * @param <T> field type
- */
- protected <T extends CalculusFieldElement<T>> FieldEventDetector<T> getFieldEventDetector(final Field<T> field,
- final AbstractAttitudeSwitch attitudeSwitch) {
- return new FieldEventDetector<T>() {
- /** {@inheritDoc} */
- @Override
- public void init(final FieldSpacecraftState<T> s0, final FieldAbsoluteDate<T> t) {
- attitudeSwitch.init(s0.toSpacecraftState(), t.toAbsoluteDate());
- }
- /** {@inheritDoc} */
- @Override
- public T g(final FieldSpacecraftState<T> s) {
- return field.getZero().newInstance(attitudeSwitch.g(s.toSpacecraftState()));
- }
- @Override
- public FieldEventDetectionSettings<T> getDetectionSettings() {
- return new FieldEventDetectionSettings<>(field, attitudeSwitch.getDetectionSettings());
- }
- /** {@inheritDoc} */
- @Override
- public FieldEventHandler<T> getHandler() {
- return new FieldEventHandler<T>() {
- /** {@inheritDoc} */
- @Override
- public Action eventOccurred(final FieldSpacecraftState<T> s,
- final FieldEventDetector<T> detector,
- final boolean increasing) {
- return attitudeSwitch.eventOccurred(s.toSpacecraftState(), attitudeSwitch, increasing);
- }
- /** {@inheritDoc} */
- @Override
- public FieldSpacecraftState<T> resetState(final FieldEventDetector<T> detector,
- final FieldSpacecraftState<T> oldState) {
- return new FieldSpacecraftState<>(field, attitudeSwitch.resetState(attitudeSwitch, oldState.toSpacecraftState()));
- }
- };
- }
- };
- }
- /** Abstract class to manage attitude switches.
- * @since 13.0
- */
- abstract static class AbstractAttitudeSwitch implements DetectorModifier, EventHandler {
- /**
- * Event direction triggering the switch.
- */
- private final boolean switchOnIncrease;
- /**
- * Event direction triggering the switch.
- */
- private final boolean switchOnDecrease;
- /**
- * Attitude provider applicable for times in the switch event occurrence past.
- */
- private final AttitudeProvider past;
- /**
- * Attitude provider applicable for times in the switch event occurrence future.
- */
- private final AttitudeProvider future;
- /**
- * Handler to call for notifying when switch occurs (may be null).
- */
- private final AttitudeSwitchHandler switchHandler;
- /** Wrapped event detector. */
- private final EventDetector event;
- /**
- * Simple constructor.
- *
- * @param event event
- * @param switchOnIncrease if true, switch is triggered on increasing event
- * @param switchOnDecrease if true, switch is triggered on decreasing event otherwise switch is triggered on
- * decreasing event
- * @param past attitude provider applicable for times in the switch event occurrence past
- * @param future attitude provider applicable for times in the switch event occurrence future
- * @param switchHandler handler to call for notifying when switch occurs (may be null)
- */
- protected AbstractAttitudeSwitch(final EventDetector event, final boolean switchOnIncrease,
- final boolean switchOnDecrease, final AttitudeProvider past,
- final AttitudeProvider future, final AttitudeSwitchHandler switchHandler) {
- this.event = event;
- this.switchOnIncrease = switchOnIncrease;
- this.switchOnDecrease = switchOnDecrease;
- this.past = past;
- this.future = future;
- this.switchHandler = switchHandler;
- }
- /** {@inheritDoc} */
- @Override
- public EventDetector getDetector() {
- return event;
- }
- /**
- * Protected getter for switch handle.
- * @return switch handler
- */
- protected AttitudeSwitchHandler getSwitchHandler() {
- return switchHandler;
- }
- /**
- * Protected getter for future attitude provider.
- * @return future provider
- */
- protected AttitudeProvider getFuture() {
- return future;
- }
- /**
- * Protected getter for past attitude provider.
- * @return pas provider
- */
- protected AttitudeProvider getPast() {
- return past;
- }
- /**
- * Protected getter for switch-on-decrease flag.
- * @return flag
- */
- protected boolean isSwitchOnDecrease() {
- return switchOnDecrease;
- }
- /**
- * Protected getter for switch-on-increase flag.
- * @return flag
- */
- protected boolean isSwitchOnIncrease() {
- return switchOnIncrease;
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public EventHandler getHandler() {
- return this;
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public SpacecraftState resetState(final EventDetector detector, final SpacecraftState oldState) {
- // delegate to underlying event
- return getDetector().getHandler().resetState(getDetector(), oldState);
- }
- }
- }