Open-source project
SciML/NeuralPDE.jl avatar
SciML/NeuralPDE.jl

NeuralPDE.jl: Physics-Informed Neural Network Solvers Behind a Symbolic PDE Interface

Physics-Informed Neural Networks (PINN) Solvers of (Partial) Differential Equations for Scientific Machine Learning (SciML) accelerated simulation

1,227 stars250 forksJuliaNOASSERTION

At a glance

What is it?
NeuralPDE.jl turns a symbolic PDESystem into a trainable loss function and hands the optimisation to the SciML ecosystem. It is a research-grade solver for people already inside Julia, not a drop-in replacement for a finite element code.
Who is it for?
Adopt NeuralPDE.jl if your problem is already expressed in ModelingToolkit symbols and you want a neural surrogate, an inverse problem, or a data-fitted solution rather than a mesh. Do not adopt it if you need a guaranteed error bound on a well-posed PDE, if you are not working in Julia, or if you cannot accept a training loop as the delivery mechanism.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Julia, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The gap NeuralPDE.jl fills: a PDE as a loss function instead of a mesh

Classical PDE solvers discretize the domain and solve the resulting algebraic system. NeuralPDE.jl does something different. The README describes it as a solver package consisting of neural network solvers for partial differential equations using physics-informed neural networks, and it states that the package uses neural stochastic differential equations to solve PDEs at increased generality compared with classical methods. The operative word is generality. A PINN does not need a mesh, so it does not need a mesh generator, and it does not need the domain to be a nice box. The residual of the differential equation becomes part of a loss function, and a neural network is trained until that residual is small on sampled points.

The intended user is visible in the dependencies the README names: ModelingToolkit, SciMLBase, Lux or Flux, and Optimization. This is a package for someone who already writes Julia and already thinks in SciML abstractions. The symbolic layer is not decoration. It is how the equation, the boundary conditions and the domains are passed in, and it is what allows the package to build the physics-informed loss automatically. The README lists automated construction of Physics-Informed loss functions from a high level symbolic interface as a feature, and that automation is the actual product. Writing a PINN by hand means differentiating the network output with respect to its inputs and assembling residual terms yourself; NeuralPDE.jl takes a PDESystem and does that assembly for you.

From PDESystem to OptimizationProblem: the discretize step

The pipeline has three moving parts, and the README example shows all of them. First, a symbolic problem is declared: parameters with @parameters, dependent variables with @variables, differential operators with Differential, an equation using ~, a vector of boundary conditions, and a vector of domains built from DomainSets.Interval. These are wrapped into a PDESystem with @named pde_system = PDESystem(eq, bcs, domains, [x, y], [u(x, y)]).

Second, a discretization is constructed from a neural network and a training strategy. In the README, discretization = PhysicsInformedNN(chain, QuadratureTraining()), where chain is a Lux.Chain of Dense layers and QuadratureTraining() is the sampling scheme used to evaluate the residual. The README lists quadrature training strategies, adaptive loss functions and neural adapters among the techniques used to accelerate training, so the second argument is a real choice rather than a formality.

Third, discretize(pde_system, discretization) returns a problem that the Optimization package can solve. That is the boundary between the physics side and the machine learning side. Everything before discretize is symbolic and deterministic; everything after is numerical and iterative. The trained network is then reachable as discretization.phi, which the README calls as phi([x, y], res.u) to evaluate the solution at a point. That call signature matters: the solution is a function of coordinates and a parameter vector, not a grid of values. You query it wherever you want.

Installing it and running the README Poisson example

Installation is the standard Julia package workflow. From the Pkg REPL, the README says to type ] add NeuralPDE. The README also notes that to exit Pkg REPL mode you press Backspace or Ctrl+C. There is no separate build step, no compiler configuration and no system dependency mentioned in the supplied material.

The example solves a 2D Poisson equation, Dxx(u(x, y)) + Dyy(u(x, y)) ~ -sin(pi * x) * sin(pi * y), on the unit square with homogeneous Dirichlet conditions on all four edges. The network is three Dense layers, 2 inputs to 16 to 16 to 1 output, with Lux.σ activations. Training is split into two Optimization.solve calls: ADAM(0.1) for 4000 iterations, then a remake of the problem with u0 = res.u and ADAM(0.01) for 2000 more. The callback prints the current loss and returns false, which is the convention for continuing rather than stopping.

The README then compares against the analytic solution (sin(pi * x) * sin(pi * y)) / (2pi^2) and plots the absolute difference. Two details are worth copying into your own work. The domain is sampled at dx/10 for the comparison grid, finer than the dx = 0.1 discretization variable, so the error plot is not evaluated on the training points. And the second solve reuses the first solution as its initialisation, which is the documented pattern for a learning-rate schedule here rather than a scheduler object. Note that the dx variable in the example is defined but not passed to PhysicsInformedNN, so its role in the README snippet is limited to the plotting grid.

Where a PINN solver is the wrong tool

A neural network solution carries no error bound. The README example validates against a closed-form answer, which is a luxury most real problems do not offer. If your PDE is well-posed, low-dimensional and you need a certified discretization error, a finite element or finite volume code gives you something NeuralPDE.jl does not attempt to give you.

Training cost is the second constraint. The README example runs 6000 optimiser iterations for a two-dimensional problem on the unit square with a three-layer network. That is a small problem, and the iteration count is still in the thousands. Scaling to three spatial dimensions plus time means more collocation points, a larger network, or both, and the README does not document a convergence guarantee that would let you predict the iteration count in advance. You tune it.

The third issue is that the loss is a weighted sum of a residual term and boundary terms, and the README does not describe how those weights are chosen by default. The feature list mentions adaptive loss functions, which suggests the package offers help here, but the example uses the default and reports only a single scalar loss per iteration. If your boundary conditions are being satisfied poorly while the interior residual looks small, the printed loss will not tell you which term is failing. You have to evaluate phi at the boundary yourself.

Finally, the license is recorded as NOASSERTION in the repository metadata. That is not a license grant. Before using NeuralPDE.jl in a product, read the LICENSE file in the repository and get your own answer on what it permits.

How this differs from a classical PDE solver

The comparison that matters is not NeuralPDE.jl against another PINN library. It is NeuralPDE.jl against a mesh-based solver such as a finite element package. The difference is in what you get back. A finite element solve returns a discretized field on a mesh, and the accuracy is tied to mesh refinement. NeuralPDE.jl returns a trained parameter vector and a callable phi, and the accuracy is tied to how well the optimiser drove the residual down. The README's own framing is that neural stochastic differential equations give greatly increased generality compared with classical methods, and the concrete form of that generality is that no mesh is constructed anywhere in the example.

That trade cuts both ways. Mesh-free means you can attack domains that are hard to mesh and equations whose operators are awkward to discretize, including the integro-differential and stochastic forms the README lists. Mesh-free also means you lose the refinement story. There is no h to halve. To improve the answer you enlarge the network, add collocation points, change the training strategy, or train longer, and none of those has a predictable error curve the way mesh refinement does.

The other real alternative is writing the PINN yourself in Flux or Lux. That is what NeuralPDE.jl automates. If your equation is unusual enough that the symbolic interface cannot express it, you are back to manual differentiation and manual loss assembly, and the package's value drops to its training strategies and logging. The README's stated compatibility with NeuralOperators.jl for mixing DeepONets and Fourier or Graph Neural Operators with physics-informed loss is the escape hatch for problems where a plain coordinate network is the wrong function class.

Maintenance, ecosystem coupling and upgrade cost

NeuralPDE.jl is not archived, and the release history in the repository metadata shows v6.3.0, v6.3.1 and v6.3.2 within a four-day window in September 2026. That cadence tells you the package is actively maintained. It also tells you something about upgrade cost: a major version in the 6.x line means the documented API in your code can move. The README example is written against the current interface, using Lux.Chain, PhysicsInformedNN and Optimization.solve, and older tutorials that use the Flux-based form or a different solve signature will not run unchanged.

The coupling is the real maintenance burden. NeuralPDE.jl sits on top of ModelingToolkit, SciMLBase, DomainSets, Lux or Flux, and Optimization. A breaking change in any of those propagates to your solver script. Pinning versions in a Project.toml is the practical defence, and it is worth doing before you build anything long-lived on this stack.

The license situation deserves a separate line. The repository metadata reports NOASSERTION, which means no license was detected or asserted by the tooling. The README does not state a license either. The README does ask that you cite the 2021 arXiv paper by Zubov et al. if you use the package in research, which is a citation request rather than a legal term. Treat the license as unresolved until you read the repository's own LICENSE file, and do not rely on this article for a legal conclusion.

Who should adopt it, and what to check before committing

Adopt NeuralPDE.jl if you are working in Julia, your problem is already expressible in ModelingToolkit symbols, and the thing you actually want is a differentiable surrogate: a solution you can evaluate at arbitrary points, differentiate, or fit against sparse data. The README's feature list explicitly covers mixing xDE solving with data fitting, and that combination is where a PINN beats a mesh solver outright. Adopt it too if your equation is stochastic, integro-differential, or defined on a domain you would rather not mesh.

Do not adopt it if you need a certified error bound, if your team is not in Julia, or if the deliverable is a field on a known grid that downstream tools already consume. Do not adopt it expecting the optimiser to be hands-off. The README example uses two ADAM stages with different learning rates and a manual remake between them, which is a tuning decision the user makes, not the package.

The first thing to verify is the discretize step on your own boundary conditions. Run the README Poisson example unchanged, confirm that u_predict tracks the analytic function in the error contour plot, then swap in your equation and check the boundary behaviour of phi directly rather than trusting the printed loss. If the boundary values drift while the loss falls, the weighting between the residual and the boundary terms is the place to look. The second thing to verify is the LICENSE file, since the metadata reports NOASSERTION and the README is silent on terms.

Editorial conclusion

Adopt NeuralPDE.jl if your problem is already expressed in ModelingToolkit symbols and you want a neural surrogate, an inverse problem, or a data-fitted solution rather than a mesh. Do not adopt it if you need a guaranteed error bound on a well-posed PDE, if you are not working in Julia, or if you cannot accept a training loop as the delivery mechanism. Verify first that your boundary conditions survive the discretize step by running the README Poisson example and comparing u_predict against the analytic function before you commit to a larger system.

Official sources

  1. Issues
  2. Project website
  3. README
  4. Releases
  5. SciML/NeuralPDE.jl on GitHub
Community notes

Community notes