From a126ef66a7ad6d7f9ad1ca8bdf8082a3bccc62fa Mon Sep 17 00:00:00 2001 From: Lucas Prates <57069366+Lucas-Prates@users.noreply.github.com> Date: Thu, 7 Nov 2024 00:51:40 -0300 Subject: [PATCH] ENH: add structural to total mass ratio for motor and rocket (#713) * ENH: add structural to total mass ratio for motor and rocket * ENH: adding structural mass ratio as an attribute of Motor * ENH: add structural mass ratio to rocket * ENH: capitalize words on prints * DOC: adding structural mass ratio attribute to docstrings * DOC: fix incorrect documentation names of attributes * Remove erroneous comment Co-authored-by: Gui-FernandesBR <63590233+Gui-FernandesBR@users.noreply.github.com> * DOC: modify changelog * ENH: properly testing division by zero when computing the structural mass ratio * MNT: make black --------- Co-authored-by: Gui-FernandesBR <63590233+Gui-FernandesBR@users.noreply.github.com> --- CHANGELOG.md | 2 +- rocketpy/motors/hybrid_motor.py | 2 ++ rocketpy/motors/liquid_motor.py | 2 ++ rocketpy/motors/motor.py | 21 +++++++++++++++++++++ rocketpy/motors/solid_motor.py | 2 ++ rocketpy/prints/hybrid_motor_prints.py | 1 + rocketpy/prints/liquid_motor_prints.py | 1 + rocketpy/prints/motor_prints.py | 1 + rocketpy/prints/rocket_prints.py | 1 + rocketpy/prints/solid_motor_prints.py | 1 + rocketpy/rocket/rocket.py | 26 ++++++++++++++++++++++++++ 11 files changed, 59 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f68f10b8c..bc4f552b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,7 +32,7 @@ Attention: The newest changes should be on top --> ### Added - +- ENH: add structural to total mass ratio for motor and rocket [#713](https://github.com/RocketPy-Team/RocketPy/pull/713) ### Changed diff --git a/rocketpy/motors/hybrid_motor.py b/rocketpy/motors/hybrid_motor.py index 1a1bbb3db..2916486d0 100644 --- a/rocketpy/motors/hybrid_motor.py +++ b/rocketpy/motors/hybrid_motor.py @@ -72,6 +72,8 @@ class HybridMotor(Motor): HybridMotor.propellant_mass : Function Total propellant mass in kg as a function of time, this includes the mass of fluids in each tank and the mass of the solid grains. + HybridMotor.structural_mass_ratio: float + Initial ratio between the dry mass and the total mass. HybridMotor.total_mass_flow_rate : Function Time derivative of propellant total mass in kg/s as a function of time as obtained by the thrust source. diff --git a/rocketpy/motors/liquid_motor.py b/rocketpy/motors/liquid_motor.py index 9ec3d1130..cde0e9d03 100644 --- a/rocketpy/motors/liquid_motor.py +++ b/rocketpy/motors/liquid_motor.py @@ -47,6 +47,8 @@ class LiquidMotor(Motor): LiquidMotor.propellant_mass : Function Total propellant mass in kg as a function of time, includes fuel and oxidizer. + LiquidMotor.structural_mass_ratio: float + Initial ratio between the dry mass and the total mass. LiquidMotor.total_mass_flow_rate : Function Time derivative of propellant total mass in kg/s as a function of time as obtained by the tanks mass flow. diff --git a/rocketpy/motors/motor.py b/rocketpy/motors/motor.py index 5fa154d88..e0e6dfc9a 100644 --- a/rocketpy/motors/motor.py +++ b/rocketpy/motors/motor.py @@ -49,6 +49,8 @@ class Motor(ABC): Motor.propellant_mass : Function Total propellant mass in kg as a function of time, including solid, liquid and gas phases. + Motor.structural_mass_ratio: float + Initial ratio between the dry mass and the total mass. Motor.total_mass_flow_rate : Function Time derivative of propellant total mass in kg/s as a function of time as obtained by the thrust source. @@ -497,6 +499,24 @@ def propellant_initial_mass(self): Propellant initial mass in kg. """ + @property + def structural_mass_ratio(self): + """Calculates the structural mass ratio. The ratio is defined as + the dry mass divided by the initial total mass. + + Returns + ------- + float + Initial structural mass ratio. + """ + initial_total_mass = self.dry_mass + self.propellant_initial_mass + try: + return self.dry_mass / initial_total_mass + except ZeroDivisionError as e: + raise ValueError( + "Total motor mass (dry + propellant) cannot be zero" + ) from e + @funcify_method("Time (s)", "Motor center of mass (m)") def center_of_mass(self): """Position of the center of mass as a function of time. The position @@ -1502,6 +1522,7 @@ def __init__(self): self.nozzle_radius = 0 self.thrust = Function(0, "Time (s)", "Thrust (N)") self.propellant_mass = Function(0, "Time (s)", "Propellant Mass (kg)") + self.propellant_initial_mass = 0 self.total_mass = Function(0, "Time (s)", "Total Mass (kg)") self.total_mass_flow_rate = Function( 0, "Time (s)", "Mass Depletion Rate (kg/s)" diff --git a/rocketpy/motors/solid_motor.py b/rocketpy/motors/solid_motor.py index 81faf453f..f6f09967e 100644 --- a/rocketpy/motors/solid_motor.py +++ b/rocketpy/motors/solid_motor.py @@ -70,6 +70,8 @@ class SolidMotor(Motor): of propellant and dry mass. SolidMotor.propellant_mass : Function Total propellant mass in kg as a function of time. + SolidMotor.structural_mass_ratio: float + Initial ratio between the dry mass and the total mass. SolidMotor.total_mass_flow_rate : Function Time derivative of propellant total mass in kg/s as a function of time as obtained by the thrust source. diff --git a/rocketpy/prints/hybrid_motor_prints.py b/rocketpy/prints/hybrid_motor_prints.py index 4dcd7b113..e69d291f5 100644 --- a/rocketpy/prints/hybrid_motor_prints.py +++ b/rocketpy/prints/hybrid_motor_prints.py @@ -77,6 +77,7 @@ def motor_details(self): print( f"Total Propellant Mass: {self.hybrid_motor.propellant_initial_mass:.3f} kg" ) + print(f"Structural Mass Ratio: {self.hybrid_motor.structural_mass_ratio:.3f}") avg = self.hybrid_motor.exhaust_velocity.average(*self.hybrid_motor.burn_time) print(f"Average Propellant Exhaust Velocity: {avg:.3f} m/s") print(f"Average Thrust: {self.hybrid_motor.average_thrust:.3f} N") diff --git a/rocketpy/prints/liquid_motor_prints.py b/rocketpy/prints/liquid_motor_prints.py index fb493ed0a..4c80326ab 100644 --- a/rocketpy/prints/liquid_motor_prints.py +++ b/rocketpy/prints/liquid_motor_prints.py @@ -47,6 +47,7 @@ def motor_details(self): print( f"Total Propellant Mass: {self.liquid_motor.propellant_initial_mass:.3f} kg" ) + print(f"Structural Mass Ratio: {self.liquid_motor.structural_mass_ratio:.3f}") avg = self.liquid_motor.exhaust_velocity.average(*self.liquid_motor.burn_time) print(f"Average Propellant Exhaust Velocity: {avg:.3f} m/s") print(f"Average Thrust: {self.liquid_motor.average_thrust:.3f} N") diff --git a/rocketpy/prints/motor_prints.py b/rocketpy/prints/motor_prints.py index d9b7fbc98..f5efff8e0 100644 --- a/rocketpy/prints/motor_prints.py +++ b/rocketpy/prints/motor_prints.py @@ -35,6 +35,7 @@ def motor_details(self): print("Motor Details") print("Total Burning Time: " + str(self.motor.burn_out_time) + " s") print(f"Total Propellant Mass: {self.motor.propellant_initial_mass:.3f} kg") + print(f"Structural Mass Ratio: {self.motor.structural_mass_ratio:.3f}") print( "Average Propellant Exhaust Velocity: " f"{self.motor.exhaust_velocity.average(*self.motor.burn_time):.3f} m/s" diff --git a/rocketpy/prints/rocket_prints.py b/rocketpy/prints/rocket_prints.py index c9f5585ac..7b768ea2f 100644 --- a/rocketpy/prints/rocket_prints.py +++ b/rocketpy/prints/rocket_prints.py @@ -36,6 +36,7 @@ def inertia_details(self): print(f"Rocket Mass: {self.rocket.mass:.3f} kg (without motor)") print(f"Rocket Dry Mass: {self.rocket.dry_mass:.3f} kg (with unloaded motor)") print(f"Rocket Loaded Mass: {self.rocket.total_mass(0):.3f} kg") + print(f"Rocket Structural Mass Ratio: {self.rocket.structural_mass_ratio:.3f}") print( f"Rocket Inertia (with unloaded motor) 11: {self.rocket.dry_I_11:.3f} kg*m2" ) diff --git a/rocketpy/prints/solid_motor_prints.py b/rocketpy/prints/solid_motor_prints.py index c37a9b69e..6f4c28d5b 100644 --- a/rocketpy/prints/solid_motor_prints.py +++ b/rocketpy/prints/solid_motor_prints.py @@ -65,6 +65,7 @@ def motor_details(self): print( f"Total Propellant Mass: {self.solid_motor.propellant_initial_mass:.3f} kg" ) + print(f"Structural Mass Ratio: {self.solid_motor.structural_mass_ratio:.3f}") average = self.solid_motor.exhaust_velocity.average(*self.solid_motor.burn_time) print(f"Average Propellant Exhaust Velocity: {average:.3f} m/s") print(f"Average Thrust: {self.solid_motor.average_thrust:.3f} N") diff --git a/rocketpy/rocket/rocket.py b/rocketpy/rocket/rocket.py index 758447fde..ed376f582 100644 --- a/rocketpy/rocket/rocket.py +++ b/rocketpy/rocket/rocket.py @@ -89,6 +89,8 @@ class Rocket: Function of time expressing the total mass of the rocket, defined as the sum of the propellant mass and the rocket mass without propellant. + Rocket.structural_mass_ratio: float + Initial ratio between the dry mass and the total mass. Rocket.total_mass_flow_rate : Function Time derivative of rocket's total mass in kg/s as a function of time as obtained by the thrust source of the added motor. @@ -361,6 +363,7 @@ def __init__( # pylint: disable=too-many-statements # calculate dynamic inertial quantities self.evaluate_dry_mass() + self.evaluate_structural_mass_ratio() self.evaluate_total_mass() self.evaluate_center_of_dry_mass() self.evaluate_center_of_mass() @@ -433,6 +436,28 @@ def evaluate_dry_mass(self): return self.dry_mass + def evaluate_structural_mass_ratio(self): + """Calculates and returns the rocket's structural mass ratio. + It is defined as the ratio between of the dry mass + (Motor + Rocket) and the initial total mass + (Motor + Propellant + Rocket). + + Returns + ------- + self.structural_mass_ratio: float + Initial structural mass ratio dry mass (Rocket + Motor) (kg) + divided by total mass (Rocket + Motor + Propellant) (kg). + """ + try: + self.structural_mass_ratio = self.dry_mass / ( + self.dry_mass + self.motor.propellant_initial_mass + ) + except ZeroDivisionError as e: + raise ValueError( + "Total rocket mass (dry + propellant) cannot be zero" + ) from e + return self.structural_mass_ratio + def evaluate_center_of_mass(self): """Evaluates rocket center of mass position relative to user defined rocket reference system. @@ -951,6 +976,7 @@ def add_motor(self, motor, position): # pylint: disable=too-many-statements self.nozzle_position = self.motor.nozzle_position * _ + self.motor_position self.total_mass_flow_rate = self.motor.total_mass_flow_rate self.evaluate_dry_mass() + self.evaluate_structural_mass_ratio() self.evaluate_total_mass() self.evaluate_center_of_dry_mass() self.evaluate_nozzle_to_cdm()