EventBasedManeuverTriggers.java
- /* Copyright 2020 Exotrail
- * 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.
- * Exotrail 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.forces.maneuvers.trigger;
- import java.util.stream.Stream;
- import org.hipparchus.Field;
- import org.hipparchus.CalculusFieldElement;
- import org.hipparchus.ode.events.Action;
- import org.orekit.errors.OrekitException;
- import org.orekit.errors.OrekitMessages;
- import org.orekit.propagation.SpacecraftState;
- import org.orekit.propagation.events.AbstractDetector;
- import org.orekit.propagation.events.EventDetector;
- import org.orekit.propagation.events.FieldEventDetector;
- import org.orekit.propagation.events.handlers.EventHandler;
- import org.orekit.time.AbsoluteDate;
- import org.orekit.time.FieldAbsoluteDate;
- /**
- * Maneuver triggers based on start and stop detectors. This allow a succession
- * of burn interval. The thruster starts firing when the start detector becomes
- * positive. The thruster stops firing when the stop detector becomes positive.
- * The 2 detectors should not be positive at the same time. A date detector is
- * not suited as it does not delimit an interval. They can be both negative at
- * the same time.
- * @author Mikael Fillastre
- * @author Andrea Fiorentino
- * @since 10.2
- */
- public class EventBasedManeuverTriggers implements ManeuverTriggers, EventHandler<EventDetector> {
- /** Detector to start firing, only detect increasing sign change. */
- private final AbstractDetector<? extends EventDetector> startFiringDetector;
- /**
- * Detector to stop firing, only detect increasing sign change. e.g. it can be a
- * negate detector of the start detector
- */
- private final AbstractDetector<? extends EventDetector> stopFiringDetector;
- /**
- * Flag for init method, called several times : force models + each detector.
- */
- private boolean initialized;
- /** Triggered date of engine start. */
- private AbsoluteDate triggeredStart;
- /** Triggered date of engine stop. */
- private AbsoluteDate triggeredEnd;
- /**
- * Constructor.
- * @param startFiringDetector Detector to start firing, only detect increasing
- * sign change
- * @param stopFiringDetector Detector to stop firing, only detect increasing
- * sign change. e.g. it can be a negate detector of
- * the start detector.
- */
- public EventBasedManeuverTriggers(final AbstractDetector<? extends EventDetector> startFiringDetector,
- final AbstractDetector<? extends EventDetector> stopFiringDetector) {
- if (startFiringDetector == null) {
- throw new OrekitException(OrekitMessages.PARAMETER_NOT_SET, "stopFiringDetector",
- EventBasedManeuverTriggers.class.getSimpleName());
- }
- if (stopFiringDetector == null) {
- throw new OrekitException(OrekitMessages.PARAMETER_NOT_SET, "startFiringDetector",
- EventBasedManeuverTriggers.class.getSimpleName());
- }
- this.startFiringDetector = startFiringDetector.withHandler(this);
- this.stopFiringDetector = stopFiringDetector.withHandler(this);
- this.triggeredStart = null;
- this.triggeredEnd = null;
- initialized = false;
- }
- /**
- * Getter for the start firing detector.
- * @return Detectors to start firing,
- */
- public AbstractDetector<? extends EventDetector> getStartFiringDetector() {
- return startFiringDetector;
- }
- /**
- * Getter for the stop firing detector.
- * @return Detectors to stop firing
- */
- public AbstractDetector<? extends EventDetector> getStopFiringDetector() {
- return stopFiringDetector;
- }
- /** {@inheritDoc} */
- @Override
- public void init(final SpacecraftState initialState, final AbsoluteDate target) {
- if (!initialized) {
- initialized = true;
- final AbsoluteDate sDate = initialState.getDate();
- if (sDate.compareTo(target) > 0) {
- // backward propagation not managed because events on detectors can not be
- // reversed :
- // the stop event of the maneuver in forward direction won't be the start in the
- // backward.
- // e.g. if a stop detector is combination of orbit position and system
- // constraint
- throw new OrekitException(OrekitMessages.FUNCTION_NOT_IMPLEMENTED,
- "EventBasedManeuverTriggers in backward propagation");
- }
- checkInitialFiringState(initialState);
- } // multiples calls to init : because it is a force model and by each detector
- }
- /**
- * Method to set the firing state on initialization. can be overloaded by sub
- * classes.
- *
- * @param initialState initial spacecraft state
- */
- protected void checkInitialFiringState(final SpacecraftState initialState) {
- if (isFiringOnInitialState(initialState)) {
- setFiring(true, initialState.getDate());
- }
- }
- /**
- * Method to check if the thruster is firing on initialization. can be called by
- * sub classes
- *
- * @param initialState initial spacecraft state
- * @return true if firing
- */
- protected boolean isFiringOnInitialState(final SpacecraftState initialState) {
- // set the initial value of firing
- final double insideThrustArcG = getStartFiringDetector().g(initialState);
- boolean isInsideThrustArc = false;
- if (insideThrustArcG == 0) {
- // bound of arc
- // check state for the next second (which can be forward or backward)
- final double nextSecond = 1;
- final double nextValue = getStartFiringDetector().g(initialState.shiftedBy(nextSecond));
- isInsideThrustArc = nextValue > 0;
- } else {
- isInsideThrustArc = insideThrustArcG > 0;
- }
- return isInsideThrustArc;
- }
- /** {@inheritDoc} */
- @Override
- public Stream<EventDetector> getEventsDetectors() {
- return Stream.of(getStartFiringDetector(), getStopFiringDetector());
- }
- /** {@inheritDoc} */
- @Override
- public <T extends CalculusFieldElement<T>> Stream<FieldEventDetector<T>> getFieldEventsDetectors(final Field<T> field) {
- // not implemented, it depends on the input detectors
- throw new OrekitException(OrekitMessages.FUNCTION_NOT_IMPLEMENTED,
- "EventBasedManeuverTriggers.getFieldEventsDetectors");
- }
- /**
- * Set the firing start or end date depending on the firing flag. There is no
- * effect if the firing state is not changing.
- * @param firing true to start a maneuver, false to stop
- * @param date date of event
- */
- public void setFiring(final boolean firing, final AbsoluteDate date) {
- if (firing != isFiring(date)) {
- if (firing) {
- if (!date.equals(triggeredEnd)) {
- triggeredStart = date;
- } // else no gap between stop and start, can not handle correctly : skip it
- } else {
- triggeredEnd = date;
- }
- }
- }
- /** {@inheritDoc} */
- @Override
- public boolean isFiring(final AbsoluteDate date, final double[] parameters) {
- // Firing state does not depend on a parameter driver here
- return isFiring(date);
- }
- /** {@inheritDoc} */
- @Override
- public <T extends CalculusFieldElement<T>> boolean isFiring(final FieldAbsoluteDate<T> date, final T[] parameters) {
- // Firing state does not depend on a parameter driver here
- return isFiring(date.toAbsoluteDate());
- }
- /** {@inheritDoc} */
- @Override
- public Action eventOccurred(final SpacecraftState s, final EventDetector detector, final boolean increasing) {
- Action action = Action.CONTINUE; // default not taken into account
- final boolean detectorManaged = getEventsDetectors()
- .anyMatch(managedDetector -> managedDetector.equals(detector));
- if (detectorManaged) {
- action = Action.RESET_EVENTS;
- if (increasing) {
- if (detector.equals(getStartFiringDetector())) { // start of firing arc
- setFiring(true, s.getDate());
- action = Action.RESET_DERIVATIVES;
- } else if (detector.equals(getStopFiringDetector())) { // end of firing arc
- setFiring(false, s.getDate());
- action = Action.RESET_DERIVATIVES;
- }
- }
- }
- return action;
- }
- /**
- * Check if maneuvering is on.
- *
- * @param date current date
- * @return true if maneuver is on at this date
- */
- public boolean isFiring(final AbsoluteDate date) {
- if (triggeredStart == null) {
- // explicitly ignores state date, as propagator did not allow us to introduce
- // discontinuity
- return false;
- } else if (date.isBefore(triggeredStart)) {
- // we are unambiguously before maneuver start
- // robustness, we should not pass here
- return false;
- } else {
- // after start date
- if (getTriggeredEnd() == null) {
- // explicitly ignores state date, as propagator did not allow us to introduce
- // discontinuity
- return true;
- } else if (getTriggeredStart().isAfter(getTriggeredEnd())) {
- // last event is a start of maneuver, end not set yet
- // we are unambiguously before maneuver end
- return true;
- } else if (date.isBefore(getTriggeredEnd())) {
- // we are unambiguously before maneuver end
- // robustness, we should not pass here
- return true;
- } else {
- // we are at or after maneuver end
- return false;
- }
- }
- }
- /**
- * Getter for the triggered date of engine stop.
- * @return Triggered date of engine stop
- */
- public AbsoluteDate getTriggeredEnd() {
- return triggeredEnd;
- }
- /**
- * Getter triggered date of engine start.
- * @return Triggered date of engine start
- */
- public AbsoluteDate getTriggeredStart() {
- return triggeredStart;
- }
- }