Skip to content

Commit

Permalink
Merge pull request #321 from RocketPy-Team/enh/improve_initial_sol
Browse files Browse the repository at this point in the history
MAINT: refactor flight class __init__ method
  • Loading branch information
Gui-FernandesBR authored Jan 8, 2023
2 parents b311fed + ac34d57 commit 1f0535f
Showing 1 changed file with 119 additions and 78 deletions.
197 changes: 119 additions & 78 deletions rocketpy/Flight.py
Original file line number Diff line number Diff line change
Expand Up @@ -544,15 +544,18 @@ def __init__(
heading : int, float, optional
Heading angle relative to north given in degrees.
Default is 90, which points in the x direction.
initialSolution : array, optional
initialSolution : array, Flight, optional
Initial solution array to be used. Format is
initialSolution = [self.tInitial,
xInit, yInit, zInit,
vxInit, vyInit, vzInit,
e0Init, e1Init, e2Init, e3Init,
w1Init, w2Init, w3Init].
If None, the initial solution will start with all null values,
except for the euler parameters which will be calculated based
initialSolution = []
self.tInitial,
xInit, yInit, zInit,
vxInit, vyInit, vzInit,
e0Init, e1Init, e2Init, e3Init,
w1Init, w2Init, w3Init
].
If a Flight object is used, the last state vector will be used as
initial solution. If None, the initial solution will start with
all null values, except for the euler parameters which will be calculated based
on given values of inclination and heading. Default is None.
terminateOnApogee : boolean, optional
Whether to terminate simulation when rocket reaches apogee.
Expand Down Expand Up @@ -609,76 +612,11 @@ def __init__(
self.timeOvershoot = timeOvershoot
self.terminateOnApogee = terminateOnApogee

# Modifying Rail Length for a better out of rail condition
upperRButton = max(self.rocket.railButtons[0])
lowerRButton = min(self.rocket.railButtons[0])
nozzle = self.rocket.distanceRocketNozzle
self.effective1RL = self.env.rL - abs(nozzle - upperRButton)
self.effective2RL = self.env.rL - abs(nozzle - lowerRButton)

# Flight initialization
self.__init_post_process_variables()
# Initialize solution monitors
self.outOfRailTime = 0
self.outOfRailTimeIndex = 0
self.outOfRailState = np.array([0])
self.outOfRailVelocity = 0
self.apogeeState = np.array([0])
self.apogeeTime = 0
self.apogeeX = 0
self.apogeeY = 0
self.apogee = 0
self.xImpact = 0
self.yImpact = 0
self.impactVelocity = 0
self.impactState = np.array([0])
self.parachuteEvents = []
self.postProcessed = False
# Initialize solver monitors
self.functionEvaluations = []
self.functionEvaluationsPerTimeStep = []
self.timeSteps = []
# Initialize solution state
self.solution = []
if self.initialSolution is None:
# Initialize time and state variables
self.tInitial = 0
xInit, yInit, zInit = 0, 0, self.env.elevation
vxInit, vyInit, vzInit = 0, 0, 0
w1Init, w2Init, w3Init = 0, 0, 0
# Initialize attitude
psiInit = -heading * (np.pi / 180) # Precession / Heading Angle
thetaInit = (inclination - 90) * (np.pi / 180) # Nutation Angle
e0Init = np.cos(psiInit / 2) * np.cos(thetaInit / 2)
e1Init = np.cos(psiInit / 2) * np.sin(thetaInit / 2)
e2Init = np.sin(psiInit / 2) * np.sin(thetaInit / 2)
e3Init = np.sin(psiInit / 2) * np.cos(thetaInit / 2)
# Store initial conditions
self.initialSolution = [
self.tInitial,
xInit,
yInit,
zInit,
vxInit,
vyInit,
vzInit,
e0Init,
e1Init,
e2Init,
e3Init,
w1Init,
w2Init,
w3Init,
]
# Set initial derivative for rail phase
self.initialDerivative = self.uDotRail1
else:
# Initial solution given, ignore rail phase
# TODO: Check if rocket is actually out of rail. Otherwise, start at rail
self.outOfRailState = self.initialSolution[1:]
self.outOfRailTime = self.initialSolution[0]
self.outOfRailTimeIndex = 0
self.initialDerivative = self.uDot
self.__init_solution_monitors()
self.__init_flight_state()

self.tInitial = self.initialSolution[0]
self.solution.append(self.initialSolution)
Expand Down Expand Up @@ -1118,6 +1056,81 @@ def __init__(
if verbose:
print("Simulation Completed at Time: {:3.4f} s".format(self.t))

def __init_flight_state(self):
"""Initialize flight state variables."""
if self.initialSolution is None:
# Initialize time and state variables
self.tInitial = 0
xInit, yInit, zInit = 0, 0, self.env.elevation
vxInit, vyInit, vzInit = 0, 0, 0
w1Init, w2Init, w3Init = 0, 0, 0
# Initialize attitude
psiInit = -self.heading * (np.pi / 180) # Precession / Heading Angle
thetaInit = (self.inclination - 90) * (np.pi / 180) # Nutation Angle
e0Init = np.cos(psiInit / 2) * np.cos(thetaInit / 2)
e1Init = np.cos(psiInit / 2) * np.sin(thetaInit / 2)
e2Init = np.sin(psiInit / 2) * np.sin(thetaInit / 2)
e3Init = np.sin(psiInit / 2) * np.cos(thetaInit / 2)
# Store initial conditions
self.initialSolution = [
self.tInitial,
xInit,
yInit,
zInit,
vxInit,
vyInit,
vzInit,
e0Init,
e1Init,
e2Init,
e3Init,
w1Init,
w2Init,
w3Init,
]
# Set initial derivative for rail phase
self.initialDerivative = self.uDotRail1
elif isinstance(self.initialSolution, Flight):
# Initialize time and state variables based on last solution of
# previous flight
self.initialSolution = self.initialSolution.solution[-1]
# Set unused monitors
self.outOfRailState = self.initialSolution[1:]
self.outOfRailTime = self.initialSolution[0]
# Set initial derivative for 6-DOF flight phase
self.initialDerivative = self.uDot
else:
# Initial solution given, ignore rail phase
# TODO: Check if rocket is actually out of rail. Otherwise, start at rail
self.outOfRailState = self.initialSolution[1:]
self.outOfRailTime = self.initialSolution[0]
self.outOfRailTimeIndex = 0
self.initialDerivative = self.uDot

def __init_solution_monitors(self):
"""Initialize solution monitors."""
self.outOfRailTime = 0
self.outOfRailTimeIndex = 0
self.outOfRailState = np.array([0])
self.outOfRailVelocity = 0
self.apogeeState = np.array([0])
self.apogeeTime = 0
self.apogeeX = 0
self.apogeeY = 0
self.apogee = 0
self.xImpact = 0
self.yImpact = 0
self.impactVelocity = 0
self.impactState = np.array([0])
self.parachuteEvents = []
self.postProcessed = False
# Initialize solver monitors
self.functionEvaluations = []
self.functionEvaluationsPerTimeStep = []
self.timeSteps = []
# Initialize solution state
self.solution = []

def __init_post_process_variables(self):
"""Initialize post-process variables."""
# Initialize all variables calculated after initialization.
Expand All @@ -1126,6 +1139,29 @@ def __init_post_process_variables(self):
self.difference = Function(0)
self.safetyFactor = Function(0)

@cached_property
def effective1RL(self):
# Modifying Rail Length for a better out of rail condition
nozzle = self.rocket.distanceRocketNozzle # Kinda works for single nozzle
try:
upperRButton = max(self.rocket.railButtons[0])
except AttributeError: # If there is no rail button
upperRButton = nozzle
effective1RL = self.env.rL - abs(nozzle - upperRButton)

return effective1RL

@cached_property
def effective2RL(self):
# Modifying Rail Length for a better out of rail condition
nozzle = self.rocket.distanceRocketNozzle
try:
lowerRButton = min(self.rocket.railButtons[0])
except AttributeError:
lowerRButton = nozzle
effective2RL = self.env.rL - abs(nozzle - lowerRButton)
return effective2RL

def uDotRail1(self, t, u, postProcessing=False):
"""Calculates derivative of u state vector with respect to time
when rocket is flying in 1 DOF motion in the rail.
Expand Down Expand Up @@ -2309,7 +2345,9 @@ def retrieve_acceleration_arrays(self):
callback(self)
# Loop through time steps in flight phase
for step in self.solution: # Can be optimized
if initTime < step[0] <= finalTime:
if initTime < step[0] <= finalTime or (
initTime == self.tInitial and step[0] == self.tInitial
):
# Get derivatives
uDot = currentDerivative(step[0], step[1:])
# Get accelerations
Expand Down Expand Up @@ -2397,7 +2435,9 @@ def retrieve_temporary_values_arrays(self):
callback(self)
# Loop through time steps in flight phase
for step in self.solution: # Can be optimized
if initTime < step[0] <= finalTime or (initTime == 0 and step[0] == 0):
if initTime < step[0] <= finalTime or (
initTime == self.tInitial and step[0] == self.tInitial
):
# Call derivatives in post processing mode
uDot = currentDerivative(step[0], step[1:], postProcessing=True)

Expand Down Expand Up @@ -3171,7 +3211,8 @@ def plotTrajectoryForceData(self):
eventTimeIndex = -1

# Rail Button Forces
fig6 = plt.figure(figsize=(9, 6))
if self.rocket.railButtons is not None:
fig6 = plt.figure(figsize=(9, 6))

ax1 = plt.subplot(211)
ax1.plot(
Expand Down

0 comments on commit 1f0535f

Please sign in to comment.