Skip to content

Commit 7074040

Browse files
MNT: fix lint formatting and skip UnstableRocketWarning for GenericSurface
black/ruff reformat the multi-name exception imports in rocketpy/__init__.py and rocketpy/rocket/rocket.py. evaluate_center_of_pressure ignores GenericSurface lift coefficients, so the computed static margin does not reflect rockets that rely on them. Skip the UnstableRocketWarning in that case to avoid false positives, echoing the concern raised in the review of #764 that blocked a similar check.
1 parent a03e17d commit 7074040

4 files changed

Lines changed: 83 additions & 16 deletions

File tree

rocketpy/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
from .control import _Controller
22
from .environment import Environment, EnvironmentAnalysis
3-
from .exceptions import InvalidInertiaError, InvalidParameterError, UnstableRocketWarning
3+
from .exceptions import (
4+
InvalidInertiaError,
5+
InvalidParameterError,
6+
UnstableRocketWarning,
7+
)
48
from .mathutils import (
59
Function,
610
PiecewiseFunction,

rocketpy/exceptions.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,10 @@ class InvalidInertiaError(RocketPyError, ValueError):
1616

1717
class UnstableRocketWarning(UserWarning):
1818
"""Issued when the rocket's static margin is negative at motor ignition,
19-
indicating an aerodynamically unstable configuration."""
19+
indicating an aerodynamically unstable configuration.
20+
21+
Not issued when the rocket has any ``GenericSurface`` aerodynamic
22+
surfaces, since their lift coefficient derivative is not accounted for
23+
in the center of pressure calculation, making the static margin
24+
unreliable for this check in that case.
25+
"""

rocketpy/rocket/rocket.py

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@
2323
)
2424
from rocketpy.rocket.aero_surface.fins.free_form_fins import FreeFormFins
2525
from rocketpy.rocket.aero_surface.generic_surface import GenericSurface
26-
from rocketpy.exceptions import InvalidInertiaError, InvalidParameterError, UnstableRocketWarning
26+
from rocketpy.exceptions import (
27+
InvalidInertiaError,
28+
InvalidParameterError,
29+
UnstableRocketWarning,
30+
)
2731
from rocketpy.rocket.components import Components
2832
from rocketpy.rocket.parachute import Parachute
2933
from rocketpy.tools import (
@@ -742,17 +746,26 @@ def evaluate_static_margin(self):
742746
self.static_margin.set_discrete(
743747
lower=0, upper=self.motor.burn_out_time, samples=200
744748
)
745-
# Warn the user if the rocket is aerodynamically unstable at ignition
746-
initial_static_margin = self.static_margin.get_value_opt(0)
747-
if initial_static_margin < 0:
748-
warnings.warn(
749-
f"The rocket has a negative static margin ({initial_static_margin:.2f} cal) "
750-
"at motor ignition (t=0), indicating an aerodynamically unstable "
751-
"configuration. Check the placement of fins and nose cone relative "
752-
"to the center of mass.",
753-
UnstableRocketWarning,
754-
stacklevel=2,
755-
)
749+
# Warn the user if the rocket is aerodynamically unstable at ignition.
750+
# Skipped when GenericSurface instances are present: their lift
751+
# coefficient derivative is not accounted for in
752+
# evaluate_center_of_pressure, so the computed static margin does not
753+
# reflect their contribution and cannot be trusted for this check.
754+
has_generic_surface = any(
755+
isinstance(aero_surface, GenericSurface)
756+
for aero_surface, _position in self.aerodynamic_surfaces
757+
)
758+
if not has_generic_surface:
759+
initial_static_margin = self.static_margin.get_value_opt(0)
760+
if initial_static_margin < 0:
761+
warnings.warn(
762+
f"The rocket has a negative static margin ({initial_static_margin:.2f} cal) "
763+
"at motor ignition (t=0), indicating an aerodynamically unstable "
764+
"configuration. Check the placement of fins and nose cone relative "
765+
"to the center of mass.",
766+
UnstableRocketWarning,
767+
stacklevel=2,
768+
)
756769
return self.static_margin
757770

758771
def evaluate_dry_inertias(self):

tests/unit/rocket/test_rocket.py

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@
55
import numpy as np
66
import pytest
77

8-
from rocketpy import Function, NoseCone, Rocket, SolidMotor
9-
from rocketpy.exceptions import InvalidInertiaError, InvalidParameterError
8+
from rocketpy import Function, GenericSurface, NoseCone, Rocket, SolidMotor
9+
from rocketpy.exceptions import (
10+
InvalidInertiaError,
11+
InvalidParameterError,
12+
UnstableRocketWarning,
13+
)
1014
from rocketpy.mathutils.vector_matrix import Vector
1115
from rocketpy.motors.empty_motor import EmptyMotor
1216
from rocketpy.motors.motor import Motor
@@ -878,3 +882,43 @@ def test_rocket_invalid_inertia_length_raises(inertia):
878882
power_on_drag=0.3,
879883
center_of_mass_without_motor=0,
880884
)
885+
886+
887+
def test_unstable_rocket_warning_raised(calisto):
888+
"""UnstableRocketWarning must be raised when the static margin at motor
889+
ignition is negative."""
890+
nose = NoseCone(
891+
length=0.55829,
892+
kind="vonkarman",
893+
base_radius=0.0635,
894+
rocket_radius=0.0635,
895+
name="Nose Cone",
896+
)
897+
with pytest.warns(UnstableRocketWarning):
898+
calisto.add_surfaces(nose, 1.16)
899+
assert calisto.static_margin(0) < 0
900+
901+
902+
def test_unstable_rocket_warning_skipped_with_generic_surface(calisto):
903+
"""UnstableRocketWarning must not be raised when the rocket has a
904+
GenericSurface, since its lift coefficient derivative is not accounted
905+
for in the center of pressure calculation, making the static margin
906+
unreliable for this check."""
907+
nose = NoseCone(
908+
length=0.55829,
909+
kind="vonkarman",
910+
base_radius=0.0635,
911+
rocket_radius=0.0635,
912+
name="Nose Cone",
913+
)
914+
generic_surface = GenericSurface(
915+
reference_area=None,
916+
reference_length=None,
917+
coefficients={
918+
"cL": lambda alpha, beta, mach, reynolds, pitch_rate, yaw_rate, roll_rate: 1
919+
},
920+
)
921+
with warnings.catch_warnings():
922+
warnings.simplefilter("error", UnstableRocketWarning)
923+
calisto.add_surfaces([nose, generic_surface], [1.16, 0])
924+
assert calisto.static_margin(0) < 0

0 commit comments

Comments
 (0)