Skip to content

Commit

Permalink
feat: Event Condition termination for Sequences (#262)
Browse files Browse the repository at this point in the history
* feat: add event condition option to a Sequence

* feat: add python bindings and test

* chore: style

* feat: formatting

* feat: fix docs

* feat: address Kyle's feedback

---------

Co-authored-by: Vishwa Shah <vishwa@loftorbital.com>
  • Loading branch information
vishwa2710 and vishwaLoft authored Oct 31, 2023
1 parent ab528cf commit be6a9af
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,4 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_LocalOrbitalFrameFactory(
)

;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_Model(pybind11::module &a
.def("__str__", &(shiftToString<BaseModel>))
.def("__repr__", &(shiftToString<BaseModel>))

.def("is_defined", &BaseModel::isDefined,
.def(
"is_defined",
&BaseModel::isDefined,
R"doc(
Check if the model is defined.
Expand All @@ -46,7 +48,10 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_Model(pybind11::module &a
)doc"
)

.def("calculate_state_at", &BaseModel::calculateStateAt, arg("instant"),
.def(
"calculate_state_at",
&BaseModel::calculateStateAt,
arg("instant"),
R"doc(
Calculate the state at a given instant.
Expand All @@ -58,7 +63,10 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_Model(pybind11::module &a
)doc"
)
.def("calculate_states_at", &BaseModel::calculateStatesAt, arg("instants"),
.def(
"calculate_states_at",
&BaseModel::calculateStatesAt,
arg("instants"),
R"doc(
Calculate the states at given instants.
Expand All @@ -71,4 +79,4 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_Model(pybind11::module &a
)

;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_Sequence(pybind11::module
.def(
"compute_delta_v",
&Sequence::Solution::computeDeltaV,
arg("specific_impulse"),
R"doc(
Compute the delta V.
Expand All @@ -144,7 +143,8 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_Sequence(pybind11::module
Returns:
float: The delta V.
)doc"
)doc",
arg("specific_impulse")
)

;
Expand All @@ -169,12 +169,6 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_Sequence(pybind11::module
const Array<Shared<Dynamics>>&,
const Duration&,
const Size&>(),
arg("segments") = Array<Segment>::Empty(),
arg("repetition_count") = 1,
arg("numerical_solver") = NumericalSolver::DefaultConditional(),
arg("dynamics") = Array<Shared<Dynamics>>::Empty(),
arg("maximum_propagation_duration") = Duration::Days(30.0),
arg("verbosity") = 1,
R"doc(
Construct a new `Sequence` object.
Expand All @@ -189,7 +183,13 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_Sequence(pybind11::module
Returns:
Sequence: The new `Sequence` object.
)doc"
)doc",
arg("segments") = Array<Segment>::Empty(),
arg("repetition_count") = 1,
arg("numerical_solver") = NumericalSolver::DefaultConditional(),
arg("dynamics") = Array<Shared<Dynamics>>::Empty(),
arg("maximum_propagation_duration") = Duration::Days(30.0),
arg("verbosity") = 1
)

.def("__str__", &(shiftToString<Sequence>))
Expand Down Expand Up @@ -243,14 +243,14 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_Sequence(pybind11::module
.def(
"add_segment",
overload_cast<const Segment&>(&Sequence::addSegment),
arg("segment"),
R"doc(
Add a segment.
Args:
segment (Segment): The segment.
)doc"
)doc",
arg("segment")
)
.def(
"add_segment",
Expand All @@ -267,44 +267,52 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_Sequence(pybind11::module
.def(
"add_coast_segment",
&Sequence::addCoastSegment,
arg("event_condition"),
R"doc(
Add a coast segment.
Args:
event_condition (EventCondition): The event condition.
)doc"
)doc",
arg("event_condition")
)
.def(
"add_maneuver_segment",
&Sequence::addManeuverSegment,
arg("event_condition"),
arg("thruster_dynamics"),
R"doc(
Add a maneuver segment.
Args:
event_condition (EventCondition): The event condition.
thruster_dynamics (Thruster): The thruster dynamics.
)doc"
)doc",
arg("event_condition"),
arg("thruster_dynamics")
)

.def(
"solve",
&Sequence::solve,
arg("state"),
R"doc(
Solve the sequence.
This method will terminate early if the maximum propagation duration is exceeded.
If an event condition is provided, it will terminate if the event condition is met.
In the case that the event condition is not met, it will return the `SequenceSolution` with `executionIsComplete` set to `False`.
Args:
state (State): The state.
maximum_propagation_duration (Duration, optional): The maximum propagation duration.
event_condition (EventCondition, optional): The event condition.
Returns:
SequenceSolution: The sequence solution.
)doc"
)doc",
arg("state"),
arg("maximum_propagation_duration") = Duration::Days(30.0),
arg("event_condition") = nullptr
)

;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,4 +252,4 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_State(pybind11::module& a
OpenSpaceToolkitAstrodynamicsPy_Trajectory_State_CoordinatesBroker(state);
OpenSpaceToolkitAstrodynamicsPy_Trajectory_State_CoordinatesSubset(state);
OpenSpaceToolkitAstrodynamicsPy_Trajectory_State_NumericalSolver(state);
}
}
11 changes: 10 additions & 1 deletion bindings/python/test/trajectory/test_sequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,13 @@ def test_add_maneuver_segment(

assert len(sequence.get_segments()) == segments_count + 1

def test_solve(self, state: State, sequence: Sequence, segments: list[Segment]):
def test_solve(
self,
state: State,
sequence: Sequence,
segments: list[Segment],
instant_condition: InstantCondition,
):
solution = sequence.solve(state)

assert len(solution.segment_solutions) == len(segments)
Expand All @@ -388,3 +394,6 @@ def test_solve(self, state: State, sequence: Sequence, segments: list[Segment]):

assert solution.compute_delta_mass() is not None
assert solution.compute_delta_v(1500.0) is not None

assert sequence.solve(state, Duration.minutes(5.0)) is not None
assert sequence.solve(state, Duration.hours(5.0), instant_condition) is not None
21 changes: 15 additions & 6 deletions include/OpenSpaceToolkit/Astrodynamics/Trajectory/Sequence.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,25 +66,27 @@ class Sequence
/// const Array<Shared<Dynamics>> dynamicsArray =
/// {std::make_shared<CentralBodyGravity>(Earth::GravitationalParameter())};
/// const Duration maximumPropagationDuration = Duration::Days(7.0);
/// const Size verbosity = 0;
///
/// Sequence sequence = {repetitionCount,numericalSolver, dynamicsArray,
/// maximumPropagationDuration};
/// Sequence sequence = {repetitionCount, numericalSolver, dynamicsArray,
/// maximumPropagationDuration, verbosity};
///
/// @endcode
///
/// @param [in] aSegmentArray An array of segments. Defaults to empty.
/// @param [in] aRepetitionCount A repetition count. Defaults to 1.
/// @param [in] aNumericalSolver A Numerical Solver. Defaults to Undefined.
/// @param [in] aDynamicsArray An array of shared dynamics. Defaults to empty.
/// @param [in] maximumPropagationDuration Maximum duration for propagation. Defaults to 7.0 days.
/// @param [in] segmentPropagationDurationLimit Maximum duration for propagation. Defaults to 7.0
/// days.
/// @param [in] verbosity Verbosity level for the solver [0 (low) - 5 (high)]. Defaults to 0.

Sequence(
const Array<Segment>& aSegmentArray = Array<Segment>::Empty(),
const Size& aRepetitionCount = 1,
const NumericalSolver& aNumericalSolver = NumericalSolver::Undefined(),
const Array<Shared<Dynamics>>& aDynamicsArray = Array<Shared<Dynamics>>::Empty(),
const Duration& maximumPropagationDuration = Duration::Days(7.0),
const Duration& segmentPropagationDurationLimit = Duration::Days(7.0),
const Size& verbosity = 0
);

Expand Down Expand Up @@ -148,9 +150,16 @@ class Sequence
/// @brief Solve the sequence given an initial state.
///
/// @param [in] aState Initial state for the sequence.
/// @param [in] sequencePropagationDurationLimit Maximum propagation duration for the Sequence.
/// Defaults to 30.0 days.
/// @param [in] anEventCondition An event condition. Defaults to nullptr.
/// @return A Solution that contains solutions for each segment.

Solution solve(const State& aState) const;
Solution solve(
const State& aState,
const Duration& sequencePropagationDurationLimit = Duration::Days(30.0),
const Shared<EventCondition>& anEventConditionSPtr = nullptr
) const;

/// @brief Print the sequence.
///
Expand All @@ -164,7 +173,7 @@ class Sequence
Size repetitionCount_;
NumericalSolver numericalSolver_;
Array<Shared<Dynamics>> dynamics_;
Duration maximumPropagationDuration_;
Duration segmentPropagationDurationLimit_;
};

} // namespace trajectory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,7 @@ Array<State> Propagated::calculateStatesAt(const Array<Instant>& anInstantArray)
(forwardStates[k].accessCoordinates() * forwardWeight +
backwardStates[k].accessCoordinates() * backwardWeight);

averagedStates.add(
outputStateBuilder.build(
instants[k],
coordinates
)
);
averagedStates.add(outputStateBuilder.build(instants[k], coordinates));
}

allStates.add(averagedStates);
Expand Down
Loading

0 comments on commit be6a9af

Please sign in to comment.