From 9fe3a37c93069156ac45a6f241f5935832ddb21d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20Alca=C3=B1iz?= Date: Fri, 14 Mar 2025 18:46:09 +0100 Subject: [PATCH 01/12] wind factor bug corrected the wind factor wasn't applied to the env.wind_velocity properties --- rocketpy/stochastic/stochastic_environment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/rocketpy/stochastic/stochastic_environment.py b/rocketpy/stochastic/stochastic_environment.py index 58afe0fed..e0fc33eec 100644 --- a/rocketpy/stochastic/stochastic_environment.py +++ b/rocketpy/stochastic/stochastic_environment.py @@ -184,5 +184,6 @@ def create_object(self): # get original attribute value and multiply by factor attribute_name = f"_{key.replace('_factor', '')}" value = getattr(self, attribute_name) * value + key = f"{key.replace('_factor', '')}" setattr(self.obj, key, value) return self.obj From f6efa816442a740279ebaf880458049d28799b3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20Alca=C3=B1iz?= Date: Sat, 15 Mar 2025 11:46:06 +0100 Subject: [PATCH 02/12] BUG: StochasticModel visualize attributes of a uniform distribution It showed the nominal and the standard deviation values and it doesn't make sense in a uniform distribution. In a np.random.uniform the 'nominal value' is the lower bound of the distribution, and the 'standard deviation' value is the upper bound. Now, a new condition has been added for the uniform distributions where the mean and semi range are calculated and showed. This way the visualize_attribute function will show the whole range where the random values are uniformly taken in --- rocketpy/stochastic/stochastic_model.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/rocketpy/stochastic/stochastic_model.py b/rocketpy/stochastic/stochastic_model.py index c82232fcb..e44e2613d 100644 --- a/rocketpy/stochastic/stochastic_model.py +++ b/rocketpy/stochastic/stochastic_model.py @@ -486,11 +486,20 @@ def format_attribute(attr, value): ) elif isinstance(value, tuple): nominal_value, std_dev, dist_func = value - return ( - f"\t{attr.ljust(max_str_length)} " - f"{nominal_value:.5f} ± " - f"{std_dev:.5f} ({dist_func.__name__})" - ) + if dist_func == np.random.uniform: + mean = (std_dev + nominal_value) / 2 + semi_range = (std_dev - nominal_value) / 2 + return ( + f"\t{attr.ljust(max_str_length)} " + f"{mean:.5f} ± " + f"{semi_range:.5f} ({dist_func.__name__})" + ) + else: + return ( + f"\t{attr.ljust(max_str_length)} " + f"{nominal_value:.5f} ± " + f"{std_dev:.5f} ({dist_func.__name__})" + ) return None attributes = {k: v for k, v in self.__dict__.items() if not k.startswith("_")} From 04337ab79982f28196d4b3950d36407cac6752b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20Alca=C3=B1iz?= Date: Sat, 15 Mar 2025 16:11:27 +0100 Subject: [PATCH 03/12] variable names corrections --- rocketpy/stochastic/stochastic_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rocketpy/stochastic/stochastic_model.py b/rocketpy/stochastic/stochastic_model.py index e44e2613d..e833e01bf 100644 --- a/rocketpy/stochastic/stochastic_model.py +++ b/rocketpy/stochastic/stochastic_model.py @@ -488,11 +488,11 @@ def format_attribute(attr, value): nominal_value, std_dev, dist_func = value if dist_func == np.random.uniform: mean = (std_dev + nominal_value) / 2 - semi_range = (std_dev - nominal_value) / 2 + half_range = (std_dev - nominal_value) / 2 return ( f"\t{attr.ljust(max_str_length)} " f"{mean:.5f} ± " - f"{semi_range:.5f} ({dist_func.__name__})" + f"{half_range:.5f} ({dist_func.__name__})" ) else: return ( From 18f8323f39798ae90caada573660dcf63b113769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20Alca=C3=B1iz?= Date: Sat, 15 Mar 2025 17:46:04 +0100 Subject: [PATCH 04/12] Corrections requested by the pylint test --- rocketpy/stochastic/stochastic_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocketpy/stochastic/stochastic_model.py b/rocketpy/stochastic/stochastic_model.py index e833e01bf..39fc478b7 100644 --- a/rocketpy/stochastic/stochastic_model.py +++ b/rocketpy/stochastic/stochastic_model.py @@ -486,7 +486,7 @@ def format_attribute(attr, value): ) elif isinstance(value, tuple): nominal_value, std_dev, dist_func = value - if dist_func == np.random.uniform: + if callable(dist_func) and dist_func.__name__ == "uniform": mean = (std_dev + nominal_value) / 2 half_range = (std_dev - nominal_value) / 2 return ( From 7c68241adf11fe0d8b08b8047eb3c9f511dd242d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20Alca=C3=B1iz?= Date: Sat, 22 Mar 2025 10:06:13 +0100 Subject: [PATCH 05/12] ENH: more intuitive uniform distribution display in StochasticModel Co-authored-by: MateusStano <69485049+MateusStano@users.noreply.github.com> --- rocketpy/stochastic/stochastic_model.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/rocketpy/stochastic/stochastic_model.py b/rocketpy/stochastic/stochastic_model.py index b5be5293e..fe47a252a 100644 --- a/rocketpy/stochastic/stochastic_model.py +++ b/rocketpy/stochastic/stochastic_model.py @@ -515,12 +515,11 @@ def format_attribute(attr, value): elif isinstance(value, tuple): nominal_value, std_dev, dist_func = value if callable(dist_func) and dist_func.__name__ == "uniform": - mean = (std_dev + nominal_value) / 2 - half_range = (std_dev - nominal_value) / 2 + lower_bound = nominal_value + upper_bound = std_dev return ( f"\t{attr.ljust(max_str_length)} " - f"{mean:.5f} ± " - f"{half_range:.5f} ({dist_func.__name__})" + f"{lower_bound:.5f}, {upper_bound:.5f} ({dist_func.__name__})" ) else: return ( From 1f45817878be15e164741e592f81103bb21be2ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20Alca=C3=B1iz?= Date: Sat, 22 Mar 2025 14:18:24 +0100 Subject: [PATCH 06/12] ENH: Eccentricities added to the StochasticRocket class A bug has been corrected in Flight class and an enhancement has been performed in the Rocket class as well --- rocketpy/rocket/rocket.py | 33 +++--- rocketpy/simulation/flight.py | 8 +- rocketpy/stochastic/stochastic_rocket.py | 142 +++++++++++++++++++++++ 3 files changed, 159 insertions(+), 24 deletions(-) diff --git a/rocketpy/rocket/rocket.py b/rocketpy/rocket/rocket.py index 609e1b76c..04ec12fc8 100644 --- a/rocketpy/rocket/rocket.py +++ b/rocketpy/rocket/rocket.py @@ -1744,8 +1744,8 @@ def set_rail_buttons( def add_cm_eccentricity(self, x, y): """Moves line of action of aerodynamic and thrust forces by equal translation amount to simulate an eccentricity in the - position of the center of mass of the rocket relative to its - geometrical center line. + position of the center of dry mass of the rocket relative to + its geometrical center line. Parameters ---------- @@ -1766,11 +1766,6 @@ def add_cm_eccentricity(self, x, y): See Also -------- :ref:`rocket_axes` - - Notes - ----- - Should not be used together with add_cp_eccentricity and - add_thrust_eccentricity. """ self.cm_eccentricity_x = x self.cm_eccentricity_y = y @@ -1781,20 +1776,18 @@ def add_cm_eccentricity(self, x, y): def add_cp_eccentricity(self, x, y): """Moves line of action of aerodynamic forces to simulate an eccentricity in the position of the center of pressure relative - to the center of mass of the rocket. + to the center of dry mass of the rocket. Parameters ---------- x : float Distance in meters by which the CP is to be translated in - the x direction relative to the center of mass axial line. - The x axis is defined according to the body axes coordinate - system. + the x direction relative to geometrical center line. The x axis + is defined according to the body axes coordinate system. y : float Distance in meters by which the CP is to be translated in - the y direction relative to the center of mass axial line. - The y axis is defined according to the body axes coordinate - system. + the y direction relative to geometrical center line. The y axis + is defined according to the body axes coordinate system. Returns ------- @@ -1805,8 +1798,8 @@ def add_cp_eccentricity(self, x, y): -------- :ref:`rocket_axes` """ - self.cp_eccentricity_x = x - self.cp_eccentricity_y = y + self.cp_eccentricity_x += x + self.cp_eccentricity_y += y return self def add_thrust_eccentricity(self, x, y): @@ -1818,12 +1811,12 @@ def add_thrust_eccentricity(self, x, y): x : float Distance in meters by which the line of action of the thrust force is to be translated in the x direction - relative to the center of mass axial line. The x axis + relative to geometrical center line. The x axis is defined according to the body axes coordinate system. y : float Distance in meters by which the line of action of the thrust force is to be translated in the x direction - relative to the center of mass axial line. The y axis + relative to geometrical center line. The y axis is defined according to the body axes coordinate system. Returns @@ -1835,8 +1828,8 @@ def add_thrust_eccentricity(self, x, y): -------- :ref:`rocket_axes` """ - self.thrust_eccentricity_y = x - self.thrust_eccentricity_x = y + self.thrust_eccentricity_y += x + self.thrust_eccentricity_x += y return self def draw(self, vis_args=None, plane="xz", *, filename=None): diff --git a/rocketpy/simulation/flight.py b/rocketpy/simulation/flight.py index 035323533..80bb9f6ee 100644 --- a/rocketpy/simulation/flight.py +++ b/rocketpy/simulation/flight.py @@ -1469,8 +1469,8 @@ def u_dot(self, t, u, post_processing=False): # pylint: disable=too-many-locals # Thrust thrust = self.rocket.motor.thrust.get_value_opt(t) # Off center moment - M1 += self.rocket.thrust_eccentricity_x * thrust - M2 -= self.rocket.thrust_eccentricity_y * thrust + M1 += self.rocket.thrust_eccentricity_y * thrust + M2 -= self.rocket.thrust_eccentricity_x * thrust else: # Motor stopped # Inertias @@ -1856,11 +1856,11 @@ def u_dot_generalized(self, t, u, post_processing=False): # pylint: disable=too thrust = self.rocket.motor.thrust.get_value_opt(t) M1 += ( self.rocket.cp_eccentricity_y * R3 - + self.rocket.thrust_eccentricity_x * thrust + + self.rocket.thrust_eccentricity_y * thrust ) M2 -= ( self.rocket.cp_eccentricity_x * R3 - - self.rocket.thrust_eccentricity_y * thrust + + self.rocket.thrust_eccentricity_x * thrust ) M3 += self.rocket.cp_eccentricity_x * R2 - self.rocket.cp_eccentricity_y * R1 diff --git a/rocketpy/stochastic/stochastic_rocket.py b/rocketpy/stochastic/stochastic_rocket.py index 224262ff1..ed0568cb7 100644 --- a/rocketpy/stochastic/stochastic_rocket.py +++ b/rocketpy/stochastic/stochastic_rocket.py @@ -2,6 +2,7 @@ import warnings from random import choice +import numpy as np from rocketpy.mathutils.vector_matrix import Vector from rocketpy.motors.empty_motor import EmptyMotor @@ -168,6 +169,14 @@ def __init__( coordinate_system_orientation=None, ) + # Eccentricity data initialization + self.cm_eccentricity_x = (0, 0, np.random.normal()) + self.cm_eccentricity_y = (0, 0, np.random.normal()) + self.cp_eccentricity_x = (0, 0, np.random.normal()) + self.cp_eccentricity_y = (0, 0, np.random.normal()) + self.thrust_eccentricity_y = (0, 0, np.random.normal()) + self.thrust_eccentricity_x = (0, 0, np.random.normal()) + def _set_stochastic(self, seed=None): """Set the stochastic attributes for Components, positions and inputs. @@ -389,6 +398,127 @@ def set_rail_buttons( rail_buttons, self._validate_position(rail_buttons, lower_button_position) ) + def add_cm_eccentricity(self, x=None, y=None): + """Moves line of action of aerodynamic and thrust forces by + equal translation amount to simulate an eccentricity in the + position of the center of dry mass of the rocket relative to + its geometrical center line. + + Parameters + ---------- + x : tuple, list, int, float, optional + Distance in meters by which the CM is to be translated in + the x direction relative to geometrical center line. The x axis + is defined according to the body axes coordinate system. + y : tuple, list, int, float, optional + Distance in meters by which the CM is to be translated in + the y direction relative to geometrical center line. The y axis + is defined according to the body axes coordinate system. + + Returns + ------- + self : StochasticRocket + Object of the StochasticRocket class. + """ + self.cm_eccentricity_x = self._validate_eccentricity("cm_eccentricity_x", x) + self.cm_eccentricity_y = self._validate_eccentricity("cm_eccentricity_y", y) + return self + + def add_cp_eccentricity(self, x=None, y=None): + """Moves line of action of aerodynamic forces to simulate an + eccentricity in the position of the center of pressure relative + to the center of dry mass of the rocket. + + Parameters + ---------- + x : tuple, list, int, float, optional + Distance in meters by which the CP is to be translated in + the x direction relative to geometrical center line. The x axis + is defined according to the body axes coordinate system. + y : tuple, list, int, float, optional + Distance in meters by which the CP is to be translated in + the y direction relative to geometrical center line. The y axis + is defined according to the body axes coordinate system. + + Returns + ------- + self : StochasticRocket + Object of the StochasticRocket class. + """ + self.cp_eccentricity_x = self._validate_eccentricity("cp_eccentricity_x", x) + self.cp_eccentricity_y = self._validate_eccentricity("cp_eccentricity_y", y) + return self + + def add_thrust_eccentricity(self, x=None, y=None): + """Moves line of action of thrust forces to simulate a + misalignment of the thrust vector and the center of mass. + + Parameters + ---------- + x : tuple, list, int, float, optional + Distance in meters by which the line of action of the + thrust force is to be translated in the x direction + relative to geometrical center line. The x axis + is defined according to the body axes coordinate system. + y : tuple, list, int, float, optional + Distance in meters by which the line of action of the + thrust force is to be translated in the x direction + relative to geometrical center line. The y axis + is defined according to the body axes coordinate system. + + Returns + ------- + self : StochasticRocket + Object of the StochasticRocket class. + """ + self.thrust_eccentricity_y = self._validate_eccentricity("thrust_eccentricity_x", x) + self.thrust_eccentricity_x = self._validate_eccentricity("thrust_eccentricity_y", y) + return self + + def _validate_eccentricity(self, eccentricity, position): + """Validate the eccentricity argument. + + Parameters + ---------- + eccentricity : str + The eccentricity to which the position argument refers to. + position : tuple, list, int, float + The position argument to be validated. + + Returns + ------- + tuple or list + Validated position argument. + + Raises + ------ + ValueError + If the position argument does not conform to the specified formats. + """ + if isinstance(position, tuple): + return self._validate_tuple( + eccentricity, + position, + ) + elif isinstance(position, (int, float)): + return self._validate_scalar( + eccentricity, + position, + ) + elif isinstance(position, list): + return self._validate_list( + eccentricity, + position, + ) + elif position is None: + position = [] + return self._validate_list( + eccentricity, + position, + ) + else: + raise AssertionError("`position` must be a tuple, list, int, or float") + def _validate_position(self, validated_object, position): """Validate the position argument. @@ -577,6 +707,11 @@ def _create_parachute(self, stochastic_parachute): parachute = stochastic_parachute.create_object() self.last_rnd_dict["parachutes"].append(stochastic_parachute.last_rnd_dict) return parachute + + def _create_eccentricities(self, stochastic_x, stochastic_y): + x_rnd = self._randomize_position(stochastic_x) + y_rnd = self._randomize_position(stochastic_y) + return x_rnd, y_rnd def create_object(self): """Creates and returns a Rocket object from the randomly generated input @@ -609,6 +744,13 @@ def create_object(self): rocket.power_off_drag *= generated_dict["power_off_drag_factor"] rocket.power_on_drag *= generated_dict["power_on_drag_factor"] + cm_ecc_x, cm_ecc_y = self._create_eccentricities(self.cm_eccentricity_x,self.cm_eccentricity_y) + rocket.add_cm_eccentricity(cm_ecc_x,cm_ecc_y) + cp_ecc_x, cp_ecc_y = self._create_eccentricities(self.cp_eccentricity_x,self.cp_eccentricity_y) + rocket.add_cp_eccentricity(cp_ecc_x,cp_ecc_y) + thrust_ecc_x, thrust_ecc_y = self._create_eccentricities(self.thrust_eccentricity_x,self.thrust_eccentricity_y) + rocket.add_thrust_eccentricity(thrust_ecc_x,thrust_ecc_y) + for component_motor in self.motors: motor, position_rnd = self._create_motor(component_motor) rocket.add_motor(motor, position_rnd) From 0602442f84dcb681f45f3d042546048844355c72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20Alca=C3=B1iz?= Date: Sat, 22 Mar 2025 16:15:37 +0100 Subject: [PATCH 07/12] BUG: thrust eccentricity bug corrected eccentricity_y was defined by x coordinate and eccentricity_x was defined by y coordinate --- rocketpy/rocket/rocket.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rocketpy/rocket/rocket.py b/rocketpy/rocket/rocket.py index 04ec12fc8..4e306d0e4 100644 --- a/rocketpy/rocket/rocket.py +++ b/rocketpy/rocket/rocket.py @@ -1815,7 +1815,7 @@ def add_thrust_eccentricity(self, x, y): is defined according to the body axes coordinate system. y : float Distance in meters by which the line of action of the - thrust force is to be translated in the x direction + thrust force is to be translated in the y direction relative to geometrical center line. The y axis is defined according to the body axes coordinate system. @@ -1828,8 +1828,8 @@ def add_thrust_eccentricity(self, x, y): -------- :ref:`rocket_axes` """ - self.thrust_eccentricity_y += x - self.thrust_eccentricity_x += y + self.thrust_eccentricity_x += x + self.thrust_eccentricity_y += y return self def draw(self, vis_args=None, plane="xz", *, filename=None): From 47cb9c1cf5d7cef8479eecbcbb19b614d3b35da9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20Alca=C3=B1iz?= Date: Sat, 22 Mar 2025 18:13:53 +0100 Subject: [PATCH 08/12] BUG: Undo some Rocket class changes --- rocketpy/rocket/rocket.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/rocketpy/rocket/rocket.py b/rocketpy/rocket/rocket.py index 4e306d0e4..415f54790 100644 --- a/rocketpy/rocket/rocket.py +++ b/rocketpy/rocket/rocket.py @@ -1766,6 +1766,11 @@ def add_cm_eccentricity(self, x, y): See Also -------- :ref:`rocket_axes` + + Notes + ----- + Should not be used together with add_cp_eccentricity and + add_thrust_eccentricity. """ self.cm_eccentricity_x = x self.cm_eccentricity_y = y @@ -1782,12 +1787,12 @@ def add_cp_eccentricity(self, x, y): ---------- x : float Distance in meters by which the CP is to be translated in - the x direction relative to geometrical center line. The x axis - is defined according to the body axes coordinate system. + the x direction relative to the center of dry mass axial line. + The x axis is defined according to the body axes coordinate system. y : float Distance in meters by which the CP is to be translated in - the y direction relative to geometrical center line. The y axis - is defined according to the body axes coordinate system. + the y direction relative to the center of dry mass axial line. + The y axis is defined according to the body axes coordinate system. Returns ------- @@ -1798,25 +1803,25 @@ def add_cp_eccentricity(self, x, y): -------- :ref:`rocket_axes` """ - self.cp_eccentricity_x += x - self.cp_eccentricity_y += y + self.cp_eccentricity_x = x + self.cp_eccentricity_y = y return self def add_thrust_eccentricity(self, x, y): """Moves line of action of thrust forces to simulate a - misalignment of the thrust vector and the center of mass. + misalignment of the thrust vector and the center of dry mass. Parameters ---------- x : float Distance in meters by which the line of action of the thrust force is to be translated in the x direction - relative to geometrical center line. The x axis + relative to the center of dry mass axial line. The x axis is defined according to the body axes coordinate system. y : float Distance in meters by which the line of action of the thrust force is to be translated in the y direction - relative to geometrical center line. The y axis + relative to the center of dry mass axial line. The y axis is defined according to the body axes coordinate system. Returns @@ -1828,8 +1833,8 @@ def add_thrust_eccentricity(self, x, y): -------- :ref:`rocket_axes` """ - self.thrust_eccentricity_x += x - self.thrust_eccentricity_y += y + self.thrust_eccentricity_x = x + self.thrust_eccentricity_y = y return self def draw(self, vis_args=None, plane="xz", *, filename=None): From b8cafd5181a27b31a7aec3166c6166b43d24f911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20Alca=C3=B1iz?= Date: Sat, 22 Mar 2025 19:04:25 +0100 Subject: [PATCH 09/12] ENH: add eccentricities to StochasticRocket --- rocketpy/stochastic/stochastic_rocket.py | 71 +++++++----------------- 1 file changed, 20 insertions(+), 51 deletions(-) diff --git a/rocketpy/stochastic/stochastic_rocket.py b/rocketpy/stochastic/stochastic_rocket.py index ed0568cb7..ad8d83c91 100644 --- a/rocketpy/stochastic/stochastic_rocket.py +++ b/rocketpy/stochastic/stochastic_rocket.py @@ -2,7 +2,6 @@ import warnings from random import choice -import numpy as np from rocketpy.mathutils.vector_matrix import Vector from rocketpy.motors.empty_motor import EmptyMotor @@ -169,14 +168,6 @@ def __init__( coordinate_system_orientation=None, ) - # Eccentricity data initialization - self.cm_eccentricity_x = (0, 0, np.random.normal()) - self.cm_eccentricity_y = (0, 0, np.random.normal()) - self.cp_eccentricity_x = (0, 0, np.random.normal()) - self.cp_eccentricity_y = (0, 0, np.random.normal()) - self.thrust_eccentricity_y = (0, 0, np.random.normal()) - self.thrust_eccentricity_x = (0, 0, np.random.normal()) - def _set_stochastic(self, seed=None): """Set the stochastic attributes for Components, positions and inputs. @@ -398,32 +389,6 @@ def set_rail_buttons( rail_buttons, self._validate_position(rail_buttons, lower_button_position) ) - def add_cm_eccentricity(self, x=None, y=None): - """Moves line of action of aerodynamic and thrust forces by - equal translation amount to simulate an eccentricity in the - position of the center of dry mass of the rocket relative to - its geometrical center line. - - Parameters - ---------- - x : tuple, list, int, float, optional - Distance in meters by which the CM is to be translated in - the x direction relative to geometrical center line. The x axis - is defined according to the body axes coordinate system. - y : tuple, list, int, float, optional - Distance in meters by which the CM is to be translated in - the y direction relative to geometrical center line. The y axis - is defined according to the body axes coordinate system. - - Returns - ------- - self : StochasticRocket - Object of the StochasticRocket class. - """ - self.cm_eccentricity_x = self._validate_eccentricity("cm_eccentricity_x", x) - self.cm_eccentricity_y = self._validate_eccentricity("cm_eccentricity_y", y) - return self - def add_cp_eccentricity(self, x=None, y=None): """Moves line of action of aerodynamic forces to simulate an eccentricity in the position of the center of pressure relative @@ -433,12 +398,12 @@ def add_cp_eccentricity(self, x=None, y=None): ---------- x : tuple, list, int, float, optional Distance in meters by which the CP is to be translated in - the x direction relative to geometrical center line. The x axis - is defined according to the body axes coordinate system. + the x direction relative to the center of dry mass axial line. + The x axis is defined according to the body axes coordinate system. y : tuple, list, int, float, optional Distance in meters by which the CP is to be translated in - the y direction relative to geometrical center line. The y axis - is defined according to the body axes coordinate system. + the y direction relative to the center of dry mass axial line. + The y axis is defined according to the body axes coordinate system. Returns ------- @@ -451,19 +416,19 @@ def add_cp_eccentricity(self, x=None, y=None): def add_thrust_eccentricity(self, x=None, y=None): """Moves line of action of thrust forces to simulate a - misalignment of the thrust vector and the center of mass. + misalignment of the thrust vector and the center of dry mass. Parameters ---------- x : tuple, list, int, float, optional Distance in meters by which the line of action of the thrust force is to be translated in the x direction - relative to geometrical center line. The x axis + relative to the center of dry mass axial line. The x axis is defined according to the body axes coordinate system. y : tuple, list, int, float, optional Distance in meters by which the line of action of the - thrust force is to be translated in the x direction - relative to geometrical center line. The y axis + thrust force is to be translated in the y direction + relative to the center of dry mass axial line. The y axis is defined according to the body axes coordinate system. Returns @@ -471,8 +436,8 @@ def add_thrust_eccentricity(self, x=None, y=None): self : StochasticRocket Object of the StochasticRocket class. """ - self.thrust_eccentricity_y = self._validate_eccentricity("thrust_eccentricity_x", x) - self.thrust_eccentricity_x = self._validate_eccentricity("thrust_eccentricity_y", y) + self.thrust_eccentricity_x = self._validate_eccentricity("thrust_eccentricity_x", x) + self.thrust_eccentricity_y = self._validate_eccentricity("thrust_eccentricity_y", y) return self def _validate_eccentricity(self, eccentricity, position): @@ -744,12 +709,16 @@ def create_object(self): rocket.power_off_drag *= generated_dict["power_off_drag_factor"] rocket.power_on_drag *= generated_dict["power_on_drag_factor"] - cm_ecc_x, cm_ecc_y = self._create_eccentricities(self.cm_eccentricity_x,self.cm_eccentricity_y) - rocket.add_cm_eccentricity(cm_ecc_x,cm_ecc_y) - cp_ecc_x, cp_ecc_y = self._create_eccentricities(self.cp_eccentricity_x,self.cp_eccentricity_y) - rocket.add_cp_eccentricity(cp_ecc_x,cp_ecc_y) - thrust_ecc_x, thrust_ecc_y = self._create_eccentricities(self.thrust_eccentricity_x,self.thrust_eccentricity_y) - rocket.add_thrust_eccentricity(thrust_ecc_x,thrust_ecc_y) + try: + cp_ecc_x, cp_ecc_y = self._create_eccentricities(self.cp_eccentricity_x,self.cp_eccentricity_y) + rocket.add_cp_eccentricity(cp_ecc_x,cp_ecc_y) + except: + pass + try: + thrust_ecc_x, thrust_ecc_y = self._create_eccentricities(self.thrust_eccentricity_x,self.thrust_eccentricity_y) + rocket.add_thrust_eccentricity(thrust_ecc_x,thrust_ecc_y) + except: + pass for component_motor in self.motors: motor, position_rnd = self._create_motor(component_motor) From 99ee4bd09eee8670ae78f8c1f5a6cd9b6b25508a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20Alca=C3=B1iz?= Date: Sat, 22 Mar 2025 19:19:51 +0100 Subject: [PATCH 10/12] BUG: fix MonteCarlo eccentricity inputs --- rocketpy/stochastic/stochastic_rocket.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/rocketpy/stochastic/stochastic_rocket.py b/rocketpy/stochastic/stochastic_rocket.py index ad8d83c91..c81a7fec8 100644 --- a/rocketpy/stochastic/stochastic_rocket.py +++ b/rocketpy/stochastic/stochastic_rocket.py @@ -673,9 +673,11 @@ def _create_parachute(self, stochastic_parachute): self.last_rnd_dict["parachutes"].append(stochastic_parachute.last_rnd_dict) return parachute - def _create_eccentricities(self, stochastic_x, stochastic_y): + def _create_eccentricities(self, stochastic_x, stochastic_y, eccentricity): x_rnd = self._randomize_position(stochastic_x) + self.last_rnd_dict[eccentricity + "_x"] = x_rnd y_rnd = self._randomize_position(stochastic_y) + self.last_rnd_dict[eccentricity + "_y"] = y_rnd return x_rnd, y_rnd def create_object(self): @@ -710,12 +712,20 @@ def create_object(self): rocket.power_on_drag *= generated_dict["power_on_drag_factor"] try: - cp_ecc_x, cp_ecc_y = self._create_eccentricities(self.cp_eccentricity_x,self.cp_eccentricity_y) + cp_ecc_x, cp_ecc_y = self._create_eccentricities( + self.cp_eccentricity_x, + self.cp_eccentricity_y, + "cp_eccentricity", + ) rocket.add_cp_eccentricity(cp_ecc_x,cp_ecc_y) except: pass try: - thrust_ecc_x, thrust_ecc_y = self._create_eccentricities(self.thrust_eccentricity_x,self.thrust_eccentricity_y) + thrust_ecc_x, thrust_ecc_y = self._create_eccentricities( + self.thrust_eccentricity_x, + self.thrust_eccentricity_y, + "thrust_eccentricity", + ) rocket.add_thrust_eccentricity(thrust_ecc_x,thrust_ecc_y) except: pass From 9db9076b31214f62b996b6fa666d4a28cc026e87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20Alca=C3=B1iz?= Date: Sat, 22 Mar 2025 19:37:51 +0100 Subject: [PATCH 11/12] ENH: pylint and ruff recommended changes --- rocketpy/stochastic/stochastic_rocket.py | 28 +++++++++++++----------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/rocketpy/stochastic/stochastic_rocket.py b/rocketpy/stochastic/stochastic_rocket.py index c81a7fec8..56a8a44d5 100644 --- a/rocketpy/stochastic/stochastic_rocket.py +++ b/rocketpy/stochastic/stochastic_rocket.py @@ -413,7 +413,7 @@ def add_cp_eccentricity(self, x=None, y=None): self.cp_eccentricity_x = self._validate_eccentricity("cp_eccentricity_x", x) self.cp_eccentricity_y = self._validate_eccentricity("cp_eccentricity_y", y) return self - + def add_thrust_eccentricity(self, x=None, y=None): """Moves line of action of thrust forces to simulate a misalignment of the thrust vector and the center of dry mass. @@ -436,10 +436,14 @@ def add_thrust_eccentricity(self, x=None, y=None): self : StochasticRocket Object of the StochasticRocket class. """ - self.thrust_eccentricity_x = self._validate_eccentricity("thrust_eccentricity_x", x) - self.thrust_eccentricity_y = self._validate_eccentricity("thrust_eccentricity_y", y) + self.thrust_eccentricity_x = self._validate_eccentricity( + "thrust_eccentricity_x", x + ) + self.thrust_eccentricity_y = self._validate_eccentricity( + "thrust_eccentricity_y", y + ) return self - + def _validate_eccentricity(self, eccentricity, position): """Validate the eccentricity argument. @@ -672,7 +676,7 @@ def _create_parachute(self, stochastic_parachute): parachute = stochastic_parachute.create_object() self.last_rnd_dict["parachutes"].append(stochastic_parachute.last_rnd_dict) return parachute - + def _create_eccentricities(self, stochastic_x, stochastic_y, eccentricity): x_rnd = self._randomize_position(stochastic_x) self.last_rnd_dict[eccentricity + "_x"] = x_rnd @@ -711,24 +715,22 @@ def create_object(self): rocket.power_off_drag *= generated_dict["power_off_drag_factor"] rocket.power_on_drag *= generated_dict["power_on_drag_factor"] - try: + if hasattr(self, "cp_eccentricity_x") and hasattr(self, "cp_eccentricity_y"): cp_ecc_x, cp_ecc_y = self._create_eccentricities( self.cp_eccentricity_x, self.cp_eccentricity_y, "cp_eccentricity", ) - rocket.add_cp_eccentricity(cp_ecc_x,cp_ecc_y) - except: - pass - try: + rocket.add_cp_eccentricity(cp_ecc_x, cp_ecc_y) + if hasattr(self, "thrust_eccentricity_x") and hasattr( + self, "thrust_eccentricity_y" + ): thrust_ecc_x, thrust_ecc_y = self._create_eccentricities( self.thrust_eccentricity_x, self.thrust_eccentricity_y, "thrust_eccentricity", ) - rocket.add_thrust_eccentricity(thrust_ecc_x,thrust_ecc_y) - except: - pass + rocket.add_thrust_eccentricity(thrust_ecc_x, thrust_ecc_y) for component_motor in self.motors: motor, position_rnd = self._create_motor(component_motor) From b028e00c81ccf9ae42749279d1f7e732b1adc9bd Mon Sep 17 00:00:00 2001 From: Gui-FernandesBR Date: Sun, 23 Mar 2025 16:27:07 -0300 Subject: [PATCH 12/12] TST: fix tests with eccentricity --- tests/unit/test_rocket.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/unit/test_rocket.py b/tests/unit/test_rocket.py index 47ea61eec..3c1e7168d 100644 --- a/tests/unit/test_rocket.py +++ b/tests/unit/test_rocket.py @@ -331,15 +331,15 @@ def test_add_cm_eccentricity_assert_properties_set(calisto): assert calisto.cp_eccentricity_x == -4 assert calisto.cp_eccentricity_y == -5 - assert calisto.thrust_eccentricity_y == -4 - assert calisto.thrust_eccentricity_x == -5 + assert calisto.thrust_eccentricity_x == -4 + assert calisto.thrust_eccentricity_y == -5 def test_add_thrust_eccentricity_assert_properties_set(calisto): calisto.add_thrust_eccentricity(x=4, y=5) - assert calisto.thrust_eccentricity_y == 4 - assert calisto.thrust_eccentricity_x == 5 + assert calisto.thrust_eccentricity_x == 4 + assert calisto.thrust_eccentricity_y == 5 def test_add_cp_eccentricity_assert_properties_set(calisto):