From 82bc8240ea5ad57f7aed8520eaf7f645489b6d1e Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Fri, 8 Mar 2024 11:03:52 -0500 Subject: [PATCH 1/3] MNT: Refactor inertia calculations using parallel axis theorem --- CHANGELOG.md | 1 + rocketpy/motors/motor.py | 22 ++++++------------- rocketpy/rocket/rocket.py | 45 ++++++++++++++++++--------------------- rocketpy/tools.py | 21 ++++++++++++++++++ 4 files changed, 50 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ff32bd8d..efd71050a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - ENH: adds `Function.remove_outliers` method [#554](https://github.com/RocketPy-Team/RocketPy/pull/554) ### Changed +- MNT: Refactor inertia calculations using parallel axis theorem [#573] (https://github.com/RocketPy-Team/RocketPy/pull/573) - ENH: Optional argument to show the plot in Function.compare_plots [#563](https://github.com/RocketPy-Team/RocketPy/pull/563) ### Fixed diff --git a/rocketpy/motors/motor.py b/rocketpy/motors/motor.py index 6c2242a9f..911860292 100644 --- a/rocketpy/motors/motor.py +++ b/rocketpy/motors/motor.py @@ -7,7 +7,7 @@ from ..mathutils.function import Function, funcify_method from ..plots.motor_plots import _MotorPlots from ..prints.motor_prints import _MotorPrints -from ..tools import tuple_handler +from ..tools import parallel_axis_theorem, tuple_handler try: from functools import cached_property @@ -513,25 +513,17 @@ def I_11(self): ---------- .. [1] https://en.wikipedia.org/wiki/Moment_of_inertia#Inertia_tensor """ - # Propellant inertia tensor 11 component wrt propellant center of mass - propellant_I_11 = self.propellant_I_11 - # Dry inertia tensor 11 component wrt dry center of mass + prop_I_11 = self.propellant_I_11 dry_I_11 = self.dry_I_11 - # Steiner theorem the get inertia wrt motor center of mass - propellant_I_11 += ( - self.propellant_mass - * (self.center_of_propellant_mass - self.center_of_mass) ** 2 - ) + prop_to_cm = self.center_of_propellant_mass - self.center_of_mass + dry_to_cm = self.center_of_dry_mass_position - self.center_of_mass - dry_I_11 += ( - self.dry_mass - * (self.center_of_dry_mass_position - self.center_of_mass) ** 2 - ) + prop_I_11 = parallel_axis_theorem(prop_I_11, self.propellant_mass, prop_to_cm) + dry_I_11 = parallel_axis_theorem(dry_I_11, self.dry_mass, dry_to_cm) - # Sum of inertia components - return propellant_I_11 + dry_I_11 + return prop_I_11 + dry_I_11 @funcify_method("Time (s)", "Inertia I_22 (kg m²)") def I_22(self): diff --git a/rocketpy/rocket/rocket.py b/rocketpy/rocket/rocket.py index ffcf3b1c8..58ae9c703 100644 --- a/rocketpy/rocket/rocket.py +++ b/rocketpy/rocket/rocket.py @@ -18,6 +18,7 @@ ) from rocketpy.rocket.components import Components from rocketpy.rocket.parachute import Parachute +from rocketpy.tools import parallel_axis_theorem class Rocket: @@ -620,6 +621,10 @@ def evaluate_dry_inertias(self): ---------- .. [1] https://en.wikipedia.org/wiki/Moment_of_inertia#Inertia_tensor """ + # Get masses + motor_dry_mass = self.motor.dry_mass + mass = self.mass + # Compute axes distances noMCM_to_CDM = ( self.center_of_mass_without_motor - self.center_of_dry_mass_position @@ -629,18 +634,14 @@ def evaluate_dry_inertias(self): ) # Compute dry inertias - self.dry_I_11 = ( - self.I_11_without_motor - + self.mass * noMCM_to_CDM**2 - + self.motor.dry_I_11 - + self.motor.dry_mass * motorCDM_to_CDM**2 - ) - self.dry_I_22 = ( - self.I_22_without_motor - + self.mass * noMCM_to_CDM**2 - + self.motor.dry_I_22 - + self.motor.dry_mass * motorCDM_to_CDM**2 - ) + self.dry_I_11 = parallel_axis_theorem( + self.I_11_without_motor, mass, noMCM_to_CDM + ) + parallel_axis_theorem(self.motor.dry_I_11, motor_dry_mass, motorCDM_to_CDM) + + self.dry_I_22 = parallel_axis_theorem( + self.I_22_without_motor, mass, noMCM_to_CDM + ) + parallel_axis_theorem(self.motor.dry_I_22, motor_dry_mass, motorCDM_to_CDM) + self.dry_I_33 = self.I_33_without_motor + self.motor.dry_I_33 self.dry_I_12 = self.I_12_without_motor + self.motor.dry_I_12 self.dry_I_13 = self.I_13_without_motor + self.motor.dry_I_13 @@ -697,18 +698,14 @@ def evaluate_inertias(self): CM_to_CPM = self.center_of_mass - self.center_of_propellant_position # Compute inertias - self.I_11 = ( - self.dry_I_11 - + self.motor.I_11 - + dry_mass * CM_to_CDM**2 - + prop_mass * CM_to_CPM**2 - ) - self.I_22 = ( - self.dry_I_22 - + self.motor.I_22 - + dry_mass * CM_to_CDM**2 - + prop_mass * CM_to_CPM**2 - ) + self.I_11 = parallel_axis_theorem( + self.dry_I_11, dry_mass, CM_to_CDM + ) + parallel_axis_theorem(self.motor.I_11, prop_mass, CM_to_CPM) + + self.I_22 = parallel_axis_theorem( + self.dry_I_22, dry_mass, CM_to_CDM + ) + parallel_axis_theorem(self.motor.I_22, prop_mass, CM_to_CPM) + self.I_33 = self.dry_I_33 + self.motor.I_33 self.I_12 = self.dry_I_12 + self.motor.I_12 self.I_13 = self.dry_I_13 + self.motor.I_13 diff --git a/rocketpy/tools.py b/rocketpy/tools.py index bcff91fb8..af4b0b5db 100644 --- a/rocketpy/tools.py +++ b/rocketpy/tools.py @@ -382,6 +382,27 @@ def check_requirement_version(module_name, version): return True +def parallel_axis_theorem(initial_inertia_moment, mass, distance): + """Converts the moment of inertia from one axis to another using the + parallel axis theorem. The axes must be parallel to each other. + + Parameters + ---------- + initial_inertia_moment : float + Initial moment of inertia. + mass : float + Mass of the object. + distance : float + Distance between the two points. + + Returns + ------- + float + New moment of inertia. + """ + return initial_inertia_moment + mass * distance**2 + + # Flight From 481551231e624fc165d94f8b2485824cbce4b79e Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Fri, 8 Mar 2024 11:27:48 -0500 Subject: [PATCH 2/3] MNT: apply parallel_axis_theorem function to hybrid and liquid motors --- rocketpy/motors/hybrid_motor.py | 31 +++++++++++++++---------------- rocketpy/motors/liquid_motor.py | 8 +++----- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/rocketpy/motors/hybrid_motor.py b/rocketpy/motors/hybrid_motor.py index 4b28a96d2..0320c9f3c 100644 --- a/rocketpy/motors/hybrid_motor.py +++ b/rocketpy/motors/hybrid_motor.py @@ -1,3 +1,5 @@ +from rocketpy.tools import parallel_axis_theorem + from ..mathutils.function import Function, funcify_method, reset_funcified_methods from ..plots.hybrid_motor_plots import _HybridMotorPlots from ..prints.hybrid_motor_prints import _HybridMotorPrints @@ -455,23 +457,20 @@ def propellant_I_11(self): ---------- .. [1] https://en.wikipedia.org/wiki/Moment_of_inertia#Inertia_tensor """ - solid_correction = ( - self.solid.propellant_mass - * (self.solid.center_of_propellant_mass - self.center_of_propellant_mass) - ** 2 - ) - liquid_correction = ( - self.liquid.propellant_mass - * (self.liquid.center_of_propellant_mass - self.center_of_propellant_mass) - ** 2 - ) - I_11 = ( - self.solid.propellant_I_11 - + solid_correction - + self.liquid.propellant_I_11 - + liquid_correction - ) + solid_mass = self.solid.propellant_mass + liquid_mass = self.liquid.propellant_mass + + cm = self.center_of_propellant_mass + solid_cm_to_cm = self.solid.center_of_propellant_mass - cm + liquid_cm_to_cm = self.liquid.center_of_propellant_mass - cm + + solid_prop_inertia = self.solid.propellant_I_11 + liquid_prop_inertia = self.liquid.propellant_I_11 + + I_11 = parallel_axis_theorem( + solid_prop_inertia, solid_mass, solid_cm_to_cm + ) + parallel_axis_theorem(liquid_prop_inertia, liquid_mass, liquid_cm_to_cm) return I_11 diff --git a/rocketpy/motors/liquid_motor.py b/rocketpy/motors/liquid_motor.py index ac525b379..62caa44e7 100644 --- a/rocketpy/motors/liquid_motor.py +++ b/rocketpy/motors/liquid_motor.py @@ -7,6 +7,7 @@ funcify_method, reset_funcified_methods, ) +from rocketpy.tools import parallel_axis_theorem from ..plots.liquid_motor_plots import _LiquidMotorPlots from ..prints.liquid_motor_prints import _LiquidMotorPrints @@ -388,11 +389,8 @@ def propellant_I_11(self): for positioned_tank in self.positioned_tanks: tank = positioned_tank.get("tank") tank_position = positioned_tank.get("position") - I_11 += ( - tank.inertia - + tank.fluid_mass - * (tank_position + tank.center_of_mass - center_of_mass) ** 2 - ) + distance = tank_position + tank.center_of_mass - center_of_mass + I_11 += parallel_axis_theorem(tank.inertia, tank.fluid_mass, distance) return I_11 From 4a7ba1836756de0bebc9b0054af0c263188ee7bf Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Thu, 21 Mar 2024 16:21:11 -0400 Subject: [PATCH 3/3] MNT: improve parallel_axis_theorem_from_com documentation --- rocketpy/motors/hybrid_motor.py | 8 +++++--- rocketpy/motors/liquid_motor.py | 6 ++++-- rocketpy/motors/motor.py | 8 +++++--- rocketpy/rocket/rocket.py | 22 +++++++++++++--------- rocketpy/tools.py | 22 ++++++++++++++-------- 5 files changed, 41 insertions(+), 25 deletions(-) diff --git a/rocketpy/motors/hybrid_motor.py b/rocketpy/motors/hybrid_motor.py index 0320c9f3c..6f0849cd0 100644 --- a/rocketpy/motors/hybrid_motor.py +++ b/rocketpy/motors/hybrid_motor.py @@ -1,4 +1,4 @@ -from rocketpy.tools import parallel_axis_theorem +from rocketpy.tools import parallel_axis_theorem_from_com from ..mathutils.function import Function, funcify_method, reset_funcified_methods from ..plots.hybrid_motor_plots import _HybridMotorPlots @@ -468,9 +468,11 @@ def propellant_I_11(self): solid_prop_inertia = self.solid.propellant_I_11 liquid_prop_inertia = self.liquid.propellant_I_11 - I_11 = parallel_axis_theorem( + I_11 = parallel_axis_theorem_from_com( solid_prop_inertia, solid_mass, solid_cm_to_cm - ) + parallel_axis_theorem(liquid_prop_inertia, liquid_mass, liquid_cm_to_cm) + ) + parallel_axis_theorem_from_com( + liquid_prop_inertia, liquid_mass, liquid_cm_to_cm + ) return I_11 diff --git a/rocketpy/motors/liquid_motor.py b/rocketpy/motors/liquid_motor.py index 62caa44e7..01f728473 100644 --- a/rocketpy/motors/liquid_motor.py +++ b/rocketpy/motors/liquid_motor.py @@ -7,7 +7,7 @@ funcify_method, reset_funcified_methods, ) -from rocketpy.tools import parallel_axis_theorem +from rocketpy.tools import parallel_axis_theorem_from_com from ..plots.liquid_motor_plots import _LiquidMotorPlots from ..prints.liquid_motor_prints import _LiquidMotorPrints @@ -390,7 +390,9 @@ def propellant_I_11(self): tank = positioned_tank.get("tank") tank_position = positioned_tank.get("position") distance = tank_position + tank.center_of_mass - center_of_mass - I_11 += parallel_axis_theorem(tank.inertia, tank.fluid_mass, distance) + I_11 += parallel_axis_theorem_from_com( + tank.inertia, tank.fluid_mass, distance + ) return I_11 diff --git a/rocketpy/motors/motor.py b/rocketpy/motors/motor.py index 911860292..3834f4a15 100644 --- a/rocketpy/motors/motor.py +++ b/rocketpy/motors/motor.py @@ -7,7 +7,7 @@ from ..mathutils.function import Function, funcify_method from ..plots.motor_plots import _MotorPlots from ..prints.motor_prints import _MotorPrints -from ..tools import parallel_axis_theorem, tuple_handler +from ..tools import parallel_axis_theorem_from_com, tuple_handler try: from functools import cached_property @@ -520,8 +520,10 @@ def I_11(self): prop_to_cm = self.center_of_propellant_mass - self.center_of_mass dry_to_cm = self.center_of_dry_mass_position - self.center_of_mass - prop_I_11 = parallel_axis_theorem(prop_I_11, self.propellant_mass, prop_to_cm) - dry_I_11 = parallel_axis_theorem(dry_I_11, self.dry_mass, dry_to_cm) + prop_I_11 = parallel_axis_theorem_from_com( + prop_I_11, self.propellant_mass, prop_to_cm + ) + dry_I_11 = parallel_axis_theorem_from_com(dry_I_11, self.dry_mass, dry_to_cm) return prop_I_11 + dry_I_11 diff --git a/rocketpy/rocket/rocket.py b/rocketpy/rocket/rocket.py index 58ae9c703..27195c1df 100644 --- a/rocketpy/rocket/rocket.py +++ b/rocketpy/rocket/rocket.py @@ -18,7 +18,7 @@ ) from rocketpy.rocket.components import Components from rocketpy.rocket.parachute import Parachute -from rocketpy.tools import parallel_axis_theorem +from rocketpy.tools import parallel_axis_theorem_from_com class Rocket: @@ -634,13 +634,17 @@ def evaluate_dry_inertias(self): ) # Compute dry inertias - self.dry_I_11 = parallel_axis_theorem( + self.dry_I_11 = parallel_axis_theorem_from_com( self.I_11_without_motor, mass, noMCM_to_CDM - ) + parallel_axis_theorem(self.motor.dry_I_11, motor_dry_mass, motorCDM_to_CDM) + ) + parallel_axis_theorem_from_com( + self.motor.dry_I_11, motor_dry_mass, motorCDM_to_CDM + ) - self.dry_I_22 = parallel_axis_theorem( + self.dry_I_22 = parallel_axis_theorem_from_com( self.I_22_without_motor, mass, noMCM_to_CDM - ) + parallel_axis_theorem(self.motor.dry_I_22, motor_dry_mass, motorCDM_to_CDM) + ) + parallel_axis_theorem_from_com( + self.motor.dry_I_22, motor_dry_mass, motorCDM_to_CDM + ) self.dry_I_33 = self.I_33_without_motor + self.motor.dry_I_33 self.dry_I_12 = self.I_12_without_motor + self.motor.dry_I_12 @@ -698,13 +702,13 @@ def evaluate_inertias(self): CM_to_CPM = self.center_of_mass - self.center_of_propellant_position # Compute inertias - self.I_11 = parallel_axis_theorem( + self.I_11 = parallel_axis_theorem_from_com( self.dry_I_11, dry_mass, CM_to_CDM - ) + parallel_axis_theorem(self.motor.I_11, prop_mass, CM_to_CPM) + ) + parallel_axis_theorem_from_com(self.motor.I_11, prop_mass, CM_to_CPM) - self.I_22 = parallel_axis_theorem( + self.I_22 = parallel_axis_theorem_from_com( self.dry_I_22, dry_mass, CM_to_CDM - ) + parallel_axis_theorem(self.motor.I_22, prop_mass, CM_to_CPM) + ) + parallel_axis_theorem_from_com(self.motor.I_22, prop_mass, CM_to_CPM) self.I_33 = self.dry_I_33 + self.motor.I_33 self.I_12 = self.dry_I_12 + self.motor.I_12 diff --git a/rocketpy/tools.py b/rocketpy/tools.py index af4b0b5db..1ce588636 100644 --- a/rocketpy/tools.py +++ b/rocketpy/tools.py @@ -382,25 +382,31 @@ def check_requirement_version(module_name, version): return True -def parallel_axis_theorem(initial_inertia_moment, mass, distance): - """Converts the moment of inertia from one axis to another using the - parallel axis theorem. The axes must be parallel to each other. +def parallel_axis_theorem_from_com(com_inertia_moment, mass, distance): + """Calculates the moment of inertia of a object relative to a new axis using + the parallel axis theorem. The new axis is parallel to and at a distance + 'distance' from the original axis, which *must* passes through the object's + center of mass. Parameters ---------- - initial_inertia_moment : float - Initial moment of inertia. + com_inertia_moment : float + Moment of inertia relative to the center of mass of the object. mass : float Mass of the object. distance : float - Distance between the two points. + Perpendicular distance between the original and new axis. Returns ------- float - New moment of inertia. + Moment of inertia relative to the new axis. + + Reference + --------- + https://en.wikipedia.org/wiki/Parallel_axis_theorem """ - return initial_inertia_moment + mass * distance**2 + return com_inertia_moment + mass * distance**2 # Flight