Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Attention: The newest changes should be on top -->
- ENH: ENH: Auto-Detection of Pressure Conversion Factor [#966](https://github.com/RocketPy-Team/RocketPy/pull/966)
- ENH: Auto-Detection of Pressure Conversion Factor [#966](https://github.com/RocketPy-Team/RocketPy/pull/966)
- DOC: Add aerodynamic surfaces user guide [#1043](https://github.com/RocketPy-Team/RocketPy/pull/1043)
- ENH: Add RingClusterMotor for annular clustered motor modeling [#924](https://github.com/RocketPy-Team/RocketPy/pull/924)
- ENH: MNT: introduce pressure unit conversion when using forecast/reanalysis/ensemble data [#955](https://github.com/RocketPy-Team/RocketPy/pull/955)
- ENH: Auto Populate Changelog [#919](https://github.com/RocketPy-Team/RocketPy/pull/919)
- ENH: Adaptive Monte Carlo via Convergence Criteria [#922](https://github.com/RocketPy-Team/RocketPy/pull/922)
Expand Down
5 changes: 5 additions & 0 deletions docs/reference/classes/motors/RingClusterMotor.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
RingClusterMotor Class
----------------------

.. autoclass:: rocketpy.RingClusterMotor
:members:
1 change: 1 addition & 0 deletions docs/reference/classes/motors/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Motor Classes
HybridMotor
LiquidMotor
GenericMotor
RingClusterMotor
Fluid
Tank Classes <tanks/index>
Tank Geometry Classes <geometries/index>
Expand Down
6 changes: 6 additions & 0 deletions docs/user/motors/motors.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ Motors Usage

Generic Motor Usage <genericmotor.rst>

.. toctree::
:maxdepth: 3
:caption: Ring Cluster Motors

Ring Cluster Motor Usage <ringclustermotor.rst>

.. toctree::
:maxdepth: 3
:caption: Tanks and Fluid
Expand Down
93 changes: 93 additions & 0 deletions docs/user/motors/ringclustermotor.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
.. _ringclustermotor:

RingClusterMotor Class Usage
============================

Here we explore different features of the ``RingClusterMotor`` class.

``RingClusterMotor`` models a ring (annular) configuration of ``N`` identical
motors arranged symmetrically around a circular perimeter of a given radius,
with no central motor along the rocket's longitudinal axis. It is a thin
wrapper around a single, already-defined motor: all thrust-, mass- and
inertia-related quantities are derived automatically from that base motor,
its ``number`` of copies and their ``radius`` from the rocket's central axis.

Key Assumptions
---------------

- ``number`` must be an integer ``>= 2``;
- ``radius`` must be non-negative;
- The base motor is currently expected to be a ``SolidMotor``, since
``RingClusterMotor`` reuses its grain properties directly;
- Motors are assumed identical and evenly spaced around the ring
(``360 / number`` degrees apart);
- The transverse inertia (``I11``/``I22``) contribution of each motor is
computed explicitly via the parallel axis (Steiner) theorem for every
angular position, which keeps the result accurate even for the
asymmetric ``number=2`` case.

Creating a Ring Cluster Motor
------------------------------

To define a ``RingClusterMotor``, we first need a fully defined base motor
(typically a ``SolidMotor``), then wrap it with the number of motors in the
cluster and their radial distance from the rocket's central axis:

.. jupyter-execute::

from rocketpy import SolidMotor, RingClusterMotor

base_motor = SolidMotor(
thrust_source="../data/motors/cesaroni/Cesaroni_M1670.eng",
dry_mass=1.815,
dry_inertia=(0.125, 0.125, 0.002),
nozzle_radius=33 / 1000,
grain_number=5,
grain_density=1815,
grain_outer_radius=33 / 1000,
grain_initial_inner_radius=15 / 1000,
grain_initial_height=120 / 1000,
grain_separation=5 / 1000,
grains_center_of_mass_position=0.397,
center_of_dry_mass_position=0.317,
nozzle_position=0,
burn_time=3.9,
throat_radius=11 / 1000,
coordinate_system_orientation="nozzle_to_combustion_chamber",
)

cluster_motor = RingClusterMotor(
motor=base_motor,
number=4,
radius=0.1,
)

# Print the cluster (and underlying single-motor) information
cluster_motor.info()

.. note::

``RingClusterMotor`` does not read a thrust curve file directly. Instead,
it scales the ``thrust``, ``dry_mass``, ``propellant_mass`` and inertia
properties of the ``motor`` passed in by ``number``, so any changes to
``base_motor`` must be made before it is wrapped.

Since a ``RingClusterMotor`` is a ``Motor`` like any other, it can be attached
to a ``Rocket`` with :meth:`Rocket.add_motor` exactly like a ``SolidMotor``,
``HybridMotor`` or ``LiquidMotor`` would be.

Visualizing the Cluster Layout
-------------------------------

The ``draw_cluster_layout`` method plots the position of each motor around
the ring, which is useful to double-check the ``number`` and ``radius``
parameters before running a simulation:

.. jupyter-execute::

cluster_motor.draw_cluster_layout(rocket_radius=0.15)

.. tip::

Passing ``rocket_radius`` draws the rocket's outer tube as a dashed
circle, which helps confirm that the motors fit inside the airframe.
1 change: 1 addition & 0 deletions rocketpy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
MassFlowRateBasedTank,
Motor,
PointMassMotor,
RingClusterMotor,
SolidMotor,
SphericalTank,
Tank,
Expand Down
1 change: 1 addition & 0 deletions rocketpy/motors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from .liquid_motor import LiquidMotor
from .motor import GenericMotor, Motor
from .point_mass_motor import PointMassMotor
from .ring_cluster_motor import RingClusterMotor
from .solid_motor import SolidMotor
from .tank import (
LevelBasedTank,
Expand Down
Loading
Loading