Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
22 changes: 14 additions & 8 deletions docs/notebooks/coeff_testing.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -458,25 +458,31 @@
"gennose = GenericSurface(\n",
" reference_area=np.pi * calisto.radius**2,\n",
" reference_length=2 * calisto.radius,\n",
" cL=\"nose_cL.csv\",\n",
" cQ=\"nose_cQ.csv\",\n",
" coefficients={\n",
" \"cL\": \"nose_cL.csv\",\n",
" \"cQ\": \"nose_cQ.csv\",\n",
" },\n",
" center_of_pressure=(0, 0, 0),\n",
" name=\"nose\",\n",
")\n",
"genfin = GenericSurface(\n",
" reference_area=np.pi * calisto.radius**2,\n",
" reference_length=2 * calisto.radius,\n",
" cL=\"fins_cL.csv\",\n",
" cQ=\"fins_cQ.csv\",\n",
" cl=\"fins_roll.csv\",\n",
" coefficients={\n",
" \"cL\": \"fins_cL.csv\",\n",
" \"cQ\": \"fins_cQ.csv\",\n",
" \"cl\": \"fins_roll.csv\",\n",
" },\n",
" center_of_pressure=(0, 0, 0),\n",
" name=\"fins\",\n",
")\n",
"gentail = GenericSurface(\n",
" reference_area=np.pi * calisto.radius**2,\n",
" reference_length=2 * calisto.radius,\n",
" cL=\"tail_cL.csv\",\n",
" cQ=\"tail_cQ.csv\",\n",
" coefficients={\n",
" \"cL\": \"tail_cL.csv\",\n",
" \"cQ\": \"tail_cQ.csv\",\n",
" },\n",
" center_of_pressure=(0, 0, 0),\n",
" name=\"tail\",\n",
")\n",
Expand Down Expand Up @@ -2451,7 +2457,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.0"
"version": "3.11.2"
},
"vscode": {
"interpreter": {
Expand Down
3 changes: 1 addition & 2 deletions rocketpy/rocket/aero_surface/aero_surface.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,7 @@ def compute_forces_and_moments(
rho,
cp,
*args,
**kwargs,
):
): # pylint: disable=unused-argument
"""Computes the forces and moments acting on the aerodynamic surface.
Used in each time step of the simulation. This method is valid for
the barrowman aerodynamic models.
Expand Down
30 changes: 21 additions & 9 deletions rocketpy/rocket/aero_surface/fins/fins.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,21 +373,33 @@ def compute_forces_and_moments(
stream_mach,
rho,
cp,
_,
omega1,
omega2,
omega3,
omega,
*args,
**kwargs,
):
): # pylint: disable=arguments-differ
"""Computes the forces and moments acting on the aerodynamic surface.

Parameters
----------
stream_speed : int, float
Speed of the flow stream in the body frame.
stream_velocity : tuple of float
The velocity of the airflow relative to the surface.
stream_speed : float
The magnitude of the airflow speed.
stream_mach : float
The Mach number of the airflow.
rho : float
Air density.
cp : Vector
Center of pressure coordinates in the body frame.
omega: tuple[float, float, float]
Tuple containing angular velocities around the x, y, z axes.

Returns
-------
tuple of float
The aerodynamic forces (lift, side_force, drag) and moments
(pitch, yaw, roll) in the body frame.
"""

R1, R2, R3, M1, M2, _ = super().compute_forces_and_moments(
stream_velocity,
stream_speed,
Expand All @@ -408,7 +420,7 @@ def compute_forces_and_moments(
* self.reference_area
* (self.reference_length) ** 2
* cld_omega.get_value_opt(stream_mach)
* omega3
* omega[2]
/ 2
)
M3 = M3_forcing - M3_damping
Expand Down
146 changes: 105 additions & 41 deletions rocketpy/rocket/aero_surface/generic_surface.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import copy
import csv
import math

Expand All @@ -17,12 +18,7 @@ def __init__(
self,
reference_area,
reference_length,
cL=0,
cQ=0,
cD=0,
cm=0,
cn=0,
cl=0,
coefficients,
center_of_pressure=(0, 0, 0),
name="Generic Surface",
):
Expand Down Expand Up @@ -51,31 +47,35 @@ def __init__(
reference_length : int, float
Reference length of the aerodynamic surface. Has the unit of meters.
Commonly defined as the rocket's diameter.
cL : str, callable, optional
Lift coefficient. Can be a path to a CSV file or a callable.
Default is 0.
cQ : str, callable, optional
Side force coefficient. Can be a path to a CSV file or a callable.
Default is 0.
cD : str, callable, optional
Drag coefficient. Can be a path to a CSV file or a callable.
Default is 0.
cm : str, callable, optional
Pitch moment coefficient. Can be a path to a CSV file or a callable.
Default is 0.
cn : str, callable, optional
Yaw moment coefficient. Can be a path to a CSV file or a callable.
Default is 0.
cl : str, callable, optional
Roll moment coefficient. Can be a path to a CSV file or a callable.
Default is 0.
coefficients: dict
List of coefficients. If a coefficient is omitted, it is set to 0.
The valid coefficients are:\n
cL: str, callable, optional
Lift coefficient. Can be a path to a CSV file or a callable.
Default is 0.\n
cQ: str, callable, optional
Side force coefficient. Can be a path to a CSV file or a callable.
Default is 0.\n
cD: str, callable, optional
Drag coefficient. Can be a path to a CSV file or a callable.
Default is 0.\n
cm: str, callable, optional
Pitch moment coefficient. Can be a path to a CSV file or a callable.
Default is 0.\n
cn: str, callable, optional
Yaw moment coefficient. Can be a path to a CSV file or a callable.
Default is 0.\n
cl: str, callable, optional
Roll moment coefficient. Can be a path to a CSV file or a callable.
Default is 0.\n
center_of_pressure : tuple, list, optional
Application point of the aerodynamic forces and moments. The
center of pressure is defined in the local coordinate system of the
aerodynamic surface. The default value is (0, 0, 0).
name : str, optional
Name of the aerodynamic surface. Default is 'GenericSurface'.
"""

self.reference_area = reference_area
self.reference_length = reference_length
self.center_of_pressure = center_of_pressure
Expand All @@ -85,12 +85,80 @@ def __init__(
self.cpz = center_of_pressure[2]
self.name = name

self.cL = self._process_input(cL, "cL")
self.cD = self._process_input(cD, "cD")
self.cQ = self._process_input(cQ, "cQ")
self.cm = self._process_input(cm, "cm")
self.cn = self._process_input(cn, "cn")
self.cl = self._process_input(cl, "cl")
default_coefficients = self._get_default_coefficients()
self._check_coefficients(coefficients, default_coefficients)
coefficients = self._complete_coefficients(coefficients, default_coefficients)
for coeff, coeff_value in coefficients.items():
value = self._process_input(coeff_value, coeff)
setattr(self, coeff, value)

def _get_default_coefficients(self):
"""Returns default coefficients

Returns
-------
default_coefficients: dict
Dictionary whose keys are the coefficients names and keys
are the default values.
"""
default_coefficients = {
"cL": 0,
"cQ": 0,
"cD": 0,
"cm": 0,
"cn": 0,
"cl": 0,
}
return default_coefficients

def _complete_coefficients(self, input_coefficients, default_coefficients):
"""Creates a copy of the input coefficients dict and fill it with missing
keys with default values

Parameters
----------
input_coefficients : str, dict
Coefficients dictionary passed by the user. If the user only specifies some
of the coefficients, the remaining are completed with class default
values
default_coefficients : dict
Default coefficients of the class

Returns
-------
coefficients : dict
Coefficients dictionary used to setup coefficient attributes
"""
coefficients = copy.deepcopy(input_coefficients)
for coeff, value in default_coefficients.items():
if coeff not in coefficients.keys():
coefficients[coeff] = value

return coefficients

def _check_coefficients(self, input_coefficients, default_coefficients):
"""Check if input coefficients have only valid keys

Parameters
----------
input_coefficients : str, dict
Coefficients dictionary passed by the user. If the user only specifies some
of the coefficients, the remaining are completed with class default
values
default_coefficients : dict
Default coefficients of the class

Raises
------
ValueError
Raises a value error if the input coefficient has an invalid key
"""
invalid_keys = set(input_coefficients) - set(default_coefficients)
if invalid_keys:
raise ValueError(
f"Invalid coefficient name(s) used in key(s): {', '.join(invalid_keys)}. "
"Check the documentation for valid names."
)

def _compute_from_coefficients(
self,
Expand Down Expand Up @@ -169,12 +237,8 @@ def compute_forces_and_moments(
stream_mach,
rho,
cp,
omega,
reynolds,
omega1,
omega2,
omega3,
*args,
**kwargs,
):
"""Computes the forces and moments acting on the aerodynamic surface.
Used in each time step of the simulation. This method is valid for
Expand All @@ -192,10 +256,10 @@ def compute_forces_and_moments(
Air density.
cp : Vector
Center of pressure coordinates in the body frame.
omega: tuple[float, float, float]
Tuple containing angular velocities around the x, y, z axes.
reynolds : float
Reynolds number.
omega1, omega2, omega3 : float
Angular velocities around the x, y, z axes.

Returns
-------
Expand All @@ -218,9 +282,9 @@ def compute_forces_and_moments(
beta,
stream_mach,
reynolds,
omega1,
omega2,
omega3,
omega[0],
omega[1],
omega[2],
)

# Conversion from aerodynamic frame to body frame
Expand Down Expand Up @@ -320,7 +384,7 @@ def __load_csv(self, file_path, coeff_name):
reader = csv.reader(file)
header = next(reader)
except (FileNotFoundError, IOError) as e:
raise ValueError(f"Error reading {coeff_name} CSV file: {e}")
raise ValueError(f"Error reading {coeff_name} CSV file: {e}") from e

if not header:
raise ValueError(f"Invalid or empty CSV file for {coeff_name}.")
Expand Down
Loading