Skip to content

Commit

Permalink
refactor: split sequence solve methods (#284)
Browse files Browse the repository at this point in the history
* refactor: split sequence solve methods

* feat: address remaining feedback
  • Loading branch information
vishwa2710 authored Nov 28, 2023
1 parent 93ab772 commit f06942c
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_Sequence(pybind11::module
.def(
init<
const Array<Segment>&,
const Size&,
const NumericalSolver&,
const Array<Shared<Dynamics>>&,
const Duration&,
Expand All @@ -174,7 +173,6 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_Sequence(pybind11::module
Args:
segments (list[Segment], optional): The segments.
repetition_count (int, optional): The repetition count.
numerical_solver (NumericalSolver, optional): The numerical solver.
dynamics (list[Dynamics], optional): The dynamics.
maximum_propagation_duration (Duration, optional): The maximum propagation duration.
Expand All @@ -185,7 +183,6 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_Sequence(pybind11::module
)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),
Expand Down Expand Up @@ -297,22 +294,39 @@ inline void OpenSpaceToolkitAstrodynamicsPy_Trajectory_Sequence(pybind11::module
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.
repetition_count (int, optional): The repetition count. Defaults to 1.
Returns:
SequenceSolution: The sequence solution.
)doc",
arg("state"),
arg("repetition_count") = 1
)

.def(
"solve_to_condition",
&Sequence::solveToCondition,
R"doc(
Solve the sequence until the event condition is met.
In the case that the event condition is not met due to maximum propagation duration limit,
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.
event_condition (EventCondition): The event condition.
maximum_propagation_duration_limit (Duration, optional): The maximum propagation duration limit for the sequence. Defaults to 30 days.
Returns:
SequenceSolution: The sequence solution.
)doc",
arg("state"),
arg("maximum_propagation_duration") = Duration::Days(30.0),
arg("event_condition") = nullptr
arg("event_condition"),
arg("maximum_propagation_duration_limit") = Duration::Days(30.0)
)

;
Expand Down
23 changes: 17 additions & 6 deletions bindings/python/test/trajectory/test_sequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,14 +306,12 @@ def repetition_count() -> int:
@pytest.fixture
def sequence(
segments: list[Segment],
repetition_count: int,
numerical_solver: NumericalSolver,
dynamics: list,
maximum_propagation_duration: Duration,
):
return Sequence(
segments=segments,
repetition_count=repetition_count,
dynamics=dynamics,
numerical_solver=numerical_solver,
maximum_propagation_duration=maximum_propagation_duration,
Expand Down Expand Up @@ -392,11 +390,11 @@ def test_add_maneuver_segment(
def test_solve(
self,
state: State,
repetition_count: int,
sequence: Sequence,
segments: list[Segment],
instant_condition: InstantCondition,
):
solution = sequence.solve(state)
solution = sequence.solve(state, repetition_count)

assert len(solution.segment_solutions) == len(segments)

Expand All @@ -413,5 +411,18 @@ def test_solve(
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
def test_solve_to_condition(
self,
state: State,
sequence: Sequence,
instant_condition: InstantCondition,
):
assert sequence.solve_to_condition(state, instant_condition) is not None
assert (
sequence.solve_to_condition(
state=state,
event_condition=instant_condition,
maximum_propagation_duration_limit=Duration.hours(1.0),
)
is not None
)
21 changes: 13 additions & 8 deletions include/OpenSpaceToolkit/Astrodynamics/Trajectory/Sequence.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ class Sequence

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& segmentPropagationDurationLimit = Duration::Days(7.0),
Expand Down Expand Up @@ -147,18 +146,25 @@ class Sequence

void addManeuverSegment(const Shared<EventCondition>& anEventConditionSPtr, const Shared<Thruster>& aThruster);

/// @brief Solve the sequence given an initial state, for a number of reptitions.
///
/// @param [in] aState Initial state for the sequence.
/// @param [in] aRepetitionCount Number of repetitions. Defaults to 1, i.e. execute sequence once.
/// @return A Solution that contains solutions for each segment.

Solution solve(const State& aState, const Size& aRepetitionCount = 1) const;

/// @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.
/// @param [in] anEventCondition An event condition.
/// @param [in] aMaximumPropagationDuration Maximum duration for sequence propagation.
/// @return A Solution that contains solutions for each segment.

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

/// @brief Print the sequence.
Expand All @@ -170,7 +176,6 @@ class Sequence

private:
Array<Segment> segments_;
Size repetitionCount_;
NumericalSolver numericalSolver_;
Array<Shared<Dynamics>> dynamics_;
Duration segmentPropagationDurationLimit_;
Expand Down
92 changes: 55 additions & 37 deletions src/OpenSpaceToolkit/Astrodynamics/Trajectory/Sequence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,12 @@ std::ostream& operator<<(std::ostream& anOutputStream, const Sequence::Solution&

Sequence::Sequence(
const Array<Segment>& aSegmentArray,
const Size& aRepetitionCount,
const NumericalSolver& aNumericalSolver,
const Array<Shared<Dynamics>>& aDynamicsArray,
const Duration& maximumPropagationDuration,
const Size& verbosity
)
: segments_(aSegmentArray),
repetitionCount_(aRepetitionCount),
numericalSolver_(aNumericalSolver),
dynamics_(aDynamicsArray),
segmentPropagationDurationLimit_(maximumPropagationDuration)
Expand Down Expand Up @@ -172,11 +170,6 @@ Sequence::Sequence(
{
throw ostk::core::error::runtime::Wrong("verbosity level");
}

if (repetitionCount_ < 1)
{
throw ostk::core::error::runtime::Wrong("Repetition count");
}
}

std::ostream& operator<<(std::ostream& anOutputStream, const Sequence& aSequence)
Expand Down Expand Up @@ -226,52 +219,83 @@ void Sequence::addManeuverSegment(const Shared<EventCondition>& anEventCondition
segments_.add(Segment::Maneuver("Maneuver", anEventConditionSPtr, aThruster, dynamics_, numericalSolver_));
}

Sequence::Solution Sequence::solve(
const State& aState,
const Duration& sequencePropagationDurationLimit,
const Shared<EventCondition>& anEventConditionSPtr
) const
Sequence::Solution Sequence::solve(const State& aState, const Size& aRepetitionCount) const
{
if (aRepetitionCount <= 0)
{
throw ostk::core::error::runtime::Wrong("Repetition count.");
}

Array<Segment::Solution> segmentSolutions;

State initialState = aState;
State finalState = State::Undefined();

Duration totalPropagationDuration = Duration::Seconds(0.0);

for (Size i = 0; i < repetitionCount_; ++i)
for (Size i = 0; i < aRepetitionCount; ++i)
{
for (const Segment& segment : segments_)
{
segment.accessEventCondition()->updateTarget(initialState);

// Terminate Sequence unsuccessfully if the propagation limit was exceeded
if (totalPropagationDuration > sequencePropagationDurationLimit)
BOOST_LOG_TRIVIAL(debug) << "Solving Segment:\n" << segment << std::endl;

Segment::Solution segmentSolution = segment.solve(initialState, segmentPropagationDurationLimit_);

segmentSolution.name =
String::Format("{} - {} - {}", segmentSolution.name, segment.getEventCondition()->getName(), i);

BOOST_LOG_TRIVIAL(debug) << "\n" << segmentSolution << std::endl;

segmentSolutions.add(segmentSolution);

// Terminate Sequence unsuccessfully if the segment condition was not satisfied
if (!segmentSolution.conditionIsSatisfied)
{
BOOST_LOG_TRIVIAL(warning)
<< "Terminating Sequence because maximum propagation duration is reached." << std::endl;
BOOST_LOG_TRIVIAL(warning) << "Segment condition is not satisfied." << std::endl;

return {segmentSolutions, false};
}

initialState = segmentSolution.states.accessLast();
}
}

return {segmentSolutions, true};
}

Sequence::Solution Sequence::solveToCondition(
const State& aState, const EventCondition& anEventCondition, const Duration& aMaximumPropagationDuration
) const
{
Array<Segment::Solution> segmentSolutions;

State initialState = aState;
State finalState = State::Undefined();

bool eventConditionIsSatisfied = false;

Duration propagationDuration = Duration::Zero();

while (!eventConditionIsSatisfied && propagationDuration <= aMaximumPropagationDuration)
{
for (const Segment& segment : segments_)
{
segment.accessEventCondition()->updateTarget(initialState);

BOOST_LOG_TRIVIAL(debug) << "Solving Segment:\n" << segment << std::endl;

// Clip the segment propagation limit if it will exceed the Sequence propagation limit
const Duration segmentPropagationDurationLimit = std::min(
segmentPropagationDurationLimit_, (sequencePropagationDurationLimit - totalPropagationDuration)
);
const Duration segmentPropagationDurationLimit =
std::min(segmentPropagationDurationLimit_, aMaximumPropagationDuration - propagationDuration);

Segment::Solution segmentSolution = segment.solve(initialState, segmentPropagationDurationLimit);

segmentSolution.name =
String::Format("{} - {} - {}", segmentSolution.name, segment.getEventCondition()->getName(), i);
String::Format("{} - {}", segmentSolution.name, segment.getEventCondition()->getName());

BOOST_LOG_TRIVIAL(debug) << "\n" << segmentSolution << std::endl;

segmentSolutions.add(segmentSolution);

totalPropagationDuration += segmentSolution.getPropagationDuration();

// Terminate Sequence unsuccessfully if the segment condition was not satisfied
if (!segmentSolution.conditionIsSatisfied)
{
Expand All @@ -280,26 +304,20 @@ Sequence::Solution Sequence::solve(
return {segmentSolutions, false};
}

eventConditionIsSatisfied = anEventCondition.isSatisfied(segmentSolution.states.accessLast(), initialState);

// Terminate Sequence successfully if a provided event condition was satisfied
if (anEventConditionSPtr != nullptr &&
anEventConditionSPtr->isSatisfied(segmentSolution.states.accessLast(), initialState))
if (eventConditionIsSatisfied)
{
BOOST_LOG_TRIVIAL(debug) << "Sequence Event condition is satisfied." << std::endl;

return {segmentSolutions, true};
}

propagationDuration += segmentSolution.getPropagationDuration();

initialState = segmentSolution.states.accessLast();
}
}

// No Event Condition was provided, therefore the Sequence has successfully completed
if (anEventConditionSPtr == nullptr)
{
return {segmentSolutions, true};
}

// An Event Condition was provided, however the condition was not met, therefore the completion is unsuccessful
return {segmentSolutions, false};
}

Expand Down
Loading

0 comments on commit f06942c

Please sign in to comment.