From 10911f5c923df86821535a41f3474684e3dda7b2 Mon Sep 17 00:00:00 2001 From: Giovani Hidalgo Ceotto Date: Wed, 5 Oct 2022 03:31:41 +0000 Subject: [PATCH 1/4] BUG: miss matching arrays init solution --- rocketpy/Flight.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rocketpy/Flight.py b/rocketpy/Flight.py index a02c9885b..d2e626bdb 100644 --- a/rocketpy/Flight.py +++ b/rocketpy/Flight.py @@ -2309,7 +2309,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 @@ -2397,7 +2399,7 @@ 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) From 247fe7f465b727afac3de12bc1ec537ce29b2deb Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Tue, 27 Sep 2022 16:59:30 +0200 Subject: [PATCH 2/4] MAINT: Make rail buttons optional in simulation --- rocketpy/Flight.py | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/rocketpy/Flight.py b/rocketpy/Flight.py index d2e626bdb..60b25c068 100644 --- a/rocketpy/Flight.py +++ b/rocketpy/Flight.py @@ -609,13 +609,6 @@ 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 @@ -1126,6 +1119,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. @@ -3173,7 +3189,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( From c9c46157b740059fe400944d82642a585ce8e0ab Mon Sep 17 00:00:00 2001 From: giovaniceotto Date: Wed, 14 Sep 2022 08:19:17 -0300 Subject: [PATCH 3/4] MAINT: refactor solution monitors initialization --- rocketpy/Flight.py | 132 ++++++++++++++++++++++++--------------------- 1 file changed, 71 insertions(+), 61 deletions(-) diff --git a/rocketpy/Flight.py b/rocketpy/Flight.py index 60b25c068..a29cfd2f2 100644 --- a/rocketpy/Flight.py +++ b/rocketpy/Flight.py @@ -612,66 +612,8 @@ def __init__( # 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) @@ -1111,6 +1053,72 @@ 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 + 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. @@ -2415,7 +2423,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 == self.tInitial and step[0] == self.tInitial): + 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) From ac34d5773d2b3003b7b4dccd1dc26b6167a08cec Mon Sep 17 00:00:00 2001 From: giovaniceotto Date: Wed, 14 Sep 2022 08:15:17 -0300 Subject: [PATCH 4/4] MAINT: Make rail buttons optional in simulation --- rocketpy/Flight.py | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/rocketpy/Flight.py b/rocketpy/Flight.py index a29cfd2f2..14550643f 100644 --- a/rocketpy/Flight.py +++ b/rocketpy/Flight.py @@ -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. @@ -1087,6 +1090,15 @@ def __init_flight_state(self): ] # 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