From 2a1dffcca429b6181b18c6155ee0604cbc2798ee Mon Sep 17 00:00:00 2001 From: thc1006 <84045975+thc1006@users.noreply.github.com> Date: Tue, 25 Aug 2026 23:57:05 +0800 Subject: [PATCH 1/2] BUG: correct the nozzle gyration tensor parallel axis term The lateral components of the nozzle gyration tensor carried a quarter of the squared nozzle offset. The exit disk second moment per unit area gives the full square, and letting the exit radius go to zero has to leave diag(d^2, d^2, 0). Flight.u_dot already uses the full squared distance for the same quantity. The docstring said the tensor is in kg*m^2. Since T05 = mdot * S - I_dot has to be kg*m^2/s and mdot is kg/s, S is in m^2. Three recorded values in tests/unit/simulation/test_flight.py move past their tolerance and are updated. Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> --- rocketpy/rocket/rocket.py | 6 +++--- tests/unit/rocket/test_rocket.py | 32 ++++++++++++++++++++++++++-- tests/unit/simulation/test_flight.py | 6 +++--- 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/rocketpy/rocket/rocket.py b/rocketpy/rocket/rocket.py index 68c2d102e..602ad1543 100644 --- a/rocketpy/rocket/rocket.py +++ b/rocketpy/rocket/rocket.py @@ -1004,8 +1004,8 @@ def evaluate_nozzle_to_cdm(self): def evaluate_nozzle_gyration_tensor(self): """Calculates and returns the nozzle gyration tensor relative to the - rocket's center of dry mass. The gyration tensor is saved and returned - in units of kg*m². + rocket's center of dry mass. The gyration tensor is a second moment of + area per unit area, so it is saved and returned in units of m². Returns ------- @@ -1013,7 +1013,7 @@ def evaluate_nozzle_gyration_tensor(self): Matrix containing the nozzle gyration tensor. """ S_noz_33 = 0.5 * self.motor.nozzle_radius**2 - S_noz_11 = S_noz_22 = 0.5 * S_noz_33 + 0.25 * self.nozzle_to_cdm**2 + S_noz_11 = S_noz_22 = 0.5 * S_noz_33 + self.nozzle_to_cdm**2 S_noz_12, S_noz_13, S_noz_23 = 0, 0, 0 # Due to axis symmetry self.nozzle_gyration_tensor = Matrix( [ diff --git a/tests/unit/rocket/test_rocket.py b/tests/unit/rocket/test_rocket.py index 2682f5b90..d1914d688 100644 --- a/tests/unit/rocket/test_rocket.py +++ b/tests/unit/rocket/test_rocket.py @@ -515,9 +515,9 @@ def test_evaluate_nozzle_to_cdm(calisto): def test_evaluate_nozzle_gyration_tensor(calisto): expected_gyration_tensor = np.array( - [[0.3940207, 0, 0], [0, 0.3940207, 0], [0, 0, 0.0005445]] + [[1.5752660, 0, 0], [0, 1.5752660, 0], [0, 0, 0.0005445]] ) - atol = 1e-3 * 1e-2 * 1e-2 # Equivalent to 1g * 1cm^2 + atol = 1e-7 # equivalent to 0.1 mm^2 assert np.allclose( expected_gyration_tensor, np.array(calisto.nozzle_gyration_tensor), atol=atol ) @@ -526,6 +526,34 @@ def test_evaluate_nozzle_gyration_tensor(calisto): assert np.allclose(expected_gyration_tensor, np.array(res), atol=atol) +@pytest.mark.parametrize( + "rocket_fixture", + ["calisto", "calisto_liquid_modded", "calisto_hybrid_modded"], +) +def test_evaluate_nozzle_gyration_tensor_matches_the_exit_disk(rocket_fixture, request): + """The tensor is the exit disk second moment per unit area, about the CDM.""" + rocket = request.getfixturevalue(rocket_fixture) + radius = rocket.motor.nozzle_radius + offset = rocket.nozzle_to_cdm + + tensor = np.array(rocket.evaluate_nozzle_gyration_tensor()) + + lateral = radius**2 / 4 + offset**2 + assert tensor[0, 0] == pytest.approx(lateral, rel=1e-12) + assert tensor[1, 1] == pytest.approx(lateral, rel=1e-12) + assert tensor[2, 2] == pytest.approx(radius**2 / 2, rel=1e-12) + assert (tensor[0, 1], tensor[0, 2], tensor[1, 2]) == (0, 0, 0) + + +def test_evaluate_nozzle_gyration_tensor_parallel_axis_term(calisto): + """Taking the disk term out leaves the whole squared offset, not a fraction.""" + tensor = np.array(calisto.evaluate_nozzle_gyration_tensor()) + + parallel_axis = tensor[0, 0] - tensor[2, 2] / 2 + + assert parallel_axis == pytest.approx(calisto.nozzle_to_cdm**2, rel=1e-12) + + def test_evaluate_com_to_cdm_function(calisto): atol = 1e-3 # Equivalent to 1mm assert np.allclose( diff --git a/tests/unit/simulation/test_flight.py b/tests/unit/simulation/test_flight.py index a6ef31d80..3d35d1cdb 100644 --- a/tests/unit/simulation/test_flight.py +++ b/tests/unit/simulation/test_flight.py @@ -316,7 +316,7 @@ def test_export_sensor_data(flight_calisto_with_sensors): [ ("t_initial", (0.25886, -0.649623, 0)), ("out_of_rail_time", (0.792028, -1.987634, 0)), - ("apogee_time", (-0.509420, -0.732933, -2.089120e-14)), + ("apogee_time", (-0.519917, -0.734918, -1.005368e-18)), ("t_final", (0, 0, 0)), ], ) @@ -355,7 +355,7 @@ def test_aerodynamic_moments(flight_calisto_custom_wind, flight_time, expected_v [ ("t_initial", (1.654150, 0.659142, -0.067103)), ("out_of_rail_time", (5.052628, 2.013361, -1.75370)), - ("apogee_time", (2.321838, -1.613641, -0.962108)), + ("apogee_time", (2.322999, -1.643037, -0.950316)), ("t_final", (-0.019802, 0.012030, 159.051604)), ], ) @@ -396,7 +396,7 @@ def test_aerodynamic_forces(flight_calisto_custom_wind, flight_time, expected_va ("out_of_rail_time", (0, 2.248540, 25.700928)), ( "apogee_time", - (-14.826350, 15.670022, -0.000264), + (-14.593411, 15.743567, -0.000409), ), ("t_final", (5, 2, -5.660155)), ], From 2953fd43d805a1e0f64b13d7f36114d2e74c5a15 Mon Sep 17 00:00:00 2001 From: thc1006 <84045975+thc1006@users.noreply.github.com> Date: Wed, 26 Aug 2026 02:43:28 +0800 Subject: [PATCH 2/2] TST: re-record the Defiance impact drift guard The nozzle gyration tensor correction moves the Defiance example's impact point about 17 m over a 1626 m range, which is outside the band the guard allows for y and inside it by 0.1 m for x. These two constants are recorded from the deterministic example rather than measured, so they track the model. The measured quantity in the same file is the apogee, and the correction moves the simulation closer to it: 0.709 percent error before, 0.693 percent after. Signed-off-by: thc1006 <84045975+thc1006@users.noreply.github.com> --- tests/acceptance/test_defiance_rocket.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/acceptance/test_defiance_rocket.py b/tests/acceptance/test_defiance_rocket.py index 9ac574671..47d96359b 100644 --- a/tests/acceptance/test_defiance_rocket.py +++ b/tests/acceptance/test_defiance_rocket.py @@ -11,8 +11,8 @@ MAX_RELATIVE_APOGEE_ERROR = 0.01 REFERENCE_MAX_SPEED = 444.24 REFERENCE_MAX_ACCELERATION = 10400.76 -REFERENCE_IMPACT_X = 1625.55 -REFERENCE_IMPACT_Y = 81.78 +REFERENCE_IMPACT_X = 1609.40 +REFERENCE_IMPACT_Y = 87.03 REFERENCE_METRIC_RELATIVE_TOLERANCE = 0.01 REFERENCE_IMPACT_ABSOLUTE_TOLERANCE = 3.0