GEOS-DEV / GEOS

GEOS Simulation Framework
GNU Lesser General Public License v2.1
221 stars 89 forks source link

Wave solvers: Source on a mesh node/edge results in wrong signal (same for receivers) #3104

Closed Bertbk closed 3 months ago

Bertbk commented 7 months ago

Describe the bug When running a wave propagation solver (eg acoustic), if the source lies on the boundary of 2 or more elements, the amplitude of the source signal can be counted multiple times, or not a all, resulting in a wrong result. This has been reported on issue #2256 but closed for duplicate reason with #2227. However, the problem persists. Could it be due to parallel concurrency?

To Reproduce Launch numerous time an xml file with the following geometry and solver. The source is at the origin and the mesh is such that the origin is a mesh node. The complete file is provided at the end.

  <Mesh>
    <InternalMesh
      name="mesh"
      elementTypes="{ C3D8 }"
      xCoords="{ -1500,1500}"
      yCoords="{ -1500,1500 }"
      zCoords="{ -1500,1500 }"
      nx="{ 150 }"
      ny="{ 150 }"
      nz="{ 150 }"
      cellBlockNames="{ cb }"/>
  </Mesh>
  <Solvers>
    <AcousticSEM
    name="acousticSolver"
      cflFactor="0.25"
      discretization="FE1"
      targetRegions="{ Region }"
      sourceCoordinates="{ { 0, 0, 0 } }"
      outputSeismoTrace = "1"
      dtSeismoTrace="0.0013"
      timeSourceFrequency="5"
      receiverCoordinates="{ { 1, 2, 3 }}"/>
  </Solvers>
  <NumericalMethods>
    <FiniteElements>
      <FiniteElementSpace
        name="FE1"
        order="1"
        formulation="SEM"/>
    </FiniteElements>
  </NumericalMethods>

Screenshots

Here is a plot of different signal obtained through the same piece of code. The amplitude varies from 0 to the double. 99 simulations have been launched. The source is at the origin belonging to 8 elements, the receiver is close to at (1,2,3), inside an element.

acousticSolver_Sources

Platform (please complete the following information):

Additional information

If a source is on a mesh node, then it belongs to 8 elements. Currently, GEOS loops on each element and check if the source is inside the element (boundary included). If so, GEOS pre-computes the parameters and quantities for the source. As the loop on the element is achieved in parallel, concurrency can appear.

The loop on the element is in function Compute1DSourceAndReceiverConstantsWithElementsAndRegionStorage in the file vti/src/coreComponents/physicsSolvers/wavePropagation/PrecomputeSourcesAndReceiversKermel.hpp

In case it helps, here is a piece of log of Compute1DSourceAndReceiverConstantsWithElementsAndRegionStorage obtained through (ugly) printf:

// file recomputeSourcesAndReceiversKernel.hpp
// Function Compute1DSourceAndReceiverConstants
  for( localIndex a = 0; a < numNodesPerElem; ++a )
  {
    sourceNodeIds[isrc][a] = elemsToNodes[k][a];
    sourceConstants[isrc][a] = Ntest[a];
// ugly but useful printf :-)
    printf("sourceNodeIds[%d][%d] = %d \n", isrc, a, elemsToNodes[k][a]);
    printf("sourceConstants[%d][%d] = %.2f \n", isrc, a, Ntest[a]);
  }

Part of the resulting printf, for the case where the source went to zero:

sourceNodeIds[0][0] = 196374 
sourceNodeIds[0][0] = 196375 
sourceNodeIds[0][0] = 193773 
sourceNodeIds[0][0] = 193774 
sourceNodeIds[0][0] = 193722 
sourceNodeIds[0][0] = 193723 
sourceNodeIds[0][0] = 196323 
sourceNodeIds[0][0] = 196324 
sourceConstants[0][0] = 0.00 
sourceConstants[0][0] = 1.00 
sourceConstants[0][0] = 0.00 
sourceConstants[0][0] = 0.00 
sourceConstants[0][0] = 0.00 
sourceConstants[0][0] = 0.00 
sourceConstants[0][0] = 0.00 
sourceConstants[0][0] = 0.00 
...

The source information sourceConstants[0][0] and sourceNodeIds[0][0] have been changed 8 times... Same for 8 other nodes.

Same problem for Receivers

The same problem happens for receivers. In addition, if a receiver is at the boundary between 2 subdomains (of the domain decomposition method) then GEOS crashes unexpectedly. To observe that, simply change the receiver's position to, eg, the origin: receiverCoordinates="{ { 0, 0, 0 }}" Launch then in parallel with a ddm 2 in the x direction, for example: mpirun -n 8 geosx -i issue.xml -x 2 -y 2 -z 2

You should get something like

***** ERROR
***** LOCATION: src/coreComponents/physicsSolvers/wavePropagation/WaveSolverUtils.hpp:108
***** Controlling expression (should be false): nReceivers != total
***** Rank 0: : Invalid distribution of receivers: nReceivers=1 != MPI::sum=8.

Maybe due to the check on ghostElement in Compute1DSourceAndReceiverConstantsWithElementsAndRegionStorage ?

xml complete file

The complete xml is the following

<?xml version="1.0" ?>
<Problem>
  <!-- hexahedral mesh generated internally by GEOSX -->
  <Mesh>
    <InternalMesh
      name="mesh"
      elementTypes="{ C3D8 }"
      xCoords="{ -1500,1500}"
      yCoords="{ -1500,1500 }"
      zCoords="{ -1500,1500 }"
      nx="{ 150 }"
      ny="{ 150 }"
      nz="{ 150 }"
      cellBlockNames="{ cb }"/>
  </Mesh>

  <Geometry>
    <Box
      name="zpos"
      xMin="{ -1500.1, -1500.1, 1499.9}"
      xMax="{ 1500.1, 1500.1, 1500.1}"/>
    <Box
      name="zneg"
      xMin="{ -1500.1, -1500.1, -1500.1}"
      xMax="{ 1500.1, 1500.1, -1499.9}"/>
    <Box
      name="xpos"
      xMin="{ 1499.9, -1500.1, -1500.1}"
      xMax="{ 1500.1, 1500.1, 1500.1}"/>
    <Box
      name="xneg"
      xMin="{ -1500.1, -1500.1, -1500.1}"
      xMax="{ -1499.9, 1500.1, 1500.1}"/>
    <Box
      name="ypos"
      xMin="{ -1500.1, 1499.9, -1500.1}"
      xMax="{ 1500.1, 1500.1, 1500.1}"/>
    <Box
      name="yneg"
      xMin="{ -1500.1, -1500.1, -1500.1}"
      xMax="{ 1500.1, -1499.9, 1500.1}"/>
  </Geometry>

    <!-- The free surface condition the domain -->
  <FieldSpecifications>
    <FieldSpecification
      name="zposFreeSurface"
      objectPath="faceManager"
      fieldName="acousticFreeSurface"
      scale="0.0"
      setNames="{ zpos }"/>
    <FieldSpecification
      name="znegBottomSurface"
      objectPath="faceManager"
      fieldName="acousticBottomSurface"
      scale="0.0"
      setNames="{ zneg }"/>
    <FieldSpecification
      name="LateralFreeSurface"
      objectPath="faceManager"
      fieldName="acousticLateralSurface"
      scale="0.0"
      setNames="{ xpos, xneg, ypos, yneg }"/>
  </FieldSpecifications>

  <Solvers>
    <AcousticSEM
    name="acousticSolver"
      cflFactor="0.25"
      discretization="FE1"
      targetRegions="{ Region }"
      sourceCoordinates="{ { 0, 0, 0 } }"
      outputSeismoTrace = "1"
      dtSeismoTrace="0.0013"
      timeSourceFrequency="5"
      receiverCoordinates="{ { 1, 2, 3 }}"/>
  </Solvers>

  <NumericalMethods>
    <FiniteElements>
      <FiniteElementSpace
        name="FE1"
        order="1"
        formulation="SEM"/>
    </FiniteElements>
  </NumericalMethods>

  <ElementRegions>
    <CellElementRegion
      name="Region"
      cellBlocks="{ cb }"
      materialList="{ nullModel }"/>
  </ElementRegions>

  <Constitutive>
    <NullModel
      name="nullModel"/>
  </Constitutive>

  <FieldSpecifications>
    <!-- 1) The initial pressure field -->
    <FieldSpecification
      name="initialPressure_n"
      initialCondition="1"
      setNames="{ all }"
      objectPath="nodeManager"
      fieldName="pressure_n"
      scale="0.0"/>

    <FieldSpecification
      name="initialPressure_nm1"
      initialCondition="1"
      setNames="{ all }"
      objectPath="nodeManager"
      fieldName="pressure_nm1"
      scale="0.0"/>

    <!-- 2) The velocity in the domain -->
    <FieldSpecification
      name="cellVelocity"
      initialCondition="1"
      objectPath="ElementRegions/Region/cb"
      fieldName="acousticVelocity"
      scale="3000"
      setNames="{ all }"/>

    <FieldSpecification
      name="cellDensity"
      initialCondition="1"
      objectPath="ElementRegions/Region/cb"
      fieldName="acousticDensity"
      scale="1.0"
      setNames="{ all }"/>
    </FieldSpecifications>
  <Events
    maxTime="0.5">
    <!-- trigger the application of the solver -->
    <!-- control the timestepping here with forceDt -->
    <PeriodicEvent
      name="solverApplications"
      forceDt="0.0013"
      target="/Solvers/acousticSolver"/>
  </Events>
  <!-- collect the pressure values at the nodes -->
  <Tasks>
    <PackCollection
      name="pressureCollection"
      objectPath="/Problem/domain/MeshBodies/mesh/meshLevels/FE1/nodeManager"
      fieldName="pressure_np1"/>
  </Tasks>
</Problem>

Thank you and sorry for the long issue!

sframba commented 7 months ago

Related to #2888

sframba commented 3 months ago

Solved by PR #3202