Metadata-Version: 2.4
Name: optixde
Version: 0.2.4
Summary: OptiXDE: optical-inspired PDE solver
Author-email: Yang Yang <yangyhhu@foxmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/yangyLab/OptiXDE
Project-URL: Repository, https://github.com/yangyLab/OptiXDE
Project-URL: Issues, https://github.com/yangyLab/OptiXDE/issues
Keywords: PDE,spectral methods,FFT,scientific computing,GPU
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.20
Provides-Extra: plot
Requires-Dist: matplotlib>=3.6; extra == "plot"
Provides-Extra: sparse
Requires-Dist: scipy>=1.9; extra == "sparse"
Provides-Extra: torch
Requires-Dist: torch; extra == "torch"
Provides-Extra: gpu
Requires-Dist: torch; extra == "gpu"
Provides-Extra: cupy
Requires-Dist: cupy; extra == "cupy"
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: coverage>=7.5; extra == "dev"
Requires-Dist: matplotlib>=3.6; extra == "dev"
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: ruff>=0.5; extra == "dev"
Requires-Dist: scipy>=1.9; extra == "dev"
Requires-Dist: twine>=5; extra == "dev"
Dynamic: license-file

<p align="center">
  <img src="./optixde_logo_horizontal.svg" alt="OptiXDE logo" width="620">
</p>

# OptiXDE

[![Python](https://img.shields.io/badge/python-3.9%2B-blue.svg)](pyproject.toml)
[![Release](https://img.shields.io/badge/release-v0.2.4-blueviolet.svg)](https://github.com/yangyLab/OptiXDE/releases/tag/v0.2.4)
[![Tests](https://img.shields.io/badge/tests-unittest-green.svg)](#development)
[![GPU](https://img.shields.io/badge/GPU-PyTorch%20periodic%20FFT-purple.svg)](docs/colab_torch_gpu.md)

OptiXDE is a lightweight Python package for optical-inspired PDE solvers on
uniform grids. It focuses on fast, matrix-free spectral methods for rectangular
domains, with experimental embedded-domain and solid-mechanics modules growing
alongside the core solver stack.

The core convention is consistent across the package:

- Poisson: `-Δu = f`
- Helmholtz: `(-Δ + k0^2)u = f`
- Diffusion: `u_t = D Δu`
- Wave: `u_tt = c^2 Δu`

## Highlights

- **Matrix-free solvers** for Poisson, Helmholtz, diffusion, and wave equations.
- **Operator splitting** utilities for nonlinear PDEs such as Allen--Cahn.
- **Custom linear PDE compilation** from symbolic equations to periodic
  spectral operators, without changing the existing specialized solvers.
- **Nonlinear examples** for Allen--Cahn and 1D periodic viscous Burgers.
- **Periodic incompressible flow** via 2D vorticity-streamfunction Navier--Stokes.
- **Periodic immersed-cylinder flow** with a Brinkman mask and inflow-restoring fringe.
- **Schrödinger/paraxial propagation** for optical-style complex wave fields.
- **FFT/DCT/DST transforms** for periodic, Dirichlet, and Neumann boundary
  conditions.
- **Robin boundary support** through specialized fallbacks and finite-difference
  projection helpers.
- **PyTorch backend** for periodic FFT solvers on CPU or CUDA GPUs.
- **Backend diagnostics** with `return_info=True` and capability flags.
- **Geometry helpers** for signed-distance primitives and Boolean operations.
- **Experimental modules** for segmented domains and periodic solid mechanics.

## Install

Install the current release from PyPI:

```bash
pip install optixde
```

Install optional features from PyPI as needed:

```bash
pip install "optixde[plot]"    # Matplotlib plotting helpers
pip install "optixde[sparse]"  # SciPy-based polygonal embedded solvers
pip install "optixde[gpu]"     # PyTorch backend for periodic GPU FFT solvers
```

For local development:

```bash
git clone https://github.com/yangyLab/OptiXDE.git
cd OptiXDE
pip install -e .
```

For development, optional feature groups can be installed from the checkout:

```bash
pip install -e ".[plot]"    # Matplotlib plotting helpers and examples
pip install -e ".[sparse]"  # SciPy-based polygonal embedded solvers
pip install -e ".[torch]"   # PyTorch backend alias
pip install -e ".[gpu]"     # PyTorch backend for periodic GPU FFT solvers
pip install -e ".[cupy]"    # CuPy backend, if your CUDA/CuPy stack is ready
pip install -e ".[dev]"     # tests, lint, plotting, sparse extras
```

## Quick Start

```python
import numpy as np
from optixde.solvers import (
    diffusion2d_solve,
    helmholtz2d_solve,
    poisson2d_solve,
    wave2d_solve,
)

Lx = Ly = 2.0 * np.pi
N = 64
x = np.linspace(0.0, Lx, N, endpoint=False)
y = np.linspace(0.0, Ly, N, endpoint=False)
X, Y = np.meshgrid(x, y, indexing="xy")

u_exact = np.sin(2 * X) * np.cos(3 * Y)
f = 13.0 * u_exact

u = poisson2d_solve(f, Lx, Ly, bc="periodic")
w = helmholtz2d_solve(f, Lx, Ly, k0=1.0, bc="periodic")
next_u = diffusion2d_solve(
    u_exact,
    D=0.1,
    Lx=Lx,
    Ly=Ly,
    dt=0.01,
    bc="periodic",
)
next_wave_u, next_wave_v = wave2d_solve(
    u_exact,
    np.zeros_like(u_exact),
    c=1.0,
    Lx=Lx,
    Ly=Ly,
    dt=0.01,
    bc="periodic",
)
```

## Solver Map

### Poisson

```python
u = poisson2d_solve(f, Lx, Ly, bc="periodic")
u = poisson2d_solve(f, Lx, Ly, bc="dirichlet")
u = poisson2d_solve(f, Lx, Ly, bc="neumann")
u = poisson2d_solve(f, Lx, Ly, bc="robin", robin=(alpha, beta, g))
```

Periodic and Neumann Poisson problems require `mean(f) = 0`; OptiXDE enforces
this by default and fixes the additive constant with a zero-mean gauge.

### Helmholtz

```python
u = helmholtz2d_solve(f, Lx, Ly, k0=1.0, bc="periodic")
u = helmholtz2d_solve(f, Lx, Ly, k0=1.0, bc="dirichlet")
u = helmholtz2d_solve(f, Lx, Ly, k0=1.0, bc="neumann")
```

`k0 > 0` makes the operator strictly elliptic, so no zero-mean constraint is
needed.

### Diffusion

```python
u = diffusion2d_solve(u0, D, Lx, Ly, dt, bc="periodic")
u = diffusion2d_solve(u0, D, Lx, Ly, dt, bc="dirichlet")
u = diffusion2d_solve(u0, D, Lx, Ly, dt, bc="neumann")
u = diffusion2d_solve(u0, D, Lx, Ly, dt, bc="robin", robin=(alpha, beta, g))
```

Periodic diffusion also supports an ETD1 source term through `source=`.

### Wave

```python
u, v = wave2d_solve(u0, v0, c, Lx, Ly, dt, bc="periodic")
u, v = wave2d_solve(u0, v0, c, Lx, Ly, dt, bc="dirichlet")
u, v = wave2d_solve(u0, v0, c, Lx, Ly, dt, bc="neumann")
```

The wave solver advances the first-order state `(u, v)` for `u_tt = c^2 Δu`
with an exact spectral update for each mode. With `return_info=True`, it returns
`u_next, v_next, info`.

## Boundary Conditions

| Boundary condition | Poisson | Helmholtz | Diffusion | Wave | Notes |
| --- | --- | --- | --- | --- | --- |
| `periodic` | Yes | Yes | Yes | Yes | FFT-based; supports NumPy, Torch, and CuPy backends. |
| `dirichlet` | Yes | Yes | Yes | Yes | DST-based rectangular-domain solver. |
| `neumann` | Yes | Yes | Yes | Yes | DCT-based rectangular-domain solver; Poisson uses a zero-mean gauge. |
| `robin` | Yes | No | Yes | No | Uses exact Dirichlet/Neumann fallbacks where possible and penalty/projection helpers otherwise. |

The older `mode=` keyword remains accepted as a compatibility alias for `bc=`.

## Backends And GPU

The default backend is NumPy:

```python
u = poisson2d_solve(f, Lx, Ly, bc="periodic", backend_name="numpy")
```

For GPU work, PyTorch is the recommended path:

```python
u = poisson2d_solve(
    f,
    Lx,
    Ly,
    bc="periodic",
    backend_name="torch",
    device="cuda",
)
```

Current PyTorch scope:

- Supported: periodic Poisson, Helmholtz, diffusion, wave, Burgers,
  vorticity-streamfunction Navier--Stokes, and Schrödinger FFT paths.
- Supported: CPU tensors and CUDA tensors, depending on your PyTorch install.
- Not yet supported: Torch DCT/DST paths for Dirichlet and Neumann solvers.
- Periodic Brinkman/fringe Navier--Stokes supports NumPy and CuPy arrays; the
  compatibility `cylinder_re200_*` names refer to the same general solver.
- The final Re=200 paper driver defaults to CuPy/CUDA and provides
  `--backend numpy` for CPU smoke and regression runs.

For Colab GPU validation, see `docs/colab_torch_gpu.md`.

## Diagnostics

Backends expose lightweight capability flags:

```python
from optixde.fft_backend import get_backend

backend = get_backend("torch", device="cuda")
print(backend.capabilities)
```

Solver entry points can return metadata with `return_info=True`:

```python
u, info = poisson2d_solve(
    f,
    Lx,
    Ly,
    bc="periodic",
    backend_name="torch",
    device="cuda",
    return_info=True,
)

print(info["backend"], info["device"], info["bc"], info["transform"])
```

Common `info` fields are stable across solvers:

- `solver`, `equation`, `bc`, `transform`: which equation and numerical path ran.
- `backend`, `device`, `capabilities`: NumPy/Torch/CuPy backend and feature flags.
- `input_shape`, `output_shape`, `input_dtype`, `output_dtype`: array metadata.
- PDE extras such as `dt`, `viscosity`, `epsilon`, `wave_speed`, or `coefficient`.

This is useful for tests, benchmarks, Colab runs, and checking whether a solve
used FFT, DCT, DST, operator splitting, or a fallback path.

## Examples

Example scripts live under `examples/`:

- `examples/base/`: core PDE demos and rectangular-domain experiments.
- `examples/benchmarks/`: CPU/GPU backend timing scripts and benchmark cases.
- `examples/solid/`: periodic solid-mechanics demos.
- `examples/demo_post.py`: plotting helper demo.

See `examples/README.md` for a command index.

Run a small backend benchmark:

```bash
python examples/benchmarks/torch_fft_backend_benchmark.py --device cpu --sizes 64 128
```

On a CUDA machine or Colab runtime:

```bash
python examples/benchmarks/colab_torch_gpu_smoke.py --device cuda --n 256
python examples/benchmarks/torch_fft_backend_benchmark.py --device cuda --sizes 512 1024
```

Run the paper-style wave examples:

```bash
python examples/base/wave_single_mode_phase.py --sizes 128 256 512
python examples/base/wave_gaussian_packet.py --n 256
python examples/base/wave_gaussian_packet.py --n 192 --sigma 0.28 --center-x 3.141592653589793 --center-y 3.141592653589793 --T 6 --animation-output output/animations/wave/gaussian_packet.gif
python examples/base/wave_section_6_3_reproduction.py --output-dir examples/artifacts/section_6_3_wave
```

Run the nonlinear Allen--Cahn splitting example:

```bash
python examples/base/allen_cahn_splitting.py --n 128 --T 0.1
python examples/base/burgers_1d_periodic.py --n 256 --T 1.0
python examples/base/burgers_1d_periodic.py --backend torch --device cuda --n 1024 --T 1.0
python examples/base/burgers_section_reproduction.py --n 256 --ref-n 2048 --output-dir examples/artifacts/burgers_section --scan
python examples/base/navier_stokes_taylor_green.py --n 128 --T 1.0
python examples/base/navier_stokes_cylinder_brinkman.py --nx 128 --ny 64 --steps 1000 --plot --output examples/artifacts/navier_stokes_cylinder_brinkman.png --history-output examples/artifacts/navier_stokes_cylinder_brinkman_history.csv --history-figure examples/artifacts/navier_stokes_cylinder_brinkman_history.png --summary-output examples/artifacts/navier_stokes_cylinder_summary.csv --wake-figure examples/artifacts/navier_stokes_cylinder_wake.png --spectrum-figure examples/artifacts/navier_stokes_cylinder_spectrum.png
python examples/base/navier_stokes_cylinder_brinkman.py --nx 160 --ny 80 --steps 16000 --dt 0.001 --viscosity 0.005 --forcing 0.05 --perturbation 0.08 --penalty-eta 0.002 --animation-output output/animations/navier_stokes/cylinder_wake_vorticity.gif --animation-stride 200 --animation-vmax 8 --quiet
python examples/base/navier_stokes_cylinder_brinkman.py --nx 128 --ny 64 --steps 5000 --report-every 10 --quiet
python examples/base/navier_stokes_cylinder_brinkman.py --nx 96 --ny 48 --steps 400 --scan --scan-viscosity 0.002 0.0036 --scan-forcing 0.1 0.15 --scan-output examples/artifacts/navier_stokes_cylinder_scan.csv --quiet
python examples/base/schrodinger_gaussian_packet.py --n 128 --T 1.0
```

Compile a scalar constant-coefficient periodic PDE:

```python
from optixde.custom_pde import Equation, Field, compile_pde, dt, laplacian, solve_pde

u = Field("u")
problem = compile_pde(
    Equation(dt(u), 0.05 * laplacian(u)),
    shape=u0.shape,
    domain=(Lx, Ly),
)
times, states = solve_pde(problem, u0, dt=0.01, t_end=1.0)
```

The first compiler version supports one scalar field, constant coefficients,
two-dimensional periodic domains, steady equations, and first-order transient
equations with derivatives up to fourth order. Existing PDE-specific solver
APIs remain unchanged.

The paper Burgers driver uses the public solver with fourth-order nonlinear
stages and exact three-halves padding:

```python
u_next = burgers1d_step(
    u,
    nu,
    L,
    dt,
    nonlinear_order=4,
    dealias="three_halves",
)
```

Run the unified reference-validation table:

```bash
python examples/benchmarks/solver_reference_validation.py --sizes 64 128 --output examples/artifacts/solver_reference_validation.csv
```

## Package Layout

```text
optixde/
  bc/             Robin, rasterization, and segmented-boundary helpers
  fft_backend/    NumPy, PyTorch, CuPy, and propagator-cache utilities
  geometry/       Signed-distance primitives and Boolean geometry
  operators/      Spectral operators and transform helpers
  post/           Optional Matplotlib plotting utilities
  solvers/        Core, segmented-domain, and solid-mechanics solvers
```

Primary public imports:

- `from optixde.solvers import poisson2d_solve, diffusion2d_solve, wave2d_solve`
- `from optixde.solvers import burgers1d_solve, navier_stokes2d_vorticity_solve`
- `from optixde.solvers import navier_stokes2d_brinkman_fringe_step`
- `from optixde.solvers import cylinder_re200_step` (compatibility alias)
- `from optixde.solvers import schrodinger2d_solve, allen_cahn2d_solve`

PDE-specific modules are also kept as stable compatibility namespaces:

- `optixde.solvers.poisson`
- `optixde.solvers.helmholtz`
- `optixde.solvers.diffusion`
- `optixde.solvers.wave`
- `optixde.solvers.splitting`
- `optixde.solvers.allen_cahn`
- `optixde.solvers.burgers`
- `optixde.solvers.navier_stokes`
- `optixde.solvers.cylinder_re200`
- `optixde.solvers.schrodinger`
- `optixde.fft_backend`
- `optixde.geometry`
- `optixde.bc`

## Development

Install development extras:

```bash
pip install -e ".[dev]"
```

Run tests:

```bash
python -m unittest discover -s tests -p "test*.py"
```

Optional checks:

```bash
python -m compileall -q optixde tests examples/benchmarks
python examples/benchmarks/solver_reference_validation.py --sizes 16 32 --burgers-ref-n 64 --burgers-dt 0.005 --burgers-ref-dt 0.0025 --burgers-T 0.02 --ns-dt 0.01 --ns-T 0.02 --wave-T 0.02
ruff check optixde tests
```

The test suite includes public import checks, transform checks, solver
diagnostics, Robin smoke tests, analytic convergence tests for the core
solvers, and a lightweight reference-validation benchmark used by CI. Torch GPU
tests are skipped automatically when PyTorch or CUDA is not available.

## Citation

If you use OptiXDE in academic work, please cite the software release and the
related paper or preprint when available. GitHub can read the citation metadata
from `CITATION.cff`.

```bibtex
@software{optixde2026,
  title   = {OptiXDE: optical-inspired PDE solvers},
  author  = {Yang, Yang},
  year    = {2026},
  url     = {https://github.com/yangyLab/OptiXDE},
  version = {0.2.4},
}
```

Release notes are tracked in `CHANGELOG.md`.

## Copyright, License, and Disclaimer

Copyright (c) 2025-2026 Yang Yang
<yangyhhu@foxmail.com>.

OptiXDE is open-source software distributed under the
[MIT License](LICENSE). You may use, copy, modify, and redistribute the
software subject to the terms of that license. Third-party libraries,
datasets, papers, and other referenced materials remain subject to their
respective licenses and copyrights.

OptiXDE is research software provided "as is", without warranty of any kind.
Numerical results should be independently verified before the software is used
for engineering, safety-critical, clinical, financial, or other consequential
decisions. The authors and contributors are not liable for losses or damages
arising from use of the software, to the extent permitted by applicable law.

Project information, source code, issue reporting, and release history are
available at [github.com/yangyLab/OptiXDE](https://github.com/yangyLab/OptiXDE).

## Project Status

OptiXDE is currently an early-stage research/development package. The stable
center is the rectangular-domain spectral solver stack; segmented-domain,
Robin, CuPy, and solid-mechanics pieces are still evolving.

When adding new solvers, keep the `-Δ` operator convention consistent across
the package and prefer backend-aware, matrix-free implementations where
possible.
