This project aims to use the PDE-Find method 1 for symbolic regression of the governing equation of PDEs. The PDE-Find method is an extension of the SINDy method 2 and it uses sparse regression to solve a linear system of equations (LSE) that contains the coefficients of the relevant terms of the governing equation as the unknown.
This README.md serves only as a brief overview on how to run our code. For more details, please see the project 2 section of the main project report.
Warning
Please make sure to create a data folder data/, then install and unzip the source datasets systems.zip from Polybox. Then move to the data/ folder and then perform unzip systems.zip to obtain the data files {X}.npz for X ∈ {1, 2, 3} before performing predictions.
Note
- The prediction file
results/prediction_1.txtis the redirection of the I/O by runningpython3 evaluate.py --system=1 > results/prediction_1.txt. - The prediction file
results/prediction_2.txtis the redirection of the I/O by runningpython3 evaluate.py --system=2 > results/prediction_2.txt. - The prediction file
results/prediction_3.txtis the redirection of the I/O by runningpython3 evaluate_2d.py > results/prediction_3.txt.
In project 2, we initially wanted to train simple feedforward neural networks (FNNs) on all three provided datasets, and then we can use the trained FNN to approximate the dataset better and then perform automatic differentiation to compute derivatives.
However, due to the high training cost, we only used FNN + automatic differentiation for the first two systems. For the third coupled system, we simply perform second-order accurate central differences method with first order estimates at the boundaries via torch.gradient directly on the dataset.
For affordable 1D datasets, we trained simple neural networks to approximate spatiotemporal solutions of the PDE, solely based on the provided X.npz dataset (for
# Train NN to approximate u(x,t) of the system 1 or 2
python3 train.py --system=1Before we can use the trained NN to approximate our solution, we can compare it against the ground truth using the provided dataset:
# Test out the NN and compare it against the dataset ground truth for system 1 or 2
python3 test.py --system=1This file will generate the a heat map of the approximated solution, as well as a gif showing the spatial-temporal evolution of the system. As we can see our approximation is of good quality, we can be reassured to further use the NN to compute derivatives. We also could visually already identify the first system to emerge from Burgers' equation, and the second system to be the Korteweg–De Vries equation (KdV equation) just from the animation and combined with the supplementary materials from the original paper 1. These assumptions will later be confirmed in our "Results" section too.
| System | Approximate Solution Heatmap | Solution Comparison |
|---|---|---|
| System 1 | ![]() |
![]() |
| System 2 | ![]() |
![]() |
In order to be able to flexibly generate candidate derivatives and specify eligible binary operations to be performed, we use SymPy to generate the candidate symbols automatically.
The symbols can be passed to different actual compute kernels that compute the specified derivatives. In our implementation, we provide these derivatives via automatic differentiation on the trained neural networks that approximate our solution data.
We opted to use the neural network-based approach for computing derivatives. The main motivation of this is because we want to leverage the power of automatic differentiation.
The feature library can now be built very easily because the results from automatic differentiation are already column vectors in our target shape. The only thing we need to do now is to assign these values column-wise to the
We provide concise utility functions build_theta and build_u_t for assembling the sparse LSE that can be directly used in the upcoming regression. The implementation of the algorithm can be found under optimizers.py
We used STRidge algorithm as in the PDE-Find paper 1 for obtaining sparse coefficient solution vector TrainSTRidge as in the original paper for automatic selecting the best parameters based on customizable split on the dataset, this function wraps around the STRidge and is called instead.
For applying PDE-Find on 2D datasets, we did not train a FNN, but performed the torch.gradient directly on the dataset as we stated earlier. For simplicity, we place the utility functions for building the feature library for the 2D data directly within the evaluate_2d.py script.
For solving the LSE with sparse regression, we reused previous routines. The identical TrainSTRidge algorithm as for previous systems is used but with slightly different parameters. One can find the original parameters we used for the final report also in the script.
By passing create_gif = True to the main function of the evaluate_2d.py script, one can visualize the underlying solution 3.npz) as animations. Based on the animations and the original paper 1, we assume the system of PDEs to be the reaction-diffusion system:
| System | Original Solution |
Original Velocity |
|---|---|---|
| System 3 | ![]() |
![]() |
Our results on all three systems are plausible and match our expectations on the guess of the systems as in previous section. The systems are governed by Burger's equation, KdV equation and reaction-diffusion equation respectively.
# Run PDE-Find and obtain symbols of governing equation for system 1
python3 evaluate.py --system=1running the PDE-Find algorithm based on 31 candidates
31 candidates: ['1', 'u', 'u**2', 'u**2*u_x', 'u**2*u_x**2', 'u**2*u_x**3', 'u**2*u_xx', 'u**2*u_xx**2', 'u**2*u_xx**3', 'u**3', 'u**3*u_x', 'u**3*u_x**2', 'u**3*u_x**3', 'u**3*u_xx', 'u**3*u_xx**2', 'u**3*u_xx**3', 'u*u_x', 'u*u_x**2', 'u*u_x**3', 'u*u_xx', 'u*u_xx**2', 'u*u_xx**3', 'u_x', 'u_x**2', 'u_x**3', 'u_xx', 'u_xx**2', 'u_xx**3', 'u_xxx', 'u_xxx**2', 'u_xxx**3']
we found the following equation for system 1:
With these coefficients, we compute the error between the LHS and the RHS and obtained for the first found PDE and got the relative L2 error is at around 3.140%.
For the second PDE solutions given by the dataset 2.npz, the same evaluate.py script is used, because we have again 1D solutions for one specific PDE:
# Similarly for system 2
python3 evaluate.py --system=2with 13 candidate terms,
13 candidates: ['1', 'u', 'u*u_t', 'u*u_tt', 'u*u_x', 'u*u_xx', 'u*u_xxx', 'u_t*u_x', 'u_tt', 'u_tt*u_xx', 'u_x', 'u_xx', 'u_xxx']we found the following equation for system 2:
With these coefficients, we compute the error between the LHS and the RHS and obtained for the first found PDE, which is around 4.389%.
To run the PDE-Find on the system 3:
# Run PDE-Find and obtain symbols of governing equation for system 3
python3 evaluate_2d.pywe used 23 candidates function to build the feature library
candidates ['u', 'u_x', 'u_y', 'u_xx', 'u_yy', 'u_xy', 'u**4', 'u**3', 'u**2', 'v', 'v_x', 'v_y', 'v_xx', 'v_yy', 'v_xy', 'v**4', 'v**3', 'v**2', 'u*v', 'u*v**2', 'u**2*v', 'u*v**3', 'u**3*v']
We obtain the following two equations
each with an relative L2 error of
Footnotes
-
Data-driven discovery of partial differential equations S. H. Rudy, S. L. Brunton, J. L. Proctor, and J. N. Kutz Science Advances, vol. 3, no. 4, 2017 [paper] ↩ ↩2 ↩3 ↩4
-
Discovering governing equations from data: Sparse identification of nonlinear dynamical systems S. L. Brunton, J. L. Proctor, and J. N. Kutz Proceedings of the National Academy of Sciences of the United States of America, vol. 113, no. 15, pp. 3932–3937, 2015 [paper] ↩





