Skip to content

Commit f18f2e5

Browse files
ayoubdspCopilotGui-FernandesBRCopilot
authored
Feature/cluster motor structure (#924)
* feat: implement cluster_motor class with dynamic inertias * feat: implement cluster_motor class with dynamic inertias * fix: scale thrust source before Motor init Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * refactor: apply remaining Copilot review suggestions * style: run black formatter and fix pylint warnings * test: add coverage for validation, setters, and display methods * refactor: resolve pylint too-many-statements and number of parameters * feat(plots): add visual rendering and layout support for ClusterMotor * fix: add missing numpy import for environment integration tests (that appeared through th merge * style: reformat code with ruff * style: fix pylint callables * refactor: rename to RingClusterMotor and compute exact geometric inertia for N=2 * fix: remove duplicate imports in rocket_plots.py caused by previous merge * DOC: update changelog for RingClusterMotor Add unreleased changelog entry for PR #924 (RingClusterMotor annular cluster feature). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * MNT: fix rocket plots imports after rebase Restore required aero surface and motor imports in rocket plots and fix Fin type dispatch to keep cluster motor plotting code valid after rebase. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * MNT: export RingClusterMotor publicly and fix formatting RingClusterMotor was not exported from rocketpy.motors or rocketpy, making it unreachable except via its internal module path. Also switches its Function/Motor imports to relative imports (matching sibling motor modules), which removes a pylint-flagged circular import introduced by the new export, and applies a missed ruff-format fix in test_ring_cluster_motor.py. * DOC: add RingClusterMotor user guide and API reference Adds a user-guide page (docs/user/motors/ringclustermotor.rst) with a worked example and layout visualization, plus an API reference page, wiring both into their respective toctrees alongside the other motor classes. --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Gui-FernandesBR <guilherme_fernandes@usp.br> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent b86bf8f commit f18f2e5

11 files changed

Lines changed: 582 additions & 32 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ Attention: The newest changes should be on top -->
4444
- ENH: ENH: Auto-Detection of Pressure Conversion Factor [#966](https://github.com/RocketPy-Team/RocketPy/pull/966)
4545
- ENH: Auto-Detection of Pressure Conversion Factor [#966](https://github.com/RocketPy-Team/RocketPy/pull/966)
4646
- DOC: Add aerodynamic surfaces user guide [#1043](https://github.com/RocketPy-Team/RocketPy/pull/1043)
47+
- ENH: Add RingClusterMotor for annular clustered motor modeling [#924](https://github.com/RocketPy-Team/RocketPy/pull/924)
4748
- ENH: MNT: introduce pressure unit conversion when using forecast/reanalysis/ensemble data [#955](https://github.com/RocketPy-Team/RocketPy/pull/955)
4849
- ENH: Auto Populate Changelog [#919](https://github.com/RocketPy-Team/RocketPy/pull/919)
4950
- ENH: Adaptive Monte Carlo via Convergence Criteria [#922](https://github.com/RocketPy-Team/RocketPy/pull/922)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
RingClusterMotor Class
2+
----------------------
3+
4+
.. autoclass:: rocketpy.RingClusterMotor
5+
:members:

docs/reference/classes/motors/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Motor Classes
1010
HybridMotor
1111
LiquidMotor
1212
GenericMotor
13+
RingClusterMotor
1314
Fluid
1415
Tank Classes <tanks/index>
1516
Tank Geometry Classes <geometries/index>

docs/user/motors/motors.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ Motors Usage
3333

3434
Generic Motor Usage <genericmotor.rst>
3535

36+
.. toctree::
37+
:maxdepth: 3
38+
:caption: Ring Cluster Motors
39+
40+
Ring Cluster Motor Usage <ringclustermotor.rst>
41+
3642
.. toctree::
3743
:maxdepth: 3
3844
:caption: Tanks and Fluid
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
.. _ringclustermotor:
2+
3+
RingClusterMotor Class Usage
4+
============================
5+
6+
Here we explore different features of the ``RingClusterMotor`` class.
7+
8+
``RingClusterMotor`` models a ring (annular) configuration of ``N`` identical
9+
motors arranged symmetrically around a circular perimeter of a given radius,
10+
with no central motor along the rocket's longitudinal axis. It is a thin
11+
wrapper around a single, already-defined motor: all thrust-, mass- and
12+
inertia-related quantities are derived automatically from that base motor,
13+
its ``number`` of copies and their ``radius`` from the rocket's central axis.
14+
15+
Key Assumptions
16+
---------------
17+
18+
- ``number`` must be an integer ``>= 2``;
19+
- ``radius`` must be non-negative;
20+
- The base motor is currently expected to be a ``SolidMotor``, since
21+
``RingClusterMotor`` reuses its grain properties directly;
22+
- Motors are assumed identical and evenly spaced around the ring
23+
(``360 / number`` degrees apart);
24+
- The transverse inertia (``I11``/``I22``) contribution of each motor is
25+
computed explicitly via the parallel axis (Steiner) theorem for every
26+
angular position, which keeps the result accurate even for the
27+
asymmetric ``number=2`` case.
28+
29+
Creating a Ring Cluster Motor
30+
------------------------------
31+
32+
To define a ``RingClusterMotor``, we first need a fully defined base motor
33+
(typically a ``SolidMotor``), then wrap it with the number of motors in the
34+
cluster and their radial distance from the rocket's central axis:
35+
36+
.. jupyter-execute::
37+
38+
from rocketpy import SolidMotor, RingClusterMotor
39+
40+
base_motor = SolidMotor(
41+
thrust_source="../data/motors/cesaroni/Cesaroni_M1670.eng",
42+
dry_mass=1.815,
43+
dry_inertia=(0.125, 0.125, 0.002),
44+
nozzle_radius=33 / 1000,
45+
grain_number=5,
46+
grain_density=1815,
47+
grain_outer_radius=33 / 1000,
48+
grain_initial_inner_radius=15 / 1000,
49+
grain_initial_height=120 / 1000,
50+
grain_separation=5 / 1000,
51+
grains_center_of_mass_position=0.397,
52+
center_of_dry_mass_position=0.317,
53+
nozzle_position=0,
54+
burn_time=3.9,
55+
throat_radius=11 / 1000,
56+
coordinate_system_orientation="nozzle_to_combustion_chamber",
57+
)
58+
59+
cluster_motor = RingClusterMotor(
60+
motor=base_motor,
61+
number=4,
62+
radius=0.1,
63+
)
64+
65+
# Print the cluster (and underlying single-motor) information
66+
cluster_motor.info()
67+
68+
.. note::
69+
70+
``RingClusterMotor`` does not read a thrust curve file directly. Instead,
71+
it scales the ``thrust``, ``dry_mass``, ``propellant_mass`` and inertia
72+
properties of the ``motor`` passed in by ``number``, so any changes to
73+
``base_motor`` must be made before it is wrapped.
74+
75+
Since a ``RingClusterMotor`` is a ``Motor`` like any other, it can be attached
76+
to a ``Rocket`` with :meth:`Rocket.add_motor` exactly like a ``SolidMotor``,
77+
``HybridMotor`` or ``LiquidMotor`` would be.
78+
79+
Visualizing the Cluster Layout
80+
-------------------------------
81+
82+
The ``draw_cluster_layout`` method plots the position of each motor around
83+
the ring, which is useful to double-check the ``number`` and ``radius``
84+
parameters before running a simulation:
85+
86+
.. jupyter-execute::
87+
88+
cluster_motor.draw_cluster_layout(rocket_radius=0.15)
89+
90+
.. tip::
91+
92+
Passing ``rocket_radius`` draws the rocket's outer tube as a dashed
93+
circle, which helps confirm that the motors fit inside the airframe.

rocketpy/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
MassFlowRateBasedTank,
2424
Motor,
2525
PointMassMotor,
26+
RingClusterMotor,
2627
SolidMotor,
2728
SphericalTank,
2829
Tank,

rocketpy/motors/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from .liquid_motor import LiquidMotor
55
from .motor import GenericMotor, Motor
66
from .point_mass_motor import PointMassMotor
7+
from .ring_cluster_motor import RingClusterMotor
78
from .solid_motor import SolidMotor
89
from .tank import (
910
LevelBasedTank,

0 commit comments

Comments
 (0)