Hi Matthew,

I have joined the ex44.c example so you can see that we see.

The problem is about the "f" field number which I can't see any clue in the documentation to what to put there... We are missing some information maybe written elsewhere?

I have tried 3 different calls (lines 180-182) with comments aside:

  //ierr = DMSetBasicAdjacency(ddm, PETSC_TRUE, PETSC_FALSE); CHKERRQ(ierr); //This works: it give only 2 cells for the overlap   //ierr = DMSetAdjacency(ddm, 0, PETSC_TRUE, PETSC_FALSE); CHKERRQ(ierr); //This works too, but why do I have to use field #0 ???  Is it a convention?   ierr = DMSetAdjacency(ddm, PETSC_DEFAULT, PETSC_TRUE, PETSC_FALSE); CHKERRQ(ierr); //This does not works: it give 3 cells for the overlap instead of 2.

Also, do you think your gitlab/knepley/fix-plex-g2n branch will find it's way into next or main? ;)

Thanks,

Eric

On 2021-11-10 3:26 p.m., Matthew Knepley wrote:
Okay, so the PETSC_DEFAULT one is what is used for topology. There  are two separate uses for adjacency info. First, for this kind of topological extension, and the second is for calculating Jacobians. You should be able to see the difference between FEM and FVM in just the case of a 2x2 mesh where each process gets 1 cell. With FEM, the overlap is the whole mesh, whereas with FVM it leaves out the diagonal partner.

  Thanks,

     Matt

static char help[] = "The main goal of this code is to retrieve the original element numbers as found in the "
                     "initial partitions (sInitialPartition)... but after the call to DMPlexDistribute";

#include <petsc.h>

PetscReal sCoords2x5Mesh[18][2] = {
 {0.00000000000000000e+00, 0.00000000000000000e+00},
 {2.00000000000000000e+00, 0.00000000000000000e+00},
 {0.00000000000000000e+00, 1.00000000000000000e+00},
 {2.00000000000000000e+00, 1.00000000000000000e+00},
 {9.99999999997387978e-01, 0.00000000000000000e+00},
 {9.99999999997387978e-01, 1.00000000000000000e+00},
 {0.00000000000000000e+00, 2.00000000000000011e-01},
 {0.00000000000000000e+00, 4.00000000000000022e-01},
 {0.00000000000000000e+00, 5.99999999999999978e-01},
 {0.00000000000000000e+00, 8.00000000000000044e-01},
 {2.00000000000000000e+00, 2.00000000000000011e-01},
 {2.00000000000000000e+00, 4.00000000000000022e-01},
 {2.00000000000000000e+00, 5.99999999999999978e-01},
 {2.00000000000000000e+00, 8.00000000000000044e-01},
 {9.99999999997387756e-01, 2.00000000000000011e-01},
 {9.99999999997387978e-01, 4.00000000000000022e-01},
 {9.99999999997387978e-01, 6.00000000000000089e-01},
 {9.99999999997388089e-01, 8.00000000000000044e-01}};

//Connectivity of a 2x5 rectangular mesh of quads :
const PetscInt sConnectivity2x5Mesh[10][4] = {
  {0,4,14,6},
  {6,14,15,7},
  {7,15,16,8},
  {8,16,17,9},
  {9,17,5,2},
  {4,1,10,14},
  {14,10,11,15},
  {15,11,12,16},
  {16,12,13,17},
  {17,13,3,5}};

const PetscInt sInitialPartition2x5Mesh[2][5] = {
  {0,2,4,6,8},
  {1,3,5,7,9}
};

const PetscInt sNLoclCells2x5Mesh = 5;
const PetscInt sNGlobVerts2x5Mesh = 18;

int main(int argc, char **argv)
{
  const PetscInt   Nc                 = sNLoclCells2x5Mesh; //Same on each rank for this example...
  const PetscInt   Nv                 = sNGlobVerts2x5Mesh;
  const PetscInt*  InitPartForRank[2] = {&sInitialPartition2x5Mesh[0][0],
                                         &sInitialPartition2x5Mesh[1][0]};
  const PetscInt (*Conn)[4]           = sConnectivity2x5Mesh;

  const PetscInt   Ncor = 4;
  const PetscInt   dim  = 2;
  DM               dm, idm, ddm;
  PetscSF          sfVert, sfMig, sfPart;
  PetscPartitioner part;
  PetscSection     s;
  PetscInt        *cells, c;
  PetscMPIInt      size, rank;
  PetscBool        box = PETSC_FALSE, field = PETSC_FALSE;
  PetscErrorCode   ierr;

  ierr = PetscInitialize(&argc, &argv, NULL, help);if (ierr) return ierr;
  ierr = MPI_Comm_size(PETSC_COMM_WORLD, &size);CHKERRMPI(ierr);
  ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank);CHKERRMPI(ierr);
  if (size != 2) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "This is a 2 processors example only");
  ierr = PetscOptionsGetBool(NULL, NULL, "-box", &box, NULL);CHKERRQ(ierr);
  ierr = PetscOptionsGetBool(NULL, NULL, "-field", &field, NULL);CHKERRQ(ierr);

  ierr = DMPlexCreate(PETSC_COMM_WORLD, &dm);CHKERRQ(ierr);
  if (box) {
    ierr = DMSetType(dm, DMPLEX);CHKERRQ(ierr);
    ierr = DMSetFromOptions(dm);CHKERRQ(ierr);
  } else {
    ierr = PetscMalloc1(Nc * Ncor, &cells);CHKERRQ(ierr);
    for (c = 0; c < Nc; ++c) {
      PetscInt cell = (InitPartForRank[rank])[c], cor;

      for (cor = 0; cor < Ncor; ++cor) {
        cells[c*Ncor + cor] = Conn[cell][cor];
      }
    }
    ierr = DMSetDimension(dm, dim);CHKERRQ(ierr);
    ierr = DMPlexBuildFromCellListParallel(dm, Nc, PETSC_DECIDE, Nv, Ncor, cells, &sfVert);CHKERRQ(ierr);
    //ierr = DMPlexBuildCoordinatesFromCellListParallel(dm, dim, sfVert, coords);CHKERRQ(ierr);
    ierr = PetscSFDestroy(&sfVert);CHKERRQ(ierr);
    ierr = PetscFree(cells);CHKERRQ(ierr);
    ierr = DMPlexInterpolate(dm, &idm);CHKERRQ(ierr);
    ierr = DMDestroy(&dm);CHKERRQ(ierr);
    dm   = idm;
  }
  ierr = DMSetUseNatural(dm, PETSC_TRUE);CHKERRQ(ierr);
  ierr = DMViewFromOptions(dm, NULL, "-dm_view");CHKERRQ(ierr);

  if (field) {
   const PetscInt Nf         = 1;
   const PetscInt numComp[1] = {1};
   const PetscInt numDof[3]  = {0, 0, 1};
   const PetscInt numBC      = 0;

   ierr = DMSetNumFields(dm, Nf); CHKERRQ(ierr);
   ierr = DMPlexCreateSection(dm, NULL, numComp, numDof, numBC, NULL, NULL, NULL, NULL, &s);  CHKERRQ(ierr);
   ierr = DMSetLocalSection(dm, s); CHKERRQ(ierr);
   ierr = PetscSectionView(s, PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr);
   ierr = PetscSectionDestroy(&s);CHKERRQ(ierr);
  }

  ierr = DMPlexGetPartitioner(dm, &part);CHKERRQ(ierr);
  ierr = PetscPartitionerSetFromOptions(part);CHKERRQ(ierr);

  ierr = DMPlexDistribute(dm, 0, &sfMig, &ddm); CHKERRQ(ierr);
  ierr = PetscSFView(sfMig, PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr);
  ierr = PetscSFCreateInverseSF(sfMig, &sfPart); CHKERRQ(ierr);
  ierr = PetscObjectSetName((PetscObject) sfPart, "Inverse Migration SF");CHKERRQ(ierr);
  ierr = PetscSFView(sfPart, PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr);

  Vec lNatVec   ;
  Vec lGlobalVec;
  ierr = DMGetGlobalVector(dm,&lNatVec); CHKERRQ(ierr);
  ierr = PetscObjectSetName((PetscObject) lNatVec, "Natural Vector (initial partition)");CHKERRQ(ierr);
  PetscScalar   *lNatVecArray;
  ierr = VecGetArray(lNatVec, &lNatVecArray); CHKERRQ(ierr);

  //Copying the initial partition into the "natural" vector:
  for (c = 0; c < Nc; ++c) {
    lNatVecArray[c] = (InitPartForRank[rank])[c];
  }
  ierr = VecRestoreArray(lNatVec, &lNatVecArray); CHKERRQ(ierr);

  ierr = DMGetGlobalVector(ddm,&lGlobalVec); CHKERRQ(ierr);
  ierr = PetscObjectSetName((PetscObject) lGlobalVec, "Global Vector (reordered element numbers in the petsc distributed order)");CHKERRQ(ierr);
  ierr = VecZeroEntries(lGlobalVec); CHKERRQ(ierr);

  // The call to DMPlexNaturalToGlobalBegin/End does not produce our expected result...
  // In lGlobalVec, we expect to have:
  /*
   * Process [0]
   * 2.
   * 4.
   * 8.
   * 3.
   * 9.
   * Process [1]
   * 1.
   * 5.
   * 7.
   * 0.
   * 6.
   */

  ierr = DMPlexNaturalToGlobalBegin(ddm, lNatVec, lGlobalVec); CHKERRQ(ierr);
  ierr = DMPlexNaturalToGlobalEnd  (ddm, lNatVec, lGlobalVec); CHKERRQ(ierr);

  ierr = VecView(lNatVec, PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr);
  ierr = VecView(lGlobalVec, PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr);

  // Returning the Global vector to the natural one should give the initial values...
  ierr = VecZeroEntries(lNatVec); CHKERRQ(ierr);

  ierr = DMPlexGlobalToNaturalBegin(ddm, lGlobalVec, lNatVec); CHKERRQ(ierr);
  ierr = DMPlexGlobalToNaturalEnd  (ddm, lGlobalVec, lNatVec); CHKERRQ(ierr);

  ierr = VecView(lNatVec, PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr);

  //Verification
  ierr = VecGetArray(lNatVec, &lNatVecArray); CHKERRQ(ierr);

  //Verify that we got the initial partition back into the "natural" vector:
  PetscBool lResultBad = PETSC_FALSE;
  for (c = 0; c < Nc; ++c) {
    lResultBad |= lNatVecArray[c] != (InitPartForRank[rank])[c];
  }

  ierr = VecRestoreArray(lNatVec, &lNatVecArray); CHKERRQ(ierr);

  // Now create an Overlap:
  //ierr = DMSetBasicAdjacency(ddm, PETSC_TRUE, PETSC_FALSE); CHKERRQ(ierr); //This works: it give only 2 cells for the overlap
  //ierr = DMSetAdjacency(ddm, 0, PETSC_TRUE, PETSC_FALSE); CHKERRQ(ierr); //This works too, but why do I have to use field #0 ???  Is it a convention?
  ierr = DMSetAdjacency(ddm, PETSC_DEFAULT, PETSC_TRUE, PETSC_FALSE); CHKERRQ(ierr); //This does not works: it give 3 cells for the overlap instead of 2.
  DM ddmo;
  PetscSF sfo;
  ierr = DMPlexDistributeOverlap(ddm, 1, &sfo, &ddmo); CHKERRQ(ierr);

  IS lCellsWithOvl = 0;
  ierr = DMPlexGetCellNumbering(ddmo, &lCellsWithOvl); CHKERRQ(ierr);

  PetscScalar   *lGlobVecArray = 0;
  ierr = VecGetArray(lGlobalVec, &lGlobVecArray); CHKERRQ(ierr);
  PetscInt n = 0;
  const PetscInt   *lCellsPetscNum = 0;
  ierr = ISGetLocalSize(lCellsWithOvl, &n);  CHKERRQ(ierr);
  ierr = ISGetIndices(lCellsWithOvl, &lCellsPetscNum); CHKERRQ(ierr);
  int i;
  for (i = 0; i < n; i++) {
    const int lGlobCellNum  = lCellsPetscNum[i];
    const int lLocalCellNum = lGlobCellNum - rank*5; //hard coded 5 elements by process
    if (lGlobCellNum >= 0) {
      const int lInitialCellNum =  lGlobVecArray[lLocalCellNum];
      printf("[%d] petsc_cell_# %d is initial (as in sInitialPartition) cell num %d\n", rank, lCellsPetscNum[i], lInitialCellNum);
    }
    else {
      printf("[%d] overlap petsc_cell_# %d \n", rank, -lCellsPetscNum[i]-1);
    }
  }
  ierr = ISRestoreIndices(lCellsWithOvl, &lCellsPetscNum);
  ierr = ISView(lCellsWithOvl,PETSC_VIEWER_STDOUT_WORLD);  CHKERRQ(ierr);

  ierr = VecRestoreArray(lGlobalVec, &lGlobVecArray); CHKERRQ(ierr);
  ierr = DMRestoreGlobalVector(dm,&lNatVec); CHKERRQ(ierr);
  ierr = DMRestoreGlobalVector(ddm,&lGlobalVec); CHKERRQ(ierr);
  ierr = PetscSFDestroy(&sfMig);CHKERRQ(ierr);
  ierr = PetscSFDestroy(&sfPart);CHKERRQ(ierr);
  ierr = DMDestroy(&dm);CHKERRQ(ierr);
  ierr = DMDestroy(&ddm);CHKERRQ(ierr);
  ierr = PetscFinalize();

  return ierr || lResultBad;
}

/*TEST

  testset:
    args: -field
    nsize: 2

    test:
      suffix: 0
      args:

    test:
      suffix: 1
      args: -box -dm_plex_simplex 0 -dm_plex_box_faces 7,10 -dm_distribute

TEST*/

Reply via email to