11from functools import cached_property
2-
32import numpy as np
4-
5- from typing import Callable
6-
3+ from typing import Callable
74from rocketpy .mathutils .function import Function , funcify_method
8- from .motor import Motor
5+ from .motor import Motor
96
10- class PointMassMotor (Motor ):
11- """Class representing a motor modeled as a point mass.
12-
13- Inherits from the Motor class and simplifies the model to a thrust-producing
14- object without detailed structural components. The total mass of the motor
15- will vary with propellant consumption, similar to a standard motor. However,
16- its inertia components and the center of propellant mass are considered zero
17- and fixed at the motor's reference point, respectively.
18- """
7+ class PointMassMotor (Motor ):
8+ """Motor modeled as a point mass for 3-DOF simulations."""
199
2010 def __init__ (
2111 self ,
2212 thrust_source ,
2313 dry_mass ,
2414 propellant_initial_mass ,
25- burn_time = None ,
26- propellant_final_mass = None ,
27- reshape_thrust_curve = False ,
28- interpolation_method = "linear" ,
15+ burn_time = None ,
16+ propellant_final_mass = None ,
17+ reshape_thrust_curve = False ,
18+ interpolation_method = "linear" ,
2919 ):
30- """Initialize the PointMassMotor class.
31-
32- This motor simplifies the physical model by considering its mass to be
33- concentrated at a single point, effectively setting all its inertia
34- components to zero. Propellant mass variation and exhaust velocity
35- are still simulated and derived from the thrust and propellant consumption
36- characteristics, similar to the base Motor class.
37-
38- Parameters
39- ----------
40- thrust_source : int, float, callable, str, numpy.ndarray, Function
41- Thrust source. Can be a constant value (int, float), a callable
42- function of time, a path to a CSV file, a NumPy array, or a
43- RocketPy `Function` object.
44- dry_mass : float
45- Total dry mass of the motor in kg.
46- propellant_initial_mass : float
47- Initial mass of the propellant in kg. This is a required parameter
48- as the point mass motor will still simulate propellant consumption.
49- burn_time : float, optional
50- Total burn time of the motor in seconds. Required if `thrust_source`
51- is a constant value or a callable function, and `propellant_final_mass`
52- is not provided. If `thrust_source` is a CSV, array, or Function,
53- the burn time is derived from it.
54- propellant_final_mass : float, optional
55- Final mass of the propellant in kg. Required if `thrust_source`
56- is a callable function and `burn_time` is not provided. If not
57- provided, it is calculated by the base Motor class.
58- reshape_thrust_curve : bool, optional
59- Whether to reshape the thrust curve to start at t=0 and end at
60- burn_time. Defaults to False.
61- interpolation_method : str, optional
62- Interpolation method for the thrust curve, if applicable.
63- Defaults to 'linear'.
64-
65- Raises
66- ------
67- ValueError
68- If insufficient data is provided for mass flow rate calculation.
69- TypeError
70- If an invalid type is provided for `thrust_source`.
71- """
7220 if isinstance (thrust_source , (int , float , Callable )):
7321 if propellant_initial_mass is None :
7422 raise ValueError (
@@ -79,14 +27,13 @@ def __init__(
7927 "For constant or callable thrust, either 'burn_time' or "
8028 "'propellant_final_mass' must be provided."
8129 )
82-
8330 elif isinstance (thrust_source , (Function , np .ndarray , str )):
8431 if propellant_initial_mass is None :
8532 raise ValueError (
8633 "For thrust from a Function, NumPy array, or CSV, 'propellant_initial_mass' is required."
8734 )
8835 else :
89- raise TypeError (
36+ raise TypeError (
9037 "Invalid 'thrust_source' type. Must be int, float, callable, str, numpy.ndarray, or Function."
9138 )
9239
@@ -95,172 +42,50 @@ def __init__(
9542
9643 super ().__init__ (
9744 thrust_source = thrust_source ,
98- dry_inertia = (0 , 0 , 0 ), # Inertia is zero for a point mass
99- nozzle_radius = 0 , # Nozzle radius is irrelevant for a point mass model
100- center_of_dry_mass_position = 0 , # Pass 0 directly to the superclass
45+ dry_inertia = (0 , 0 , 0 ),
46+ nozzle_radius = 0 ,
47+ center_of_dry_mass_position = 0 ,
10148 dry_mass = dry_mass ,
102- nozzle_position = 0 , # Nozzle is at the motor's origin
49+ nozzle_position = 0 ,
10350 burn_time = burn_time ,
104- reshape_thrust_curve = reshape_thrust_curve ,
51+ reshape_thrust_curve = reshape_thrust_curve ,
10552 interpolation_method = interpolation_method ,
106- coordinate_system_orientation = "nozzle_to_combustion_chamber" , # Standard orientation
53+ coordinate_system_orientation = "nozzle_to_combustion_chamber" ,
10754 )
10855
109- # Removed the thrust method. It will now be inherited directly from the Motor base class,
110- # which already correctly handles the conversion of thrust_source to a Function
111- # and exposes it as a cached property.
112-
113- # Removed the total_mass override. The base Motor class's total_mass property
114- # will now correctly calculate dry_mass + propellant_mass(t), which is the desired
115- # varying mass behavior for the point mass motor.
116-
117- # Removed the center_of_dry_mass_position override. It is now passed directly
118- # to the super().__init__ as 0.
11956 @property
12057 def propellant_initial_mass (self ):
121- """Returns the initial propellant mass for a point mass motor.
122-
123- This property retrieves the value set during initialization. This implementation
124- is required as 'propellant_initial_mass' is an abstract method in the parent Motor class.
125-
126- Returns
127- -------
128- float
129- Propellant initial mass in kg.
130- """
13158 return self ._propellant_initial_mass
132-
59+
13360 @funcify_method ("Time (s)" , "Exhaust velocity (m/s)" )
13461 def exhaust_velocity (self ):
135- """Exhaust velocity by assuming it as a constant. The formula used is
136- total impulse/propellant initial mass.
137-
138- Returns
139- -------
140- self.exhaust_velocity : Function
141- Gas exhaust velocity of the motor.
62+ """Assume constant exhaust velocity: total impulse / propellant mass"""
63+ v_e = self .total_impulse / self .propellant_initial_mass
64+ return Function (v_e ).set_discrete_based_on_model (self .thrust )
14265
143- Notes
144- -----
145- This corresponds to the actual exhaust velocity only when the nozzle
146- exit pressure equals the atmospheric pressure.
147- """
148- return Function (
149- self .total_impulse / self .propellant_initial_mass
150- ).set_discrete_based_on_model (self .thrust )
151-
15266 @cached_property
153- @funcify_method ("Time (s)" , "Mass flow rate (kg/s)" , extrapolation = "zero" )
15467 def total_mass_flow_rate (self ) -> Function :
155- """Time derivative of the propellant mass as a function of time.
156-
157- It calculates mass flow rate as the negative of thrust divided by exhaust velocity,
158- consistent with the fundamental rocket equation.
159-
160- Returns
161- -------
162- Function
163- Time derivative of total propellant mass a function of time.
164- """
165-
166- exhaust_vel_func = self .exhaust_velocity
167- return - self .thrust / exhaust_vel_func
68+ """Mass flow rate: -thrust / exhaust_velocity"""
69+ return - self .thrust / self .exhaust_velocity
16870
16971 @cached_property
170- @funcify_method ("Time (s)" , "Propellant Mass (kg)" )
17172 def center_of_propellant_mass (self ):
172- """Returns the position of the center of mass of the propellant.
173-
174- For a point mass motor, the propellant's center of mass is considered
175- to be at the origin (0) of the motor's coordinate system.
73+ """Center of propellant mass is always zero"""
74+ return Function (0.0 )
17675
177- Returns
178- -------
179- Function
180- A Function object representing the center of propellant mass (always 0).
181- """
182- return 0
76+ # Propellant inertias: always zero, but return as Function objects
77+ def _zero_inertia_func (self ):
78+ return Function (0.0 )
18379
18480 @cached_property
185- @funcify_method ("Time (s)" , "Inertia (kg·m²)" )
186- def propellant_I_11 (self ):
187- """Returns the propellant moment of inertia around the x-axis.
188-
189- For a point mass motor, this is always zero.
190-
191- Returns
192- -------
193- Function
194- A Function object representing zero propellant inertia.
195- """
196- return 0
197-
81+ def propellant_I_11 (self ): return self ._zero_inertia_func ()
19882 @cached_property
199- @funcify_method ("Time (s)" , "Inertia (kg·m²)" )
200- def propellant_I_12 (self ):
201- """Returns the propellant product of inertia I_xy.
202-
203- For a point mass motor, this is always zero.
204-
205- Returns
206- -------
207- Function
208- A Function object representing zero propellant inertia.
209- """
210- return 0
211-
83+ def propellant_I_12 (self ): return self ._zero_inertia_func ()
21284 @cached_property
213- @funcify_method ("Time (s)" , "Inertia (kg·m²)" )
214- def propellant_I_13 (self ):
215- """Returns the propellant product of inertia I_xz.
216-
217- For a point mass motor, this is always zero.
218-
219- Returns
220- -------
221- Function
222- A Function object representing zero propellant inertia.
223- """
224- return 0
225-
85+ def propellant_I_13 (self ): return self ._zero_inertia_func ()
22686 @cached_property
227- @funcify_method ("Time (s)" , "Inertia (kg·m²)" )
228- def propellant_I_22 (self ):
229- """Returns the propellant moment of inertia around the y-axis.
230-
231- For a point mass motor, this is always zero.
232-
233- Returns
234- -------
235- Function
236- A Function object representing zero propellant inertia.
237- """
238- return 0
239-
87+ def propellant_I_22 (self ): return self ._zero_inertia_func ()
24088 @cached_property
241- @funcify_method ("Time (s)" , "Inertia (kg·m²)" )
242- def propellant_I_23 (self ):
243- """Returns the propellant product of inertia I_yz.
244-
245- For a point mass motor, this is always zero.
246-
247- Returns
248- -------
249- Function
250- A Function object representing zero propellant inertia.
251- """
252- return 0
253-
89+ def propellant_I_23 (self ): return self ._zero_inertia_func ()
25490 @cached_property
255- @funcify_method ("Time (s)" , "Inertia (kg·m²)" )
256- def propellant_I_33 (self ):
257- """Returns the propellant moment of inertia around the z-axis.
258-
259- For a point mass motor, this is always zero.
260-
261- Returns
262- -------
263- Function
264- A Function object representing zero propellant inertia.
265- """
266- return 0
91+ def propellant_I_33 (self ): return self ._zero_inertia_func ()
0 commit comments