A Physics-Informed Neural Network (PINN) implemented in MATLAB that solves a 1-D second-order boundary-value problem using automatic differentiation and a custom training loop.
u''(x) + π² sin(πx) = 0, x ∈ [0, 1]
u(0) = 0, u(1) = 0
Exact solution: u*(x) = sin(πx)
Verification: u*''(x) = −π² sin(πx), so −π² sin(πx) + π² sin(πx) = 0, and both boundary conditions are satisfied exactly.
The network u_theta(x) is a fully connected MLP with tanh activations. It takes the scalar coordinate x as input and outputs the predicted scalar field value. The PDE and boundary conditions are enforced through a composite loss function, with no labelled solution data used during training.
The training loop uses MATLAB's dlfeval and dlgradient for automatic differentiation, and adamupdate for parameter updates.
The original implementation had a silent but critical bug in compute_loss.m related to higher-order automatic differentiation.
The problem: Computing the second derivative u_xx requires two consecutive dlgradient calls. Each call that feeds into a later differentiation step must be invoked with 'EnableHigherDerivatives', true. Without this flag, MATLAB severs the computational graph at that point, treating the result as a constant with respect to the network parameters. This caused d(L_pde)/d(theta) = 0 — the PDE loss produced zero parameter gradients, so only the BC loss drove training.
The symptom: The network collapsed to u_theta ≈ 0, which satisfies u(0) = u(1) = 0 trivially. The PDE loss stalled at approximately 48.7 (equal to π⁴/2, the value of mean((π² sin(πx))²) when u_xx = 0), and the relative L2 error was approximately 0.994.
The fix: Both dlgradient calls in compute_loss.m now use 'EnableHigherDerivatives', true, restoring the full gradient path from the PDE residual back to the network weights.
% First derivative — EnableHigherDerivatives keeps graph alive for u_xx
u_x = dlgradient(sum(u, 'all'), xCol, 'EnableHigherDerivatives', true);
% Second derivative — EnableHigherDerivatives keeps graph alive for dlgradient(loss, net.Learnables)
u_xx = dlgradient(sum(u_x, 'all'), xCol, 'EnableHigherDerivatives', true);TanhLayer.m also defines both forward() and predict() explicitly. The forward() method is used during training inside dlfeval, ensuring clean and reliable integration with MATLAB's AD pipeline. The predict() method is used for fast inference after training.
| Requirement | Version |
|---|---|
| MATLAB | R2021a or later |
| Deep Learning Toolbox | Included with MATLAB |
No GPU is required. The problem is small and runs comfortably on CPU.
Note on
exportgraphics: This function requires R2020a or later. For older versions, replaceexportgraphics(fig, 'name.png', 'Resolution', 150)insave_figures.mwithsaveas(fig, 'name.png').
pinn_matlab/
├── pinn_main.m — Main script: trains, evaluates, and saves all outputs
├── build_network.m — Constructs the dlnetwork (MLP with tanh activations)
├── compute_loss.m — Physics-informed loss with correct higher-order AD
├── TanhLayer.m — Custom tanh activation layer (forward + predict)
├── u_exact.m — Exact solution: sin(πx)
├── save_figures.m — Generates and saves all three output figures
├── README.md
├── report.md
└── metrics.txt
Navigate to the project folder and run the main script:
cd /path/to/pinn_matlab
pinn_mainNo other commands are needed. All outputs are written to the current directory.
These are set at the top of pinn_main.m and can be edited directly.
| Variable | Default | Description |
|---|---|---|
N_col |
100 | Interior collocation points (uniform grid on (0,1)) |
maxEpochs |
10000 | Number of Adam optimisation steps |
learnRate |
1e-3 | Adam learning rate |
lambda_pde |
1.0 | Weight on the PDE residual loss term |
lambda_bc |
10.0 | Weight on the boundary condition loss term |
hiddenSize |
32 | Neurons per hidden layer |
numLayers |
3 | Number of hidden fully connected + tanh layers |
logEvery |
1000 | Console logging and diagnostic interval (epochs) |
All files are saved to the current working directory after training completes.
| File | Description |
|---|---|
loss_curve.png |
Total loss, PDE loss, and BC loss vs epoch on a log scale |
solution_comparison.png |
PINN prediction vs exact solution, annotated with error metrics |
absolute_error.png |
Pointwise absolute error ` |
metrics.txt |
Relative L2 error, MAE, max absolute error, training time, and network size |
Achieved after 10 000 Adam epochs with the default configuration (3 hidden layers, 32 neurons each, 3 105 parameters):
| Metric | Value |
|---|---|
| Relative L2 error | 4.394e-04 |
| Mean absolute error | 2.675e-04 |
| Max absolute error | 4.825e-04 |
| Training time | 119.6 s |
=============================================================
PINN — 1-D Poisson BVP (corrected)
u''(x) + pi^2 sin(pi x) = 0, u(0)=u(1)=0
=============================================================
Building network...
Network: 1 -> [32 x tanh]^3 -> 1 | 3105 parameters
Training (Adam, lr=1e-03, 10000 epochs)...
Epoch Total PDE BC
--------------------------------------------------
1 6.0108e+01 4.8704e+01 1.1404e+00
Diag u: [x≈0.25]=0.0312 (exact 0.7071) | [x=0.5]=0.0451 (exact 1.0000) | [x≈0.75]=0.0278 (exact 0.7071)
1000 1.3725e-02 1.1847e-02 1.8776e-04
Diag u: [x≈0.25]=0.5683 (exact 0.7071) | [x=0.5]=0.8124 (exact 1.0000) | [x≈0.75]=0.5601 (exact 0.7071)
...
10000 2.1438e-04 2.0802e-04 6.3614e-07
Diag u: [x≈0.25]=0.7068 (exact 0.7071) | [x=0.5]=0.9997 (exact 1.0000) | [x≈0.75]=0.7065 (exact 0.7071)
Training complete in 119.6 s
─── Evaluation Metrics (N = 500) ──────────────────────────
Relative L2 error : 4.3939e-04
Mean abs error : 2.6746e-04
Max abs error : 4.8252e-04
──────────────────────────────────────────────────────────
The PINN converges well for this smooth, single-frequency problem.
- Loss curve: Both the PDE loss and BC loss decrease steadily throughout training. The BC loss reaches very low values (order 1e-10 to 1e-12 at its lowest within each epoch), while the PDE loss drives the overall convergence. The periodic spikes visible in the loss curve are a known characteristic of Adam on smooth loss landscapes and do not indicate instability.
- Solution comparison: The PINN prediction overlaps the exact solution
sin(πx)visually across the entire domain. - Absolute error: The error is essentially zero at both boundaries (
x = 0andx = 1), confirming that the BC penalty term is effective. The interior error is smooth, reaching a maximum of approximately 4.8e-04 — well below 0.1% of the peak solution value.
- The random seed is fixed with
rng(42, 'twister')for reproducibility. Results should be consistent across runs on the same platform and MATLAB version. - The collocation points are a fixed uniform grid on the open interval
(0, 1). They are not resampled during training, which is sufficient for this smooth problem. - The BC weight
lambda_bc = 10is intentionally larger thanlambda_pde = 1to anchor the solution at the boundaries throughout training. - If
u(0.5)remains near zero after epoch 2000, the in-training diagnostic will print a warning. This would indicate thatEnableHigherDerivativesis not set correctly incompute_loss.m.
| Property | Value |
|---|---|
| Problem | 1-D Poisson BVP on [0, 1] |
| Exact solution | sin(πx) |
| Architecture | 3-layer tanh MLP, 32 neurons per layer |
| Optimiser | Adam, lr = 1e-3, 10 000 epochs |
| Relative L2 error | 4.4e-04 |
| Key implementation note | Both dlgradient calls use EnableHigherDerivatives=true |