Skip to content

Commit 2b8ee0a

Browse files
Merge branch 'beta/v1.0.0' into enh/new_plots
2 parents 973cf60 + 1f0535f commit 2b8ee0a

File tree

1 file changed

+117
-82
lines changed

1 file changed

+117
-82
lines changed

rocketpy/Flight.py

Lines changed: 117 additions & 82 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
@@ -549,15 +549,18 @@ def __init__(
549
heading : int, float, optional
549
heading : int, float, optional
550
Heading angle relative to north given in degrees.
550
Heading angle relative to north given in degrees.
551
Default is 90, which points in the x direction.
551
Default is 90, which points in the x direction.
552-
initialSolution : array, optional
552+
initialSolution : array, Flight, optional
553
Initial solution array to be used. Format is
553
Initial solution array to be used. Format is
554-
initialSolution = [self.tInitial,
554+
initialSolution = []
555-
xInit, yInit, zInit,
555+
self.tInitial,
556-
vxInit, vyInit, vzInit,
556+
xInit, yInit, zInit,
557-
e0Init, e1Init, e2Init, e3Init,
557+
vxInit, vyInit, vzInit,
558-
w1Init, w2Init, w3Init].
558+
e0Init, e1Init, e2Init, e3Init,
559-
If None, the initial solution will start with all null values,
559+
w1Init, w2Init, w3Init
560-
except for the euler parameters which will be calculated based
560+
].
561+
If a Flight object is used, the last state vector will be used as
562+
initial solution. If None, the initial solution will start with
563+
all null values, except for the euler parameters which will be calculated based
561
on given values of inclination and heading. Default is None.
564
on given values of inclination and heading. Default is None.
562
terminateOnApogee : boolean, optional
565
terminateOnApogee : boolean, optional
563
Whether to terminate simulation when rocket reaches apogee.
566
Whether to terminate simulation when rocket reaches apogee.
@@ -617,86 +620,17 @@ def __init__(
617
self.terminateOnApogee = terminateOnApogee
620
self.terminateOnApogee = terminateOnApogee
618
self.name = name
621
self.name = name
619

622

620-
# Modifying Rail Length for a better out of rail condition
621-
upperRButton = max(self.rocket.railButtons[0])
622-
lowerRButton = min(self.rocket.railButtons[0])
623-
nozzle = self.rocket.distanceRocketNozzle
624-
self.effective1RL = self.env.rL - abs(nozzle - upperRButton)
625-
self.effective2RL = self.env.rL - abs(nozzle - lowerRButton)
626-
627
# Flight initialization
623
# Flight initialization
628
self.__init_post_process_variables()
624
self.__init_post_process_variables()
625+
629
# Initialize solution monitors
626
# Initialize solution monitors
630-
self.outOfRailTime = 0
627+
self.__init_solution_monitors()
631-
self.outOfRailTimeIndex = 0
628+
self.__init_flight_state()
632-
self.outOfRailState = np.array([0])
633-
self.outOfRailVelocity = 0
634-
self.apogeeState = np.array([0])
635-
self.apogeeTime = 0
636-
self.apogeeX = 0
637-
self.apogeeY = 0
638-
self.apogee = 0
639-
self.xImpact = 0
640-
self.yImpact = 0
641-
self.impactVelocity = 0
642-
self.impactState = np.array([0])
643-
self.parachuteEvents = []
644-
self.postProcessed = False
645-
self._drift = Function(0)
646-
self._bearing = Function(0)
647-
self._latitude = Function(0)
648-
self._longitude = Function(0)
649

629

650
# Initialize prints and plots objects
630
# Initialize prints and plots objects
651
self.prints = _FlightPrints(self)
631
self.prints = _FlightPrints(self)
652
self.plots = _FlightPlots(self)
632
self.plots = _FlightPlots(self)
653

633

654-
# Initialize solver monitors
655-
self.functionEvaluations = []
656-
self.functionEvaluationsPerTimeStep = []
657-
self.timeSteps = []
658-
# Initialize solution state
659-
self.solution = []
660-
if self.initialSolution is None:
661-
# Initialize time and state variables
662-
self.tInitial = 0
663-
xInit, yInit, zInit = 0, 0, self.env.elevation
664-
vxInit, vyInit, vzInit = 0, 0, 0
665-
w1Init, w2Init, w3Init = 0, 0, 0
666-
# Initialize attitude
667-
psiInit = -heading * (np.pi / 180) # Precession / Heading Angle
668-
thetaInit = (inclination - 90) * (np.pi / 180) # Nutation Angle
669-
e0Init = np.cos(psiInit / 2) * np.cos(thetaInit / 2)
670-
e1Init = np.cos(psiInit / 2) * np.sin(thetaInit / 2)
671-
e2Init = np.sin(psiInit / 2) * np.sin(thetaInit / 2)
672-
e3Init = np.sin(psiInit / 2) * np.cos(thetaInit / 2)
673-
# Store initial conditions
674-
self.initialSolution = [
675-
self.tInitial,
676-
xInit,
677-
yInit,
678-
zInit,
679-
vxInit,
680-
vyInit,
681-
vzInit,
682-
e0Init,
683-
e1Init,
684-
e2Init,
685-
e3Init,
686-
w1Init,
687-
w2Init,
688-
w3Init,
689-
]
690-
# Set initial derivative for rail phase
691-
self.initialDerivative = self.uDotRail1
692-
else:
693-
# Initial solution given, ignore rail phase
694-
# TODO: Check if rocket is actually out of rail. Otherwise, start at rail
695-
self.outOfRailState = self.initialSolution[1:]
696-
self.outOfRailTime = self.initialSolution[0]
697-
self.outOfRailTimeIndex = 0
698-
self.initialDerivative = self.uDot
699-
700
self.tInitial = self.initialSolution[0]
634
self.tInitial = self.initialSolution[0]
701
self.solution.append(self.initialSolution)
635
self.solution.append(self.initialSolution)
702
self.t = self.solution[-1][0]
636
self.t = self.solution[-1][0]
@@ -1135,6 +1069,80 @@ def __init__(
1135
if verbose:
1069
if verbose:
1136
print("Simulation Completed at Time: {:3.4f} s".format(self.t))
1070
print("Simulation Completed at Time: {:3.4f} s".format(self.t))
1137

1071

1072+
def __init_flight_state(self):
1073+
"""Initialize flight state variables."""
1074+
if self.initialSolution is None:
1075+
# Initialize time and state variables
1076+
self.tInitial = 0
1077+
xInit, yInit, zInit = 0, 0, self.env.elevation
1078+
vxInit, vyInit, vzInit = 0, 0, 0
1079+
w1Init, w2Init, w3Init = 0, 0, 0
1080+
# Initialize attitude
1081+
psiInit = -self.heading * (np.pi / 180) # Precession / Heading Angle
1082+
thetaInit = (self.inclination - 90) * (np.pi / 180) # Nutation Angle
1083+
e0Init = np.cos(psiInit / 2) * np.cos(thetaInit / 2)
1084+
e1Init = np.cos(psiInit / 2) * np.sin(thetaInit / 2)
1085+
e2Init = np.sin(psiInit / 2) * np.sin(thetaInit / 2)
1086+
e3Init = np.sin(psiInit / 2) * np.cos(thetaInit / 2)
1087+
# Store initial conditions
1088+
self.initialSolution = [
1089+
self.tInitial,
1090+
xInit,
1091+
yInit,
1092+
zInit,
1093+
vxInit,
1094+
vyInit,
1095+
vzInit,
1096+
e0Init,
1097+
e1Init,
1098+
e2Init,
1099+
e3Init,
1100+
w1Init,
1101+
w2Init,
1102+
w3Init,
1103+
]
1104+
# Set initial derivative for rail phase
1105+
self.initialDerivative = self.uDotRail1
1106+
elif isinstance(self.initialSolution, Flight):
1107+
# Initialize time and state variables based on last solution of
1108+
# previous flight
1109+
self.initialSolution = self.initialSolution.solution[-1]
1110+
# Set unused monitors
1111+
self.outOfRailState = self.initialSolution[1:]
1112+
self.outOfRailTime = self.initialSolution[0]
1113+
# Set initial derivative for 6-DOF flight phase
1114+
self.initialDerivative = self.uDot
1115+
else:
1116+
# TODO: Check if rocket is actually out of rail. Otherwise, start at rail
1117+
self.outOfRailState = self.initialSolution[1:]
1118+
self.outOfRailTime = self.initialSolution[0]
1119+
self.outOfRailTimeIndex = 0
1120+
self.initialDerivative = self.uDot
1121+
1122+
def __init_solution_monitors(self):
1123+
"""Initialize solution monitors."""
1124+
self.outOfRailTime = 0
1125+
self.outOfRailTimeIndex = 0
1126+
self.outOfRailState = np.array([0])
1127+
self.outOfRailVelocity = 0
1128+
self.apogeeState = np.array([0])
1129+
self.apogeeTime = 0
1130+
self.apogeeX = 0
1131+
self.apogeeY = 0
1132+
self.apogee = 0
1133+
self.xImpact = 0
1134+
self.yImpact = 0
1135+
self.impactVelocity = 0
1136+
self.impactState = np.array([0])
1137+
self.parachuteEvents = []
1138+
self.postProcessed = False
1139+
# Initialize solver monitors
1140+
self.functionEvaluations = []
1141+
self.functionEvaluationsPerTimeStep = []
1142+
self.timeSteps = []
1143+
# Initialize solution state
1144+
self.solution = []
1145+
1138
def __init_post_process_variables(self):
1146
def __init_post_process_variables(self):
1139
"""Initialize post-process variables."""
1147
"""Initialize post-process variables."""
1140
# Initialize all variables calculated after initialization.
1148
# Initialize all variables calculated after initialization.
@@ -1143,6 +1151,29 @@ def __init_post_process_variables(self):
1143
self.difference = Function(0)
1151
self.difference = Function(0)
1144
self.safetyFactor = Function(0)
1152
self.safetyFactor = Function(0)
1145

1153

1154+
@cached_property
1155+
def effective1RL(self):
1156+
# Modifying Rail Length for a better out of rail condition
1157+
nozzle = self.rocket.distanceRocketNozzle # Kinda works for single nozzle
1158+
try:
1159+
upperRButton = max(self.rocket.railButtons[0])
1160+
except AttributeError: # If there is no rail button
1161+
upperRButton = nozzle
1162+
effective1RL = self.env.rL - abs(nozzle - upperRButton)
1163+
1164+
return effective1RL
1165+
1166+
@cached_property
1167+
def effective2RL(self):
1168+
# Modifying Rail Length for a better out of rail condition
1169+
nozzle = self.rocket.distanceRocketNozzle
1170+
try:
1171+
lowerRButton = min(self.rocket.railButtons[0])
1172+
except AttributeError:
1173+
lowerRButton = nozzle
1174+
effective2RL = self.env.rL - abs(nozzle - lowerRButton)
1175+
return effective2RL
1176+
1146
def uDotRail1(self, t, u, postProcessing=False):
1177
def uDotRail1(self, t, u, postProcessing=False):
1147
"""Calculates derivative of u state vector with respect to time
1178
"""Calculates derivative of u state vector with respect to time
1148
when rocket is flying in 1 DOF motion in the rail.
1179
when rocket is flying in 1 DOF motion in the rail.
@@ -2326,7 +2357,9 @@ def retrieve_acceleration_arrays(self):
2326
callback(self)
2357
callback(self)
2327
# Loop through time steps in flight phase
2358
# Loop through time steps in flight phase
2328
for step in self.solution: # Can be optimized
2359
for step in self.solution: # Can be optimized
2329-
if initTime < step[0] <= finalTime:
2360+
if initTime < step[0] <= finalTime or (
2361+
initTime == self.tInitial and step[0] == self.tInitial
2362+
):
2330
# Get derivatives
2363
# Get derivatives
2331
uDot = currentDerivative(step[0], step[1:])
2364
uDot = currentDerivative(step[0], step[1:])
2332
# Get accelerations
2365
# Get accelerations
@@ -2414,7 +2447,9 @@ def retrieve_temporary_values_arrays(self):
2414
callback(self)
2447
callback(self)
2415
# Loop through time steps in flight phase
2448
# Loop through time steps in flight phase
2416
for step in self.solution: # Can be optimized
2449
for step in self.solution: # Can be optimized
2417-
if initTime < step[0] <= finalTime or (initTime == 0 and step[0] == 0):
2450+
if initTime < step[0] <= finalTime or (
2451+
initTime == self.tInitial and step[0] == self.tInitial
2452+
):
2418
# Call derivatives in post processing mode
2453
# Call derivatives in post processing mode
2419
uDot = currentDerivative(step[0], step[1:], postProcessing=True)
2454
uDot = currentDerivative(step[0], step[1:], postProcessing=True)
2420

2455

0 commit comments

Comments
 (0)