|
5 | 5 | import numpy as np |
6 | 6 | import pytest |
7 | 7 |
|
8 | | -from rocketpy import Function, NoseCone, Rocket, SolidMotor |
| 8 | +from rocketpy import Function, GenericSurface, NoseCone, Rocket, SolidMotor |
| 9 | +from rocketpy.exceptions import ( |
| 10 | + InvalidInertiaError, |
| 11 | + InvalidParameterError, |
| 12 | + UnstableRocketWarning, |
| 13 | +) |
9 | 14 | from rocketpy.mathutils.vector_matrix import Vector |
10 | 15 | from rocketpy.motors.empty_motor import EmptyMotor |
11 | 16 | from rocketpy.motors.motor import Motor |
@@ -835,3 +840,85 @@ def test_drag_input_types_supported_for_power_on_and_power_off(tmp_path): |
835 | 840 |
|
836 | 841 | assert rocket.power_off_drag_7d(*query_point) == pytest.approx(expected) |
837 | 842 | assert rocket.power_on_drag_7d(*query_point) == pytest.approx(expected) |
| 843 | + |
| 844 | + |
| 845 | +@pytest.mark.parametrize("radius", [-1, 0, -0.001]) |
| 846 | +def test_rocket_invalid_radius_raises(radius): |
| 847 | + """InvalidParameterError must be raised for non-positive radius values.""" |
| 848 | + with pytest.raises(InvalidParameterError, match="radius"): |
| 849 | + Rocket( |
| 850 | + radius=radius, |
| 851 | + mass=10, |
| 852 | + inertia=(0.1, 0.1, 0.01), |
| 853 | + power_off_drag=0.3, |
| 854 | + power_on_drag=0.3, |
| 855 | + center_of_mass_without_motor=0, |
| 856 | + ) |
| 857 | + |
| 858 | + |
| 859 | +@pytest.mark.parametrize("mass", [-1, 0, -0.001]) |
| 860 | +def test_rocket_invalid_mass_raises(mass): |
| 861 | + """InvalidParameterError must be raised for non-positive mass values.""" |
| 862 | + with pytest.raises(InvalidParameterError, match="mass"): |
| 863 | + Rocket( |
| 864 | + radius=0.05, |
| 865 | + mass=mass, |
| 866 | + inertia=(0.1, 0.1, 0.01), |
| 867 | + power_off_drag=0.3, |
| 868 | + power_on_drag=0.3, |
| 869 | + center_of_mass_without_motor=0, |
| 870 | + ) |
| 871 | + |
| 872 | + |
| 873 | +@pytest.mark.parametrize("inertia", [(0.1,), (0.1, 0.1), (0.1, 0.1, 0.01, 0.0, 0.0)]) |
| 874 | +def test_rocket_invalid_inertia_length_raises(inertia): |
| 875 | + """InvalidInertiaError must be raised when inertia tuple has wrong length.""" |
| 876 | + with pytest.raises(InvalidInertiaError): |
| 877 | + Rocket( |
| 878 | + radius=0.05, |
| 879 | + mass=10, |
| 880 | + inertia=inertia, |
| 881 | + power_off_drag=0.3, |
| 882 | + power_on_drag=0.3, |
| 883 | + center_of_mass_without_motor=0, |
| 884 | + ) |
| 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