Skip to content

Commit 00c1349

Browse files
committed
MNT: address copilot review
1 parent 20937b9 commit 00c1349

4 files changed

Lines changed: 84 additions & 18 deletions

File tree

rocketpy/rocket/aero_surface/fins/fin.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -399,15 +399,20 @@ def _compute_leading_edge_position(self, position, _csys):
399399
# Rotate the point to the user-defined coordinate system
400400
p = Vector([p.x * _csys, p.y, p.z * _csys])
401401

402-
# Calculate the position of the fin leading edge in the user frame
403-
# as if no cant angle was applied
404-
position = Vector(
405-
[
406-
-self.rocket_radius * math.sin(self.angular_position_rad) * _csys,
407-
self.rocket_radius * math.cos(self.angular_position_rad),
408-
position,
409-
]
410-
)
402+
# Build the leading-edge position in the user frame as if no cant
403+
# angle was applied. Scalars are interpreted as z coordinates only,
404+
# while vectors/tuples/lists are interpreted as full (x, y, z)
405+
# coordinates.
406+
if isinstance(position, (Vector, tuple, list)):
407+
position = Vector(position)
408+
else:
409+
position = Vector(
410+
[
411+
-self.rocket_radius * math.sin(self.angular_position_rad) * _csys,
412+
self.rocket_radius * math.cos(self.angular_position_rad),
413+
position,
414+
]
415+
)
411416

412417
# Translate the position of the fin leading edge to the position of the
413418
# fin leading edge with cant angle

rocketpy/rocket/aero_surface/fins/trapezoidal_fin.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ def from_dict(cls, data):
230230
span=data["span"],
231231
rocket_radius=data["rocket_radius"],
232232
cant_angle=data["cant_angle"],
233+
sweep_length=data.get("sweep_length"),
233234
airfoil=data["airfoil"],
234235
name=data["name"],
235236
)

rocketpy/rocket/rocket.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,9 +1365,9 @@ def add_trapezoidal_fins(
13651365
"""
13661366
if n <= 2:
13671367
raise ValueError(
1368-
"Number of fins must be greater than 2."
1369-
"If you want to add 2 or 1 fins, create a TrapezoidalFin object "
1370-
" and add it to the rocket using the add_surfaces method."
1368+
"Number of fins must be greater than 2. "
1369+
"For 1 or 2 fins, create a FreeFormFin object "
1370+
"and add it to the rocket using the add_surfaces method."
13711371
)
13721372

13731373
# Modify radius if not given, use rocket radius, otherwise use given.
@@ -1457,9 +1457,9 @@ def add_elliptical_fins(
14571457
"""
14581458
if n <= 2:
14591459
raise ValueError(
1460-
"Number of fins must be greater than 2."
1461-
"If you want to add 2 or 1 fins, create a EllipticalFin object "
1462-
" and add it to the rocket using the add_surfaces method."
1460+
"Number of fins must be greater than 2. "
1461+
"For 1 or 2 fins, create a FreeFormFin object "
1462+
"and add it to the rocket using the add_surfaces method."
14631463
)
14641464

14651465
radius = radius if radius is not None else self.radius
@@ -1530,9 +1530,9 @@ def add_free_form_fins(
15301530
"""
15311531
if n <= 2:
15321532
raise ValueError(
1533-
"Number of fins must be greater than 2."
1534-
"If you want to add 2 or 1 fins, create a FreeFormFin object "
1535-
" and add it to the rocket using the add_surfaces method."
1533+
"Number of fins must be greater than 2. "
1534+
"For 1 or 2 fins, create a FreeFormFin object "
1535+
"and add it to the rocket using the add_surfaces method."
15361536
)
15371537

15381538
# Modify radius if not given, use rocket radius, otherwise use given.

tests/unit/rocket/aero_surface/test_individual_fins.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
TrapezoidalFin,
1313
TrapezoidalFins,
1414
)
15+
from rocketpy.mathutils.vector_matrix import Vector
1516

1617

1718
@pytest.mark.parametrize(
@@ -219,6 +220,28 @@ def test_individual_fin_from_dict_roundtrip(
219220
assert reconstructed.shape_points == fin.shape_points
220221

221222

223+
def test_trapezoidal_fin_from_dict_roundtrip_preserves_sweep_length():
224+
"""Ensure TrapezoidalFin round-trip preserves non-default sweep geometry."""
225+
# Arrange
226+
original = TrapezoidalFin(
227+
angular_position=0,
228+
root_chord=0.12,
229+
tip_chord=0.04,
230+
span=0.1,
231+
rocket_radius=0.0635,
232+
cant_angle=0,
233+
sweep_angle=15.0,
234+
name="roundtrip_trapezoidal_fin",
235+
)
236+
data = original.to_dict()
237+
238+
# Act
239+
reconstructed = TrapezoidalFin.from_dict(data)
240+
241+
# Assert
242+
assert reconstructed.sweep_length == pytest.approx(original.sweep_length)
243+
244+
222245
def test_calisto_finset_vs_four_individual_fins_close():
223246
"""Ensure a 4-fin set and 4 individual fins produce close aerodynamics.
224247
@@ -294,3 +317,40 @@ def test_calisto_finset_vs_four_individual_fins_close():
294317
# Assert
295318
np.testing.assert_allclose(cp_individual, cp_finset, rtol=1e-6, atol=1e-6)
296319
np.testing.assert_allclose(clalpha_individual_corrected, clalpha_finset)
320+
321+
322+
@pytest.mark.parametrize(
323+
"position_input",
324+
[
325+
(0.02, -0.01, -1.2),
326+
Vector([0.02, -0.01, -1.2]),
327+
],
328+
)
329+
def test_add_individual_fin_accepts_full_3d_position(position_input):
330+
"""Ensure individual fins accept full (x, y, z) position inputs."""
331+
# Arrange
332+
rocket = Rocket(
333+
radius=0.0635,
334+
mass=14.426,
335+
inertia=(6.321, 6.321, 0.034),
336+
power_off_drag="data/rockets/calisto/powerOffDragCurve.csv",
337+
power_on_drag="data/rockets/calisto/powerOnDragCurve.csv",
338+
center_of_mass_without_motor=0,
339+
coordinate_system_orientation="tail_to_nose",
340+
)
341+
fin = TrapezoidalFin(
342+
angular_position=30,
343+
root_chord=0.120,
344+
tip_chord=0.040,
345+
span=0.100,
346+
rocket_radius=0.0635,
347+
cant_angle=0,
348+
name="position_test_fin",
349+
)
350+
351+
# Act
352+
rocket.add_surfaces(fin, position_input)
353+
stored_position = rocket.aerodynamic_surfaces[0].position
354+
355+
# Assert
356+
assert stored_position == Vector([0.02, -0.01, -1.2])

0 commit comments

Comments
 (0)