export tutorials changed in 62fe6f8 (#670)

Co-authored-by: dario-coscia <dario-coscia@users.noreply.github.com>
This commit is contained in:
github-actions[bot]
2025-10-16 15:59:25 +02:00
committed by GitHub
parent 62fe6f81b5
commit 6d7ce0e4e2
4 changed files with 10234 additions and 86 deletions

View File

@@ -2,15 +2,15 @@
# coding: utf-8
# # Tutorial: Reduced Order Model with Graph Neural Networks
#
#
# [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/mathLab/PINA/blob/master/tutorials/tutorial22/tutorial.ipynb)
#
#
#
#
# > ##### ⚠️ ***Before starting:***
# > We assume you are already familiar with the concepts covered in the [Data Structure for SciML](https://mathlab.github.io/PINA/tutorial19/tutorial.html) tutorial. If not, we strongly recommend reviewing them before exploring this advanced topic.
#
#
# In this tutorial, we will demonstrate a typical use case of **PINA** for Reduced Order Modelling using Graph Convolutional Neural Network. The tutorial is largely inspired by the paper [A graph convolutional autoencoder approach to model order reduction for parametrized PDEs](https://www.sciencedirect.com/science/article/pii/S0021999124000111).
#
#
# Let's start by importing the useful modules:
# In[ ]:
@@ -25,7 +25,9 @@ except:
IN_COLAB = False
if IN_COLAB:
get_ipython().system('pip install "pina-mathlab[tutorial]"')
get_ipython().system('wget "https://github.com/mathLab/PINA/raw/refs/heads/master/tutorials/tutorial22/holed_poisson.pt" -O "holed_poisson.pt"')
get_ipython().system(
'wget "https://github.com/mathLab/PINA/raw/refs/heads/master/tutorials/tutorial22/holed_poisson.pt" -O "holed_poisson.pt"'
)
import torch
from torch import nn
@@ -49,22 +51,22 @@ from pina.problem.zoo import SupervisedProblem
# ## Data Generation
#
#
# In this tutorial, we will focus on solving the parametric **Poisson** equation, a linear PDE. The equation is given by:
#
#
# $$
# \begin{cases}
# -\frac{1}{10}\Delta u = 1, &\Omega(\boldsymbol{\mu}),\\
# u = 0, &\partial \Omega(\boldsymbol{\mu}).
# \end{cases}
# $$
#
# In this equation, $\Omega(\boldsymbol{\mu}) = [0, 1]\times[0,1] \setminus [\mu_1, \mu_2]\times[\mu_1+0.3, \mu_2+0.3]$ represents the spatial domain characterized by a parametrized hole defined via $\boldsymbol{\mu} = (\mu_1, \mu_2) \in \mathbb{P} = [0.1, 0.6]\times[0.1, 0.6]$. Thus, the geometrical parameters define the left bottom corner of a square obstacle of dimension $0.3$. The problem is coupled with homogenous Dirichlet conditions on both internal and external boundaries. In this setting, $u(\mathbf{x}, \boldsymbol{\mu})\in \mathbb{R}$ is the value of the function $u$ at each point in space for a specific parameter $\boldsymbol{\mu}$.
#
# We have already generated data for different parameters. The dataset is obtained via $\mathbb{P}^1$ FE method, and an equispaced sampling with 11 points in each direction of the parametric space.
#
#
# In this equation, $\Omega(\boldsymbol{\mu}) = [0, 1]\times[0,1] \setminus [\mu_1, \mu_2]\times[\mu_1+0.3, \mu_2+0.3]$ represents the spatial domain characterized by a parametrized hole defined via $\boldsymbol{\mu} = (\mu_1, \mu_2) \in \mathbb{P} = [0.1, 0.6]\times[0.1, 0.6]$. Thus, the geometrical parameters define the left bottom corner of a square obstacle of dimension $0.3$. The problem is coupled with homogenous Dirichlet conditions on both internal and external boundaries. In this setting, $u(\mathbf{x}, \boldsymbol{\mu})\in \mathbb{R}$ is the value of the function $u$ at each point in space for a specific parameter $\boldsymbol{\mu}$.
#
# We have already generated data for different parameters. The dataset is obtained via $\mathbb{P}^1$ FE method, and an equispaced sampling with 11 points in each direction of the parametric space.
#
# The goal is to build a Reduced Order Model that given a new parameter $\boldsymbol{\mu}^*$, is able to get the solution $u$ *for any discretization* $\mathbf{x}$. To this end, we will train a Graph Convolutional Autoencoder Reduced Order Model (GCA-ROM), as presented in [A graph convolutional autoencoder approach to model order reduction for parametrized PDEs](https://www.sciencedirect.com/science/article/pii/S0021999124000111). We will cover the architecture details later, but for now, lets start by importing the data.
#
#
# **Note:**
# The numerical integration is obtained using a finite element method with the [RBniCS library](https://www.rbnicsproject.org/).
@@ -93,42 +95,42 @@ plt.show()
# ## Graph-Based Reduced Order Modeling
#
#
# In this problem, the geometry of the spatial domain is **unstructured**, meaning that classical grid-based methods (e.g., CNNs) are not well suited. Instead, we represent the mesh as a **graph**, where nodes correspond to spatial degrees of freedom and edges represent connectivity. This makes **Graph Neural Networks (GNNs)**, and in particular **Graph Convolutional Networks (GCNs)**, a natural choice to process the data.
#
#
# <p align="center">
# <img src="http://raw.githubusercontent.com/mathLab/PINA/master/tutorials/static/gca_off_on_3_pina.png" alt="GCA-ROM" width="800"/>
# </p>
#
#
# To reduce computational complexity while preserving accuracy, we employ a **Reduced Order Modeling (ROM)** strategy (see picture above). The idea is to map high-dimensional simulation data $u(\mathbf{x}, \boldsymbol{\mu})$ to a compact **latent space** using a **graph convolutional encoder**, and then reconstruct it back via a **decoder** (offline phase). The latent representation captures the essential features of the solution manifold. Moreover, we can learn a **parametric map** $\mathcal{M}$ from the parameter space $\boldsymbol{\mu}$ directly into the latent space, enabling predictions for new unseen parameters.
#
#
# Formally, the autoencoder consists of an **encoder** $\mathcal{E}$, a **decoder** $\mathcal{D}$, and a **parametric mapping** $\mathcal{M}$:
# $$
# z = \mathcal{E}(u(\mathbf{x}, \boldsymbol{\mu})),
# z = \mathcal{E}(u(\mathbf{x}, \boldsymbol{\mu})),
# \quad
# \hat{u}(\mathbf{x}, \boldsymbol{\mu}) = \mathcal{D}(z),
# \quad
# \hat{z} = \mathcal{M}(\boldsymbol{\mu}),
# $$
# where $z \in \mathbb{R}^r$ is the latent representation with $r \ll N$ (the number of degrees of freedom) and the **hat notation** ($\hat{u}, \hat{z}$) indicates *learned or approximated quantities*.
#
#
# The training objective balances two terms:
# 1. **Reconstruction loss**: ensuring the autoencoder can faithfully reconstruct $u$ from $z$.
# 2. **Latent consistency loss**: enforcing that the parametric map $\mathcal{M}(\boldsymbol{\mu})$ approximates the encoders latent space.
#
#
# The combined loss function is:
# $$
# \mathcal{L}(\theta) = \frac{1}{N} \sum_{i=1}^N
# \big\| u(\mathbf{x}, \boldsymbol{\mu}_i) -
# \mathcal{D}\!\big(\mathcal{E}(u(\mathbf{x}, \boldsymbol{\mu}_i))\big)
# \mathcal{L}(\theta) = \frac{1}{N} \sum_{i=1}^N
# \big\| u(\mathbf{x}, \boldsymbol{\mu}_i) -
# \mathcal{D}\!\big(\mathcal{E}(u(\mathbf{x}, \boldsymbol{\mu}_i))\big)
# \big\|_2^2
# \;+\; \frac{1}{N} \sum_{i=1}^N
# \big\| \mathcal{E}(u(\mathbf{x}, \boldsymbol{\mu}_i)) - \mathcal{M}(\boldsymbol{\mu}_i) \big\|_2^2.
# $$
# This framework leverages the expressive power of GNNs for unstructured geometries and the efficiency of ROMs for handling parametric PDEs.
#
#
# We will now build the autoencoder network, which is a `nn.Module` with two methods: `encode` and `decode`.
#
#
# In[3]:
@@ -196,17 +198,17 @@ class GraphConvolutionalAutoencoder(nn.Module):
# Great! We now need to build the graph structure (a PyTorch Geometric `Data` object) from the numerical solver outputs.
#
#
# The solver provides the solution values $u(\mathbf{x}, \boldsymbol{\mu})$ for each parameter instance $\boldsymbol{\mu}$, along with the node coordinates $(x, y)$ of the unstructured mesh. Because the geometry is not defined on a regular grid, we naturally represent the mesh as a graph:
#
# - **Nodes** correspond to spatial points in the mesh. Each node stores the **solution value** $u$ at that point as a feature.
#
# - **Nodes** correspond to spatial points in the mesh. Each node stores the **solution value** $u$ at that point as a feature.
# - **Edges** represent mesh connectivity. For each edge, we compute:
# - **Edge attributes**: the relative displacement vector between the two nodes.
# - **Edge weights**: the Euclidean distance between the connected nodes.
# - **Edge attributes**: the relative displacement vector between the two nodes.
# - **Edge weights**: the Euclidean distance between the connected nodes.
# - **Positions** store the physical $(x, y)$ coordinates of the nodes.
#
#
# For each parameter realization $\boldsymbol{\mu}_i$, we therefore construct a PyTorch Geometric `Data` object:
#
#
# In[4]:
@@ -237,11 +239,11 @@ for g in range(num_graphs):
# ## Training with PINA
#
# Everything is now ready! We can use **PINA** to train the model, following the workflow from previous tutorials. First, we need to define the problem. In this case, we will use the [`SupervisedProblem`](https://mathlab.github.io/PINA/_rst/problem/zoo/supervised_problem.html#module-pina.problem.zoo.supervised_problem), which expects:
#
# - **Input**: the parameter tensor $\boldsymbol{\mu}$ describing each scenario.
# - **Output**: the corresponding graph structure (PyTorch Geometric `Data` object) that we aim to reconstruct.
#
# Everything is now ready! We can use **PINA** to train the model, following the workflow from previous tutorials. First, we need to define the problem. In this case, we will use the [`SupervisedProblem`](https://mathlab.github.io/PINA/_rst/problem/zoo/supervised_problem.html#module-pina.problem.zoo.supervised_problem), which expects:
#
# - **Input**: the parameter tensor $\boldsymbol{\mu}$ describing each scenario.
# - **Output**: the corresponding graph structure (PyTorch Geometric `Data` object) that we aim to reconstruct.
# In[5]:
@@ -249,9 +251,9 @@ for g in range(num_graphs):
problem = SupervisedProblem(params, graphs)
# Next, we build the **autoencoder network** and the **interpolation network**.
#
# - The **Graph Convolutional Autoencoder (GCA)** encodes the high-dimensional graph data into a compact latent space and reconstructs the graphs from this latent representation.
# Next, we build the **autoencoder network** and the **interpolation network**.
#
# - The **Graph Convolutional Autoencoder (GCA)** encodes the high-dimensional graph data into a compact latent space and reconstructs the graphs from this latent representation.
# - The **interpolation network** (or parametric map) learns to map a new parameter $\boldsymbol{\mu}^*$ directly into the latent space, enabling the model to predict solutions for unseen parameter instances without running the full encoder.
# In[6]:
@@ -269,11 +271,11 @@ interpolation_network = FeedForward(
)
# Finally, we will use the [`ReducedOrderModelSolver`](https://mathlab.github.io/PINA/_rst/solver/supervised_solver/reduced_order_model.html#pina.solver.supervised_solver.reduced_order_model.ReducedOrderModelSolver) to perform the training, as discussed earlier.
#
# This solver requires two components:
# - an **interpolation network**, which maps parameters $\boldsymbol{\mu}$ to the latent space, and
# - a **reduction network**, which in our case is the **autoencoder** that compresses and reconstructs the graph data.
# Finally, we will use the [`ReducedOrderModelSolver`](https://mathlab.github.io/PINA/_rst/solver/supervised_solver/reduced_order_model.html#pina.solver.supervised_solver.reduced_order_model.ReducedOrderModelSolver) to perform the training, as discussed earlier.
#
# This solver requires two components:
# - an **interpolation network**, which maps parameters $\boldsymbol{\mu}$ to the latent space, and
# - a **reduction network**, which in our case is the **autoencoder** that compresses and reconstructs the graph data.
# In[7]:
@@ -319,8 +321,8 @@ trainer.train()
# Once the model is trained, we can test the reconstruction by following two steps:
#
# 1. **Interpolate**: Use the `interpolation_network` to map a new parameter $\boldsymbol{\mu}^*$ to the latent space.
#
# 1. **Interpolate**: Use the `interpolation_network` to map a new parameter $\boldsymbol{\mu}^*$ to the latent space.
# 2. **Decode**: Pass the interpolated latent vector through the autoencoder (`reduction_network`) to reconstruct the corresponding graph data.
# In[9]:
@@ -392,18 +394,18 @@ plt.ticklabel_format()
plt.show()
# Nice! We can see that the network is correctly learning the solution operator, and the workflow was very straightforward.
#
# Nice! We can see that the network is correctly learning the solution operator, and the workflow was very straightforward.
#
# You may notice that the network outputs are not as smooth as the actual solution. Dont worry — training for longer (e.g., ~5000 epochs) will produce a smoother, more accurate reconstruction.
#
#
# ## What's Next?
#
#
# Congratulations on completing the introductory tutorial on **Graph Convolutional Reduced Order Modeling**! Now that you have a solid foundation, here are a few directions to explore:
#
#
# 1. **Experiment with Training Duration** — Try different training durations and adjust the network architecture to optimize performance. Explore different integral kernels and observe how the results vary.
#
#
# 2. **Explore Physical Constraints** — Incorporate physics-informed terms or constraints during training to improve model generalization and ensure physically consistent predictions.
#
#
# 3. **...and many more!** — The possibilities are vast! Continue experimenting with advanced configurations, solvers, and features in PINA.
#
#
# For more resources and tutorials, check out the [PINA Documentation](https://mathlab.github.io/PINA/).