Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Fluid Generation #328

Merged
merged 9 commits into from
Jun 1, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,31 @@

from boat_simulator.common.generators import VectorGenerator
from boat_simulator.common.types import Scalar
from boat_simulator.common.utils import bound_to_180, rad_to_degrees


class FluidGenerator:
"""This class provides functionality to generate velocity vectors representing fluid movements.

Attributes:
`generator` (VectorGenerator): The vector generator used to generate fluid velocities.
`generator` (VectorGenerator): The vector generator used to generate 2D fluid velocities.
`velocity` (NDArray): The most recently generated fluid velocity vector, expressed in
meters per second (m/s).
meters per second (m/s). It is expected to be a 2D vector.
"""

def __init__(self, generator: VectorGenerator):
self.__generator = generator
self.__velocity = np.array(self.__generator.next())
assert self.__velocity.shape == (2,)

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()
self.__velocity = np.array(self.__generator.next())
return self.__velocity

@property
def velocity(self) -> NDArray:
Expand All @@ -39,8 +39,7 @@ def velocity(self) -> NDArray:
NDArray: The velocity vector of the fluid, expressed in meters per second (m/s) and
ranging from negative infinity to positive infinity.
"""

raise NotImplementedError()
return self.__velocity

@property
def speed(self) -> Scalar:
Expand All @@ -50,10 +49,7 @@ def speed(self) -> Scalar:
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()
return np.linalg.norm(self.__velocity)

@property
def direction(self) -> Scalar:
Expand All @@ -63,7 +59,6 @@ def direction(self) -> Scalar:
Scalar: The direction of the fluid, expressed in degrees and bounded between
[-180, 180).
"""

# TODO: Implement this using the current velocity vector.

raise NotImplementedError()
angle_rad = np.arctan2(self.__velocity[1], self.__velocity[0])
angle_deg = rad_to_degrees(angle_rad)
return bound_to_180(angle_deg)
Original file line number Diff line number Diff line change
@@ -1,9 +1,75 @@
"""Tests classes and functions in boat_simulator/nodes/physics_engine/fluids.py"""

import numpy as np
import pytest

from boat_simulator.common.generators import ConstantGenerator, MVGaussianGenerator
from boat_simulator.nodes.physics_engine.fluid_generation import FluidGenerator


class TestFluidGenerator:
pass
@pytest.mark.parametrize(
"vector",
[
(np.array([1, 0])),
(np.array([0, 1])),
(np.array([1, 0])),
],
)
def test_velocity_constant(self, vector):
vector_generator = ConstantGenerator(constant=vector)
fluid_generator = FluidGenerator(generator=vector_generator)
first_fluid_vector = fluid_generator.velocity
assert np.all(first_fluid_vector == vector)
eomielan marked this conversation as resolved.
Show resolved Hide resolved
assert np.all(first_fluid_vector == fluid_generator.next())

@pytest.mark.parametrize(
"mean, cov",
[
(np.array([1, 2]), np.array([[2, 1], [1, 2]])),
(np.array([4, 5]), np.array([[3, 1], [1, 3]])),
(np.array([100, 50]), np.array([[10, 5], [5, 10]])),
(np.array([120, 130]), np.array([[10, 5], [5, 10]])),
],
)
def test_velocity_random(self, mean, cov):
vector_generator = MVGaussianGenerator(mean=mean, cov=cov)
fluid_generator = FluidGenerator(vector_generator)
first_fluid_vector = fluid_generator.velocity
next_fluid_vector = fluid_generator.next()
assert np.all(next_fluid_vector != first_fluid_vector)

@pytest.mark.parametrize(
"vector",
[
(np.array([1, 0])),
(np.array([0, 1])),
(np.array([-1, 0])),
(np.array([0, -1])),
(np.array([1, 1])),
(np.array([-1, -1])),
],
)
def test_speed(self, vector):
vector_generator = ConstantGenerator(constant=vector)
fluid_generator = FluidGenerator(generator=vector_generator)
generated_fluid_vector = fluid_generator.next()
assert np.all(vector == generated_fluid_vector)
assert np.linalg.norm(vector) == fluid_generator.speed

class TestWindGenerator:
pass
@pytest.mark.parametrize(
"vector, expected_direction",
[
(np.array([1, 0]), 0),
(np.array([0, 1]), 90),
(np.array([-1, 0]), -180),
(np.array([0, -1]), -90),
(np.array([1, 1]), 45),
(np.array([-1, -1]), -135),
],
)
def test_direction(self, vector, expected_direction):
vector_generator = ConstantGenerator(constant=vector)
fluid_generator = FluidGenerator(generator=vector_generator)
calculated_direction = fluid_generator.direction
assert np.isclose(calculated_direction, expected_direction, atol=1e-7)