1*c4762a1bSJed Brown static char help[] = "Test that shared points on interface of partitions can be rebalanced.\n\n"; 2*c4762a1bSJed Brown static char FILENAME[] = "ex31.c"; 3*c4762a1bSJed Brown 4*c4762a1bSJed Brown #include <petscdmplex.h> 5*c4762a1bSJed Brown #include <petscviewerhdf5.h> 6*c4762a1bSJed Brown #include "petscsf.h" 7*c4762a1bSJed Brown 8*c4762a1bSJed Brown 9*c4762a1bSJed Brown typedef struct { 10*c4762a1bSJed Brown PetscInt dim; /* The topological mesh dimension */ PetscInt faces[3]; /* Number of faces per dimension */ 11*c4762a1bSJed Brown PetscBool simplex; /* Use simplices or hexes */ 12*c4762a1bSJed Brown PetscBool interpolate; /* Interpolate mesh */ 13*c4762a1bSJed Brown PetscBool parallel; /* Use ParMetis or Metis */ 14*c4762a1bSJed Brown PetscBool useInitialGuess; /* Only active when in parallel, uses RefineKway of ParMetis */ 15*c4762a1bSJed Brown PetscInt entityDepth; /* depth of the entities to rebalance ( 0 => vertices ) */ 16*c4762a1bSJed Brown } AppCtx; 17*c4762a1bSJed Brown 18*c4762a1bSJed Brown static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options) 19*c4762a1bSJed Brown { 20*c4762a1bSJed Brown PetscInt dim; 21*c4762a1bSJed Brown PetscErrorCode ierr; 22*c4762a1bSJed Brown 23*c4762a1bSJed Brown PetscFunctionBegin; 24*c4762a1bSJed Brown options->dim = 3; 25*c4762a1bSJed Brown options->simplex = PETSC_FALSE; 26*c4762a1bSJed Brown options->interpolate = PETSC_FALSE; 27*c4762a1bSJed Brown options->entityDepth = 0; 28*c4762a1bSJed Brown options->parallel = PETSC_FALSE; 29*c4762a1bSJed Brown options->useInitialGuess = PETSC_FALSE; 30*c4762a1bSJed Brown options->entityDepth = 0; 31*c4762a1bSJed Brown ierr = PetscOptionsBegin(comm, "", "Meshing Interpolation Test Options", "DMPLEX");CHKERRQ(ierr); 32*c4762a1bSJed Brown ierr = PetscOptionsBoundedInt("-entity_depth", "Depth of the entities to rebalance ( 0 => vertices )", FILENAME, options->entityDepth, &options->entityDepth, NULL,0);CHKERRQ(ierr); 33*c4762a1bSJed Brown ierr = PetscOptionsRangeInt("-dim", "The topological mesh dimension", FILENAME, options->dim, &options->dim, NULL,1,3);CHKERRQ(ierr); 34*c4762a1bSJed Brown if (options->dim > 3) SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "dimension set to %d, must be <= 3", options->dim); 35*c4762a1bSJed Brown ierr = PetscOptionsBool("-simplex", "Use simplices if true, otherwise hexes", FILENAME, options->simplex, &options->simplex, NULL);CHKERRQ(ierr); 36*c4762a1bSJed Brown ierr = PetscOptionsBool("-interpolate", "Interpolate the mesh", FILENAME, options->interpolate, &options->interpolate, NULL);CHKERRQ(ierr); 37*c4762a1bSJed Brown ierr = PetscOptionsBool("-parallel", "Use ParMetis instead of Metis", FILENAME, options->parallel, &options->parallel, NULL);CHKERRQ(ierr); 38*c4762a1bSJed Brown ierr = PetscOptionsBool("-use_initial_guess", "Use RefineKway function of ParMetis", FILENAME, options->useInitialGuess, &options->useInitialGuess, NULL);CHKERRQ(ierr); 39*c4762a1bSJed Brown options->faces[0] = 1; options->faces[1] = 1; options->faces[2] = 1; 40*c4762a1bSJed Brown dim = options->dim; 41*c4762a1bSJed Brown ierr = PetscOptionsIntArray("-faces", "Number of faces per dimension", FILENAME, options->faces, &dim, NULL);CHKERRQ(ierr); 42*c4762a1bSJed Brown if (dim) options->dim = dim; 43*c4762a1bSJed Brown ierr = PetscOptionsEnd(); 44*c4762a1bSJed Brown PetscFunctionReturn(0); 45*c4762a1bSJed Brown } 46*c4762a1bSJed Brown 47*c4762a1bSJed Brown 48*c4762a1bSJed Brown static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm) 49*c4762a1bSJed Brown { 50*c4762a1bSJed Brown PetscInt dim = user->dim; 51*c4762a1bSJed Brown PetscInt *faces = user->faces; 52*c4762a1bSJed Brown PetscBool simplex = user->simplex; 53*c4762a1bSJed Brown PetscBool interpolate = user->interpolate; 54*c4762a1bSJed Brown PetscMPIInt rank; 55*c4762a1bSJed Brown PetscErrorCode ierr; 56*c4762a1bSJed Brown 57*c4762a1bSJed Brown PetscFunctionBegin; 58*c4762a1bSJed Brown ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 59*c4762a1bSJed Brown ierr = DMPlexCreateBoxMesh(comm, dim, simplex, faces, NULL, NULL, NULL, interpolate, dm);CHKERRQ(ierr); 60*c4762a1bSJed Brown PetscFunctionReturn(0); 61*c4762a1bSJed Brown } 62*c4762a1bSJed Brown 63*c4762a1bSJed Brown int main(int argc, char **argv) 64*c4762a1bSJed Brown { 65*c4762a1bSJed Brown MPI_Comm comm; 66*c4762a1bSJed Brown DM dm, dmdist; 67*c4762a1bSJed Brown PetscPartitioner part; 68*c4762a1bSJed Brown AppCtx user; 69*c4762a1bSJed Brown IS is=NULL; 70*c4762a1bSJed Brown PetscSection s=NULL, gsection=NULL; 71*c4762a1bSJed Brown PetscErrorCode ierr; 72*c4762a1bSJed Brown PetscMPIInt size; 73*c4762a1bSJed Brown PetscSF sf; 74*c4762a1bSJed Brown PetscInt pStart, pEnd, p, minBefore, maxBefore, minAfter, maxAfter, gSizeBefore, gSizeAfter; 75*c4762a1bSJed Brown PetscBool success; 76*c4762a1bSJed Brown 77*c4762a1bSJed Brown ierr = PetscInitialize(&argc, &argv, NULL,help);if (ierr) return ierr; 78*c4762a1bSJed Brown comm = PETSC_COMM_WORLD; 79*c4762a1bSJed Brown ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr); 80*c4762a1bSJed Brown ierr = ProcessOptions(comm, &user);CHKERRQ(ierr); 81*c4762a1bSJed Brown ierr = CreateMesh(comm, &user, &dm);CHKERRQ(ierr); 82*c4762a1bSJed Brown 83*c4762a1bSJed Brown /* partition dm using PETSCPARTITIONERPARMETIS */ 84*c4762a1bSJed Brown ierr = DMPlexGetPartitioner(dm, &part);CHKERRQ(ierr); 85*c4762a1bSJed Brown ierr = PetscObjectSetOptionsPrefix((PetscObject)part,"p_");CHKERRQ(ierr); 86*c4762a1bSJed Brown ierr = PetscPartitionerSetType(part, PETSCPARTITIONERPARMETIS);CHKERRQ(ierr); 87*c4762a1bSJed Brown ierr = PetscPartitionerSetFromOptions(part);CHKERRQ(ierr); 88*c4762a1bSJed Brown ierr = PetscSectionCreate(comm, &s);CHKERRQ(ierr); 89*c4762a1bSJed Brown ierr = PetscPartitionerDMPlexPartition(part, dm, NULL, s, &is);CHKERRQ(ierr); 90*c4762a1bSJed Brown 91*c4762a1bSJed Brown ierr = DMPlexDistribute(dm, 0, NULL, &dmdist);CHKERRQ(ierr); 92*c4762a1bSJed Brown if (dmdist) { 93*c4762a1bSJed Brown ierr = DMDestroy(&dm);CHKERRQ(ierr); 94*c4762a1bSJed Brown dm = dmdist; 95*c4762a1bSJed Brown } 96*c4762a1bSJed Brown 97*c4762a1bSJed Brown /* cleanup */ 98*c4762a1bSJed Brown ierr = PetscSectionDestroy(&s);CHKERRQ(ierr); 99*c4762a1bSJed Brown ierr = ISDestroy(&is);CHKERRQ(ierr); 100*c4762a1bSJed Brown 101*c4762a1bSJed Brown /* We make a PetscSection with a DOF on every mesh entity of depth 102*c4762a1bSJed Brown * user.entityDepth, then make a global section and look at its storage size. 103*c4762a1bSJed Brown * We do the same thing after the rebalancing and then assert that the size 104*c4762a1bSJed Brown * remains the same. We also make sure that the balance has improved at least 105*c4762a1bSJed Brown * a little bit compared to the initial decomposition. */ 106*c4762a1bSJed Brown 107*c4762a1bSJed Brown if (size>1) { 108*c4762a1bSJed Brown ierr = PetscSectionCreate(comm, &s);CHKERRQ(ierr); 109*c4762a1bSJed Brown ierr = PetscSectionSetNumFields(s, 1);CHKERRQ(ierr); 110*c4762a1bSJed Brown ierr = PetscSectionSetFieldComponents(s, 0, 1);CHKERRQ(ierr); 111*c4762a1bSJed Brown ierr = DMPlexGetDepthStratum(dm, user.entityDepth, &pStart, &pEnd);CHKERRQ(ierr); 112*c4762a1bSJed Brown ierr = PetscSectionSetChart(s, pStart, pEnd);CHKERRQ(ierr); 113*c4762a1bSJed Brown for (p = pStart; p < pEnd; ++p) { 114*c4762a1bSJed Brown ierr = PetscSectionSetDof(s, p, 1);CHKERRQ(ierr); 115*c4762a1bSJed Brown ierr = PetscSectionSetFieldDof(s, p, 0, 1);CHKERRQ(ierr); 116*c4762a1bSJed Brown } 117*c4762a1bSJed Brown ierr = PetscSectionSetUp(s);CHKERRQ(ierr); 118*c4762a1bSJed Brown ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr); 119*c4762a1bSJed Brown ierr = PetscSectionCreateGlobalSection(s, sf, PETSC_FALSE, PETSC_FALSE, &gsection);CHKERRQ(ierr); 120*c4762a1bSJed Brown ierr = PetscSectionGetStorageSize(gsection, &gSizeBefore);CHKERRQ(ierr); 121*c4762a1bSJed Brown minBefore = gSizeBefore; 122*c4762a1bSJed Brown maxBefore = gSizeBefore; 123*c4762a1bSJed Brown ierr = MPI_Allreduce(MPI_IN_PLACE, &gSizeBefore, 1, MPIU_INT, MPI_SUM, comm);CHKERRQ(ierr); 124*c4762a1bSJed Brown ierr = MPI_Allreduce(MPI_IN_PLACE, &minBefore, 1, MPIU_INT, MPI_MIN, comm);CHKERRQ(ierr); 125*c4762a1bSJed Brown ierr = MPI_Allreduce(MPI_IN_PLACE, &maxBefore, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr); 126*c4762a1bSJed Brown ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr); 127*c4762a1bSJed Brown } 128*c4762a1bSJed Brown 129*c4762a1bSJed Brown ierr = DMPlexRebalanceSharedPoints(dm, user.entityDepth, user.useInitialGuess, user.parallel, &success);CHKERRQ(ierr); 130*c4762a1bSJed Brown 131*c4762a1bSJed Brown if (size>1) { 132*c4762a1bSJed Brown ierr = PetscSectionCreateGlobalSection(s, sf, PETSC_FALSE, PETSC_FALSE, &gsection);CHKERRQ(ierr); 133*c4762a1bSJed Brown ierr = PetscSectionGetStorageSize(gsection, &gSizeAfter);CHKERRQ(ierr); 134*c4762a1bSJed Brown minAfter = gSizeAfter; 135*c4762a1bSJed Brown maxAfter = gSizeAfter; 136*c4762a1bSJed Brown ierr = MPI_Allreduce(MPI_IN_PLACE, &gSizeAfter, 1, MPIU_INT, MPI_SUM, comm);CHKERRQ(ierr); 137*c4762a1bSJed Brown ierr = MPI_Allreduce(MPI_IN_PLACE, &minAfter, 1, MPIU_INT, MPI_MIN, comm);CHKERRQ(ierr); 138*c4762a1bSJed Brown ierr = MPI_Allreduce(MPI_IN_PLACE, &maxAfter, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr); 139*c4762a1bSJed Brown if (gSizeAfter != gSizeBefore) SETERRQ(comm, PETSC_ERR_PLIB, "Global section has not the same size before and after."); 140*c4762a1bSJed Brown if (!(minAfter >= minBefore && maxAfter <= maxBefore && (minAfter > minBefore || maxAfter < maxBefore))) SETERRQ(comm, PETSC_ERR_PLIB, "DMPlexRebalanceSharedPoints did not improve mesh point balance."); 141*c4762a1bSJed Brown ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr); 142*c4762a1bSJed Brown ierr = PetscSectionDestroy(&s);CHKERRQ(ierr); 143*c4762a1bSJed Brown } 144*c4762a1bSJed Brown 145*c4762a1bSJed Brown ierr = DMDestroy(&dm);CHKERRQ(ierr); 146*c4762a1bSJed Brown 147*c4762a1bSJed Brown ierr = PetscFinalize(); 148*c4762a1bSJed Brown return ierr; 149*c4762a1bSJed Brown } 150*c4762a1bSJed Brown 151*c4762a1bSJed Brown /*TEST 152*c4762a1bSJed Brown 153*c4762a1bSJed Brown test: 154*c4762a1bSJed Brown # rebalance a mesh 155*c4762a1bSJed Brown suffix: 0 156*c4762a1bSJed Brown nsize: {{2 3 4}} 157*c4762a1bSJed Brown requires: parmetis 158*c4762a1bSJed Brown args: -faces {{2,3,4 5,4,3 7,11,5}} -interpolate -entity_depth {{0 1}} -parallel {{FALSE TRUE}} -use_initial_guess FALSE 159*c4762a1bSJed Brown 160*c4762a1bSJed Brown test: 161*c4762a1bSJed Brown # rebalance a mesh but use the initial guess (uses a random algorithm and gives different results on different machines, so just check that it runs). 162*c4762a1bSJed Brown suffix: 1 163*c4762a1bSJed Brown nsize: {{2 3 4}} 164*c4762a1bSJed Brown requires: parmetis 165*c4762a1bSJed Brown args: -faces {{2,3,4 5,4,3 7,11,5}} -interpolate -entity_depth {{0 1}} -parallel TRUE -use_initial_guess TRUE 166*c4762a1bSJed Brown 167*c4762a1bSJed Brown test: 168*c4762a1bSJed Brown # no-op in serial 169*c4762a1bSJed Brown suffix: 2 170*c4762a1bSJed Brown nsize: {{1}} 171*c4762a1bSJed Brown requires: parmetis 172*c4762a1bSJed Brown args: -faces 2,3,4 -interpolate -entity_depth 0 -parallel FALSE -use_initial_guess FALSE 173*c4762a1bSJed Brown 174*c4762a1bSJed Brown TEST*/ 175*c4762a1bSJed Brown 176