DateBasedManeuverTriggers.java
/* Copyright 2002-2021 CS GROUP
* 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.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.propagation.FieldSpacecraftState;
import org.orekit.propagation.SpacecraftState;
import org.orekit.propagation.events.DateDetector;
import org.orekit.propagation.events.EventDetector;
import org.orekit.propagation.events.FieldDateDetector;
import org.orekit.propagation.events.FieldEventDetector;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.FieldAbsoluteDate;
/** Maneuver triggers based on a start and end date, with no parameter drivers.
* @author Maxime Journot
* @since 10.2
*/
public class DateBasedManeuverTriggers implements ManeuverTriggers {
/** Start of the maneuver. */
private final AbsoluteDate startDate;
/** End of the maneuver. */
private final AbsoluteDate endDate;
/** Triggered date of engine start. */
private AbsoluteDate triggeredStart;
/** Triggered date of engine stop. */
private AbsoluteDate triggeredEnd;
/** Propagation direction. */
private boolean forward;
public DateBasedManeuverTriggers(final AbsoluteDate date,
final double duration) {
if (duration >= 0) {
this.startDate = date;
this.endDate = date.shiftedBy(duration);
} else {
this.endDate = date;
this.startDate = endDate.shiftedBy(duration);
}
this.triggeredStart = null;
this.triggeredEnd = null;
}
/** Get the start date.
* @return the start date
*/
public AbsoluteDate getStartDate() {
return startDate;
}
/** Get the end date.
* @return the end date
*/
public AbsoluteDate getEndDate() {
return endDate;
}
/** Get the duration of the maneuver (s).
* duration = endDate - startDate
* @return the duration of the maneuver (s)
*/
public double getDuration() {
return endDate.durationFrom(startDate);
}
/** {@inheritDoc} */
@Override
public void init(final SpacecraftState initialState, final AbsoluteDate target) {
// set the initial value of firing
final AbsoluteDate sDate = initialState.getDate();
this.forward = sDate.compareTo(target) < 0;
final boolean isBetween = sDate.isBetween(startDate, endDate);
final boolean isOnStart = startDate.compareTo(sDate) == 0;
final boolean isOnEnd = endDate.compareTo(sDate) == 0;
triggeredStart = null;
triggeredEnd = null;
if (forward) {
if (isBetween || isOnStart) {
triggeredStart = startDate;
}
} else {
if (isBetween || isOnEnd) {
triggeredEnd = endDate;
}
}
}
/** {@inheritDoc} */
@Override
public Stream<EventDetector> getEventsDetectors() {
// In forward propagation direction, firing must be enabled
// at start time and disabled at end time; in backward
// propagation direction, firing must be enabled
// at end time and disabled at start time
final DateDetector startDetector = new DateDetector(startDate).
withHandler((SpacecraftState state, DateDetector d, boolean increasing) -> {
triggeredStart = state.getDate();
return Action.RESET_DERIVATIVES;
}
);
final DateDetector endDetector = new DateDetector(endDate).
withHandler((SpacecraftState state, DateDetector d, boolean increasing) -> {
triggeredEnd = state.getDate();
return Action.RESET_DERIVATIVES;
});
return Stream.of(startDetector, endDetector);
}
/** {@inheritDoc} */
@Override
public <T extends CalculusFieldElement<T>> Stream<FieldEventDetector<T>> getFieldEventsDetectors(final Field<T> field) {
// In forward propagation direction, firing must be enabled
// at start time and disabled at end time; in backward
// propagation direction, firing must be enabled
// at end time and disabled at start time
final FieldDateDetector<T> startDetector = new FieldDateDetector<>(new FieldAbsoluteDate<>(field, startDate)).
withHandler((FieldSpacecraftState<T> state, FieldDateDetector<T> d, boolean increasing) -> {
triggeredStart = state.getDate().toAbsoluteDate();
return Action.RESET_DERIVATIVES;
});
final FieldDateDetector<T> endDetector = new FieldDateDetector<>(new FieldAbsoluteDate<>(field, endDate)).
withHandler((FieldSpacecraftState<T> state, FieldDateDetector<T> d, boolean increasing) -> {
triggeredEnd = state.getDate().toAbsoluteDate();
return Action.RESET_DERIVATIVES;
});
return Stream.of(startDetector, endDetector);
}
/** {@inheritDoc} */
@Override
public boolean isFiring(final AbsoluteDate date, final double[] parameters) {
// Firing state does not depend on a parameter driver here
return isFiring(date);
}
@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());
}
/** 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 (forward) {
if (triggeredStart == null) {
// explicitly ignores state date, as propagator did not allow us to introduce discontinuity
return false;
} else if (date.durationFrom(triggeredStart) < 0.0) {
// we are unambiguously before maneuver start
return false;
} else {
if (triggeredEnd == null) {
// explicitly ignores state date, as propagator did not allow us to introduce discontinuity
return true;
} else if (date.durationFrom(triggeredEnd) < 0.0) {
// we are unambiguously before maneuver end
return true;
} else {
// we are at or after maneuver end
return false;
}
}
} else {
if (triggeredEnd == null) {
// explicitly ignores state date, as propagator did not allow us to introduce discontinuity
return false;
} else if (date.durationFrom(triggeredEnd) > 0.0) {
// we are unambiguously after maneuver end
return false;
} else {
if (triggeredStart == null) {
// explicitly ignores state date, as propagator did not allow us to introduce discontinuity
return true;
} else if (date.durationFrom(triggeredStart) > 0.0) {
// we are unambiguously after maneuver start
return true;
} else {
// we are at or before maneuver start
return false;
}
}
}
}
}