Multiple fluid domains interacting with a shell structure - preCICE configuration on the OpenFOAM side

Hello preCICE support,

We need to simulate FSI in the case of a ball (modeled as a shell in our FE solver) that has one fluid (air) inside it and another fluid (water) outside of it. We model both air and water in OpenFOAM. Forces/Stresses from OpenFOAM need to be passed on to the ball’s outer surface as well as the inner surface. So, there are essentially two different interactions that must be configured/modeled.

  1. Ball’s outer shell surface interacting with the wet surface of the outer water domain, and
  2. Ball’s inner shell surface interacting with the wet surface of the inner air domain.

Assuming ‘ball_external’ is the wet surface of the fluid domain outside of the ball and ‘ball_internal’ is the wet surface of the fluid domain inside the ball AND the data to be exchanged are stresses and forces, does the preciceDict file shown below make sense? Is this the correct/recommended way to complete the CFD side of the preCICE setup? Is there an example somewhere that highlights this scenario that you can point me to? Any response would be appreciated.

interfaces
{
Interface1 // Data written to the wet surface corresponding to the ball’s outer fluid domain
{
mesh “openFoam_precice-Mesh-Faces-External”;
patches 1 ( ball_external );
locations faceCenters;
readData ();
writeData 1 ( Stress );
};
Interface2 // Data written to the wet surface corresponding to the ball’s inner fluid domain
{
mesh “openFoam_precice-Mesh-Faces-Internal”;
patches 1 (ball_internal );
locations faceCenters;
readData ();
writeData 1 ( Stress );
};

Interface3 **//Displacements data read on the nodes at the interface of water and air**
{
    mesh            "openFoam_precice-Mesh-Nodes";
    patches         1 ( ball_external ); **//Perhaps, this can also be ball_internal** patch
    locations       faceNodes;
    readData        (Displacements0);
    writeData       ();
};

};

Thanks in advance,
Satish

Hi @Satish_Chimakurthi,

if I understand correctly, this sounds very similar to this tutorial: Multiple perpendicular flaps | preCICE - The Coupling Library

What you need is to use a coupling-scheme:multi and to define multiple patches in the preciceDict (as you have already done).

Hi @Makis,

In my case, there are still only two solvers, not three. There are two fluid domains (air and water) modeled within the same solver. The air is inside a shell structure (ball) and water is outside the ball. Forces/stresses from the air side as well as the water side have to be applied to the shell. Is coupling-scheme:multi still required in my case? The tutorial you pointed me to includes three solvers. Is that still the best reference for my case?

Thanks,
Satish

ah, so you want two interfaces between two solvers. This should be possible (I have not tried it), but you need to iterate over them in each adapter. I am just wondering if there is any relevant restriction in preCICE. But you can try sketching a preCICE configuration file and let preCICE check it: Built-in tooling | preCICE - The Coupling Library

For the OpenFOAM adapter, what you described looks correct: two interfaces with two different meshes and patches.

Might be easier to do this with 3 solvers though. The 2 fluid domains have no direct interaction, right?

No, they don’t have any direct interaction but I will check with my team just in case there are any stumbling blocks. Do you recommend using two instances of the same fluid solver then, one for each domain? If yes, the example that Gerasimos pointed me to is the way to go to follow through for the setup? And, by the way, we are currently using preCICE version 2.2.0.

Regards,
Satish

Hi Satish,

I would indeed recommend to use two instances of the same fluid solver:

<participant name="Fluid-Inner"> ... </participant>
<participant name="Fluid-Outer"> ... </participant>
<participant name="Solid"> ... </participant>

Simply, because your two fluid domains have no direct interaction. I could imagine that some numerical solvers do not even like this full block structure. Also, using two fluid solver, you have much more flexibility on how to configure both. As you describe above you want water and air. Maybe you also want different numerical setting for both in the long run.

As you use OpenFOAM, both fluid participants then have their own preciceDict file.

Coupling scheme

For implicit coupling, you should then use a multi-coupling scheme:

<coupling-scheme:multi>
  <participant name="Solid" control="yes"/>
  <participant name="Fluid-Inner" />
  <participant name="Fluid-Outer" />
  ...
</coupling-scheme:multi>

You should give control to the Solid participant as it has connections to both other solvers. Since preCICE v2.3, also one of the fluid participants could be in control, but this comes with restrictions and is presumably less efficient in your case.

For explicit coupling, you could simply combine two explicit coupling schemes:

<coupling-scheme:parallel-explicit>
  <participants first="Fluid1" second="Solid"/>
  ...
</coupling-scheme:parallel-explicit>
<coupling-scheme:parallel-explicit>
  <participants first="Fluid2" second="Solid"/>
  ...
</coupling-scheme:parallel-explicit>

You could also do two serial-explicit schemes. Then both fluid participants would still run in parallel, but both staggered with the solid participant.

Boundary conditions

The tricky part here is the solid ball. Somewhere on the surface of the ball, you need a Dirichlet boundary condition, otherwise it is mathematically ill-defined. As an intermediate step, you could mount the ball, meaning to set displacements on some part to zero. Then, on the rest of the surface, you could use Neumann boundary conditions (setting forces).

Without this mounting, things become complicated. Then, you need to turn one fluid solver around: it then needs to read forces (or stresses) and write displacements. I am not sure if the OpenFOAM adapter can already handle this. The recent extension to also support solids4foam goes in this direction.

Let’s assume for the moment that you mount the ball. The participants could then look like this:

<participant name="Fluid-Inner">
  <use-mesh name="Fluid-Inner-Mesh" provide="yes" />
  <write-data name="Force-Inner" mesh="Fluid-Inner-Mesh" />
  <read-data name="Displacement-Inner" mesh="Fluid-Inner-Mesh" />
  
  <use-mesh name="Solid-Mesh-Inner" from="Solid" />
  <mapping:nearest-neighbor 
    direction="write"
    from="Fluid-Inner-Mesh"
    to="Solid-Mesh-Inner"
    constraint="conservative" />
  <mapping:nearest-neighbor
    direction="read"
    from="Solid-Mesh-Inner"
    to="Fluid-Inner-Mesh"
    constraint="consistent" />
</participant>

<participant name="Fluid-Outer">
  <use-mesh name="Fluid-Outer-Mesh" provide="yes" />
  <write-data name="Force-Outer" mesh="Fluid-Outer-Mesh" />
  <read-data name="Displacement-Outer" mesh="Fluid-Outer-Mesh" />
  
  <use-mesh name="Solid-Mesh-Outer" from="Solid" />
  <mapping:nearest-neighbor 
    direction="write"
    from="Fluid-Outer-Mesh"
    to="Solid-Mesh-Outer"
    constraint="conservative" />
  <mapping:nearest-neighbor
    direction="read"
    from="Solid-Mesh-Outer"
    to="Fluid-Outer-Mesh"
    constraint="consistent" />
</participant>

The complete config:
config.xml (4.4 KB)

Required changes in solid solver

Probably obvious: The solid solver then needs to be able to define two interfaces.

int innerMeshID = precice.getMeshID("Solid-Mesh-Inner");
int outerMeshID = precice.getMeshID("Solid-Mesh-Outer");
...
precice.setMeshVertices(innerMeshID, innerVertexSize, innerCoords, innerVertexIDs);
precice.setMeshVertices(outerMeshID, outerVertexSize, outerCoords, outerVertexIDs);

More

we are currently using preCICE version 2.2.0.

This should not be a problem, but I would still recommend to update preCICE. There are a few bugs we fixed and other things that are simply more efficient. Updating should be very easy. Let me know if you do not know how.

FEBio

Did you know that there is also some effort coupling FEBio here?