Skip to content
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
4149918
Partitioned Burgers eq. 1D initial commit. Dirichlet Neumann coupling.
vidulejs Sep 29, 2025
1dabcb0
Rename Flux to Gradient (du_dx). Print residual and compare gradient…
vidulejs Oct 1, 2025
6c8660c
Fully working Neumann surrogate participant. Scripts: run-partitione…
vidulejs Oct 14, 2025
82accc2
Rename surrogate burgers to neumann-surrogate
vidulejs Oct 14, 2025
2c425e4
activate-env.sh script
vidulejs Oct 14, 2025
5ab08f6
Add readme and requirements.txt. Move DG old files
vidulejs Oct 14, 2025
c5844c1
Rename solver-scipy-fvolumes to solver-scipy. Add proper run and clea…
vidulejs Oct 15, 2025
8b78407
Update README.md. Conform to tutorial images standard. Update run scr…
vidulejs Oct 15, 2025
2357008
add equation to readme
vidulejs Oct 15, 2025
5d66f9f
Remove DG solver
vidulejs Dec 15, 2025
8213367
Create utils directory and move scripts. Create output directory, sep…
vidulejs Dec 15, 2025
6546901
Update run scripts to conform to other preCICE tutorials. Fix package…
vidulejs Dec 15, 2025
20cab48
clean.sh to clean-tutorial.sh
vidulejs Dec 15, 2025
fd63b1d
remove comment from precice-config.xml
vidulejs Dec 15, 2025
9beb26b
Update README and add domain diagram image
vidulejs Dec 15, 2025
1e8b1ea
Specify IC script in readme
vidulejs Dec 15, 2025
11b91fc
Changelog entry
vidulejs Dec 15, 2025
854ad44
Updated format: #704
vidulejs Feb 3, 2026
292a672
Pre-commit formatting
vidulejs Feb 3, 2026
b193d05
Pre-commit formatting fix 2
vidulejs Feb 3, 2026
6c99c35
Allow skipping venv setup
vidulejs Feb 3, 2026
3c66728
Update readme ## Visualization
vidulejs Feb 5, 2026
bb434d9
Pre-commit formatting fix
vidulejs Feb 5, 2026
c06bede
Update changelog-entries/670.md
vidulejs Feb 20, 2026
83218df
Update partitioned-burgers-1d/README.md
vidulejs Feb 20, 2026
602a2b0
Merge branch 'develop' into partitioned-burgers-1d
vidulejs Feb 20, 2026
51d1b2f
Update clean.sh scripts in solver directories to match the other tuto…
vidulejs Feb 20, 2026
ea81634
Exclude utils and output folders in cleaning-tools.sh script. This wi…
vidulejs Feb 20, 2026
e692a53
Update precice-config.xml. Fix logging and change from serial to para…
vidulejs Feb 20, 2026
bbf7f20
Use pytorch CPU version by default, user can configure GPU version by…
vidulejs Feb 20, 2026
9a8dc51
Remove unnecessary comments and commented out code
vidulejs Feb 20, 2026
84cafd5
Fix formatting with pre-commit hook. Why did it flatten one but not t…
vidulejs Feb 20, 2026
a476880
Remove html image formatting from README.md. Change section Visualiza…
vidulejs Feb 20, 2026
1c69601
Update README.md
vidulejs Feb 20, 2026
ad6b1ee
Minor README changes
vidulejs Feb 20, 2026
4f36c9d
Update changelog-entries/670.md
MakisH Jun 11, 2026
d50d7fa
Merge branch 'develop' into partitioned-burgers-1d
MakisH Jun 11, 2026
a64d1ca
Add metadata.yaml
MakisH Jun 11, 2026
285b58e
Update venv handling
MakisH Jun 11, 2026
98cc4a8
Merge branch 'develop' into partitioned-burgers-1d
MakisH Jun 11, 2026
17b1244
Add *.npz to .gitignore
MakisH Jun 11, 2026
6d85d91
Setup logging earlier
MakisH Jun 11, 2026
d18ade4
Update venv handling in additional scripts
MakisH Jun 11, 2026
8bed094
Remove thin helper scripts
MakisH Jun 11, 2026
a739e1e
Adjust requirements.txt
MakisH Jun 11, 2026
7005053
Add more details about using generate_ic.py
MakisH Jun 11, 2026
20f8722
Make utils/generate-training-data.sh use solver-scipy/run.sh
MakisH Jun 11, 2026
ab00a15
Integrate into the system tests
MakisH Jun 11, 2026
5153005
Set TUTORIALS_REF
MakisH Jun 11, 2026
8c5deab
Add reference results for partitioned-burgers-1d
Jun 11, 2026
a57a54a
Reset TUTORIALS_REF
MakisH Jun 11, 2026
5bbae3d
Merge branch 'develop' into partitioned-burgers-1d
MakisH Jun 11, 2026
795f225
Further update venv handling
MakisH Jun 11, 2026
89ce0ad
Merge branch 'develop' into partitioned-burgers-1d
MakisH Jun 11, 2026
0b3ed91
Merge branch 'develop' into partitioned-burgers-1d
MakisH Jun 14, 2026
973de67
Add additional info on the NN checkpoints
Jun 16, 2026
e9124d8
Comment about the visualization timestep argument
Jun 16, 2026
04ff643
Add reference to thesis
Jun 16, 2026
494a5b2
Fix typo in argument
Jun 16, 2026
a224e9a
Optionally point to my development repo?
Jun 16, 2026
b360199
Fix trailing space
Jun 16, 2026
c922b84
Merge branch 'develop' into partitioned-burgers-1d
MakisH Jun 23, 2026
5913f65
Remove confusing mention of monolithic from the post-processing
MakisH Jun 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog-entries/670.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
New tutorial case: Partitioned Burgers' Equation in 1D solved with Finite Volumes and a Neural Network surrogate model !
Comment thread
vidulejs marked this conversation as resolved.
Outdated
141 changes: 141 additions & 0 deletions partitioned-burgers-1d/README.md
Comment thread
vidulejs marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
---
title: Partitioned Burgers' equation 1D
permalink: tutorials-partitioned-burgers-1d.html
keywords: Python, Neural Network, Surrogate, Burgers Equation, Finite Volume, CFD
summary: This tutorial demonstrates the partitioned solution of the 1D Burgers' equation using preCICE and a neural network surrogate solver.
---

{% note %}
Get the [case files of this tutorial](https://github.com/precice/tutorials/tree/develop/partitioned-burgers-1d), as continuously rendered here, or see the [latest released version](https://github.com/precice/tutorials/tree/master/partitioned-burgers-1d) (if there is already one). Read how in the [tutorials introduction](https://precice.org/tutorials.html).
{% endnote %}

## Setup

We solve the 1D viscous Burgers' equation on the domain $[0,2]$:

$$
\frac{\partial u}{\partial t} = \nu \frac{\partial^2 u}{\partial x^2} - u \frac{\partial u}{\partial x},
$$

where $u(x,t)$ is the scalar velocity field and $\nu$ is the viscosity. In this tutorial by default $\nu$ is very small ($10^{-12}$), but can be changed in the solver.

The domain is partitioned into participants at $x=1$:

- **Dirichlet**: Solves the left half $[0,1]$ and receives Dirichlet boundary conditions at the interface.
- **Neumann**: Solves the right half $[1,2]$ and receives Neumann boundary conditions at the interface.

Both outer boundaries use zero-gradient conditions $\frac{\partial u}{\partial x} = 0$. The problem can be solved for different initial conditions of superimposed sine waves, which can be generated using the provided script `utils/generate_ic.py`.

<p align="center">
<img src="images/tutorials-partitioned-burgers-1d-full-domain-diagram.png" alt="Domain Diagram" width="500"/>
<br><em>Diagram of the partitioned domain with an example initial condition.</em>
</p>

## Configuration

preCICE configuration (image generated using the [precice-config-visualizer](https://precice.org/tooling-config-visualization.html)):

<p align="center">
<img src="images/tutorials-partitioned-burgers-1d-precice-config.png" alt="preCICE configuration visualization" width="600"/>
</p>
Comment thread
uekerman marked this conversation as resolved.
Outdated

## Available Solvers
Comment thread
vidulejs marked this conversation as resolved.
Outdated

The conservative formulation of the Burgers' equation `solver-scipy` is implemented in a first-order finite volume code using Lax-Friedrichs fluxes and implicit Euler time stepping.

This tutorial includes two versions for the Neumann participant:

- A standard finite volume solver (`neumann-scipy`).
- A pre-trained neural network surrogate that approximates the solver (`neumann-surrogate`).
Comment thread
vidulejs marked this conversation as resolved.
Outdated

{% note %}
The surrogate participant requires PyTorch and related dependencies, which requires several gigabytes of disk space (~7Gb).
{% endnote %}

## Running the simulation

### Running the participants

To run the partitioned simulation, open two separate terminals and start each participant individually:

You can find the corresponding `run.sh` script for running the case in the folders corresponding to the participant you want to use:

```bash
cd dirichlet-scipy
./run.sh
```

and

```bash
cd neumann-scipy
./run.sh
```

or, to use the pretrained neural network surrogate participant:

```bash
cd neumann-surrogate
./run.sh
```

### Initial condition

The initial condition file `initial_condition.npz` is automatically generated by the run scripts if it does not exist.
You can also manually generate it using the script in `utils/`:

```bash
python3 utils/generate_ic.py --epoch <seed>
Comment thread
MakisH marked this conversation as resolved.
Outdated
```

This script requires the Python libraries `numpy` and `matplotlib`.

---
Comment thread
vidulejs marked this conversation as resolved.
Outdated

### Helper scripts

There are helper scripts in the `utils/` directory that automate runs and visualization of both participants. They also accept an integer seed argument to specify the initial condition.

```bash
./utils/run-partitioned-scipy.sh
```

and

```bash
./utils/run-partitioned-surrogate.sh
```

### Monolithic solution (reference)

You can run the whole domain using the monolithic solver for comparison:

```bash
cd solver-scipy
./run.sh
```

## Visualization

After both participants (and/or monolithic simulation) have finished, you can run the visualization script.
Comment thread
MakisH marked this conversation as resolved.
Outdated
`visualize_partitioned_domain.py` generates plots comparing the partitioned and monolithic solutions. You can specify which timestep to plot:
Comment thread
vidulejs marked this conversation as resolved.
Outdated
Comment thread
MakisH marked this conversation as resolved.
Outdated

```bash
python3 visualize_partitioned_domain.py --neumann neumann-surrogate/surrogate.npz [timestep]
Comment thread
vidulejs marked this conversation as resolved.
Outdated
```

The script will produce the following output files in the `output/` directory:

- `full-domain-timestep-slice.png`: Solution $u$ at a selected timestep
Comment thread
vidulejs marked this conversation as resolved.
Outdated

<p align="left">
<img src="images/tutorials-partitioned-burgers-1d-full-domain-timestep-slice.png" alt="Full Domain Timestep Slice" width="400"/>
</p>

- `gradient-timestep-slice.png`: Gradient $du/dx$ at a selected timestep
Comment thread
vidulejs marked this conversation as resolved.
Outdated

- `full-domain-evolution.png`: Time evolution of the solution

<p align="left">
<img src="images/tutorials-partitioned-burgers-1d-full-domain-evolution.png" alt="Full Domain Evolution" width="400"/>
</p>
16 changes: 16 additions & 0 deletions partitioned-burgers-1d/clean-tutorial.sh
Comment thread
MakisH marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env sh
set -e -u

# shellcheck disable=SC1091
. ../tools/cleaning-tools.sh

clean_tutorial .
clean_precice_logs .
rm -fv ./*.log
rm -fv ./*.vtu

rm -f solver-scipy/full_domain.npz
rm -f dirichlet-scipy/dirichlet.npz
rm -f neumann-scipy/neumann.npz
rm -rf output/
rm -f initial_condition.npz
6 changes: 6 additions & 0 deletions partitioned-burgers-1d/dirichlet-scipy/clean.sh
Comment thread
vidulejs marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env sh
set -e -u

rm -rf precice-profiling
rm -f dirichlet-scipy.log precice-Dirichlet-convergence.log precice-Dirichlet-iterations.log
rm -f dirichlet.npz
21 changes: 21 additions & 0 deletions partitioned-burgers-1d/dirichlet-scipy/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -e -u

if [ ! -v PRECICE_TUTORIALS_NO_VENV ]
then
python3 -m venv .venv
. .venv/bin/activate
pip install -r ../solver-scipy/requirements.txt && pip freeze > pip-installed-packages.log
fi

if [ ! -f "../initial_condition.npz" ]; then
echo "Generating initial condition..."
python3 ../utils/generate_ic.py
fi

. ../../tools/log.sh
exec > >(tee --append "$LOGFILE") 2>&1
Comment thread
MakisH marked this conversation as resolved.
Outdated

python3 ../solver-scipy/solver.py Dirichlet

close_log
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Comment thread
vidulejs marked this conversation as resolved.
Outdated
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions partitioned-burgers-1d/neumann-scipy/clean.sh
Comment thread
vidulejs marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env sh
set -e -u

rm -rf precice-profiling
rm -f neumann-scipy.log precice-Neumann-convergence.log precice-Neumann-iterations.log
rm -f neumann.npz
21 changes: 21 additions & 0 deletions partitioned-burgers-1d/neumann-scipy/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -e -u

if [ ! -v PRECICE_TUTORIALS_NO_VENV ]
then
python3 -m venv .venv
. .venv/bin/activate
pip install -r ../solver-scipy/requirements.txt && pip freeze > pip-installed-packages.log
fi

if [ ! -f "../initial_condition.npz" ]; then
echo "Generating initial condition..."
python3 ../utils/generate_ic.py
fi

. ../../tools/log.sh
exec > >(tee --append "$LOGFILE") 2>&1

python3 ../solver-scipy/solver.py Neumann

close_log
Comment thread
vidulejs marked this conversation as resolved.
Binary file not shown.
Binary file not shown.
6 changes: 6 additions & 0 deletions partitioned-burgers-1d/neumann-surrogate/clean.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env sh
set -e -u

rm -rf precice-profiling
rm -f neumann-surrogate.log precice-Neumann-convergence.log precice-Neumann-iterations.log
rm -f surrogate.npz
Comment thread
uekerman marked this conversation as resolved.
Outdated
15 changes: 15 additions & 0 deletions partitioned-burgers-1d/neumann-surrogate/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import torch

# Model architecture
INPUT_SIZE = 128 + 2 # +2 for ghost cells
HIDDEN_SIZE = 64 # num filters
OUTPUT_SIZE = 128

assert INPUT_SIZE >= OUTPUT_SIZE, "Input size must be greater or equal to output size."
assert (INPUT_SIZE - OUTPUT_SIZE) % 2 == 0, "Input and output sizes must differ by an even number (for ghost cells)."

NUM_RES_BLOCKS = 4
KERNEL_SIZE = 5
ACTIVATION = torch.nn.ReLU

MODEL_NAME = "CNN_RES_UNROLL_7.pth"
117 changes: 117 additions & 0 deletions partitioned-burgers-1d/neumann-surrogate/model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.nn.utils import weight_norm


def pad_with_ghost_cells(input_seq, bc_left, bc_right):
return torch.cat([bc_left, input_seq, bc_right], dim=1)


class LinearExtrapolationPadding1D(nn.Module):
"""Applies 'same' padding using linear extrapolation."""

def __init__(self, kernel_size: int, dilation: int = 1):
super().__init__()
self.pad_total = dilation * (kernel_size - 1)
self.pad_beg = self.pad_total // 2
self.pad_end = self.pad_total - self.pad_beg

def forward(self, x):
# Don't pad if not necessary
if self.pad_total == 0:
return x

ghost_cell_left = x[:, :, :1]
ghost_cell_right = x[:, :, -1:]

# Calculate the gradient at each boundary
grad_left = x[:, :, 1:2] - ghost_cell_left
grad_right = ghost_cell_right - x[:, :, -2:-1]

# Higher order finite difference gradient approximation
# grad_left = ( -11 * ghost_cell_left + 18 * x[:, :, 1:2] - 9 * x[:, :, 2:3] + 2 * x[:, :, 3:4]) / 6
# grad_right = (11 * ghost_cell_right - 18 * x[:, :, -2:-1] + 9 * x[:, :, -3:-2] - 2 * x[:, :, -4:-3]) / 6
Comment thread
vidulejs marked this conversation as resolved.
Outdated

# 3. Extrapolated padding tensors
left_ramp = torch.arange(self.pad_beg, 0, -1, device=x.device, dtype=x.dtype).view(1, 1, -1)
left_padding = ghost_cell_left - left_ramp * grad_left

right_ramp = torch.arange(1, self.pad_end + 1, device=x.device, dtype=x.dtype).view(1, 1, -1)
right_padding = ghost_cell_right + right_ramp * grad_right

return torch.cat([left_padding, x, right_padding], dim=2)


class ResidualBlock1D(nn.Module):
"""A residual block that uses custom 'same' padding with linear extrapolation and weight normalization."""

def __init__(self, channels, kernel_size=3, activation=nn.ReLU):
super(ResidualBlock1D, self).__init__()
self.activation = activation()
# Apply weight normalization
self.conv1 = weight_norm(nn.Conv1d(channels, channels, kernel_size, padding='valid', bias=True))
self.ghost_padding1 = LinearExtrapolationPadding1D(kernel_size)
self.conv2 = weight_norm(nn.Conv1d(channels, channels, kernel_size, padding='valid', bias=True))
self.ghost_padding2 = LinearExtrapolationPadding1D(kernel_size)

def forward(self, x):
identity = x

out = self.ghost_padding1(x)
out = self.conv1(out)
out = self.activation(out)

out = self.ghost_padding2(out)
out = self.conv2(out)

return self.activation(out) + identity


class CNN_RES(nn.Module):
"""
A CNN with residual blocks for 1D data.
Expects a pre-padded input with ghost_cells//2 number ghost cells on each side.
Applies a custom linear extrapolation padding for inner layers.
"""

def __init__(self, hidden_channels, num_blocks=2, kernel_size=3, activation=nn.ReLU, ghost_cells=2):
super(CNN_RES, self).__init__()
self.activation = activation()
self.hidden_channels = hidden_channels
self.num_blocks = num_blocks
self.kernel_size = kernel_size
assert ghost_cells % 2 == 0, "ghost_cells must be even"
self.ghost_cells = ghost_cells

self.ghost_padding = LinearExtrapolationPadding1D(self.ghost_cells + self.kernel_size)

# Apply weight normalization to the input convolution
self.conv_in = weight_norm(nn.Conv1d(1, hidden_channels, kernel_size=1, bias=True))

layers = [ResidualBlock1D(hidden_channels, kernel_size, activation=activation) for _ in range(num_blocks)]
self.res_blocks = nn.Sequential(*layers)

self.conv_out = nn.Conv1d(hidden_channels, 1, kernel_size=1)

def forward(self, x):

if x.dim() == 2:
x = x.unsqueeze(1) # Add channel dim: (B, 1, L)

if not self.ghost_cells == 0:
x_padded = self.ghost_padding(x)

else:
x_padded = x

total_pad_each_side = self.ghost_padding.pad_beg + self.ghost_cells // 2

out = self.activation(self.conv_in(x_padded)) # no extra padding here
out = self.res_blocks(out)
out = self.conv_out(out) # no extra padding here

if not self.ghost_cells == 0:
out = out[:, :, total_pad_each_side:-total_pad_each_side] # remove ghost cells, return only internal domain

return out.squeeze(1)
5 changes: 5 additions & 0 deletions partitioned-burgers-1d/neumann-surrogate/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
numpy==2.3.5
pyprecice==3.3.1
Comment thread
vidulejs marked this conversation as resolved.
Outdated
scipy==1.16.3
matplotlib==3.10.8
torch==2.9.1
Comment thread
uekerman marked this conversation as resolved.
Outdated
21 changes: 21 additions & 0 deletions partitioned-burgers-1d/neumann-surrogate/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -e -u

if [ ! -v PRECICE_TUTORIALS_NO_VENV ]
then
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt && pip freeze > pip-installed-packages.log
fi

if [ ! -f "../initial_condition.npz" ]; then
echo "Generating initial condition..."
python3 ../utils/generate_ic.py
fi

. ../../tools/log.sh
exec > >(tee --append "$LOGFILE") 2>&1

python3 solver.py

close_log
Loading