import numpy as np
"""
Module containing the geometry of the domain ,
the mesh and the time window.
"""
[docs]
class MeshRect2D:
r"""
Class containing the geometry of a 2D rectangular domain :math:`\Omega = [x_0;x_0+L_x]\times [y_0;y_0+L_y]`
with a cartesian mesh with constant space steps :math:`\Delta x` and :math:`\Delta y`, and
a time window :math:`[0;T]` discretized with constant time step :math:`\Delta t`.
Attributes
----------
L_x : float
Length of the domain along the :math:`x`-axis :math:`L_x`.
L_y : float
Length of the domain along the :math:`y`-axis :math:`L_y`.
dx : float
Space step of the mesh along the :math:`x`-axis :math:`\Delta x`.
dy : float
Space step of the mesh along the :math:`y`-axis :math:`\Delta y`.
x : ~numpy.ndarray
Array of the :math:`x`-coordinates of the center of the cells of the mesh.
y : ~numpy.ndarray
Array of the :math:`y`-coordinates of the center of the cells of the mesh.
x_vertical_interface : ~numpy.ndarray
Array of the :math:`x`-coordinates of the vertical interfaces between the cells of the mesh.
y_horizontal_interface : ~numpy.ndarray
Array of the :math:`y`-coordinates of the horizontal interfaces between the cells of the mesh.
mass_cell : float
The volume of mesh cells :math:`\Delta x\times \Delta y`.
t : float
The current time :math:`t` of the modelling, initialized to :math:`t=0s`.
T_final : float
The final time :math:`T` of the modeling time window.
dt : float
The time step :math:`\Delta t`.
Initialized to `None` and
to be computed using the methods :func:`calc_dt_explicit_solver`
or :func:`calc_dt_implicit_solver`.
t_array : ~numpy.ndarray
The time array.
Initialized to `None` and
to be computed from the attribute :attr:`dt`
using the methods :func:`calc_dt_explicit_solver`
or :func:`calc_dt_implicit_solver`.
X_0 : tuple of float
Coordinates of the origin of the mesh :math:`(x_0, y_0)`. By default set to :math:`(x_0, y_0)=(0, 0)`.
"""
[docs]
def __init__(self, L_x, L_y, dx, dy, T_final, X_0=None):
r"""
Constructor method.
Parameters
----------
L_x : float
Length of the domain along the :math:`x`-axis :math:`L_x`.
L_y : float
Length of the domain along the :math:`y`-axis :math:`L_y`.
dx : float
Space step of the mesh along the :math:`x`-axis :math:`\Delta x`.
dy : float
Space step of the mesh along the :math:`y`-axis :math:`\Delta y`.
T_final : float
The final time :math:`T` of the modeling time window.
X_0 : tuple of float, default: None
Coordinates of the origin of the mesh :math:`(x_0, y_0)`. If `None`, set to :math:`(x_0, y_0)=(0, 0)`.
"""
# To do:
# Add exceptions to ensure all inputs are float.
self.L_x = L_x
self.L_y = L_y
self.dx = dx
self.dy = dy
nx = L_x // dx
ny = L_y // dy
if dx - 1e-12 < L_x % dx:
nx += 1
if dy - 1e-12 < L_y % dy:
ny += 1
if X_0 is None:
X_0 = (0.0, 0.0)
self.x_vertical_interface = np.arange(0, (nx + 0.5) * dx, dx) + X_0[0]
self.x = 0.5 * (self.x_vertical_interface[:-1] + self.x_vertical_interface[1:])
self.y_horizontal_interface = np.arange(0, (ny + 0.5) * dy, dy) + X_0[1]
self.y = 0.5 * (self.y_horizontal_interface[:-1] + self.y_horizontal_interface[1:])
self.mass_cell = dx * dy
self.t = 0
self.T_final = T_final
self.dt = None
self.t_array = None
[docs]
def calc_dt_explicit_solver(self, U, dt_max=0.1):
r"""
Compute the time step :math:`\Delta t`
such as it satisfies the CFL condition
:math:`\Delta t<\left(\frac{max(u)}{\Delta x}+\frac{max(v)}{\Delta y}\right)^{-1}`
for a given wind field :math:`\vec{u}=(u,v)`.
To be used with an explicit or semi-implicit numerical scheme.
Parameters
----------
U: ~pheromone_dispersion.velocity.Velocity
The wind field :math:`\vec{u}(x,y,t)`.
dt_max: float, optional, default: 0.1
The maximal time step :math:`\Delta t_{max}` imposing that :math:`\Delta t<\Delta t_{max}` to ensure a certain accuracy
Notes
-----
Compute a time step :math:`\Delta t`, store it in the attribute :attr:`dt` and compute the attribute :attr:`t_array` accordingly.
"""
# To do:
# add exceptions to make sure that all the inputs are float
self.dt = np.min([1.0 / (1.2 * U.max_horizontal_U / self.dx + 1.2 * U.max_vertical_U / self.dy), dt_max])
self.t_array = np.arange(0, self.T_final + self.dt, self.dt)
self.T_final = self.t_array[-1]
[docs]
def calc_dt_implicit_solver(self, dt):
r"""
Store the provided time step :math:`\Delta t` in the attribute :attr:`dt` and compute the attribute :attr:`t_array` accordingly.
To be used with an implicit numerical scheme.
Parameters
----------
dt : float
The provided time step :math:`\Delta t`.
"""
# To do:
# add exceptions to make sure that all the inputs are float
self.dt = dt
self.t_array = np.arange(0, self.T_final + self.dt, self.dt)
self.T_final = self.t_array[-1]