There are two types of coupling actions: pre-implemented ones and user-defined ones. For the latter, you can access coupling meshes through a Python callback interface.
Basics and pre-implemented actions
<participant name="MySolver1">
<use-mesh name="MyMesh1" provide="yes"/>
<write-data name="Stresses" mesh="MyMesh1"/>
...
<action:multiply-by-area mesh="MyMesh1" timing="write-mapping-post">
<target-data name="Stresses"/>
</action:multiply-by-area>
...
</participant>
This example multiplies the stresses values by the respective element area, transforming stresses into forces. Please note that for this specific action, mesh connectivity information needs to be provided. (edges, triangles, etc. through setMeshEdge
or similar API functions.
timing
defines when the action is executed. Options are:
write-mapping-prior
andwrite-mapping-post
: directly before or after each time the write mappings are applied.read-mapping-prior
andread-mapping-post
: directly before or after each time the read mappings are applied.on-time-window-complete-post
: after the coupling in a complete time window has converged, afterread
data is mapped.
Older (preCICE version < 2.1.0) timings that are deprecated and revert to one of the above options: (click for details)
regular-prior
: In everyadvance
call (also for subcycling) and ininitializeData
, afterwrite
data is mapped, but before data might be sent. (v2.1 or later: reverts towrite-mapping-prior
)regular-post
: In everyadvance
call (also for subcycling), ininitializeData
and ininitialize
, beforeread
data is mapped, but after data might be received and after acceleration. (v2.1 or later: reverts toread-mapping-prior
)on-exchange-prior
: Only in thoseadvance
calls which lead to data exchange (and ininitializeData
), afterwrite
data is mapped, but before data might be sent. (v2.1 or later: reverts towrite-mapping-post
)on-exchange-post
: Only in thoseadvance
calls which lead to data exchange (and ininitializeData
andìnitialize
), beforeread
data is mapped, but after data might be received. (v2.1 or later: reverts toread-mapping-prior
)
Pre-implemented actions are:
multiply-by-area
/divide-by-area
: Modify coupling data by mesh areascale-by-computed-dt-ratio
/scale-by-computed-dt-part-ratio
/scale-by-dt
: Modify coupling data by time step sizecompute-curvature
: Compute curvature values at verticessummation
: Sum up the data from source participants and write to target participant
<read-data ... />
or <write-data ... />
tags.
For more details, please refer to the XML reference.
Python callback interface
Other than the pre-implemented coupling actions, preCICE also provides a callback interface for Python scripts to execute coupling actions. To use this feature, you need to build preCICE with python support.
We show an example for the 1D elastic tube:
<participant name="Solid">
<use-mesh name="Solid-Nodes-Mesh" provide="yes"/>
<use-mesh name="Fluid-Nodes-Mesh" from "Fluid" />
<write-data name="CrossSectionLength" mesh="Solid-Nodes-Mesh" />
<read-data name="Pressure" mesh="Solid-Nodes-Mesh" />
<action:python mesh="Solid-Nodes-Mesh" timing="read-mapping-prior">
<path name="<PATH_TO_PYTHON_ACTION_SCRIPT>"/>
<module name="<PYTHON_SCRIPT_NAME.PY>"/>
<source-data name="Pressure"/>
<target-data name="Pressure"/>
</action:python>
</participant>
The callback interface consists of the following three (optional) functions:
performAction(time, sourceData, targetData)
vertexCallback(id, coords, normal)
postAction()
performAction
gives access to the coupling value arrays. You can store these values in global variables to grant access to the other two functions.
vertexCallback
gives access to the geometric data of each vertex. This function is called successively for every vertex of the specified coupling mesh and you can use the corresponding geometric data.
postAction
is called at the final step. You can perform any finalizing code after deriving information from the vertices, if wished.
Without the Python action, the 1D elastic tube gives the following results:
Now, we want to ramp up the pressure values written by the fluid solver over time. A feature often needed to get a stable coupled simulation.
mySourceData = 0
myTargetData = 0
def performAction(time, dt, sourceData, targetData):
# This function is called first at configured timing. It can be omitted, if not
# needed. Its parameters are time, time step size, the source data, followed by the target data.
# Source and target data can be omitted (selectively or both) by not mentioning
# them in the preCICE XML configuration.
global mySourceData
global myTargetData
mySourceData = sourceData # store (reference to) sourceData for later use
myTargetData = targetData # store (reference to) targetData for later use
timeThreshold = 0.2 # Ramp up the pressure values until this point in time
if time < timeThreshold:
for i in range(myTargetData.size):
# Ramp up pressure value
myTargetData[i] = (time / timeThreshold) * mySourceData[i]
else:
for i in range(myTargetData.size):
# Assign the computed physical pressure values
myTargetData[i] = mySourceData[i]
def vertexCallback(id, coords, normal):
# This function is called for every vertex in the configured mesh. It is called
# after performAction, and can also be omitted.
# Usage example:
global mySourceData # Make global data set in performAction visible
global myTargetData
# Example usage, add data to vertex coords:
# myTargetData[id] += coords[0] + mySourceData[id]
def postAction():
# This function is called at last, if not omitted.
global mySourceData # Make global data set in performAction visible
global myTargetData
# Do something ...
With the Python action, you should now get the following results. Note the lower maximum diameter and the change at t=0.2
(t=20
in the graph).