From 050637d3415f223ea7af649432f1ca9be42cb4b8 Mon Sep 17 00:00:00 2001 From: Eric Omielan <112828024+eomielan@users.noreply.github.com> Date: Sat, 10 Feb 2024 11:06:56 -0800 Subject: [PATCH] Implement fluid simulation template classes (#66) * Add preliminary template classes * Fix velocity initial value fluid generation * Fix missing return values * Add/fix docstrings, add drag coeffs, remove extra attributes * Switch area to lookup table and fix mypy errors * Improve docstring to mention ref vector & pre-rotate velocity * Remove implementations for fluid generation * Switch to arrays for lookup tables & replace aoa with orientation * Add TODO to create linear interpolation helper * Add template for interpolation function * Fix docstring for orientation parameter * Remove extra word from docstring --- .../nodes/physics_engine/fluid_forces.py | 93 +++++++++++++++++++ .../nodes/physics_engine/fluid_generation.py | 69 ++++++++++++++ boat_simulator/nodes/physics_engine/fluids.py | 19 ---- 3 files changed, 162 insertions(+), 19 deletions(-) create mode 100644 boat_simulator/nodes/physics_engine/fluid_forces.py create mode 100644 boat_simulator/nodes/physics_engine/fluid_generation.py delete mode 100644 boat_simulator/nodes/physics_engine/fluids.py diff --git a/boat_simulator/nodes/physics_engine/fluid_forces.py b/boat_simulator/nodes/physics_engine/fluid_forces.py new file mode 100644 index 0000000..c479bdb --- /dev/null +++ b/boat_simulator/nodes/physics_engine/fluid_forces.py @@ -0,0 +1,93 @@ +"""This module provides functionality for computing the lift and drag forces acting on a medium.""" + +from typing import Tuple + +from numpy.typing import NDArray + +from boat_simulator.common.types import Scalar + + +class MediumForceComputation: + """This class calculates the lift and drag forces experienced by a medium when subjected to + fluid flow. + + Attributes: + `lift_coefficients` (NDArray): An array of shape (n, 2) where each row contains a pair + (x, y) representing an angle of attack, in degrees, and its corresponding lift + coefficient. + `drag_coefficients` (NDArray): An array of shape (n, 2) where each row contains a pair + (x, y) representing an angle of attack, in degrees, and its corresponding drag + coefficient. + `areas` (NDArray): An array of shape (n, 2) where each row contains a pair (x, y), + representing an angle of attack, in degrees, and its corresponding area, in square + meters (m^2). + `fluid_density` (Scalar): The density of the fluid acting on the medium, expressed in + kilograms per cubic meter (kg/m^3). + """ + + def __init__( + self, + lift_coefficients: NDArray, + drag_coefficients: NDArray, + areas: NDArray, + fluid_density: Scalar, + ): + self.__lift_coefficients = lift_coefficients + self.__drag_coefficients = drag_coefficients + self.__areas = areas + self.__fluid_density = fluid_density + + def compute(self, apparent_velocity: NDArray, orientation: Scalar) -> Tuple[NDArray, NDArray]: + """Computes the lift and drag forces experienced by a medium immersed in a fluid. + + Args: + apparent_velocity (NDArray): The apparent (relative) velocity between the fluid and the + medium, calculated as the difference between the fluid velocity and the medium + velocity (fluid_velocity - medium_velocity), expressed in meters per second (m/s). + orientation (Scalar): The orientation angle of the medium in degrees, where 0 degrees + corresponds to the positive x-axis, and angles increase counter-clockwise (CCW). + + Returns: + Tuple[NDArray, NDArray]: A tuple containing the lift force and drag force experienced + by the medium, both expressed in newtons (N). + """ + + # TODO: Implement this method. + + raise NotImplementedError() + + def interpolate(self, attack_angle: Scalar) -> Tuple[Scalar, Scalar, Scalar]: + """Performs linear interpolation to estimate the lift and drag coefficients, as well as the + associated area upon which the fluid acts, based on the provided angle of attack. + + Args: + attack_angle (Scalar): The angle of attack formed between the orientation angle of + the medium and the direction of the apparent velocity, expressed in degrees. + + Returns: + Tuple[Scalar, Scalar, Scalar]: A tuple representing the computed parameters. The + first scalar denotes the lift coefficient, the second scalar represents the + drag coefficient, and the third scalar indicates the surface area upon which + the fluid acts. Both lift and drag coefficients are unitless, while the + area is expressed in square meters (m^2). + """ + + # TODO: Implement this method using `np.interp`. + + raise NotImplementedError() + + @property + def lift_coefficients(self) -> NDArray: + return self.__lift_coefficients + + @property + def drag_coefficients(self) -> NDArray: + return self.__drag_coefficients + + @property + def areas(self) -> NDArray: + return self.__areas + + @property + def fluid_density(self) -> Scalar: + return self.__fluid_density diff --git a/boat_simulator/nodes/physics_engine/fluid_generation.py b/boat_simulator/nodes/physics_engine/fluid_generation.py new file mode 100644 index 0000000..8c544ee --- /dev/null +++ b/boat_simulator/nodes/physics_engine/fluid_generation.py @@ -0,0 +1,69 @@ +"""This module provides a generator for fluid vectors used within the physics engine.""" + +import numpy as np +from numpy.typing import NDArray + +from boat_simulator.common.generators import VectorGenerator +from boat_simulator.common.types import Scalar + + +class FluidGenerator: + """This class provides functionality to generate velocity vectors representing fluid movements. + + Attributes: + `generator` (VectorGenerator): The vector generator used to generate fluid velocities. + `velocity` (NDArray): The most recently generated fluid velocity vector, expressed in + meters per second (m/s). + """ + + def __init__(self, generator: VectorGenerator): + self.__generator = generator + self.__velocity = np.array(self.__generator.next()) + + def next(self) -> NDArray: + """Generates the next velocity vector for the fluid simulation. + + Returns: + NDArray: An array representing the updated velocity vector for the fluid simulation. + """ + + # TODO: Implement this to generate the next velocity vector. + + raise NotImplementedError() + + @property + def velocity(self) -> NDArray: + """Returns the fluid's current velocity vector. + + Returns: + NDArray: The velocity vector of the fluid, expressed in meters per second (m/s) and + ranging from negative infinity to positive infinity. + """ + + raise NotImplementedError() + + @property + def speed(self) -> Scalar: + """Calculates the current speed of the fluid. + + Returns: + Scalar: The speed of the fluid, expressed in meters per second (m/s) and within the + range of 0 to positive infinity. + """ + + # TODO: Implement this using the current velocity vector. + + raise NotImplementedError() + + @property + def direction(self) -> Scalar: + """Calculates the current direction of the fluid. + + Returns: + Scalar: The direction of the fluid, expressed in degrees and bounded between + [-180, 180). + """ + + # TODO: Implement this using the current velocity vector. + + raise NotImplementedError() diff --git a/boat_simulator/nodes/physics_engine/fluids.py b/boat_simulator/nodes/physics_engine/fluids.py deleted file mode 100644 index 8da1f17..0000000 --- a/boat_simulator/nodes/physics_engine/fluids.py +++ /dev/null @@ -1,19 +0,0 @@ -"""Generators for wind and current kinematics used in the physics engine.""" - -from abc import ABC, abstractmethod - -from numpy.typing import ArrayLike - - -class FluidGenerator(ABC): - @abstractmethod - def next(self) -> ArrayLike: - pass - - -class WindGenerator(FluidGenerator): - def __init__(self): - super().__init__() - - def next(self) -> ArrayLike: - return []