-
-
Notifications
You must be signed in to change notification settings - Fork 122
Growing mesh case #600
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
base: develop
Are you sure you want to change the base?
Growing mesh case #600
Changes from all commits
a977a22
ccbf23b
fd588d8
c799433
1b0adc3
c56f34d
6195a93
00b7860
5f009d8
e2a94c6
4ea4cd4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,6 +33,7 @@ build/ | |
.venv/ | ||
__pycache__/ | ||
*.pyc | ||
*.egg-info | ||
|
||
# Rust | ||
Cargo.lock | ||
|
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-python | ||
|
||
if [ $# -eq 0 ]; then | ||
growing A | ||
else | ||
mpirun -n "$@" growing A | ||
fi |
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-python | ||
|
||
if [ $# -eq 0 ]; then | ||
growing B | ||
else | ||
mpirun -n "$@" growing B | ||
fi |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
--- | ||
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 | ||
|
||
The problem consists of a unit-square uniformly discretized by 768 x 768 nodes. | ||
Running in parallel is only allowed for 1, 4, 9, or 16 ranks. | ||
The unit square is partitioned equally among the ranks of a solver. | ||
|
||
The mesh starts with 2 nodes in z direction and at a given frequency, 2 nodes are added to the mesh, changing only the load per rank, not the partitioning. | ||
|
||
## Configuration | ||
|
||
preCICE configuration (image generated using the [precice-config-visualizer](https://precice.org/tooling-config-visualization.html)): | ||
|
||
 | ||
|
||
## 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 A | ||
./run.sh 2 | ||
``` | ||
|
||
and | ||
|
||
```bash | ||
cd B | ||
./run.sh 2 | ||
``` |
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> |
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" |
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() |
Uh oh!
There was an error while loading. Please reload this page.