Skip to content

common

Value objects and helpers shared across the library, belonging to no single model package.

  • FluidState — A fluid at a thermodynamic state point: fluid name, pressure, temperature, and density. What a feed system hands the injector, so neither package has to import the other.
  • DryMassProperties — Mass, center of gravity, and inertia tensor of a device's dry structure.
  • Array manipulation helpers and a @timing decorator for profiling.

machwave.common.fluid_state

FluidState dataclass

A fluid at a thermodynamic state point.

Attributes:

Name Type Description
fluid_name str

Name of the fluid in the CoolProp database.

pressure float

Pressure [Pa].

temperature float

Temperature [K].

density float

Density [kg/m^3].

Source code in machwave/common/fluid_state.py
@dataclasses.dataclass(frozen=True, kw_only=True, slots=True)
class FluidState:
    """
    A fluid at a thermodynamic state point.

    Attributes:
        fluid_name: Name of the fluid in the CoolProp database.
        pressure: Pressure [Pa].
        temperature: Temperature [K].
        density: Density [kg/m^3].
    """

    fluid_name: str
    pressure: float
    temperature: float
    density: float

machwave.common.mass_properties

DryMassProperties dataclass

Properties common to devices that contain dry mass.

Attributes:

Name Type Description
dry_mass float

Dry mass scalar [kg].

center_of_gravity_coordinate tuple[float, float, float]

Dry mass center of gravity position measured from the nozzle exit (x, y, z) [m]. Positive x points toward the bulkhead.

moment_of_inertia tuple[float, float, float]

Dry mass principal moments of inertia (I_11, I_22, I_33) [kg-m^2], evaluated at the dry mass center of gravity. Assumes the thrust chamber is aligned with the x-axis.

Source code in machwave/common/mass_properties.py
@dataclasses.dataclass(frozen=True, kw_only=True)
class DryMassProperties:
    """
    Properties common to devices that contain dry mass.

    Attributes:
        dry_mass: Dry mass scalar [kg].
        center_of_gravity_coordinate: Dry mass center of gravity position measured from
            the nozzle exit `(x, y, z)` [m]. Positive x points toward the bulkhead.
        moment_of_inertia: Dry mass principal moments of inertia `(I_11, I_22, I_33)`
            [kg-m^2], evaluated at the dry mass center of gravity. Assumes the thrust
            chamber is aligned with the x-axis.
    """

    dry_mass: float
    center_of_gravity_coordinate: tuple[float, float, float]
    moment_of_inertia: tuple[float, float, float]

    def __post_init__(self) -> None:
        """
        Validate and normalize the dry mass properties.

        Raises:
            ValueError: If the dry mass is non-positive or non-finite, either triple is
                malformed, or a moment of inertia is negative or non-finite.
        """
        if not math.isfinite(self.dry_mass) or self.dry_mass <= 0.0:
            raise ValueError(
                f"dry_mass must be a positive finite number, got {self.dry_mass}"
            )

        cog = _as_3d_vector(
            "center_of_gravity_coordinate", self.center_of_gravity_coordinate
        )
        moment_of_inertia = _as_3d_vector("moment_of_inertia", self.moment_of_inertia)

        if any(not math.isfinite(c) or c < 0.0 for c in moment_of_inertia):
            raise ValueError(
                "moment_of_inertia components must be non-negative finite numbers, got "
                f"{moment_of_inertia}"
            )

        object.__setattr__(self, "center_of_gravity_coordinate", cog)
        object.__setattr__(self, "moment_of_inertia", moment_of_inertia)

__post_init__()

Validate and normalize the dry mass properties.

Raises:

Type Description
ValueError

If the dry mass is non-positive or non-finite, either triple is malformed, or a moment of inertia is negative or non-finite.

Source code in machwave/common/mass_properties.py
def __post_init__(self) -> None:
    """
    Validate and normalize the dry mass properties.

    Raises:
        ValueError: If the dry mass is non-positive or non-finite, either triple is
            malformed, or a moment of inertia is negative or non-finite.
    """
    if not math.isfinite(self.dry_mass) or self.dry_mass <= 0.0:
        raise ValueError(
            f"dry_mass must be a positive finite number, got {self.dry_mass}"
        )

    cog = _as_3d_vector(
        "center_of_gravity_coordinate", self.center_of_gravity_coordinate
    )
    moment_of_inertia = _as_3d_vector("moment_of_inertia", self.moment_of_inertia)

    if any(not math.isfinite(c) or c < 0.0 for c in moment_of_inertia):
        raise ValueError(
            "moment_of_inertia components must be non-negative finite numbers, got "
            f"{moment_of_inertia}"
        )

    object.__setattr__(self, "center_of_gravity_coordinate", cog)
    object.__setattr__(self, "moment_of_inertia", moment_of_inertia)

machwave.common.arrays

replace_array_values(arr, to_replace, value)

Replaces values in a NumPy array with another value.

Parameters:

Name Type Description Default
arr NDArray[number]

The array in which to replace values.

required
to_replace int | float

The value to be replaced.

required
value int | float

The value to replace with.

required

Returns:

Type Description
NDArray[number]

A new array with the values replaced.

Source code in machwave/common/arrays.py
def replace_array_values(
    arr: npt.NDArray[np.number],
    to_replace: int | float,
    value: int | float,
) -> npt.NDArray[np.number]:
    """
    Replaces values in a NumPy array with another value.

    Args:
        arr: The array in which to replace values.
        to_replace: The value to be replaced.
        value: The value to replace with.

    Returns:
        A new array with the values replaced.
    """
    arr = arr.copy()
    arr[arr == to_replace] = value
    return arr

machwave.common.decorators

timing(f)

Decorator to print the execution time of a function.

Parameters:

Name Type Description Default
f F

The function to be timed.

required

Returns:

Type Description
F

The wrapped function with added timing functionality.

Source code in machwave/common/decorators.py
def timing(f: F) -> F:
    """
    Decorator to print the execution time of a function.

    Args:
        f: The function to be timed.

    Returns:
        The wrapped function with added timing functionality.
    """

    @functools.wraps(f)
    def wrapper(*args: typing.Any, **kwargs: typing.Any) -> typing.Any:
        start_time = time.time()
        result = f(*args, **kwargs)
        end_time = time.time()
        print(f"\nExecution time: {end_time - start_time:.4f} seconds")
        return result

    return typing.cast(F, wrapper)

machwave.common.objects

get_object_dict(obj)

Extract the attribute dictionary from an object.

Parameters:

Name Type Description Default
obj Any

Any Python object to inspect.

required

Returns:

Type Description
dict[str, Any]

A dictionary mapping attribute names to their values, or an empty dictionary

dict[str, Any]

if the object has no dict.

Examples:

>>> class Example:
...     def __init__(self):
...         self.x = 1
...         self.y = 2
>>> get_object_dict(Example())
{'x': 1, 'y': 2}
Source code in machwave/common/objects.py
def get_object_dict(obj: typing.Any) -> dict[str, typing.Any]:
    """
    Extract the attribute dictionary from an object.

    Args:
        obj: Any Python object to inspect.

    Returns:
        A dictionary mapping attribute names to their values, or an empty dictionary
        if the object has no __dict__.

    Examples:
        >>> class Example:
        ...     def __init__(self):
        ...         self.x = 1
        ...         self.y = 2
        >>> get_object_dict(Example())
        {'x': 1, 'y': 2}
    """
    try:
        return vars(obj)
    except TypeError:
        return {}