Skip to content

Commit

Permalink
MNT: major refactor FlightPhases class
Browse files Browse the repository at this point in the history
- add docstring to the class and its methods
- avoid using mutable default arguments
- simple display_warning method
- add method: use early returns to increase readability
- add method: more if comprehensions, more readability
- add highlights to warning messages
  • Loading branch information
Gui-FernandesBR committed Oct 15, 2023
1 parent 92fa7be commit d145cec
Showing 1 changed file with 158 additions and 79 deletions.
237 changes: 158 additions & 79 deletions rocketpy/simulation/flight.py
Original file line number Diff line number Diff line change
Expand Up @@ -3276,7 +3276,19 @@ def time_iterator(self, node_list):
i += 1

class FlightPhases:
def __init__(self, init_list=[]):
"""Class to handle flight phases. It is used to store the derivatives
and callbacks for each flight phase. It is also used to handle the
insertion of flight phases in the correct order, according to their
initial time.
Attributes
----------
list : list
A list of FlightPhase objects. See FlightPhase subclass.
"""

def __init__(self, init_list=None):
init_list = [] if init_list is None else init_list
self.list = init_list[:]

def __getitem__(self, index):
Expand All @@ -3288,102 +3300,169 @@ def __len__(self):
def __repr__(self):
return str(self.list)

def display_warning(self, *messages):
"""A simple function to print a warning message."""
print("WARNING:", *messages)

def add(self, flight_phase, index=None):
"""Add a flight phase to the list. It will be inserted in the
correct position, according to its initial time. If no index is
provided, it will be appended to the end of the list. If by any
reason the flight phase cannot be inserted in the correct position,
a warning will be displayed and the flight phase will be inserted
in the closest position possible.
Parameters
----------
flight_phase : FlightPhase
The flight phase object to be added. See FlightPhase class.
index : int, optional
The index of the flight phase to be added. If no index is
provided, the flight phase will be appended to the end of the
list. Default is None.
Returns
-------
None
"""
# Handle first phase
if len(self.list) == 0:
self.list.append(flight_phase)
return None

# Handle appending to last position
elif index is None:
# Check if new flight phase respects time
if index is None:
previous_phase = self.list[-1]
if flight_phase.t > previous_phase.t:
# All good! Add phase.
self.list.append(flight_phase)
elif flight_phase.t == previous_phase.t:
print(
"WARNING: Trying to add a flight phase starting "
+ "together with the one preceding it."
)
print(
"This may be caused by more than when parachute being "
+ "triggered simultaneously."
)
flight_phase.t += 1e-7
self.add(flight_phase)
elif flight_phase.t < previous_phase.t:
print(
"WARNING: Trying to add a flight phase starting before "
+ "the one preceding it."
)
print(
"This may be caused by more than when parachute being "
+ "triggered simultaneously."
)
print("Or by having a negative parachute lag.")
self.add(flight_phase, -2)
# Handle inserting into intermediary position
else:
# Check if new flight phase respects time
next_phase = self.list[index]
previous_phase = self.list[index - 1]
if previous_phase.t < flight_phase.t < next_phase.t:
# All good! Add phase.
self.list.insert(index, flight_phase)
elif flight_phase.t < previous_phase.t:
print(
"WARNING: Trying to add a flight phase starting before "
+ "the one preceding it."
)
print(
"This may be caused by more than when parachute being "
+ "triggered simultaneously."
)
print("Or by having a negative parachute lag.")
self.add(flight_phase, index - 1)
elif flight_phase.t == previous_phase.t:
print(
"WARNING: Trying to add a flight phase starting "
+ "together with the one preceding it."
)
print(
"This may be caused by more than when parachute being "
+ "triggered simultaneously."
)
flight_phase.t += 1e-7
self.add(flight_phase, index)
elif flight_phase.t == next_phase.t:
print(
"WARNING: Trying to add a flight phase starting "
+ "together with the one proceeding it."
)
print(
"This may be caused by more than when parachute being "
+ "triggered simultaneously."
)
flight_phase.t += 1e-7
self.add(flight_phase, index + 1)
elif flight_phase.t > next_phase.t:
print(
"WARNING: Trying to add a flight phase starting after "
+ "the one proceeding it."
return None
warning_msg = (
(
"Trying to add flight phase starting together with the one preceding it. ",
"This may be caused by multiple parachutes being triggered simultaneously.",
)
print(
"This may be caused by more than when parachute being "
+ "triggered simultaneously."
if flight_phase.t == previous_phase.t
else (
"Trying to add flight phase starting *before* the one *preceding* it. ",
"This may be caused by multiple parachutes being triggered simultaneously",
" or by having a negative parachute lag.",
)
self.add(flight_phase, index + 1)

def add_phase(self, t, derivatives=None, callback=[], clear=True, index=None):
)
self.display_warning(*warning_msg)
flight_phase.t += 1e-7 if flight_phase.t == previous_phase.t else 0
self.add(
flight_phase, -2 if flight_phase.t < previous_phase.t else None
)
return None

# Handle inserting into intermediary position.
# Check if new flight phase respects time
next_phase = self.list[index]
previous_phase = self.list[index - 1]
if previous_phase.t < flight_phase.t < next_phase.t:
self.list.insert(index, flight_phase)
return None
warning_msg = (
(
"Trying to add flight phase starting *together* with the one *preceding* it. ",
"This may be caused by multiple parachutes being triggered simultaneously.",
)
if flight_phase.t == previous_phase.t
else (
"Trying to add flight phase starting *together* with the one *proceeding* it. ",
"This may be caused by multiple parachutes being triggered simultaneously.",
)
if flight_phase.t == next_phase.t
else (
"Trying to add flight phase starting *before* the one *preceding* it. ",
"This may be caused by multiple parachutes being triggered simultaneously",
" or by having a negative parachute lag.",
)
if flight_phase.t < previous_phase.t
else (
"Trying to add flight phase starting *after* the one *proceeding* it.",
"This may be caused by multiple parachutes being triggered simultaneously.",
)
)
self.display_warning(*warning_msg)
adjust = 1e-7 if flight_phase.t in {previous_phase.t, next_phase.t} else 0
new_index = (
index - 1
if flight_phase.t < previous_phase.t
else index + 1
if flight_phase.t > next_phase.t
else index
)
flight_phase.t += adjust
self.add(flight_phase, new_index)

def add_phase(self, t, derivatives=None, callback=None, clear=True, index=None):
"""Add a new flight phase to the list, with the specified
characteristics. This method creates a new FlightPhase instance and
adds it to the flight phases list, either at the specified index
position or appended to the end. See FlightPhases.add() for more
information.
Parameters
----------
t : float
The initial time of the new flight phase.
derivatives : function, optional
A function representing the derivatives of the flight phase.
Default is None.
callback : list of functions, optional
A list of callback functions to be executed during the flight
phase. Default is None. You can also pass an empty list.
clear : bool, optional
A flag indicating whether to clear the solution after the phase.
Default is True.
index : int, optional
The index at which the new flight phase should be inserted.
If not provided, the flight phase will be appended
to the end of the list. Default is None.
Returns
-------
None
"""
self.add(self.FlightPhase(t, derivatives, callback, clear), index)

def flush_after(self, index):
"""This function deletes all flight phases after a given index.
Parameters
----------
index : int
The index of the last flight phase to be kept.
Returns
-------
None
"""
del self.list[index + 1 :]

class FlightPhase:
def __init__(self, t, derivative=None, callbacks=[], clear=True):
"""Class to store a flight phase. It stores the initial time, the
derivative function, the callback functions and a flag to clear
the solution after the phase.
Attributes
----------
t : float
The initial time of the flight phase.
derivative : function
A function representing the derivatives of the flight phase.
callbacks : list of functions
A list of callback functions to be executed during the flight
phase.
clear : bool
A flag indicating whether to clear the solution after the phase.
"""

def __init__(self, t, derivative=None, callbacks=None, clear=True):
self.t = t
self.derivative = derivative
self.callbacks = callbacks[:]
self.callbacks = callbacks[:] if callbacks is not None else []
self.clear = clear

def __repr__(self):
Expand Down

0 comments on commit d145cec

Please sign in to comment.