Source code for fridom.framework.modules.closures.biharmonic_diffusion
"""Biharmonic diffusion module."""
from __future__ import annotations
import fridom.framework as fr
[docs]
@fr.utils.jaxify
class BiharmonicDiffusion(fr.modules.closures.HarmonicDiffusion):
r"""
Biharmonic diffusion module.
Description
-----------
Following Griffiies et al. (2000), the biharmonic mixing operator
:math:`\mathcal{B}` iterates twice over the harmonic mixing operator
:math:`\mathcal{H}`. For a scalar field :math:`u` it is given by:
.. math::
\mathcal{B}(u) = - \mathcal{H} \left( \mathcal{H}(u) \right)
where we use the biharmonic diffusion coefficient :math:`\sqrt{|\kappa_i|}`.
The index :math:`i` refers to the direction of the diffusion.
Parameters
----------
field_flags : list[str]
A list of strings that indicate which fields should be diffused.
For example, if `field_flags=["ENABLE_MIXING"]`, all fields with the
flag "ENABLE_MIXING" will be diffused. For more information on possible
flags, see :py:mod:`fridom.framework.ScalarField`.
diffusion_coefficients : tuple[float | fr.ScalarField]
A tuple of diffusion coefficients. The length of the tuple must match
the number of dimensions of the grid.
"""
name = "Biharmonic Diffusion"
[docs]
@fr.utils.jaxjit
def diffusion_operator(self, u: fr.ScalarField) -> fr.ScalarField:
"""Apply the biharmonic diffusion operator on a scalar field :math:`u`."""
# apply the first harmonic diffusion operator
div1 = super().diffusion_operator(u)
# apply the second harmonic diffusion operator
div2 = super().diffusion_operator(div1)
return - div2 * self._sign
# ----------------------------------------------------------------
# Properties
# ----------------------------------------------------------------
@property
def diffusion_coefficients(self) -> list[float | fr.ScalarField]:
"""A list of diffusion coefficients."""
return self._diffusion_coefficients
@diffusion_coefficients.setter
def diffusion_coefficients(self, value: tuple[float | fr.ScalarField]) -> None:
# we need to take the square root of the diffusion coefficients
ncp = fr.config.ncp
coeffs = []
for coeff in value:
if isinstance(coeff, fr.ScalarField):
self._sign = ncp.sign(coeff.arr)
kappa = ncp.sqrt(ncp.abs(coeff.arr))
kappa = fr.ScalarField(mset=coeff.mset,
arr=kappa,
mdata=coeff.mdata)
else:
self._sign = ncp.sign(coeff)
kappa = ncp.sqrt(ncp.abs(coeff))
coeffs.append(kappa)
self._diffusion_coefficients = coeffs