"""
Notes
-----
This module contains the HPC fracture functions.
"""
import numpy as np
import numba as nb
from andfn.hpc import (
hpc_intersection,
hpc_const_head_line,
hpc_well,
hpc_bounding_circle,
hpc_imp_object,
CACHE,
)
[docs]
@nb.njit()
def calc_omega(self_, z, element_struc_array, exclude=-1):
"""
Calculates the omega for the fracture excluding element "exclude".
Parameters
----------
self_ : np.ndarray[fracture_dtype]
The fracture element.
z : complex
A point in the complex z plane.
element_struc_array : np.ndarray[element_dtype]
Array of elements.
exclude : int
Label of element to exclude from the omega calculation.
Returns
-------
omega : complex
The complex potential for the fracture.
"""
omega = self_["constant"] + 0.0j
for e in range(self_["nelements"]):
el = self_["elements"][e]
if el != exclude:
element = element_struc_array[el]
if element["type_"] == 0: # Intersection
omega += hpc_intersection.calc_omega(element, z, self_["id_"])
elif element["type_"] == 1: # Bounding circle
omega += hpc_bounding_circle.calc_omega(element, z)
elif element["type_"] == 2: # Well
omega += hpc_well.calc_omega(element, z)
elif element["type_"] == 3: # Constant head line
omega += hpc_const_head_line.calc_omega(element, z)
elif element["type_"] == 4: # Impermeable circle
omega += hpc_imp_object.calc_omega_circle(element, z)
elif element["type_"] == 5: # Impermeable line
omega += hpc_imp_object.calc_omega_line(element, z)
return omega
[docs]
def calc_w(self_, z, element_struc_array, exclude=-1):
"""
Calculates the omega for the fracture excluding element "exclude".
Parameters
----------
self_ : np.ndarray[fracture_dtype]
The fracture element.
z : complex
A point in the complex z plane.
element_struc_array : np.ndarray[element_dtype]
Array of elements.
exclude : int
Label of element to exclude from the omega calculation.
Returns
-------
w : complex
The complex potential for the fracture.
"""
w = 0.0 + 0.0j
for e in range(self_["nelements"]):
el = self_["elements"][e]
if el != exclude:
element = element_struc_array[el]
if element["type_"] == 0: # Intersection
w += hpc_intersection.calc_w(element, z, self_["id_"])
elif element["type_"] == 1: # Bounding circle
w += hpc_bounding_circle.calc_w(element, z)
elif element["type_"] == 2: # Well
w += hpc_well.calc_w(element, z)
elif element["type_"] == 3: # Constant head line
w += hpc_const_head_line.calc_w(element, z)
return w
[docs]
@nb.njit(cache=CACHE)
def calc_flow_net(self_, n_points, margin, element_struc_array):
"""
Calculates the flow net for the fracture.
Parameters
----------
self_ : np.ndarray[fracture_dtype]
The fracture element.
n_points : int
Number of points in the flow net.
margin : float
Margin for the flow net.
element_struc_array : np.ndarray[element_dtype]
Array of elements.
Returns
-------
flow_net : np.ndarray[complex]
The flow net for the fracture.
"""
# Create the z array
flow_net = np.zeros((n_points, n_points), dtype=np.complex128)
radius_margin = self_["radius"] * (1 + margin)
radius2 = self_["radius"] * self_["radius"]
x_array = np.linspace(-radius_margin, radius_margin, n_points)
y_array = np.linspace(-radius_margin, radius_margin, n_points)
for i in range(n_points):
for j in range(n_points):
z = x_array[i] + 1j * y_array[j]
if np.real(z * np.conj(z)) > radius2:
flow_net[j, i] = np.nan
else:
flow_net[j, i] = calc_omega(self_, z, element_struc_array)
return flow_net, x_array, y_array
[docs]
def head_from_phi(self_, phi):
"""
Calculates the head net for the fracture.
Parameters
----------
self_ : np.ndarray[fracture_dtype]
The fracture element.
phi : float
The discharge potential for the fracture.
Returns
-------
head : np.ndarray[complex]
The head net for the fracture.
"""
# Create the z array
head = phi / self_["t"]
return head
[docs]
@nb.njit(cache=CACHE)
def calc_heads(self_, n_points, margin, element_struc_array):
"""
Calculates the head net for the fracture.
Parameters
----------
self_ : np.ndarray[fracture_dtype]
The fracture element.
n_points : int
Number of points in the flow net.
margin : float
Margin for the flow net.
element_struc_array : np.ndarray[element_dtype]
Array of elements.
Returns
-------
heads : np.ndarray[complex]
The head net for the fracture.
"""
# Create the z array
heads = np.zeros((n_points, n_points), dtype=np.float64)
radius_margin = self_["radius"] * (1 + margin)
radius2 = self_["radius"] * self_["radius"]
x_array = np.linspace(-radius_margin, radius_margin, n_points)
y_array = np.linspace(-radius_margin, radius_margin, n_points)
t = self_["t"]
for i in range(n_points):
for j in range(n_points):
z = x_array[i] + 1j * y_array[j]
if np.real(z * np.conj(z)) > radius2:
heads[j, i] = np.nan
else:
phi = np.real(calc_omega(self_, z, element_struc_array))
heads[j, i] = phi / t
return heads, x_array, y_array
[docs]
@nb.njit(cache=CACHE, parallel=True)
def get_flow_nets(fracture_struc_array, n_points, margin, element_struc_array):
"""
Get the flow nets for all fractures.
Parameters
----------
fracture_struc_array : np.ndarray[fracture_dtype]
The fracture structure array.
n_points : int
Number of points in the flow net.
margin : float
Margin for the flow net.
element_struc_array : np.ndarray[element_dtype]
Array of elements.
Returns
-------
flow_nets : list[np.ndarray[complex]]
List of flow nets for each fracture.
"""
# Create the flow nets arrays
flow_nets = np.zeros(
(len(fracture_struc_array), n_points, n_points), dtype=np.complex128
)
x_arrays = np.zeros((len(fracture_struc_array), n_points), dtype=np.float64)
y_arrays = np.zeros((len(fracture_struc_array), n_points), dtype=np.float64)
for i in nb.prange(len(fracture_struc_array)):
flow_net, x_array, y_array = calc_flow_net(
fracture_struc_array[i], n_points, margin, element_struc_array
)
flow_nets[i] = flow_net
x_arrays[i] = x_array
y_arrays[i] = y_array
return flow_nets, x_arrays, y_arrays
[docs]
@nb.njit(cache=CACHE, parallel=True)
def get_heads(fracture_struc_array, n_points, margin, element_struc_array):
"""
Get the heads for all fractures.
Parameters
----------
fracture_struc_array : np.ndarray[fracture_dtype]
The fracture structure array.
n_points : int
Number of points in the flow net.
margin : float
Margin for the flow net.
element_struc_array : np.ndarray[element_dtype]
Array of elements.
Returns
-------
heads : list[np.ndarray[complex]]
List of heads for each fracture.
"""
# Create the heads arrays
heads = np.zeros((len(fracture_struc_array), n_points, n_points), dtype=np.float64)
x_arrays = np.zeros((len(fracture_struc_array), n_points), dtype=np.float64)
y_arrays = np.zeros((len(fracture_struc_array), n_points), dtype=np.float64)
for i in nb.prange(len(fracture_struc_array)):
head, x_array, y_array = calc_heads(
fracture_struc_array[i], n_points, margin, element_struc_array
)
heads[i] = head
x_arrays[i] = x_array
y_arrays[i] = y_array
return heads, x_arrays, y_arrays