How does preCICE use meshes for mapping and communication?

Dear preCICE community,

I use nearest neighbor mapping to exchange data between fluid (OpenFOAM) and solid (python code). The fluid mesh use 9 nodes in the vertical direction, and the solid uses 5 nodes only but they are exactly a subset of the fluid nodes.

The conservative mapping seems wrong in two aspects (Figs 1 and 2).

  • the right nodes do not get data from the fluid. (Fig. 2)
  • the left nodes only get the data from its neighbors but no data from itself (the same location of fluid mesh). (Fig. 2) For example, the data 2.0 boxed in Solid Mesh of Fig.2, should be (0.2+1.0+2.2)=3.4, and all the other values at solid nodes should be calculated the same way.

The consistent mapping (Figs 3 and 4) looks reasonable, but the error looks large. I expect the consistent mapping gives the exact the same value if the coordinates of the fluid and solid nodes are the same.

Please note I deliberately move the left nodes in the solid mesh a little bit for testing. It seems the nodes of solid Mesh which are closer to the face center can receive the data, because the fluid data(force) are located at the face center.

What could be the reasons causing these errors?

Best,
Michael

If “mapping:rbf-thin-plate-splines” is used, the results are ever worse. If I decrease the dimension of y direction which only has one cell, it improves, but still not good. Setting y-dead=“true” does not help.

In the documentation, it is clear and easy to understand how the data are mapped from finer mesh to coarse mesh. However, it will be very helpful if this is illustrated in 2D fashion.

For example, in the configuration figure above, how are ‘S1’ to ‘S4’ calculated from the data of ‘F1’ and ‘F2’ when using consistent and conservative nearest mappings?

On the contrary, how are ‘F1’ and ‘F2’ calculated if ‘S1’ to ‘S4’ are known?

Are you referring to this page? Mapping configuration | preCICE - The Coupling Library
There is a similar example there.

  • If the mapping has a direction from S to F:
    • The closest neighbors to F1 are S1 and S2.
    • Since S1 and S2 have equal distances from F1, a nearest-neighbor consistent mapping will just pick one arbitrarily.
    • A conservative mapping will give F1 the sum of S1 and S2.
  • If the mapping has a direction from F to S:
    • The closest neighbor to S1 is F1.
    • A consistent mapping will just assign the value to S1.
    • A conservative mapping will assign half of the value to S1, assigning the other half to S2.

There is a chance that I am writing something wrong here, though.

Your explanation makes things really clear!

If the mapping has a direction from F to S:

  • The closest neighbor to S1 is F1.
  • A consistent mapping will just assign the value to S1.

Can the list be extended the same way for S2 for consistent mapping?

  • The closest neighbor to S2 is F1.
  • A consistent mapping will just assign the value to S2 (from F1).
  • Same principle applies to S3 and S4.

Yes, I was referring to that page. Mapping configuration | preCICE - The Coupling Library

However, I don’t know why the forces from fluid faceCenters are not evenly distributed to both nodes of the solid grid.

I was using nearest conservative mapping to transfer force from OpenFOAM to solid nodes.

I am not sure I understand the setup and the question. Do you mean why the spheres on the right all have value (0.0 0.0 0.0), while the spheres on the left have some correct values?

If you are reading from the grid (Fluid) to the spheres (Solid), then every sphere should get a value.

If you are writing from the grid to the spheres, then maybe these nodes are ommitted.

But I am starting to get dangerously confused myself here, so maybe @uekerman may be able to confirm.

Exactly. I expect they have the same values on both sides due to symmetry.

I am reading data from fluid to my solid solver:

 if interface.is_read_data_available():
        force1    = interface.read_block_vector_data(force1ID,    vertex_ids)

But I guess, in OpenFOAM, these data are written to the solid grid points as well, otherwise, they are available for reading in solid solver.

I am still not very clear about the mapping direction. Suppose I need to read force from Fluid to Solid. Do I need to set both mapping directions in both participants as follows?

Both mapping directions are set
    <participant  name="Fluid">
      <use-mesh   name="Fluid-Mesh"   provide="yes" />
      <use-mesh   name="Solid-Mesh"   from="Solid" />
      <write-data name="Force"        mesh="Fluid-Mesh" />
      <mapping:nearest-neighbor direction="write"  from="Fluid-Mesh" to="Solid-Mesh" constraint="consistent" />
    </participant>

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

Or

Only write direction is set in Fluid
    <participant  name="Fluid">
      <use-mesh   name="Fluid-Mesh"   provide="yes" />
      <use-mesh   name="Solid-Mesh"   from="Solid" />
      <write-data name="Force"        mesh="Fluid-Mesh" />
      <mapping:nearest-neighbor direction="write"  from="Fluid-Mesh" to="Solid-Mesh" constraint="consistent" />
    </participant>

	<participant   name="Solid">
      <use-mesh    name="Solid-Mesh"    provide="yes" />
	  <use-mesh    name="Fluid-Mesh"    from="Fluid" />
      <read-data   name="Force"   mesh="Solid-Mesh" />
    </participant>

Or

Only read direction is set in Solid
    <participant  name="Fluid">
      <use-mesh   name="Fluid-Mesh"   provide="yes" />
      <use-mesh   name="Solid-Mesh"   from="Solid" />
      <write-data name="Force"        mesh="Fluid-Mesh" />
    </participant>

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

You should define the mapping only once.

Either on fluid side:

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

	<participant   name="Solid">
      <use-mesh    name="Solid-Mesh"    provide="yes" />
	  <read-data   name="Force"   mesh="Solid-Mesh" />
    </participant>

Or on solid side:

    <participant  name="Fluid">
      <use-mesh   name="Fluid-Mesh"   provide="yes" />
      <write-data name="Force"        mesh="Fluid-Mesh" />
    </participant>

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

Please note the differences to your configuration:

  • In both cases, I removed one redundant mesh.
  • I made the mapping conservative as you want to map forces.

For participants running in serial, both configurations are valid. As soon as you run in parallel, only the first one (mapping on Fluid) is valid as conservative mappings always have to be write mappings. More information: Mapping configuration | preCICE - The Coupling Library

Don’t forget to also adjust the mesh over which you exchange in the coupling scheme if you change from one option to the other.

I must admit I was not able to fully follow the discussion above. I don’t think that there is an actual bug, but there seems to be a misunderstanding. In case the explanation here did not help already, please attach your preCICE configuration file and vtk files for both meshes (Exports configuration | preCICE - The Coupling Library).

Hi @uekerman,
I have a quesiton about the read and write in the configuration file.
For the perpendicular-flap case in preCICE tutorials, the mapping is defined only on the fluid side with both read and write.
precice-config.xml (2.4 KB)
However, as for the multiple-perpendicular-flaps case, the mapping is defined on both solid and fluid sides. Besides, only read is used in the mapping.
precice-config_multipleFlaps.xml (4.6 KB)

So I guess in the mapping configuration, read on the fluid side is the same as write on the solid side, right?

Yes. Here, the read mapping is consistent (to map displacements) and the write mapping conservative (to map forces).

Here, all mappings are consistent (to map stresses or displacements).

Correct. This is a choice the user can make. As pointed out above, if you run in parallel, there is only one good choice (read for a consistent mapping, write for a conservative mapping).

Try to use the config visualizer. It often helps to understand these things.

1 Like

Hi @uekerman,
Thank you for your explanation! That helps a lot and gives me the guideline when defining the mapping.

Regarding your comments on redundant mesh. I hope you can confirm or correct my following understanding:

  • If the data exchange is one way, only the participant who is responsible for the mapping uses all the meshes involved, the other participant only uses its own mesh.
  • If both participants want to read and write data from each other, then they use both meshes.

The first configuration means:
Fluid first maps data from Fluid-Mesh to Solid-Mesh, then Solid obtains the data directly from its own mesh, i.e., Solid-Mesh. Data is actively transferred by Fluid, and Solid ** passively receives the data.
Is it correct?


On the other hand, the configuration below means:
Solid fetches data from Fluid actively, and Fluid passively gives data to Solid.


So, regarding the data exchange, the two configurations are equivalent. The only difference is which participant initiates the exchange and is responsible for the mapping. Is it correct?

I would explain it this way: If you want to compute a mapping between two meshes, the participant who computes the mapping needs to “use” both meshes.

I would not use the term “active” and “passive”.

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

	<participant   name="Solid">
      <use-mesh    name="Solid-Mesh"    provide="yes" />
	  <read-data   name="Force"   mesh="Solid-Mesh" />
    </participant>

Just take it very literally:

  • Fluid uses Fluid-Mesh, which Fluid also provides (i.e. it defines the coordinates).
  • Fluid uses Solid-Mesh, which it receives from Solid.
  • Fluid writes Force data to the mesh Fluid-Mesh.
  • Fluid maps write data (here only Force data) from Fluid-Mesh to Solid-Mesh.
  • Solid uses Solid-Mesh, which Solid also provides.
  • Solid reads Force data from Solid-Mesh.

The communication of data is defined in the coupling scheme:

    <coupling-scheme:parallel-implicit>
      <participants first="Fluid" second="Solid" />
      <exchange data="Force" mesh="Solid-Mesh" from="Fluid" to="Solid" />
     ...
    </coupling-scheme:parallel-implicit>
  • The coupling scheme exchanges (i.e. communicates) Force data from Fluid to Solid.

Maybe reading through the first “couple your code” steps could help understanding:

Thank you so much for your further explanation!

This breaks up the procedure of data mapping and exchanging and makes things easier to understand. I think I was confused with Fluid and Fluid-Mesh. They have different responsibility during the mapping and exchanging. Reading the Step 1 a few more times does help understand the logic.

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.