Elliptic solvers¶
The rectangular elliptic solvers diagonalize constant-coefficient operators in a basis matched to the boundary condition. Periodic problems use the selectable FFT backend; homogeneous Dirichlet and Neumann problems use DST and DCT, respectively.
Poisson equation¶
OptiXDE solves:
Unified interface¶
poisson2d_solve(
f,
Lx,
Ly,
bc="periodic",
mode=None,
robin=None,
robin_max_iter=200,
robin_tol=1e-10,
robin_relax=0.02,
robin_penalty=10.0,
enforce_zero_mean_rhs=True,
fix_mean=True,
eps=1e-14,
backend=None,
backend_name="numpy",
workers=None,
return_info=False,
**backend_kwargs,
)
Parameters:
| Parameter | Description |
|---|---|
f |
Right-hand side with shape (Ny, Nx) |
Lx, Ly |
Positive physical domain lengths |
bc |
periodic, dirichlet, neumann, or robin |
robin |
Global or per-side (alpha, beta, g) specification |
enforce_zero_mean_rhs |
Subtract mean(f) in singular periodic/Neumann cases |
fix_mean |
Fix the Neumann solution gauge to zero mean |
eps |
Non-negative denominator regularization |
backend, backend_name |
Periodic FFT execution backend |
workers |
Thread hint for DST/DCT paths |
return_info |
Return (u, diagnostics) |
The result has the same shape as f. In Dirichlet mode the input must include
boundary nodes and the returned boundary is zero.
Specialized Poisson entry points¶
poisson2d_periodic(
f, Lx, Ly,
enforce_zero_mean_rhs=True,
eps=1e-14,
backend=None,
backend_name="numpy",
**backend_kwargs,
)
For nonzero Fourier modes,
The zero mode of f is cleared, and the zero mode of u is set to zero.
poisson2d_dirichlet(f, Lx, Ly, eps=1e-14, workers=None)
poisson2d_neumann(
f, Lx, Ly,
enforce_zero_mean_rhs=True,
fix_mean=True,
eps=1e-14,
workers=None,
)
The Dirichlet solver transforms only the interior array. The Neumann solver includes the constant cosine mode and therefore exposes compatibility and gauge controls.
poisson2d_robin_penalty(
f, Lx, Ly,
robin=None,
max_iter=200,
tol=1e-10,
relax=0.2,
penalty=10.0,
enforce_zero_mean_rhs=True,
fix_mean=True,
eps=1e-14,
backend=None,
backend_name="numpy",
**backend_kwargs,
)
This is a projected Richardson method with a fast periodic Poisson inverse as
preconditioner. It is practical for prototypes and moderate tolerances, but it
is not an exact Robin spectral diagonalization. Increasing penalty strengthens
boundary enforcement and may require decreasing relax.
Inhomogeneous Dirichlet lifting¶
The lower-level module optixde.solvers.base.poisson_inhom provides:
poisson2d_dirichlet_inhom(f, Lx, Ly, bc, workers=None)
build_tb_coons(bc, Lx, Ly)
laplacian_fd(u, Lx, Ly)
poisson2d_dirichlet_inhom builds a Coons-patch lifting from the four boundary
curves, solves a homogeneous Dirichlet correction, and overwrites the boundary
exactly. bc is a full (Ny, Nx) array; only its boundary values are used.
Shifted Helmholtz equation¶
OptiXDE uses the screened-Poisson convention:
Unified interface¶
helmholtz2d_solve(
f,
Lx,
Ly,
k0,
bc="fourier",
mode=None,
eps=1e-14,
backend=None,
backend_name="numpy",
workers=None,
return_info=False,
**backend_kwargs,
)
The spectral denominator is
For k0 > 0, the constant mode is nonsingular. When k0 = 0, the periodic and
Neumann cases reduce to a Laplacian problem; prefer poisson2d_solve when you
need explicit compatibility and gauge handling.
Specialized Helmholtz entry points¶
helmholtz2d_fourier(
f, Lx, Ly, k0,
eps=1e-14,
backend=None,
backend_name="numpy",
**backend_kwargs,
)
helmholtz2d_dirichlet(
f, Lx, Ly, k0,
eps=1e-14,
workers=None,
)
helmholtz2d_neumann(
f, Lx, Ly, k0,
eps=1e-14,
workers=None,
)
All return a real array with the same shape as f. The periodic path supports
NumPy, CuPy, and PyTorch backends. The real-transform paths are intended for
NumPy/CuPy-compatible inputs and return the corresponding array type.
Manufactured-solution check¶
import numpy as np
from optixde.solvers import poisson2d_solve
Nx = Ny = 129
Lx = Ly = 1.0
x = np.linspace(0.0, Lx, Nx)
y = np.linspace(0.0, Ly, Ny)
X, Y = np.meshgrid(x, y, indexing="xy")
u_exact = np.sin(np.pi * X) * np.sin(np.pi * Y)
f = 2.0 * np.pi**2 * u_exact
u = poisson2d_solve(f, Lx, Ly, bc="dirichlet")
relative_error = np.linalg.norm(u - u_exact) / np.linalg.norm(u_exact)
This example respects the library sign convention and includes boundary nodes, which are required by the DST path.