Skip to content
Open
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
12 changes: 8 additions & 4 deletions docs/user/function.rst
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,13 @@ plotted as follows:

.. important::

The ``Function`` class only supports interpolation ``shepard`` and \
extrapolation ``natural`` for datasets higher than one dimension (more than \
one input).
For datasets higher than one dimension (more than one input), the
``Function`` class supports interpolation ``linear``, ``shepard``, ``rbf``
and ``regular_grid``.

The ``regular_grid`` interpolation requires a complete Cartesian grid and
must be provided as ``(axes, grid_data)``. See the ``Function`` API
documentation for details.

CSV File
^^^^^^^^
Expand Down Expand Up @@ -183,7 +187,7 @@ In this section we are going to delve deeper on ``Function`` creation and its pa
- source: the ``Function`` data source. We have explored this parameter in the section above;
- inputs: a list of strings containing each input variable name. If the source only has one input, may be abbreviated as a string (e.g. "speed (m/s)");
- outputs: a list of strings containing each output variable name. If the source only has one output, may be abbreviated as a string (e.g. "total energy (J)");
- interpolation: a string that is the interpolation method to be used if the source is a dataset. Defaults to ``spline``;
- interpolation: a string that is the interpolation method to be used if the source is a dataset. For N-D datasets, supported options are ``linear``, ``shepard``, ``rbf`` and ``regular_grid``. Defaults to ``spline`` for 1-D and ``shepard`` for N-D datasets;
- extrapolation: a string that is the extrapolation method to be used if the source is a dataset. Defaults to ``constant``;
- title: the title to be shown in the plots.

Expand Down
9 changes: 5 additions & 4 deletions docs/user/rocket/generic_surface.rst
Original file line number Diff line number Diff line change
Expand Up @@ -243,16 +243,17 @@ independent variables:
- ``beta``: Side slip angle.
- ``mach``: Mach number.
- ``reynolds``: Reynolds number.
- ``q``: Pitch rate.
- ``r``: Yaw rate.
- ``p``: Roll rate.
- ``pitch_rate``: Pitch rate.
- ``yaw_rate``: Yaw rate.
- ``roll_rate``: Roll rate.

The last column must be the coefficient value, and must contain a header,
though the header name can be anything.

.. important::
Not all columns need to be present in the file, but the columns that are
present must be named, **and ordered**, as described above.
present must be correctly named as described above. Independent variable
columns can be in any order.

An example of a ``.csv`` file is shown below:

Expand Down
477 changes: 124 additions & 353 deletions rocketpy/mathutils/function.py

Large diffs are not rendered by default.

18 changes: 12 additions & 6 deletions rocketpy/plots/rocket_plots.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,20 +104,26 @@ def drag_curves(self, *, filename=None):
"""

try:
x_power_drag_on = self.rocket.power_on_drag.x_array
y_power_drag_on = self.rocket.power_on_drag.y_array
x_power_drag_on = self.rocket.power_on_drag_by_mach.x_array
y_power_drag_on = self.rocket.power_on_drag_by_mach.y_array
except AttributeError:
x_power_drag_on = np.linspace(0, 2, 50)
y_power_drag_on = np.array(
[self.rocket.power_on_drag.source(x) for x in x_power_drag_on]
[
self.rocket.power_on_drag_by_mach.get_value_opt(x)
for x in x_power_drag_on
]
)
try:
x_power_drag_off = self.rocket.power_off_drag.x_array
y_power_drag_off = self.rocket.power_off_drag.y_array
x_power_drag_off = self.rocket.power_off_drag_by_mach.x_array
y_power_drag_off = self.rocket.power_off_drag_by_mach.y_array
except AttributeError:
x_power_drag_off = np.linspace(0, 2, 50)
y_power_drag_off = np.array(
[self.rocket.power_off_drag.source(x) for x in x_power_drag_off]
[
self.rocket.power_off_drag_by_mach.get_value_opt(x)
for x in x_power_drag_off
]
)

_, ax = plt.subplots()
Expand Down
102 changes: 19 additions & 83 deletions rocketpy/rocket/aero_surface/generic_surface.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import copy
import csv
import math

import numpy as np

from rocketpy.mathutils import Function
from rocketpy.mathutils.vector_matrix import Matrix, Vector
from rocketpy.tools import load_generic_surface_csv


class GenericSurface:
Expand All @@ -32,7 +32,8 @@ def __init__(
angle of attack, angle of sideslip, Mach number, Reynolds number,
pitch rate, yaw rate and roll rate. For CSV files, the header must
contain at least one of the following: "alpha", "beta", "mach",
"reynolds", "pitch_rate", "yaw_rate" and "roll_rate".
"reynolds", "pitch_rate", "yaw_rate" and "roll_rate". The
independent variable columns can be provided in any order.

See Also
--------
Expand Down Expand Up @@ -327,7 +328,7 @@ def _process_input(self, input_data, coeff_name):
"""
if isinstance(input_data, str):
# Input is assumed to be a file path to a CSV
return self.__load_csv(input_data, coeff_name)
return load_generic_surface_csv(input_data, coeff_name)
elif isinstance(input_data, Function):
if input_data.__dom_dim__ != 7:
raise ValueError(
Expand All @@ -342,7 +343,21 @@ def _process_input(self, input_data, coeff_name):
f"{coeff_name} function must have 7 input arguments"
" (alpha, beta, mach, reynolds, pitch_rate, yaw_rate, roll_rate)."
)
return input_data
return Function(
input_data,
[
"alpha",
"beta",
"mach",
"reynolds",
"pitch_rate",
"yaw_rate",
"roll_rate",
],
[coeff_name],
interpolation="linear",
extrapolation="natural",
)
elif input_data == 0:
return Function(
lambda alpha, beta, mach, reynolds, pitch_rate, yaw_rate, roll_rate: 0,
Expand All @@ -364,82 +379,3 @@ def _process_input(self, input_data, coeff_name):
f"Invalid input for {coeff_name}: must be a CSV file path"
" or a callable."
)

def __load_csv(self, file_path, coeff_name):
"""Load a CSV file and create a Function object with the correct number
of arguments. The CSV file must have a header that specifies the
independent variables that are used.

Parameters
----------
file_path : str
Path to the CSV file.
coeff_name : str
Name of the coefficient being processed.

Returns
-------
Function
Function object with 7 input arguments (alpha, beta, mach, reynolds,
pitch_rate, yaw_rate, roll_rate).
"""
try:
with open(file_path, mode="r") as file:
reader = csv.reader(file)
header = next(reader)
except (FileNotFoundError, IOError) as 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}.")

# TODO make header strings flexible (e.g. 'alpha', 'Alpha', 'ALPHA')
independent_vars = [
"alpha",
"beta",
"mach",
"reynolds",
"pitch_rate",
"yaw_rate",
"roll_rate",
]
present_columns = [col for col in independent_vars if col in header]

# Check that the last column is not an independent variable
if header[-1] in independent_vars:
raise ValueError(
f"Last column in {coeff_name} CSV must be the coefficient"
" value, not an independent variable."
)

# Ensure that at least one independent variable is present
if not present_columns:
raise ValueError(f"No independent variables found in {coeff_name} CSV.")

# Initialize the CSV-based function
csv_func = Function(
file_path,
interpolation="linear",
extrapolation="natural",
)

# Create a mask for the presence of each independent variable
# save on self to avoid loss of scope
_mask = [1 if col in present_columns else 0 for col in independent_vars]

# Generate a lambda that applies only the relevant arguments to csv_func
def wrapper(alpha, beta, mach, reynolds, pitch_rate, yaw_rate, roll_rate):
args = [alpha, beta, mach, reynolds, pitch_rate, yaw_rate, roll_rate]
# Select arguments that correspond to present variables
selected_args = [arg for arg, m in zip(args, _mask) if m]
return csv_func(*selected_args)

# Create the interpolation function
func = Function(
wrapper,
independent_vars,
[coeff_name],
interpolation="linear",
extrapolation="natural",
)
return func
28 changes: 20 additions & 8 deletions rocketpy/rocket/point_mass_rocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,16 @@ class PointMassRocket(Rocket):
center_of_mass_without_motor : float
Position, in meters, of the rocket's center of mass without motor
relative to the rocket's coordinate system.
power_off_drag : float, callable, array, string, Function
Drag coefficient as a function of Mach number when the motor is off.
power_on_drag : float, callable, array, string, Function
Drag coefficient as a function of Mach number when the motor is on.
power_off_drag : int, float, callable, array, string, Function
Drag coefficient input when the motor is off. Accepts the same formats
as :class:`rocketpy.Rocket`, including 1D (Mach-only) and 7D
(alpha, beta, mach, reynolds, pitch_rate, yaw_rate, roll_rate)
definitions.
power_on_drag : int, float, callable, array, string, Function
Drag coefficient input when the motor is on. Accepts the same formats
as :class:`rocketpy.Rocket`, including 1D (Mach-only) and 7D
(alpha, beta, mach, reynolds, pitch_rate, yaw_rate, roll_rate)
definitions.
Attributes
----------
Expand All @@ -35,10 +41,16 @@ class PointMassRocket(Rocket):
center_of_mass_without_motor : float
Position, in meters, of the rocket's center of mass without motor
relative to the rocket's coordinate system.
power_off_drag : Function
Drag coefficient as a function of Mach number when the motor is off.
power_on_drag : Function
Drag coefficient as a function of Mach number when the motor is on.
power_off_drag_7d : Function
Drag coefficient function with seven inputs in the order:
alpha, beta, mach, reynolds, pitch_rate, yaw_rate, roll_rate.
power_on_drag_7d : Function
Drag coefficient function with seven inputs in the order:
alpha, beta, mach, reynolds, pitch_rate, yaw_rate, roll_rate.
power_off_drag_by_mach : Function
Convenience wrapper for power-off drag as a Mach-only function.
power_on_drag_by_mach : Function
Convenience wrapper for power-on drag as a Mach-only function.
"""

def __init__(
Expand Down
Loading
Loading