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

Support to communicate multiple data fields #34

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## current development

* Support communication of multiple data fields. [#34](https://github.com/precice/fenicsx-adapter/pull/34)
* Update to support dolfinx version 0.9.0 and preCICE v3. [#28](https://github.com/precice/fenicsx-adapter/pull/28)
* Developed initial working version with example case `tutorials/partitioned-heat-conduction`. [#15](https://github.com/precice/fenicsx-adapter/pull/15)
* Forked initial version of this adapter from [`precice/[email protected]`](https://github.com/precice/fenics-adapter/releases/tag/v1.2.0).
53 changes: 35 additions & 18 deletions fenicsxprecice/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ def __init__(self, adapter_config_filename):

self._config_file_name = None
self._participant_name = None
self._coupling_mesh_name = None
self._read_data_name = None
self._write_data_name = None
self._coupling_mesh_names = None
self._read_data_names = {}
self._write_data_names = {}

self.read_json(adapter_config_filename)

Expand All @@ -39,17 +39,20 @@ def read_json(self, adapter_config_filename):
data = json.load(read_file)
self._config_file_name = os.path.join(folder, data["config_file_name"])
self._participant_name = data["participant_name"]
self._coupling_mesh_name = data["interface"]["coupling_mesh_name"]
self._coupling_mesh_names = list(data["interfaces"].keys())

try:
self._write_data_name = data["interface"]["write_data_name"]
except KeyError:
self._write_data_name = None # not required for one-way coupling, if this participant reads data
for mesh_name in self._coupling_mesh_names:
try:
self._write_data_names[mesh_name] = data["interfaces"][mesh_name]["write_data_name"]
except KeyError:
# not required for one-way coupling, if this participant reads data
self._write_data_names[mesh_name] = None

try:
self._read_data_name = data["interface"]["read_data_name"]
except KeyError:
self._read_data_name = None # not required for one-way coupling, if this participant writes data
try:
self._read_data_names[mesh_name] = data["interfaces"][mesh_name]["read_data_name"]
except KeyError:
# not required for one-way coupling, if this participant writes data
self._read_data_names[mesh_name] = None

read_file.close()

Expand All @@ -59,11 +62,25 @@ def get_config_file_name(self):
def get_participant_name(self):
return self._participant_name

def get_coupling_mesh_name(self):
return self._coupling_mesh_name
def get_coupling_mesh_names(self):
return self._coupling_mesh_names

def get_read_data_name(self):
return self._read_data_name
def get_read_data_name(self, mesh_name):
"""
Parameters
----------
mesh_name : fenicsxprecice.Meshes member
Member of the enum fenicsxprecoce.Meshes

"""
return self._read_data_names[mesh_name.name]

def get_write_data_name(self):
return self._write_data_name
def get_write_data_name(self, mesh_name):
"""
Parameters
----------
mesh_name : fenicsxprecice.Meshes member
Member of the enum fenicsxprecoce.Meshes

"""
return self._write_data_names[mesh_name.name]
284 changes: 160 additions & 124 deletions fenicsxprecice/fenicsxprecice.py

Large diffs are not rendered by default.

64 changes: 64 additions & 0 deletions tutorials/multiple-fields/left.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from mpi4py import MPI
from dolfinx import mesh
from dolfinx.fem import functionspace
from dolfinx import fem
import numpy
import ufl
from dolfinx import default_scalar_type
from dolfinx.fem.petsc import LinearProblem

import fenicsxprecice

domain = mesh.create_rectangle(
MPI.COMM_WORLD, [
numpy.asarray(
(0, 0)), numpy.asarray(
(1, 1))], [
10, 10], mesh.CellType.quadrilateral)
domain2 = mesh.create_rectangle(
MPI.COMM_WORLD, [
numpy.asarray(
(0, 0)), numpy.asarray(
(1, 1))], [
11, 11], mesh.CellType.quadrilateral)
V = functionspace(domain, ("Lagrange", 1))
V2 = functionspace(domain2, ("Lagrange", 1))
uD = fem.Function(V)
uD.interpolate(lambda x: 1 + x[0])
uD2 = fem.Function(V2)
uD2.interpolate(lambda x: 2 + x[0])


def coupling_bc(x):
tol = 1E-14
return numpy.isclose(x[0], 1, tol)


precice = fenicsxprecice.Adapter(adapter_config_filename="precice-adapter-config-L.json", mpi_comm=MPI.COMM_SELF)
precice.initialize({precice.Meshes.Left1: [coupling_bc, V, uD],
precice.Meshes.Left2: [coupling_bc, V2, uD2]})

coupling_expression1 = precice.create_coupling_expression(precice.Meshes.Left1)
coupling_expression2 = precice.create_coupling_expression(precice.Meshes.Left2)

while precice.is_coupling_ongoing():

if precice.requires_writing_checkpoint():
precice.store_checkpoint(uD, 0, 0)

read_data1 = precice.read_data(0, precice.Meshes.Left1)
read_data2 = precice.read_data(0, precice.Meshes.Left2)

precice.write_data(uD, precice.Meshes.Left1)
precice.write_data(uD2, precice.Meshes.Left2)

precice.advance(1)

if precice.requires_reading_checkpoint():
pass


precice.finalize()

print(read_data1) # expected: x[0]+3
print(read_data2) # expected: x[0]+4
14 changes: 14 additions & 0 deletions tutorials/multiple-fields/precice-adapter-config-L.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"participant_name": "Left",
"config_file_name": "precice-config.xml",
"interfaces": {
"Left1": {
"write_data_name": "LeftOut",
"read_data_name": "LeftIn"
},
"Left2": {
"write_data_name": "RightIn",
"read_data_name": "RightOut"
}
}
}
14 changes: 14 additions & 0 deletions tutorials/multiple-fields/precice-adapter-config-R.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"participant_name": "Right",
"config_file_name": "precice-config.xml",
"interfaces": {
"Right1": {
"write_data_name": "LeftIn",
"read_data_name": "LeftOut"
},
"Right2": {
"write_data_name": "RightOut",
"read_data_name": "RightIn"
}
}
}
124 changes: 124 additions & 0 deletions tutorials/multiple-fields/precice-config.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8" ?>
<precice-configuration>
<log>
<sink
filter="%Severity% > debug and %Rank% = 0"
format="---[precice] %ColorizedSeverity% %Message%"
enabled="true" />
</log>

<data:scalar name="LeftIn" waveform-degree="1" />
<data:scalar name="LeftOut" waveform-degree="1" />
<data:scalar name="RightIn" waveform-degree="1" />
<data:scalar name="RightOut" waveform-degree="1" />


<mesh name="Left1" dimensions="2">
<use-data name="LeftIn" />
<use-data name="LeftOut" />
</mesh>

<mesh name="Left2" dimensions="2">
<use-data name="RightIn" />
<use-data name="RightOut" />
</mesh>

<mesh name="Right1" dimensions="2">
<use-data name="LeftIn" />
<use-data name="LeftOut" />
</mesh>

<mesh name="Right2" dimensions="2">
<use-data name="RightIn" />
<use-data name="RightOut" />
</mesh>

<participant name="Left">
<provide-mesh name="Left1" />
<receive-mesh name="Right1" from="Right" />
<provide-mesh name="Left2" />
<receive-mesh name="Right2" from="Right" />

<write-data name="LeftOut" mesh="Left1" />
<write-data name="RightIn" mesh="Left2" />

<read-data name="LeftIn" mesh="Left1" />
<mapping:nearest-neighbor
direction="read"
from="Right1"
to="Left1"
constraint="consistent" />

<read-data name="RightOut" mesh="Left2" />
<mapping:nearest-neighbor
direction="read"
from="Right2"
to="Left2"
constraint="consistent" />
</participant>

<participant name="Right">
<provide-mesh name="Right1" />
<receive-mesh name="Left1" from="Left" />
<write-data name="LeftIn" mesh="Right1" />
<read-data name="LeftOut" mesh="Right1" />
<mapping:nearest-neighbor
direction="read"
from="Left1"
to="Right1"
constraint="consistent" />
<provide-mesh name="Right2" />
<receive-mesh name="Left2" from="Left" />
<write-data name="RightOut" mesh="Right2" />
<read-data name="RightIn" mesh="Right2" />
<mapping:nearest-neighbor
direction="read"
from="Left2"
to="Right2"
constraint="consistent" />
</participant>

<m2n:sockets acceptor="Left" connector="Right" exchange-directory=".." />

<coupling-scheme:serial-implicit>
<participants first="Left" second="Right" />
<max-time value="1.0" />
<time-window-size value="1.0" />
<max-iterations value="100" />
<exchange
data="LeftOut"
mesh="Left1"
from="Left"
to="Right"
initialize="true"
substeps="true" />
<exchange
data="LeftIn"
mesh="Right1"
from="Right"
to="Left"
initialize="true"
substeps="true" />
<exchange
data="RightOut"
mesh="Right2"
from="Right"
to="Left"
initialize="true"
substeps="true" />
<exchange
data="RightIn"
mesh="Left2"
from="Left"
to="Right"
initialize="true"
substeps="true" />
<relative-convergence-measure data="LeftOut" mesh="Left1" limit="1e-10" />
<relative-convergence-measure data="RightIn" mesh="Left2" limit="1e-10" />
<relative-convergence-measure data="LeftIn" mesh="Right1" limit="1e-10" />
<relative-convergence-measure data="RightOut" mesh="Right2" limit="1e-10" />
<acceleration:constant>
<relaxation value="0.5" />
</acceleration:constant>
</coupling-scheme:serial-implicit>
</precice-configuration>
60 changes: 60 additions & 0 deletions tutorials/multiple-fields/right.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from mpi4py import MPI
from dolfinx import mesh
from dolfinx.fem import functionspace
from dolfinx import fem
import numpy

import fenicsxprecice

domain = mesh.create_rectangle(
MPI.COMM_WORLD, [
numpy.asarray(
(1, 0)), numpy.asarray(
(2, 1))], [
10, 10], mesh.CellType.quadrilateral)
domain2 = mesh.create_rectangle(
MPI.COMM_WORLD, [
numpy.asarray(
(1, 0)), numpy.asarray(
(2, 1))], [
11, 11], mesh.CellType.quadrilateral)
V = functionspace(domain, ("Lagrange", 1))
V2 = functionspace(domain2, ("Lagrange", 1))
uD = fem.Function(V)
uD.interpolate(lambda x: 3 + x[0])
uD2 = fem.Function(V2)
uD2.interpolate(lambda x: 4 + x[0])


def coupling_bc(x):
tol = 1E-14
return numpy.isclose(x[0], 1, tol)


precice = fenicsxprecice.Adapter(adapter_config_filename="precice-adapter-config-R.json", mpi_comm=MPI.COMM_WORLD)
precice.initialize({precice.Meshes.Right1: [coupling_bc, V, uD],
precice.Meshes.Right2: [coupling_bc, V2, uD2]})

coupling_expression1 = precice.create_coupling_expression(precice.Meshes.Right1)
coupling_expression2 = precice.create_coupling_expression(precice.Meshes.Right2)

while precice.is_coupling_ongoing():

if precice.requires_writing_checkpoint():
precice.store_checkpoint(uD, 0, 0)

read_data1 = precice.read_data(0, precice.Meshes.Right1)
read_data2 = precice.read_data(0, precice.Meshes.Right2)

precice.write_data(uD, precice.Meshes.Right1)
precice.write_data(uD2, precice.Meshes.Right2)

precice.advance(1)

if precice.requires_reading_checkpoint():
pass

precice.finalize()

print(read_data1) # expected: x[0]+1
print(read_data2) # expected: x[0]+2
Loading
Loading