Skip to content

Commit b852bd8

Browse files
DOCS: Update file paths in flight_comparator example and improve formatting in simulation files
1 parent eaa9181 commit b852bd8

File tree

6 files changed

+174
-158
lines changed

6 files changed

+174
-158
lines changed

docs/user/flight_comparator.rst

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ First, let's create the standard RocketPy simulation that will serve as our
7474
radius=127 / 2000,
7575
mass=19.197 - 2.956,
7676
inertia=(6.321, 6.321, 0.034),
77-
power_off_drag="../data/calisto/powerOffDragCurve.csv",
78-
power_on_drag="../data/calisto/powerOnDragCurve.csv",
77+
power_off_drag="../data/rockets/calisto/powerOffDragCurve.csv",
78+
power_on_drag="../data/rockets/calisto/powerOnDragCurve.csv",
7979
center_of_mass_without_motor=0,
8080
coordinate_system_orientation="tail_to_nose",
8181
)
@@ -101,17 +101,17 @@ First, let's create the standard RocketPy simulation that will serve as our
101101
position=-1.194656,
102102
)
103103

104-
# 4. Simulate
105-
flight = Flight(
106-
rocket=calisto,
107-
environment=env,
108-
rail_length=5.2,
109-
inclination=85,
110-
heading=0,
111-
)
104+
# 4. Simulate
105+
flight = Flight(
106+
rocket=calisto,
107+
environment=env,
108+
rail_length=5.2,
109+
inclination=85,
110+
heading=0,
111+
)
112112

113-
# 5. Create FlightComparator instance
114-
comparator = FlightComparator(flight)
113+
# 5. Create FlightComparator instance
114+
comparator = FlightComparator(flight)
115115

116116
Adding Another Flight Object
117117
----------------------------
@@ -156,7 +156,7 @@ simulation:
156156

157157
# Add the external data to our comparator
158158
comparator.add_data(
159-
"External Simulator",
159+
"External Simulator",
160160
{
161161
"altitude": (time_external, external_altitude),
162162
"vz": (time_external, external_velocity),

rocketpy/plots/motor_plots.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import matplotlib.pyplot as plt
22
import numpy as np
3-
from matplotlib.patches import Polygon
43
from matplotlib.animation import FuncAnimation
4+
from matplotlib.patches import Polygon
55

6-
from ..plots.plot_helpers import show_or_save_plot, show_or_save_animation
6+
from ..plots.plot_helpers import show_or_save_animation, show_or_save_plot
77

88

99
class _MotorPlots:

rocketpy/plots/tank_plots.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import matplotlib.pyplot as plt
22
import numpy as np
3-
from matplotlib.patches import Polygon
43
from matplotlib.animation import FuncAnimation
4+
from matplotlib.patches import Polygon
55

66
from rocketpy.mathutils.function import Function
77

8-
from .plot_helpers import show_or_save_plot, show_or_save_animation
8+
from .plot_helpers import show_or_save_animation, show_or_save_plot
99

1010

1111
class _TankPlots:

rocketpy/simulation/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
from .flight import Flight
2+
from .flight_comparator import FlightComparator
23
from .flight_data_exporter import FlightDataExporter
34
from .flight_data_importer import FlightDataImporter
45
from .monte_carlo import MonteCarlo
56
from .multivariate_rejection_sampler import MultivariateRejectionSampler
7+
8+
__all__ = [
9+
"Flight",
10+
"FlightDataExporter",
11+
"FlightDataImporter",
12+
"FlightComparator",
13+
"MonteCarlo",
14+
"MultivariateRejectionSampler",
15+
]

rocketpy/simulation/flight.py

Lines changed: 145 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -3424,6 +3424,151 @@ def max_rail_button2_shear_force(self):
34243424
"""Maximum lower rail button shear force, in Newtons."""
34253425
return np.abs(self.rail_button2_shear_force.y_array).max()
34263426

3427+
@cached_property
3428+
def calculate_rail_button_bending_moments(self):
3429+
"""Calculate internal bending moments at rail button attachment points.
3430+
3431+
This method uses beam theory to determine the internal structural
3432+
moments for stress analysis of the rail button attachments (fasteners
3433+
and airframe).
3434+
3435+
The bending moment at each button attachment consists of:
3436+
3437+
1. Bending from shear force at button contact point: $M = S \\times h$,
3438+
where $S$ is the shear (tangential) force and $h$ is button height.
3439+
2. Direct moment contribution from the button's reaction forces.
3440+
3441+
Returns
3442+
-------
3443+
tuple
3444+
rail_button1_bending_moment : Function
3445+
Bending moment at upper rail button as a function of time (N·m).
3446+
max_rail_button1_bending_moment : float
3447+
Maximum upper rail button bending moment (N·m).
3448+
rail_button2_bending_moment : Function
3449+
Bending moment at lower rail button as a function of time (N·m).
3450+
max_rail_button2_bending_moment : float
3451+
Maximum lower rail button bending moment (N·m).
3452+
3453+
Notes
3454+
-----
3455+
This calculation is meaningful only during the rail phase of flight.
3456+
Maximum values use absolute values for worst-case stress analysis.
3457+
The bending moments represent internal stresses in the rocket airframe
3458+
at the rail button attachment points.
3459+
3460+
**Assumptions:**
3461+
3462+
- Rail buttons act as simple supports: provide reaction forces (normal
3463+
and shear) but no moment reaction at the rail contact point.
3464+
- The rocket acts as a beam supported at two points (rail buttons).
3465+
- Bending moments arise from the lever arm effect of reaction forces
3466+
and the cantilever moment from button standoff height.
3467+
- Normal force moment: M = N x d, where N is normal reaction force
3468+
and d is distance from button to center of dry mass.
3469+
- Shear force cantilever moment: M = S x h, where S is shear force
3470+
and h is button standoff height.
3471+
3472+
Examples
3473+
--------
3474+
>>> moments = flight.calculate_rail_button_bending_moments
3475+
>>> print(moments[1]) # max rail button 1 bending moment
3476+
>>> print(moments[3]) # max rail button 2 bending moment
3477+
"""
3478+
# Check if rail buttons exist
3479+
null_moment = Function(0)
3480+
if len(self.rocket.rail_buttons) == 0:
3481+
warnings.warn(
3482+
"Trying to calculate rail button bending moments without "
3483+
"rail buttons defined. Setting moments to zero.",
3484+
UserWarning,
3485+
)
3486+
return (null_moment, 0.0, null_moment, 0.0)
3487+
3488+
# Get rail button geometry
3489+
rail_buttons_tuple = self.rocket.rail_buttons[0]
3490+
# Rail button standoff height
3491+
h_button = rail_buttons_tuple.component.button_height
3492+
if h_button is None:
3493+
warnings.warn(
3494+
"Rail button height not defined. Bending moments cannot be "
3495+
"calculated. Setting moments to zero.",
3496+
UserWarning,
3497+
)
3498+
return (null_moment, 0.0, null_moment, 0.0)
3499+
upper_button_position = (
3500+
rail_buttons_tuple.component.buttons_distance
3501+
+ rail_buttons_tuple.position.z
3502+
)
3503+
lower_button_position = rail_buttons_tuple.position.z
3504+
3505+
# Get center of dry mass (handle both callable and property)
3506+
if callable(self.rocket.center_of_dry_mass_position):
3507+
cdm = self.rocket.center_of_dry_mass_position(self.rocket._csys)
3508+
else:
3509+
cdm = self.rocket.center_of_dry_mass_position
3510+
3511+
# Distances from buttons to center of dry mass
3512+
d1 = abs(upper_button_position - cdm)
3513+
d2 = abs(lower_button_position - cdm)
3514+
3515+
# forces
3516+
N1 = self.rail_button1_normal_force
3517+
N2 = self.rail_button2_normal_force
3518+
S1 = self.rail_button1_shear_force
3519+
S2 = self.rail_button2_shear_force
3520+
t = N1.source[:, 0]
3521+
3522+
# Calculate bending moments at attachment points
3523+
# Primary contribution from shear force acting at button height
3524+
# Secondary contribution from normal force creating moment about attachment
3525+
m1_values = N2.source[:, 1] * d2 + S1.source[:, 1] * h_button
3526+
m2_values = N1.source[:, 1] * d1 + S2.source[:, 1] * h_button
3527+
3528+
rail_button1_bending_moment = Function(
3529+
np.column_stack([t, m1_values]),
3530+
inputs="Time (s)",
3531+
outputs="Bending Moment (N·m)",
3532+
interpolation="linear",
3533+
)
3534+
rail_button2_bending_moment = Function(
3535+
np.column_stack([t, m2_values]),
3536+
inputs="Time (s)",
3537+
outputs="Bending Moment (N·m)",
3538+
interpolation="linear",
3539+
)
3540+
3541+
# Maximum bending moments (absolute value for stress calculations)
3542+
max_rail_button1_bending_moment = float(np.max(np.abs(m1_values)))
3543+
max_rail_button2_bending_moment = float(np.max(np.abs(m2_values)))
3544+
3545+
return (
3546+
rail_button1_bending_moment,
3547+
max_rail_button1_bending_moment,
3548+
rail_button2_bending_moment,
3549+
max_rail_button2_bending_moment,
3550+
)
3551+
3552+
@property
3553+
def rail_button1_bending_moment(self):
3554+
"""Upper rail button bending moment as a Function of time."""
3555+
return self.calculate_rail_button_bending_moments[0]
3556+
3557+
@property
3558+
def max_rail_button1_bending_moment(self):
3559+
"""Maximum upper rail button bending moment, in N·m."""
3560+
return self.calculate_rail_button_bending_moments[1]
3561+
3562+
@property
3563+
def rail_button2_bending_moment(self):
3564+
"""Lower rail button bending moment as a Function of time."""
3565+
return self.calculate_rail_button_bending_moments[2]
3566+
3567+
@property
3568+
def max_rail_button2_bending_moment(self):
3569+
"""Maximum lower rail button bending moment, in N·m."""
3570+
return self.calculate_rail_button_bending_moments[3]
3571+
34273572
@funcify_method(
34283573
"Time (s)", "Horizontal Distance to Launch Point (m)", "spline", "constant"
34293574
)
@@ -4220,142 +4365,3 @@ def __lt__(self, other):
42204365
otherwise.
42214366
"""
42224367
return self.t < other.t
4223-
4224-
@cached_property
4225-
def calculate_rail_button_bending_moments(self):
4226-
"""
4227-
Calculate internal bending moments at rail button attachment points.
4228-
4229-
Uses beam theory to determine internal structural moments for stress
4230-
analysis of the rail button attachments (fasteners and airframe).
4231-
4232-
The bending moment at each button attachment consists of:
4233-
1. Bending from shear force at button contact point: M = S × h
4234-
where S is the shear (tangential) force and h is button height
4235-
2. Direct moment contribution from the button's reaction forces
4236-
4237-
Assumptions
4238-
-----------
4239-
- Rail buttons act as simple supports: provide reaction forces (normal
4240-
and shear) but no moment reaction at the rail contact point.
4241-
- The rocket acts as a beam supported at two points (rail buttons).
4242-
- Bending moments arise from the lever arm effect of reaction forces
4243-
and the cantilever moment from button standoff height.
4244-
4245-
The bending moment at each button attachment consists of:
4246-
1. Normal force moment: M = N x d, where N is normal reaction force
4247-
and d is distance from button to center of dry mass
4248-
2. Shear force cantilever moment: M = S x h, where S is shear force
4249-
and h is button standoff height
4250-
4251-
Notes
4252-
-----
4253-
- Calculated only during the rail phase of flight
4254-
- Maximum values use absolute values for worst-case stress analysis
4255-
- The bending moments represent internal stresses in the rocket
4256-
airframe at the rail button attachment points
4257-
4258-
Returns
4259-
-------
4260-
tuple
4261-
(rail_button1_bending_moment : Function,
4262-
max_rail_button1_bending_moment : float,
4263-
rail_button2_bending_moment : Function,
4264-
max_rail_button2_bending_moment : float)
4265-
4266-
Where rail_button1/2_bending_moment are Function objects of time
4267-
in N·m, and max values are floats in N·m.
4268-
"""
4269-
# Check if rail buttons exist
4270-
null_moment = Function(0)
4271-
if len(self.rocket.rail_buttons) == 0:
4272-
warnings.warn(
4273-
"Trying to calculate rail button bending moments without "
4274-
"rail buttons defined. Setting moments to zero.",
4275-
UserWarning,
4276-
)
4277-
return (null_moment, 0.0, null_moment, 0.0)
4278-
4279-
# Get rail button geometry
4280-
rail_buttons_tuple = self.rocket.rail_buttons[0]
4281-
# Rail button standoff height
4282-
h_button = rail_buttons_tuple.component.button_height
4283-
if h_button is None:
4284-
warnings.warn(
4285-
"Rail button height not defined. Bending moments cannot be "
4286-
"calculated. Setting moments to zero.",
4287-
UserWarning,
4288-
)
4289-
return (null_moment, 0.0, null_moment, 0.0)
4290-
upper_button_position = (
4291-
rail_buttons_tuple.component.buttons_distance
4292-
+ rail_buttons_tuple.position.z
4293-
)
4294-
lower_button_position = rail_buttons_tuple.position.z
4295-
4296-
# Get center of dry mass (handle both callable and property)
4297-
if callable(self.rocket.center_of_dry_mass_position):
4298-
cdm = self.rocket.center_of_dry_mass_position(self.rocket._csys)
4299-
else:
4300-
cdm = self.rocket.center_of_dry_mass_position
4301-
4302-
# Distances from buttons to center of dry mass
4303-
d1 = abs(upper_button_position - cdm)
4304-
d2 = abs(lower_button_position - cdm)
4305-
4306-
# forces
4307-
N1 = self.rail_button1_normal_force
4308-
N2 = self.rail_button2_normal_force
4309-
S1 = self.rail_button1_shear_force
4310-
S2 = self.rail_button2_shear_force
4311-
t = N1.source[:, 0]
4312-
4313-
# Calculate bending moments at attachment points
4314-
# Primary contribution from shear force acting at button height
4315-
# Secondary contribution from normal force creating moment about attachment
4316-
m1_values = N2.source[:, 1] * d2 + S1.source[:, 1] * h_button
4317-
m2_values = N1.source[:, 1] * d1 + S2.source[:, 1] * h_button
4318-
4319-
rail_button1_bending_moment = Function(
4320-
np.column_stack([t, m1_values]),
4321-
inputs="Time (s)",
4322-
outputs="Bending Moment (N·m)",
4323-
interpolation="linear",
4324-
)
4325-
rail_button2_bending_moment = Function(
4326-
np.column_stack([t, m2_values]),
4327-
inputs="Time (s)",
4328-
outputs="Bending Moment (N·m)",
4329-
interpolation="linear",
4330-
)
4331-
4332-
# Maximum bending moments (absolute value for stress calculations)
4333-
max_rail_button1_bending_moment = float(np.max(np.abs(m1_values)))
4334-
max_rail_button2_bending_moment = float(np.max(np.abs(m2_values)))
4335-
4336-
return (
4337-
rail_button1_bending_moment,
4338-
max_rail_button1_bending_moment,
4339-
rail_button2_bending_moment,
4340-
max_rail_button2_bending_moment,
4341-
)
4342-
4343-
@property
4344-
def rail_button1_bending_moment(self):
4345-
"""Upper rail button bending moment as a Function of time."""
4346-
return self.calculate_rail_button_bending_moments[0]
4347-
4348-
@property
4349-
def max_rail_button1_bending_moment(self):
4350-
"""Maximum upper rail button bending moment, in N·m."""
4351-
return self.calculate_rail_button_bending_moments[1]
4352-
4353-
@property
4354-
def rail_button2_bending_moment(self):
4355-
"""Lower rail button bending moment as a Function of time."""
4356-
return self.calculate_rail_button_bending_moments[2]
4357-
4358-
@property
4359-
def max_rail_button2_bending_moment(self):
4360-
"""Maximum lower rail button bending moment, in N·m."""
4361-
return self.calculate_rail_button_bending_moments[3]

0 commit comments

Comments
 (0)