Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Growing mesh case #600

Draft
wants to merge 11 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 6 commits
Commits
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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ build/
.venv/
__pycache__/
*.pyc
*.egg-info

# Rust
Cargo.lock
Expand Down
12 changes: 12 additions & 0 deletions growing-mesh/A/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/sh
set -e -u

python3 -m venv .venv
. .venv/bin/activate
pip install ../solver

if [ $# -eq 0 ]; then
growing A
else
mpirun -n "$@" growing A
fi
12 changes: 12 additions & 0 deletions growing-mesh/B/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/sh
set -e -u

python3 -m venv .venv
. .venv/bin/activate
pip install ../solver

if [ $# -eq 0 ]; then
growing B
else
mpirun -n "$@" growing B
fi
43 changes: 43 additions & 0 deletions growing-mesh/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
title: Growing Mesh
permalink: tutorials-growing-mesh.html
keywords: python, remeshing
summary: The growing mesh case is a showcase example of two solvers which grow their mesh at predefined points in time.
---

{% note %}
Get the [case files of this tutorial](https://github.com/precice/tutorials/tree/master/growing-mesh). Read how in the [tutorials introduction](https://precice.org/tutorials.html).
{% endnote %}

## Setup
fsimonis marked this conversation as resolved.
Show resolved Hide resolved

## Configuration

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

![preCICE configuration visualization](images/tutorials-growing-mesh-precice-config.png)

## Available solvers

There are two solvers that define the same mesh:

- A who runs first
- B who runs second
Comment on lines +30 to +31
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We so far avoid calling participants and data generic names, but try to relate to a specific physical domain and application use case. This is currently only partially described in the naming conventions.

Of course, this is fine for now (and fine for an integration test), but before merging, we should better have more descriptive names.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They both represent the same mesh and don't model any physical behaviour.

Not sure what we would name them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a physical motivation for this scenario. We could borrow names there?


## Running the Simulation

Pass the amount of ranks to the run script of the solvers.
Not passing a number, runs the simulation on a single rank.
To run both on a two rank each, use:

```bash
cd fluid-cpp
./run.sh 2
```

and

```bash
cd solid-cpp
./run.sh 2
fsimonis marked this conversation as resolved.
Show resolved Hide resolved
```
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
50 changes: 50 additions & 0 deletions growing-mesh/precice-config.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8" ?>
<precice-configuration experimental="True" allow-remeshing="True">
<log>
<sink
filter="%Severity% >= debug and %Rank% = 0"
format="---[precice] %ColorizedSeverity% %Message%"
enabled="true" />
</log>

<profiling mode="all" />

<data:scalar name="Data-A" />
<data:scalar name="Data-B" />

<mesh name="A-Mesh" dimensions="3">
<use-data name="Data-A" />
<use-data name="Data-B" />
</mesh>

<mesh name="B-Mesh" dimensions="3">
<use-data name="Data-A" />
<use-data name="Data-B" />
</mesh>

<participant name="A">
<provide-mesh name="A-Mesh" />
<write-data name="Data-A" mesh="A-Mesh" />
<read-data name="Data-B" mesh="A-Mesh" />
<receive-mesh name="B-Mesh" from="B" />
<mapping:nearest-neighbor direction="read" from="B-Mesh" to="A-Mesh" constraint="consistent" />
</participant>

<participant name="B">
<provide-mesh name="B-Mesh" />
<read-data name="Data-A" mesh="B-Mesh" />
<write-data name="Data-B" mesh="B-Mesh" />
<receive-mesh name="A-Mesh" from="A" />
<mapping:nearest-neighbor direction="read" from="A-Mesh" to="B-Mesh" constraint="consistent" />
</participant>

<m2n:sockets acceptor="A" connector="B" exchange-directory=".." />

<coupling-scheme:parallel-explicit>
<time-window-size value="1" />
<max-time-windows value="12" />
<participants first="A" second="B" />
<exchange data="Data-A" mesh="A-Mesh" from="A" to="B" />
<exchange data="Data-B" mesh="B-Mesh" from="B" to="A" />
</coupling-scheme:parallel-explicit>
</precice-configuration>
11 changes: 11 additions & 0 deletions growing-mesh/solver/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[project]
name = "growing"
version = "0"
dependencies = [
"numpy",
"pyprecice @ git+https://github.com/precice/python-bindings.git@develop",
"mpi4py"
]

[project.scripts]
growing = "solver:main"
121 changes: 121 additions & 0 deletions growing-mesh/solver/solver.py
fsimonis marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#!/bin/python3

import precice
import numpy as np
import math
import sys
from mpi4py import MPI

import argparse


def main():
parser = argparse.ArgumentParser()
parser.add_argument("participant", choices=["A", "B"])
parser.add_argument("--config", "-c", default="../precice-config.xml")
parser.add_argument("--no-remesh", dest="remesh", action="store_false")
args = parser.parse_args()

participant_name = args.participant
remote_name = "A" if participant_name == "B" else "B"

# x is partitioned per rank and doesn't change
nx = 256 * 3
x = 0.0, 1.0
ny = 256 * 3
y = 0.0, 1.0

# y grows over time
newNodesPerEvent = 2
eventFrequency = 3 # time windows
dz = 0.1

# Handle partitioning
world = MPI.COMM_WORLD
size: int = world.size
rank: int = world.rank

parts: int = int(math.sqrt(size))
assert parts**2 == size, "size must be a square value"
assert math.remainder(nx, parts) == 0, f"{nx=} must be dividable by {parts=}"

# current parition in x, y
px = rank % parts
py = rank // parts

# nodes per parition
nxp = nx // parts
nyp = ny // parts

# node slide per partition
nxps = slice(nxp * px, nxp * (px + 1))
nyps = slice(nyp * py, nyp * (py + 1))

print(f"{rank=} {nxps=} {nyps=}")

def requiresEvent(tw):
return tw % eventFrequency == 0

assert not requiresEvent(eventFrequency - 1)
assert requiresEvent(eventFrequency)
assert not requiresEvent(eventFrequency + 1)

def eventsAt(tw):
# First event block at tw=0, second at eventFrequency
return 1 + math.floor(tw / eventFrequency)

assert eventsAt(0) == 1
assert eventsAt(eventFrequency - 1) == 1
assert eventsAt(eventFrequency) == 2
assert eventsAt(eventFrequency + 1) == 2

def getMeshAtTimeWindow(tw):
znodes = eventsAt(tw) * newNodesPerEvent

xs = np.linspace(x[0], x[1], nx)[nxps]
ys = np.linspace(y[0], y[1], ny)[nyps]
zs = np.array(range(znodes)) * dz

return np.reshape([(x, y, z) for z in zs for y in ys for x in xs], (-1, 3))

participant = precice.Participant(participant_name, args.config, rank, size)

mesh_name = participant_name + "-Mesh"
read_data_name = "Data-" + remote_name
write_data_name = "Data-" + participant_name

coords = getMeshAtTimeWindow(0)
vertex_ids = participant.set_mesh_vertices(mesh_name, coords)
participant.initialize()

tw = 1
while participant.is_coupling_ongoing():
dt = participant.get_max_time_step_size()

data = participant.read_data(mesh_name, read_data_name, vertex_ids, dt)
if rank == 0:
print(data)

if args.remesh and requiresEvent(tw):
oldCount = len(coords)
coords = getMeshAtTimeWindow(tw)
if rank == 0:
print(
f"Event grows local mesh from {oldCount} to {
len(coords)} and global mesh from {
oldCount *
size} to {
len(coords) *
size}")
participant.reset_mesh(mesh_name)
vertex_ids = participant.set_mesh_vertices(mesh_name, coords)

data = np.full(len(coords), tw)
participant.write_data(mesh_name, write_data_name, vertex_ids, data)

participant.advance(dt)
tw += 1


if __name__ == "__main__":
main()