optixde 0.2.2__tar.gz → 0.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {optixde-0.2.2 → optixde-0.2.4}/CHANGELOG.md +32 -1
- {optixde-0.2.2 → optixde-0.2.4}/CITATION.cff +3 -3
- {optixde-0.2.2 → optixde-0.2.4}/PKG-INFO +47 -19
- {optixde-0.2.2 → optixde-0.2.4}/README.md +46 -18
- optixde-0.2.4/optixde/custom_pde/__init__.py +62 -0
- optixde-0.2.4/optixde/custom_pde/compiler.py +309 -0
- optixde-0.2.4/optixde/custom_pde/errors.py +23 -0
- optixde-0.2.4/optixde/custom_pde/ir.py +45 -0
- optixde-0.2.4/optixde/custom_pde/solver.py +270 -0
- optixde-0.2.4/optixde/custom_pde/symbolic.py +169 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/__init__.py +55 -1
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/base/__init__.py +36 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/base/burgers.py +146 -13
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/base/cylinder_flow.py +111 -35
- optixde-0.2.4/optixde/solvers/base/cylinder_re200.py +422 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/base/navier_stokes.py +293 -76
- optixde-0.2.4/optixde/solvers/cylinder_re200.py +7 -0
- optixde-0.2.4/optixde/solvers/dfg_cylinder.py +935 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/navier_stokes.py +8 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/solid/__init__.py +2 -0
- optixde-0.2.4/optixde/solvers/solid/elastic_halfspace.py +326 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/version.py +1 -1
- {optixde-0.2.2 → optixde-0.2.4}/optixde.egg-info/PKG-INFO +47 -19
- {optixde-0.2.2 → optixde-0.2.4}/optixde.egg-info/SOURCES.txt +17 -0
- {optixde-0.2.2 → optixde-0.2.4}/pyproject.toml +1 -1
- {optixde-0.2.2 → optixde-0.2.4}/tests/test_burgers.py +72 -0
- optixde-0.2.4/tests/test_custom_pde.py +246 -0
- optixde-0.2.4/tests/test_cylinder_flow_paper.py +225 -0
- optixde-0.2.4/tests/test_cylinder_re200.py +174 -0
- optixde-0.2.4/tests/test_dfg_cylinder.py +245 -0
- optixde-0.2.4/tests/test_elastic_halfspace.py +83 -0
- optixde-0.2.4/tests/test_lshape_poisson_paper.py +84 -0
- {optixde-0.2.2 → optixde-0.2.4}/tests/test_navier_stokes.py +48 -0
- optixde-0.2.4/tests/test_nonlinear_schrodinger_paper.py +43 -0
- {optixde-0.2.2 → optixde-0.2.4}/tests/test_public_api.py +7 -0
- {optixde-0.2.2 → optixde-0.2.4}/tests/test_validation.py +12 -0
- {optixde-0.2.2 → optixde-0.2.4}/LICENSE +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/MANIFEST.in +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/__init__.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/bc/__init__.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/bc/rasterize.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/bc/robin.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/bc/segmented.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/fft_backend/__init__.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/fft_backend/base.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/fft_backend/cupy_backend.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/fft_backend/numpy_backend.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/fft_backend/propagator_cache.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/fft_backend/torch_backend.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/geometry/__init__.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/geometry/boolean.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/geometry/primitives.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/operators/__init__.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/operators/spectral.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/operators/transforms.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/post/__init__.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/post/plotting.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/_diagnostics.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/allen_cahn.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/base/allen_cahn.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/base/diffusion.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/base/etd.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/base/helmholtz.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/base/ode.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/base/poisson.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/base/poisson_inhom.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/base/schrodinger.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/base/wave.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/burgers.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/cylinder_flow.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/diffusion.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/helmholtz.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/poisson.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/schrodinger.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/segmented/__init__.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/segmented/poisson.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/segmented/polygonal.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/segmented/transient.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/solid/elasticity_dynamic.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/solid/elasticity_static.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/solid/postprocess.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/splitting.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde/solvers/wave.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde.egg-info/dependency_links.txt +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde.egg-info/requires.txt +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/optixde.egg-info/top_level.txt +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/setup.cfg +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/tests/test_allen_cahn.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/tests/test_backend_cache.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/tests/test_core_solvers.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/tests/test_cylinder_flow.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/tests/test_cylinder_flow_example.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/tests/test_import.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/tests/test_robin.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/tests/test_schrodinger.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/tests/test_solver_convergence.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/tests/test_solver_diagnostics.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/tests/test_splitting.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/tests/test_torch_backend.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/tests/test_transforms.py +0 -0
- {optixde-0.2.2 → optixde-0.2.4}/tests/test_wave.py +0 -0
|
@@ -7,6 +7,35 @@ and OptiXDE uses semantic versioning for public releases.
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.4] - 2026-08-16
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- An additive `optixde.custom_pde` subsystem for compiling scalar,
|
|
15
|
+
constant-coefficient, two-dimensional periodic linear PDEs into steady or
|
|
16
|
+
transient generic spectral execution plans.
|
|
17
|
+
- A hybrid-spectral two-dimensional elastic half-space solver in
|
|
18
|
+
`optixde.solvers.solid`, supporting a traction-free surface, absorbing
|
|
19
|
+
exterior layers, configurable source histories, and sampled wavefields.
|
|
20
|
+
- Backend-independent periodic immersed-boundary Navier--Stokes utilities for
|
|
21
|
+
NumPy and CuPy, including nonzero mean flow and split constraints.
|
|
22
|
+
- Exact three-halves padding dealiasing for the periodic Burgers solver.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- Updated the Burgers and immersed-cylinder paper examples to call the public
|
|
27
|
+
`optixde.solvers` implementations while preserving their numerical kernels
|
|
28
|
+
and reference outputs.
|
|
29
|
+
- Aligned the canonical Re=200 paper driver with the final frozen production
|
|
30
|
+
configuration (ND=24/32/40, eta=0.0025, compact mask width 1h, T=100).
|
|
31
|
+
|
|
32
|
+
## [0.2.3] - 2026-08-04
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- Fixed the PyPI project-page logo by using an absolute HTTPS image URL.
|
|
37
|
+
- Removed the benchmark-reference subsection from the main README.
|
|
38
|
+
|
|
10
39
|
## [0.2.2] - 2026-07-27
|
|
11
40
|
|
|
12
41
|
### Added
|
|
@@ -77,7 +106,9 @@ and OptiXDE uses semantic versioning for public releases.
|
|
|
77
106
|
modules are still experimental and should be validated for each research use
|
|
78
107
|
case.
|
|
79
108
|
|
|
80
|
-
[Unreleased]: https://github.com/yangyLab/OptiXDE/compare/v0.2.
|
|
109
|
+
[Unreleased]: https://github.com/yangyLab/OptiXDE/compare/v0.2.4...main
|
|
110
|
+
[0.2.4]: https://github.com/yangyLab/OptiXDE/releases/tag/v0.2.4
|
|
111
|
+
[0.2.3]: https://github.com/yangyLab/OptiXDE/releases/tag/v0.2.3
|
|
81
112
|
[0.2.2]: https://github.com/yangyLab/OptiXDE/releases/tag/v0.2.2
|
|
82
113
|
[0.2.1]: https://github.com/yangyLab/OptiXDE/releases/tag/v0.2.1
|
|
83
114
|
[0.2.0]: https://github.com/yangyLab/OptiXDE/releases/tag/v0.2.0
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
cff-version: 1.2.0
|
|
2
2
|
message: "If you use OptiXDE in academic work, please cite this software and the related paper or preprint when available."
|
|
3
3
|
title: "OptiXDE: optical-inspired PDE solvers"
|
|
4
|
-
version: "0.2.
|
|
5
|
-
date-released: "2026-
|
|
4
|
+
version: "0.2.4"
|
|
5
|
+
date-released: "2026-08-16"
|
|
6
6
|
type: software
|
|
7
7
|
license: MIT
|
|
8
8
|
authors:
|
|
@@ -10,7 +10,7 @@ authors:
|
|
|
10
10
|
given-names: "Yang"
|
|
11
11
|
email: "yangyhhu@foxmail.com"
|
|
12
12
|
repository-code: "https://github.com/yangyLab/OptiXDE"
|
|
13
|
-
url: "https://github.com/yangyLab/OptiXDE/releases/tag/v0.2.
|
|
13
|
+
url: "https://github.com/yangyLab/OptiXDE/releases/tag/v0.2.4"
|
|
14
14
|
abstract: "OptiXDE is a lightweight Python package for optical-inspired, matrix-free spectral solvers for differential equations on uniform grids, with examples for linear PDEs, nonlinear splitting, flow, wave propagation, and GPU-oriented periodic FFT workflows."
|
|
15
15
|
keywords:
|
|
16
16
|
- PDE
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: optixde
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: OptiXDE: optical-inspired PDE solver
|
|
5
5
|
Author-email: Yang Yang <yangyhhu@foxmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -33,13 +33,13 @@ Requires-Dist: twine>=5; extra == "dev"
|
|
|
33
33
|
Dynamic: license-file
|
|
34
34
|
|
|
35
35
|
<p align="center">
|
|
36
|
-
<img src="optixde_logo_horizontal.svg" alt="OptiXDE logo" width="620">
|
|
36
|
+
<img src="./optixde_logo_horizontal.svg" alt="OptiXDE logo" width="620">
|
|
37
37
|
</p>
|
|
38
38
|
|
|
39
39
|
# OptiXDE
|
|
40
40
|
|
|
41
41
|
[](pyproject.toml)
|
|
42
|
-
[](https://github.com/yangyLab/OptiXDE/releases/tag/v0.2.4)
|
|
43
43
|
[](#development)
|
|
44
44
|
[](docs/colab_torch_gpu.md)
|
|
45
45
|
|
|
@@ -59,8 +59,11 @@ The core convention is consistent across the package:
|
|
|
59
59
|
|
|
60
60
|
- **Matrix-free solvers** for Poisson, Helmholtz, diffusion, and wave equations.
|
|
61
61
|
- **Operator splitting** utilities for nonlinear PDEs such as Allen--Cahn.
|
|
62
|
+
- **Custom linear PDE compilation** from symbolic equations to periodic
|
|
63
|
+
spectral operators, without changing the existing specialized solvers.
|
|
62
64
|
- **Nonlinear examples** for Allen--Cahn and 1D periodic viscous Burgers.
|
|
63
65
|
- **Periodic incompressible flow** via 2D vorticity-streamfunction Navier--Stokes.
|
|
66
|
+
- **Periodic immersed-cylinder flow** with a Brinkman mask and inflow-restoring fringe.
|
|
64
67
|
- **Schrödinger/paraxial propagation** for optical-style complex wave fields.
|
|
65
68
|
- **FFT/DCT/DST transforms** for periodic, Dirichlet, and Neumann boundary
|
|
66
69
|
conditions.
|
|
@@ -233,6 +236,10 @@ Current PyTorch scope:
|
|
|
233
236
|
vorticity-streamfunction Navier--Stokes, and Schrödinger FFT paths.
|
|
234
237
|
- Supported: CPU tensors and CUDA tensors, depending on your PyTorch install.
|
|
235
238
|
- Not yet supported: Torch DCT/DST paths for Dirichlet and Neumann solvers.
|
|
239
|
+
- Periodic Brinkman/fringe Navier--Stokes supports NumPy and CuPy arrays; the
|
|
240
|
+
compatibility `cylinder_re200_*` names refer to the same general solver.
|
|
241
|
+
- The final Re=200 paper driver defaults to CuPy/CUDA and provides
|
|
242
|
+
`--backend numpy` for CPU smoke and regression runs.
|
|
236
243
|
|
|
237
244
|
For Colab GPU validation, see `docs/colab_torch_gpu.md`.
|
|
238
245
|
|
|
@@ -321,6 +328,39 @@ python examples/base/navier_stokes_cylinder_brinkman.py --nx 96 --ny 48 --steps
|
|
|
321
328
|
python examples/base/schrodinger_gaussian_packet.py --n 128 --T 1.0
|
|
322
329
|
```
|
|
323
330
|
|
|
331
|
+
Compile a scalar constant-coefficient periodic PDE:
|
|
332
|
+
|
|
333
|
+
```python
|
|
334
|
+
from optixde.custom_pde import Equation, Field, compile_pde, dt, laplacian, solve_pde
|
|
335
|
+
|
|
336
|
+
u = Field("u")
|
|
337
|
+
problem = compile_pde(
|
|
338
|
+
Equation(dt(u), 0.05 * laplacian(u)),
|
|
339
|
+
shape=u0.shape,
|
|
340
|
+
domain=(Lx, Ly),
|
|
341
|
+
)
|
|
342
|
+
times, states = solve_pde(problem, u0, dt=0.01, t_end=1.0)
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
The first compiler version supports one scalar field, constant coefficients,
|
|
346
|
+
two-dimensional periodic domains, steady equations, and first-order transient
|
|
347
|
+
equations with derivatives up to fourth order. Existing PDE-specific solver
|
|
348
|
+
APIs remain unchanged.
|
|
349
|
+
|
|
350
|
+
The paper Burgers driver uses the public solver with fourth-order nonlinear
|
|
351
|
+
stages and exact three-halves padding:
|
|
352
|
+
|
|
353
|
+
```python
|
|
354
|
+
u_next = burgers1d_step(
|
|
355
|
+
u,
|
|
356
|
+
nu,
|
|
357
|
+
L,
|
|
358
|
+
dt,
|
|
359
|
+
nonlinear_order=4,
|
|
360
|
+
dealias="three_halves",
|
|
361
|
+
)
|
|
362
|
+
```
|
|
363
|
+
|
|
324
364
|
Run the unified reference-validation table:
|
|
325
365
|
|
|
326
366
|
```bash
|
|
@@ -343,6 +383,8 @@ Primary public imports:
|
|
|
343
383
|
|
|
344
384
|
- `from optixde.solvers import poisson2d_solve, diffusion2d_solve, wave2d_solve`
|
|
345
385
|
- `from optixde.solvers import burgers1d_solve, navier_stokes2d_vorticity_solve`
|
|
386
|
+
- `from optixde.solvers import navier_stokes2d_brinkman_fringe_step`
|
|
387
|
+
- `from optixde.solvers import cylinder_re200_step` (compatibility alias)
|
|
346
388
|
- `from optixde.solvers import schrodinger2d_solve, allen_cahn2d_solve`
|
|
347
389
|
|
|
348
390
|
PDE-specific modules are also kept as stable compatibility namespaces:
|
|
@@ -355,6 +397,7 @@ PDE-specific modules are also kept as stable compatibility namespaces:
|
|
|
355
397
|
- `optixde.solvers.allen_cahn`
|
|
356
398
|
- `optixde.solvers.burgers`
|
|
357
399
|
- `optixde.solvers.navier_stokes`
|
|
400
|
+
- `optixde.solvers.cylinder_re200`
|
|
358
401
|
- `optixde.solvers.schrodinger`
|
|
359
402
|
- `optixde.fft_backend`
|
|
360
403
|
- `optixde.geometry`
|
|
@@ -399,27 +442,12 @@ from `CITATION.cff`.
|
|
|
399
442
|
author = {Yang, Yang},
|
|
400
443
|
year = {2026},
|
|
401
444
|
url = {https://github.com/yangyLab/OptiXDE},
|
|
402
|
-
version = {0.2.
|
|
445
|
+
version = {0.2.4},
|
|
403
446
|
}
|
|
404
447
|
```
|
|
405
448
|
|
|
406
449
|
Release notes are tracked in `CHANGELOG.md`.
|
|
407
450
|
|
|
408
|
-
### Benchmark References
|
|
409
|
-
|
|
410
|
-
Several examples reuse published benchmark problem definitions for independent
|
|
411
|
-
OptiXDE implementations and comparisons:
|
|
412
|
-
|
|
413
|
-
- M. Raissi, P. Perdikaris, and G. E. Karniadakis, “Physics-informed neural
|
|
414
|
-
networks: A deep learning framework for solving forward and inverse problems
|
|
415
|
-
involving nonlinear partial differential equations,” *Journal of
|
|
416
|
-
Computational Physics*, 378, 686–707 (2019),
|
|
417
|
-
[doi:10.1016/j.jcp.2018.10.045](https://doi.org/10.1016/j.jcp.2018.10.045).
|
|
418
|
-
- L. Lu, X. Meng, Z. Mao, and G. E. Karniadakis, “DeepXDE: A deep learning
|
|
419
|
-
library for solving differential equations,” *SIAM Review*, 63(1), 208–228
|
|
420
|
-
(2021),
|
|
421
|
-
[doi:10.1137/19M1274067](https://doi.org/10.1137/19M1274067).
|
|
422
|
-
|
|
423
451
|
## Copyright, License, and Disclaimer
|
|
424
452
|
|
|
425
453
|
Copyright (c) 2025-2026 Yang Yang
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="optixde_logo_horizontal.svg" alt="OptiXDE logo" width="620">
|
|
2
|
+
<img src="./optixde_logo_horizontal.svg" alt="OptiXDE logo" width="620">
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
# OptiXDE
|
|
6
6
|
|
|
7
7
|
[](pyproject.toml)
|
|
8
|
-
[](https://github.com/yangyLab/OptiXDE/releases/tag/v0.2.4)
|
|
9
9
|
[](#development)
|
|
10
10
|
[](docs/colab_torch_gpu.md)
|
|
11
11
|
|
|
@@ -25,8 +25,11 @@ The core convention is consistent across the package:
|
|
|
25
25
|
|
|
26
26
|
- **Matrix-free solvers** for Poisson, Helmholtz, diffusion, and wave equations.
|
|
27
27
|
- **Operator splitting** utilities for nonlinear PDEs such as Allen--Cahn.
|
|
28
|
+
- **Custom linear PDE compilation** from symbolic equations to periodic
|
|
29
|
+
spectral operators, without changing the existing specialized solvers.
|
|
28
30
|
- **Nonlinear examples** for Allen--Cahn and 1D periodic viscous Burgers.
|
|
29
31
|
- **Periodic incompressible flow** via 2D vorticity-streamfunction Navier--Stokes.
|
|
32
|
+
- **Periodic immersed-cylinder flow** with a Brinkman mask and inflow-restoring fringe.
|
|
30
33
|
- **Schrödinger/paraxial propagation** for optical-style complex wave fields.
|
|
31
34
|
- **FFT/DCT/DST transforms** for periodic, Dirichlet, and Neumann boundary
|
|
32
35
|
conditions.
|
|
@@ -199,6 +202,10 @@ Current PyTorch scope:
|
|
|
199
202
|
vorticity-streamfunction Navier--Stokes, and Schrödinger FFT paths.
|
|
200
203
|
- Supported: CPU tensors and CUDA tensors, depending on your PyTorch install.
|
|
201
204
|
- Not yet supported: Torch DCT/DST paths for Dirichlet and Neumann solvers.
|
|
205
|
+
- Periodic Brinkman/fringe Navier--Stokes supports NumPy and CuPy arrays; the
|
|
206
|
+
compatibility `cylinder_re200_*` names refer to the same general solver.
|
|
207
|
+
- The final Re=200 paper driver defaults to CuPy/CUDA and provides
|
|
208
|
+
`--backend numpy` for CPU smoke and regression runs.
|
|
202
209
|
|
|
203
210
|
For Colab GPU validation, see `docs/colab_torch_gpu.md`.
|
|
204
211
|
|
|
@@ -287,6 +294,39 @@ python examples/base/navier_stokes_cylinder_brinkman.py --nx 96 --ny 48 --steps
|
|
|
287
294
|
python examples/base/schrodinger_gaussian_packet.py --n 128 --T 1.0
|
|
288
295
|
```
|
|
289
296
|
|
|
297
|
+
Compile a scalar constant-coefficient periodic PDE:
|
|
298
|
+
|
|
299
|
+
```python
|
|
300
|
+
from optixde.custom_pde import Equation, Field, compile_pde, dt, laplacian, solve_pde
|
|
301
|
+
|
|
302
|
+
u = Field("u")
|
|
303
|
+
problem = compile_pde(
|
|
304
|
+
Equation(dt(u), 0.05 * laplacian(u)),
|
|
305
|
+
shape=u0.shape,
|
|
306
|
+
domain=(Lx, Ly),
|
|
307
|
+
)
|
|
308
|
+
times, states = solve_pde(problem, u0, dt=0.01, t_end=1.0)
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
The first compiler version supports one scalar field, constant coefficients,
|
|
312
|
+
two-dimensional periodic domains, steady equations, and first-order transient
|
|
313
|
+
equations with derivatives up to fourth order. Existing PDE-specific solver
|
|
314
|
+
APIs remain unchanged.
|
|
315
|
+
|
|
316
|
+
The paper Burgers driver uses the public solver with fourth-order nonlinear
|
|
317
|
+
stages and exact three-halves padding:
|
|
318
|
+
|
|
319
|
+
```python
|
|
320
|
+
u_next = burgers1d_step(
|
|
321
|
+
u,
|
|
322
|
+
nu,
|
|
323
|
+
L,
|
|
324
|
+
dt,
|
|
325
|
+
nonlinear_order=4,
|
|
326
|
+
dealias="three_halves",
|
|
327
|
+
)
|
|
328
|
+
```
|
|
329
|
+
|
|
290
330
|
Run the unified reference-validation table:
|
|
291
331
|
|
|
292
332
|
```bash
|
|
@@ -309,6 +349,8 @@ Primary public imports:
|
|
|
309
349
|
|
|
310
350
|
- `from optixde.solvers import poisson2d_solve, diffusion2d_solve, wave2d_solve`
|
|
311
351
|
- `from optixde.solvers import burgers1d_solve, navier_stokes2d_vorticity_solve`
|
|
352
|
+
- `from optixde.solvers import navier_stokes2d_brinkman_fringe_step`
|
|
353
|
+
- `from optixde.solvers import cylinder_re200_step` (compatibility alias)
|
|
312
354
|
- `from optixde.solvers import schrodinger2d_solve, allen_cahn2d_solve`
|
|
313
355
|
|
|
314
356
|
PDE-specific modules are also kept as stable compatibility namespaces:
|
|
@@ -321,6 +363,7 @@ PDE-specific modules are also kept as stable compatibility namespaces:
|
|
|
321
363
|
- `optixde.solvers.allen_cahn`
|
|
322
364
|
- `optixde.solvers.burgers`
|
|
323
365
|
- `optixde.solvers.navier_stokes`
|
|
366
|
+
- `optixde.solvers.cylinder_re200`
|
|
324
367
|
- `optixde.solvers.schrodinger`
|
|
325
368
|
- `optixde.fft_backend`
|
|
326
369
|
- `optixde.geometry`
|
|
@@ -365,27 +408,12 @@ from `CITATION.cff`.
|
|
|
365
408
|
author = {Yang, Yang},
|
|
366
409
|
year = {2026},
|
|
367
410
|
url = {https://github.com/yangyLab/OptiXDE},
|
|
368
|
-
version = {0.2.
|
|
411
|
+
version = {0.2.4},
|
|
369
412
|
}
|
|
370
413
|
```
|
|
371
414
|
|
|
372
415
|
Release notes are tracked in `CHANGELOG.md`.
|
|
373
416
|
|
|
374
|
-
### Benchmark References
|
|
375
|
-
|
|
376
|
-
Several examples reuse published benchmark problem definitions for independent
|
|
377
|
-
OptiXDE implementations and comparisons:
|
|
378
|
-
|
|
379
|
-
- M. Raissi, P. Perdikaris, and G. E. Karniadakis, “Physics-informed neural
|
|
380
|
-
networks: A deep learning framework for solving forward and inverse problems
|
|
381
|
-
involving nonlinear partial differential equations,” *Journal of
|
|
382
|
-
Computational Physics*, 378, 686–707 (2019),
|
|
383
|
-
[doi:10.1016/j.jcp.2018.10.045](https://doi.org/10.1016/j.jcp.2018.10.045).
|
|
384
|
-
- L. Lu, X. Meng, Z. Mao, and G. E. Karniadakis, “DeepXDE: A deep learning
|
|
385
|
-
library for solving differential equations,” *SIAM Review*, 63(1), 208–228
|
|
386
|
-
(2021),
|
|
387
|
-
[doi:10.1137/19M1274067](https://doi.org/10.1137/19M1274067).
|
|
388
|
-
|
|
389
417
|
## Copyright, License, and Disclaimer
|
|
390
418
|
|
|
391
419
|
Copyright (c) 2025-2026 Yang Yang
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025-2026 Yang Yang <yangyhhu@foxmail.com>
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
"""Compile scalar constant-coefficient periodic PDEs to spectral solvers."""
|
|
5
|
+
|
|
6
|
+
from .compiler import CompiledLinearPDE, analyze_equation, compile_pde
|
|
7
|
+
from .errors import PDECompileError, PDEError, PDESolveError, UnsupportedPDEError
|
|
8
|
+
from .ir import IR_VERSION, LinearPDEIR, LinearTerm, SourceTerm
|
|
9
|
+
from .solver import solve_pde, solve_steady, solve_transient
|
|
10
|
+
from .symbolic import (
|
|
11
|
+
Add,
|
|
12
|
+
Constant,
|
|
13
|
+
Derivative,
|
|
14
|
+
Equation,
|
|
15
|
+
Expr,
|
|
16
|
+
Field,
|
|
17
|
+
Mul,
|
|
18
|
+
Source,
|
|
19
|
+
TimeDerivative,
|
|
20
|
+
biharmonic,
|
|
21
|
+
derivative,
|
|
22
|
+
dt,
|
|
23
|
+
dx,
|
|
24
|
+
dxx,
|
|
25
|
+
dy,
|
|
26
|
+
dyy,
|
|
27
|
+
laplacian,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
__all__ = [
|
|
31
|
+
"Expr",
|
|
32
|
+
"Constant",
|
|
33
|
+
"Field",
|
|
34
|
+
"Source",
|
|
35
|
+
"Add",
|
|
36
|
+
"Mul",
|
|
37
|
+
"Derivative",
|
|
38
|
+
"TimeDerivative",
|
|
39
|
+
"Equation",
|
|
40
|
+
"derivative",
|
|
41
|
+
"dx",
|
|
42
|
+
"dy",
|
|
43
|
+
"dxx",
|
|
44
|
+
"dyy",
|
|
45
|
+
"laplacian",
|
|
46
|
+
"biharmonic",
|
|
47
|
+
"dt",
|
|
48
|
+
"IR_VERSION",
|
|
49
|
+
"LinearTerm",
|
|
50
|
+
"SourceTerm",
|
|
51
|
+
"LinearPDEIR",
|
|
52
|
+
"CompiledLinearPDE",
|
|
53
|
+
"analyze_equation",
|
|
54
|
+
"compile_pde",
|
|
55
|
+
"solve_steady",
|
|
56
|
+
"solve_transient",
|
|
57
|
+
"solve_pde",
|
|
58
|
+
"PDEError",
|
|
59
|
+
"PDECompileError",
|
|
60
|
+
"UnsupportedPDEError",
|
|
61
|
+
"PDESolveError",
|
|
62
|
+
]
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025-2026 Yang Yang <yangyhhu@foxmail.com>
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
"""Compiler from the custom PDE expression tree to a periodic spectral plan."""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
|
|
10
|
+
from optixde.fft_backend import NumpyBackend
|
|
11
|
+
|
|
12
|
+
from .errors import PDECompileError, UnsupportedPDEError
|
|
13
|
+
from .ir import IR_VERSION, LinearPDEIR, LinearTerm, SourceTerm
|
|
14
|
+
from .symbolic import (
|
|
15
|
+
Add,
|
|
16
|
+
Constant,
|
|
17
|
+
Derivative,
|
|
18
|
+
Equation,
|
|
19
|
+
Field,
|
|
20
|
+
Mul,
|
|
21
|
+
Source,
|
|
22
|
+
TimeDerivative,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class _AnalysisState:
|
|
28
|
+
fields: set
|
|
29
|
+
time_coefficient: complex
|
|
30
|
+
linear_terms: list
|
|
31
|
+
source_terms: list
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass(frozen=True)
|
|
35
|
+
class CompiledLinearPDE:
|
|
36
|
+
"""Grid/backend-bound execution plan produced from :class:`LinearPDEIR`."""
|
|
37
|
+
|
|
38
|
+
ir: LinearPDEIR
|
|
39
|
+
shape: tuple
|
|
40
|
+
domain: tuple
|
|
41
|
+
backend: object
|
|
42
|
+
grids: object
|
|
43
|
+
spatial_symbol: object
|
|
44
|
+
evolution_symbol: object
|
|
45
|
+
zero_mode_policy: str
|
|
46
|
+
singular_tolerance: float
|
|
47
|
+
real_output: bool
|
|
48
|
+
specialized_hint: object
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def problem_type(self):
|
|
52
|
+
return self.ir.problem_type
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def report(self):
|
|
56
|
+
return {
|
|
57
|
+
"ir_version": self.ir.version,
|
|
58
|
+
"field": self.ir.field_name,
|
|
59
|
+
"problem_type": self.ir.problem_type,
|
|
60
|
+
"boundary": self.ir.boundary,
|
|
61
|
+
"shape": self.shape,
|
|
62
|
+
"domain": self.domain,
|
|
63
|
+
"max_spatial_order": self.ir.max_spatial_order,
|
|
64
|
+
"linear_term_count": len(self.ir.linear_terms),
|
|
65
|
+
"source_names": tuple(
|
|
66
|
+
term.name for term in self.ir.source_terms if term.name is not None
|
|
67
|
+
),
|
|
68
|
+
"specialized_hint": self.specialized_hint,
|
|
69
|
+
"backend": self.backend.name,
|
|
70
|
+
"device": str(self.backend.device),
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _constant_value(expression):
|
|
75
|
+
if isinstance(expression, Constant):
|
|
76
|
+
return expression.value
|
|
77
|
+
if isinstance(expression, Mul):
|
|
78
|
+
left = _constant_value(expression.left)
|
|
79
|
+
right = _constant_value(expression.right)
|
|
80
|
+
if left is not None and right is not None:
|
|
81
|
+
return left * right
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _collect(expression, state, *, scale=1.0, derivative_orders=(0, 0)):
|
|
86
|
+
if isinstance(expression, Add):
|
|
87
|
+
for term in expression.terms:
|
|
88
|
+
_collect(term, state, scale=scale, derivative_orders=derivative_orders)
|
|
89
|
+
return
|
|
90
|
+
|
|
91
|
+
if isinstance(expression, Mul):
|
|
92
|
+
left_constant = _constant_value(expression.left)
|
|
93
|
+
right_constant = _constant_value(expression.right)
|
|
94
|
+
if left_constant is not None:
|
|
95
|
+
_collect(
|
|
96
|
+
expression.right,
|
|
97
|
+
state,
|
|
98
|
+
scale=scale * left_constant,
|
|
99
|
+
derivative_orders=derivative_orders,
|
|
100
|
+
)
|
|
101
|
+
return
|
|
102
|
+
if right_constant is not None:
|
|
103
|
+
_collect(
|
|
104
|
+
expression.left,
|
|
105
|
+
state,
|
|
106
|
+
scale=scale * right_constant,
|
|
107
|
+
derivative_orders=derivative_orders,
|
|
108
|
+
)
|
|
109
|
+
return
|
|
110
|
+
raise UnsupportedPDEError(
|
|
111
|
+
"Products between non-constant expressions are nonlinear or "
|
|
112
|
+
"variable-coefficient terms and are not supported in linear PDE v1."
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
if isinstance(expression, Derivative):
|
|
116
|
+
combined = tuple(
|
|
117
|
+
int(old) + int(new)
|
|
118
|
+
for old, new in zip(derivative_orders, expression.orders)
|
|
119
|
+
)
|
|
120
|
+
_collect(expression.expression, state, scale=scale, derivative_orders=combined)
|
|
121
|
+
return
|
|
122
|
+
|
|
123
|
+
if isinstance(expression, TimeDerivative):
|
|
124
|
+
if derivative_orders != (0, 0) or not isinstance(expression.expression, Field):
|
|
125
|
+
raise UnsupportedPDEError(
|
|
126
|
+
"Only a first time derivative of the unknown field is supported."
|
|
127
|
+
)
|
|
128
|
+
state.fields.add(expression.expression.name)
|
|
129
|
+
state.time_coefficient += scale
|
|
130
|
+
return
|
|
131
|
+
|
|
132
|
+
if isinstance(expression, Field):
|
|
133
|
+
state.fields.add(expression.name)
|
|
134
|
+
state.linear_terms.append(LinearTerm(scale, derivative_orders))
|
|
135
|
+
return
|
|
136
|
+
|
|
137
|
+
if isinstance(expression, Source):
|
|
138
|
+
if derivative_orders != (0, 0):
|
|
139
|
+
raise UnsupportedPDEError(
|
|
140
|
+
"Spatial derivatives of prescribed sources are not supported in v1."
|
|
141
|
+
)
|
|
142
|
+
state.source_terms.append(SourceTerm(scale, expression.name))
|
|
143
|
+
return
|
|
144
|
+
|
|
145
|
+
if isinstance(expression, Constant):
|
|
146
|
+
if derivative_orders != (0, 0):
|
|
147
|
+
return
|
|
148
|
+
state.source_terms.append(SourceTerm(scale * expression.value, None))
|
|
149
|
+
return
|
|
150
|
+
|
|
151
|
+
raise PDECompileError(f"Unknown expression node: {type(expression).__name__}.")
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def analyze_equation(equation):
|
|
155
|
+
"""Normalize ``lhs = rhs`` into a backend-independent linear PDE IR."""
|
|
156
|
+
if not isinstance(equation, Equation):
|
|
157
|
+
raise TypeError("compile_pde expects an Equation object.")
|
|
158
|
+
state = _AnalysisState(set(), 0.0, [], [])
|
|
159
|
+
_collect(equation.lhs, state)
|
|
160
|
+
_collect(equation.rhs, state, scale=-1.0)
|
|
161
|
+
|
|
162
|
+
if len(state.fields) != 1:
|
|
163
|
+
raise UnsupportedPDEError(
|
|
164
|
+
"Linear PDE v1 requires exactly one scalar unknown field; "
|
|
165
|
+
f"found {sorted(state.fields)!r}."
|
|
166
|
+
)
|
|
167
|
+
if not state.linear_terms and state.time_coefficient == 0:
|
|
168
|
+
raise PDECompileError("The equation contains no spatial or reaction operator.")
|
|
169
|
+
max_order = max(
|
|
170
|
+
(sum(term.derivative_orders) for term in state.linear_terms), default=0
|
|
171
|
+
)
|
|
172
|
+
if max_order > 4:
|
|
173
|
+
raise UnsupportedPDEError("Linear PDE v1 supports spatial derivatives up to order four.")
|
|
174
|
+
|
|
175
|
+
transient = state.time_coefficient != 0
|
|
176
|
+
return LinearPDEIR(
|
|
177
|
+
version=IR_VERSION,
|
|
178
|
+
field_name=next(iter(state.fields)),
|
|
179
|
+
problem_type="transient" if transient else "steady",
|
|
180
|
+
time_coefficient=state.time_coefficient,
|
|
181
|
+
linear_terms=tuple(state.linear_terms),
|
|
182
|
+
source_terms=tuple(state.source_terms),
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def _combine_terms(terms):
|
|
187
|
+
combined = {}
|
|
188
|
+
for term in terms:
|
|
189
|
+
combined[term.derivative_orders] = (
|
|
190
|
+
combined.get(term.derivative_orders, 0.0) + term.coefficient
|
|
191
|
+
)
|
|
192
|
+
return {orders: value for orders, value in combined.items() if value != 0}
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _specialized_hint(ir):
|
|
196
|
+
terms = _combine_terms(ir.linear_terms)
|
|
197
|
+
isotropic_second = (
|
|
198
|
+
(2, 0) in terms
|
|
199
|
+
and (0, 2) in terms
|
|
200
|
+
and terms[(2, 0)] == terms[(0, 2)]
|
|
201
|
+
)
|
|
202
|
+
spatial_second = set(terms).issubset({(0, 0), (2, 0), (0, 2)})
|
|
203
|
+
if ir.problem_type == "steady" and spatial_second and isotropic_second:
|
|
204
|
+
if set(terms) == {(2, 0), (0, 2)}:
|
|
205
|
+
return "poisson2d_solve"
|
|
206
|
+
if set(terms) == {(0, 0), (2, 0), (0, 2)}:
|
|
207
|
+
return "helmholtz2d_solve"
|
|
208
|
+
if (
|
|
209
|
+
ir.problem_type == "transient"
|
|
210
|
+
and set(terms) == {(2, 0), (0, 2)}
|
|
211
|
+
and isotropic_second
|
|
212
|
+
):
|
|
213
|
+
return "diffusion2d_solve"
|
|
214
|
+
if (
|
|
215
|
+
ir.problem_type == "steady"
|
|
216
|
+
and set(terms) == {(4, 0), (2, 2), (0, 4)}
|
|
217
|
+
and terms[(4, 0)] == terms[(0, 4)]
|
|
218
|
+
and terms[(2, 2)] == 2.0 * terms[(4, 0)]
|
|
219
|
+
):
|
|
220
|
+
return "generic_biharmonic"
|
|
221
|
+
return None
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _build_symbol(ir, grids):
|
|
225
|
+
symbol = 0j * grids.K2
|
|
226
|
+
for term in ir.linear_terms:
|
|
227
|
+
order_x, order_y = term.derivative_orders
|
|
228
|
+
contribution = term.coefficient
|
|
229
|
+
if order_x:
|
|
230
|
+
contribution = contribution * (1j * grids.KX) ** order_x
|
|
231
|
+
if order_y:
|
|
232
|
+
contribution = contribution * (1j * grids.KY) ** order_y
|
|
233
|
+
symbol = symbol + contribution
|
|
234
|
+
return symbol
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def _make_isolated_backend(backend_name, backend_kwargs):
|
|
238
|
+
"""Create a compiler-owned backend without touching legacy shared caches."""
|
|
239
|
+
name = str(backend_name or "numpy").lower()
|
|
240
|
+
if name in {"numpy", "np"}:
|
|
241
|
+
if backend_kwargs:
|
|
242
|
+
unexpected = ", ".join(sorted(backend_kwargs))
|
|
243
|
+
raise TypeError(f"NumPy backend does not accept: {unexpected}.")
|
|
244
|
+
return NumpyBackend()
|
|
245
|
+
if name in {"torch", "pytorch"}:
|
|
246
|
+
from optixde.fft_backend import TorchBackend
|
|
247
|
+
|
|
248
|
+
return TorchBackend(**backend_kwargs)
|
|
249
|
+
if name in {"cupy", "cp", "cufft"}:
|
|
250
|
+
from optixde.fft_backend import CuPyBackend
|
|
251
|
+
|
|
252
|
+
return CuPyBackend(**backend_kwargs)
|
|
253
|
+
raise ValueError(f"Unknown backend: {backend_name!r}.")
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def compile_pde(
|
|
257
|
+
equation,
|
|
258
|
+
*,
|
|
259
|
+
shape,
|
|
260
|
+
domain,
|
|
261
|
+
boundary="periodic",
|
|
262
|
+
backend=None,
|
|
263
|
+
backend_name="numpy",
|
|
264
|
+
zero_mode_policy="project",
|
|
265
|
+
singular_tolerance=1.0e-12,
|
|
266
|
+
real_output=True,
|
|
267
|
+
**backend_kwargs,
|
|
268
|
+
):
|
|
269
|
+
"""Compile a scalar constant-coefficient periodic PDE into a spectral plan."""
|
|
270
|
+
if str(boundary).lower() != "periodic":
|
|
271
|
+
raise UnsupportedPDEError("Linear PDE v1 supports periodic boundaries only.")
|
|
272
|
+
shape = tuple(int(value) for value in shape)
|
|
273
|
+
domain = tuple(float(value) for value in domain)
|
|
274
|
+
if len(shape) != 2 or any(value < 2 for value in shape):
|
|
275
|
+
raise ValueError("shape must be a two-dimensional (Ny, Nx) tuple.")
|
|
276
|
+
if len(domain) != 2 or any(value <= 0.0 for value in domain):
|
|
277
|
+
raise ValueError("domain must contain positive lengths (Lx, Ly).")
|
|
278
|
+
if zero_mode_policy not in {"project", "check", "raise"}:
|
|
279
|
+
raise ValueError("zero_mode_policy must be 'project', 'check', or 'raise'.")
|
|
280
|
+
if singular_tolerance <= 0.0:
|
|
281
|
+
raise ValueError("singular_tolerance must be positive.")
|
|
282
|
+
|
|
283
|
+
ir = analyze_equation(equation)
|
|
284
|
+
selected_backend = backend or _make_isolated_backend(backend_name, backend_kwargs)
|
|
285
|
+
ny, nx = shape
|
|
286
|
+
lx, ly = domain
|
|
287
|
+
grids = selected_backend.make_freq_grids(nx, ny, lx, ly)
|
|
288
|
+
spatial_symbol = _build_symbol(ir, grids)
|
|
289
|
+
evolution_symbol = (
|
|
290
|
+
-spatial_symbol / ir.time_coefficient
|
|
291
|
+
if ir.problem_type == "transient"
|
|
292
|
+
else None
|
|
293
|
+
)
|
|
294
|
+
return CompiledLinearPDE(
|
|
295
|
+
ir=ir,
|
|
296
|
+
shape=shape,
|
|
297
|
+
domain=domain,
|
|
298
|
+
backend=selected_backend,
|
|
299
|
+
grids=grids,
|
|
300
|
+
spatial_symbol=spatial_symbol,
|
|
301
|
+
evolution_symbol=evolution_symbol,
|
|
302
|
+
zero_mode_policy=zero_mode_policy,
|
|
303
|
+
singular_tolerance=float(singular_tolerance),
|
|
304
|
+
real_output=bool(real_output),
|
|
305
|
+
specialized_hint=_specialized_hint(ir),
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
__all__ = ["CompiledLinearPDE", "analyze_equation", "compile_pde"]
|