Source code for yonderdrake.periodic.operator
"""Periodic Fourier fractional Laplacian."""
from __future__ import annotations
from math import isfinite
from typing import Any
from yonderdrake._firedrake import (
ExternalOperatorData,
require_real_float64_petsc,
)
[docs]
def PeriodicFractionalLaplacian(u: Any, s: Any) -> Any:
"""Create the Fourier multiplier ``(-Delta_periodic)^s``."""
try:
order = float(s)
except (TypeError, ValueError) as error:
raise TypeError("s must be a real scalar") from error
if not isfinite(order) or not 0.0 < order < 1.0:
raise ValueError("s must satisfy 0 < s < 1")
try:
space = u.function_space()
except AttributeError as error:
raise TypeError(
"u must be a Firedrake Function or symbolic coefficient"
) from error
if u.ufl_shape != ():
raise NotImplementedError(
"PeriodicFractionalLaplacian supports scalar fields only"
)
element = space.ufl_element()
degree = element.degree()
degrees = degree if isinstance(degree, tuple) else (degree,)
if element.family() not in {"Lagrange", "Q"} or any(
value != 1 for value in degrees
):
raise NotImplementedError(
"PeriodicFractionalLaplacian supports continuous degree-one "
"nodal fields only"
)
mesh = space.mesh()
dimension = int(mesh.geometric_dimension)
cell = mesh.ufl_cell().cellname
supported_cell = {1: "interval", 2: "quadrilateral", 3: "hexahedron"}
if dimension not in supported_cell or cell != supported_cell[dimension]:
raise NotImplementedError(
"PeriodicFractionalLaplacian currently supports 1D intervals, "
"2D quadrilateral rectangles, and 3D hexahedral boxes"
)
require_real_float64_petsc()
from yonderdrake.periodic._external import PeriodicExternalOperator
from yonderdrake.periodic.grid import PeriodicGridMap
grid = PeriodicGridMap.from_space(space)
return PeriodicExternalOperator(
u,
function_space=space,
operator_data=ExternalOperatorData(
order=order,
order_operand=s,
grid=grid,
manager=None,
),
)