FieldAbstractRelativeManeuver.java
/* Copyright 2002-2026 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.propagation.relative.maneuver;
import org.hipparchus.CalculusFieldElement;
import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
import org.hipparchus.ode.events.Action;
import org.orekit.propagation.FieldSpacecraftState;
import org.orekit.propagation.events.FieldEventDetector;
import org.orekit.propagation.events.handlers.FieldEventHandler;
import org.orekit.propagation.relative.FieldRelativeProvider;
import org.orekit.time.FieldAbsoluteDate;
import org.orekit.utils.FieldArrayDictionary;
import org.orekit.utils.FieldDataDictionary;
import org.orekit.utils.FieldPVCoordinates;
import org.orekit.utils.TimeStampedFieldPVCoordinates;
import java.util.Objects;
/**
* Abstract class for implementing an impulse maneuver for a chaser spacecraft.
*
* @param <T> type of the field element
* @param <P> type of the relative motion provider
* @author Romain Cuvillon
* @since 14.0
*/
public abstract class FieldAbstractRelativeManeuver<T extends CalculusFieldElement<T>, P extends FieldRelativeProvider<T>>
implements FieldRelativeManeuver<T> {
/** Trigger event. */
private final FieldEventDetector<T> trigger;
/** ΔV vector in the target's LOF. */
private final FieldVector3D<T> deltaV;
/** True if the propagation is forward in time. */
private boolean forward;
/** Relative Provider. */
private final P relativeProvider;
/** Event Handler. */
private final FieldEventHandler<T> handler;
/**
* Creates a new {@link FieldAbstractRelativeManeuver} from an event detector, a ΔV vector, and a
* {@link FieldRelativeProvider}.
*
* @param trigger Triggering event detector.
* @param deltaV ΔV vector in the local orbital frame of the theory used by the given
* {@link FieldRelativeProvider}.
* @param relativeProvider Relative motion equations provider.
*/
public FieldAbstractRelativeManeuver(final FieldEventDetector<T> trigger, final FieldVector3D<T> deltaV,
final P relativeProvider) {
this.trigger = trigger;
this.deltaV = deltaV;
this.relativeProvider = relativeProvider;
this.handler = new Handler<>();
}
/** {@inheritDoc} */
@Override
public void init(final FieldSpacecraftState<T> s0, final FieldAbsoluteDate<T> t) {
forward = t.durationFrom(s0.getDate()).getReal() >= 0;
getDetector().init(s0, t);
}
/** {@inheritDoc} */
@Override
public FieldEventDetector<T> getDetector() {
return trigger;
}
/**
* Getter for the forward boolean.
*
* @return forward boolean
*/
public boolean getForward() {
return forward;
}
/** {@inheritDoc} */
@Override
public FieldVector3D<T> getDeltaV() {
return deltaV;
}
/** {@inheritDoc} */
@Override
public P getRelativeProvider() {
return this.relativeProvider;
}
/** {@inheritDoc} */
@Override
public FieldEventHandler<T> getHandler() {
return handler;
}
/**
* Local handler.
* <p>
* Apply the maneuver to the chaser S/C in the additional state.
* </p>
*/
private static class Handler<T extends CalculusFieldElement<T>> implements FieldEventHandler<T> {
/** {@inheritDoc} */
@Override
public Action eventOccurred(final FieldSpacecraftState<T> s, final FieldEventDetector<T> detector,
final boolean increasing) {
final FieldAbstractRelativeManeuver<T, ?> im = (FieldAbstractRelativeManeuver<T, ?>) detector;
final Action underlyingAction =
im.getDetector().getHandler().eventOccurred(s, im.getDetector(), increasing);
return (underlyingAction == Action.STOP) ? Action.RESET_STATE : Action.CONTINUE;
}
/** {@inheritDoc} */
@Override
public FieldSpacecraftState<T> resetState(final FieldEventDetector<T> detector,
final FieldSpacecraftState<T> oldState) {
final FieldAbstractRelativeManeuver<T, ?> maneuver = (FieldAbstractRelativeManeuver<T, ?>) detector;
// Get velocity increment from maneuver
final FieldVector3D<T> deltaV = maneuver.getDeltaV();
final double sign = maneuver.getForward() ? +1 : -1;
// Apply increment to velocity of the chaser
final T[] chaserPV = oldState.getAdditionalState(maneuver.getRelativeProvider().getName());
chaserPV[3] = chaserPV[3].add(deltaV.getX().multiply(sign));
chaserPV[4] = chaserPV[4].add(deltaV.getY().multiply(sign));
chaserPV[5] = chaserPV[5].add(deltaV.getZ().multiply(sign));
// Reset the equations provider with the new chaser state
maneuver.getRelativeProvider().setInitialChaserPVTLof(
new TimeStampedFieldPVCoordinates<>(oldState.getDate(), new FieldPVCoordinates<>(
new FieldVector3D<>(chaserPV[0], chaserPV[1], chaserPV[2]),
new FieldVector3D<>(chaserPV[3], chaserPV[4], chaserPV[5]))));
// Pack everything in a new state
FieldSpacecraftState<T> newState =
new FieldSpacecraftState<>(oldState.getOrbit(), oldState.getAttitude()).withMass(
oldState.getMass());
// Reset the TrueAnomaly of the spacecraft to the current true anomaly if YA is used / do nothing if CW.
maneuver.resetTrueAnomalyAtManeuver(oldState.getOrbit());
// Add additional equations
for (final FieldDataDictionary<T>.Entry entry : oldState.getAdditionalDataValues().getData()) {
if (!Objects.equals(entry.getKey(), maneuver.getRelativeProvider().getName())) {
newState = newState.addAdditionalData(entry.getKey(), entry.getValue());
} else {
// Use modified chaser PV if the additional state is the currently used provider
newState = newState.addAdditionalData(maneuver.getRelativeProvider().getName(), chaserPV);
}
}
// Add additional equations' derivatives
for (final FieldArrayDictionary<T>.Entry entry : oldState.getAdditionalStatesDerivatives().getData()) {
newState = newState.addAdditionalStateDerivative(entry.getKey(), entry.getValue());
}
return newState;
}
}
}