Actual source code: ex19.c


  2: static char help[] = "Test leaf sorting in PetscSFSetGraph()\n\n";

  4: #include <petscsf.h>

  6: typedef struct {
  7:   MPI_Comm      comm;
  8:   PetscMPIInt   rank, size;
  9:   PetscInt      leaveStep, nLeavesPerRank;
 10:   PetscBool     contiguousLeaves;
 11:   PetscCopyMode localmode, remotemode;
 12:   PetscInt     *ilocal;
 13:   PetscSFNode  *iremote;
 14: } AppCtx;

 16: static PetscErrorCode GetOptions(MPI_Comm comm, AppCtx *ctx)
 17: {
 18:   PetscFunctionBegin;
 19:   ctx->comm             = comm;
 20:   ctx->nLeavesPerRank   = 4;
 21:   ctx->leaveStep        = 1;
 22:   ctx->contiguousLeaves = PETSC_FALSE;
 23:   ctx->localmode        = PETSC_OWN_POINTER;
 24:   ctx->remotemode       = PETSC_OWN_POINTER;
 25:   ctx->ilocal           = NULL;
 26:   ctx->iremote          = NULL;
 27:   PetscCall(PetscOptionsGetInt(NULL, NULL, "-n_leaves_per_rank", &ctx->nLeavesPerRank, NULL));
 28:   PetscCall(PetscOptionsGetInt(NULL, NULL, "-leave_step", &ctx->leaveStep, NULL));
 29:   PetscCall(PetscOptionsGetEnum(NULL, NULL, "-localmode", PetscCopyModes, (PetscEnum *)&ctx->localmode, NULL));
 30:   PetscCall(PetscOptionsGetEnum(NULL, NULL, "-remotemode", PetscCopyModes, (PetscEnum *)&ctx->remotemode, NULL));
 31:   ctx->contiguousLeaves = (PetscBool)(ctx->leaveStep == 1);
 32:   PetscCallMPI(MPI_Comm_size(comm, &ctx->size));
 33:   PetscCallMPI(MPI_Comm_rank(comm, &ctx->rank));
 34:   PetscFunctionReturn(PETSC_SUCCESS);
 35: }

 37: static PetscErrorCode PetscSFCheckEqual_Private(PetscSF sf0, PetscSF sf1)
 38: {
 39:   PetscInt  nRoot, nLeave;
 40:   Vec       vecRoot0, vecLeave0, vecRoot1, vecLeave1;
 41:   MPI_Comm  comm;
 42:   PetscBool flg;

 44:   PetscFunctionBegin;
 45:   PetscCall(PetscObjectGetComm((PetscObject)sf0, &comm));
 46:   PetscCall(PetscSFGetGraph(sf0, &nRoot, NULL, NULL, NULL));
 47:   PetscCall(PetscSFGetLeafRange(sf0, NULL, &nLeave));
 48:   nLeave++;
 49:   PetscCall(VecCreateMPI(comm, nRoot, PETSC_DECIDE, &vecRoot0));
 50:   PetscCall(VecCreateMPI(comm, nLeave, PETSC_DECIDE, &vecLeave0));
 51:   PetscCall(VecDuplicate(vecRoot0, &vecRoot1));
 52:   PetscCall(VecDuplicate(vecLeave0, &vecLeave1));
 53:   {
 54:     PetscRandom rand;

 56:     PetscCall(PetscRandomCreate(comm, &rand));
 57:     PetscCall(PetscRandomSetFromOptions(rand));
 58:     PetscCall(VecSetRandom(vecRoot0, rand));
 59:     PetscCall(VecSetRandom(vecLeave0, rand));
 60:     PetscCall(VecCopy(vecRoot0, vecRoot1));
 61:     PetscCall(VecCopy(vecLeave0, vecLeave1));
 62:     PetscCall(PetscRandomDestroy(&rand));
 63:   }

 65:   PetscCall(VecScatterBegin(sf0, vecRoot0, vecLeave0, ADD_VALUES, SCATTER_FORWARD));
 66:   PetscCall(VecScatterEnd(sf0, vecRoot0, vecLeave0, ADD_VALUES, SCATTER_FORWARD));
 67:   PetscCall(VecScatterBegin(sf1, vecRoot1, vecLeave1, ADD_VALUES, SCATTER_FORWARD));
 68:   PetscCall(VecScatterEnd(sf1, vecRoot1, vecLeave1, ADD_VALUES, SCATTER_FORWARD));
 69:   PetscCall(VecEqual(vecLeave0, vecLeave1, &flg));
 70:   PetscCheck(flg, comm, PETSC_ERR_PLIB, "leave vectors differ");

 72:   PetscCall(VecScatterBegin(sf0, vecLeave0, vecRoot0, ADD_VALUES, SCATTER_REVERSE));
 73:   PetscCall(VecScatterEnd(sf0, vecLeave0, vecRoot0, ADD_VALUES, SCATTER_REVERSE));
 74:   PetscCall(VecScatterBegin(sf1, vecLeave1, vecRoot1, ADD_VALUES, SCATTER_REVERSE));
 75:   PetscCall(VecScatterEnd(sf1, vecLeave1, vecRoot1, ADD_VALUES, SCATTER_REVERSE));
 76:   PetscCall(VecEqual(vecRoot0, vecRoot1, &flg));
 77:   PetscCheck(flg, comm, PETSC_ERR_PLIB, "root vectors differ");

 79:   PetscCall(VecDestroy(&vecRoot0));
 80:   PetscCall(VecDestroy(&vecRoot1));
 81:   PetscCall(VecDestroy(&vecLeave0));
 82:   PetscCall(VecDestroy(&vecLeave1));
 83:   PetscFunctionReturn(PETSC_SUCCESS);
 84: }

 86: PetscErrorCode CreateSF0(AppCtx *ctx, PetscSF *sf0)
 87: {
 88:   PetscInt     j, k, r;
 89:   PetscInt     nLeaves = ctx->nLeavesPerRank * ctx->size;
 90:   PetscInt     nroots  = ctx->nLeavesPerRank;
 91:   PetscSF      sf;
 92:   PetscInt    *ilocal;
 93:   PetscSFNode *iremote;

 95:   PetscFunctionBegin;
 96:   PetscCall(PetscMalloc1(nLeaves + 1, &ctx->ilocal));
 97:   PetscCall(PetscMalloc1(nLeaves, &ctx->iremote));
 98:   ilocal          = ctx->ilocal;
 99:   iremote         = ctx->iremote;
100:   ilocal[nLeaves] = -ctx->leaveStep;
101:   PetscCall(PetscSFCreate(ctx->comm, &sf));
102:   for (r = 0, j = nLeaves - 1; r < ctx->size; r++) {
103:     for (k = 0; k < ctx->nLeavesPerRank; k++, j--) {
104:       ilocal[j]        = ilocal[j + 1] + ctx->leaveStep;
105:       iremote[j].rank  = r;
106:       iremote[j].index = k;
107:     }
108:   }
109:   PetscCall(PetscSFSetGraph(sf, nroots, nLeaves, ilocal, ctx->localmode, iremote, ctx->remotemode));
110:   {
111:     const PetscInt *tlocal;
112:     PetscBool       sorted;

114:     PetscCall(PetscSFGetGraph(sf, NULL, NULL, &tlocal, NULL));
115:     PetscCheck(!ctx->contiguousLeaves || !tlocal, PETSC_COMM_SELF, PETSC_ERR_PLIB, "ilocal=NULL expected for contiguous case");
116:     if (tlocal) {
117:       PetscCall(PetscSortedInt(nLeaves, tlocal, &sorted));
118:       PetscCheck(sorted, PETSC_COMM_SELF, PETSC_ERR_PLIB, "ilocal expected to be sorted");
119:     }
120:   }
121:   *sf0 = sf;
122:   PetscFunctionReturn(PETSC_SUCCESS);
123: }

125: PetscErrorCode CreateSF1(AppCtx *ctx, PetscSF *sf1)
126: {
127:   PetscInt     j, k, r;
128:   PetscInt    *ilocal = NULL;
129:   PetscSFNode *iremote;
130:   PetscInt     nLeaves = ctx->nLeavesPerRank * ctx->size;
131:   PetscInt     nroots  = ctx->nLeavesPerRank;
132:   PetscSF      sf;

134:   PetscFunctionBegin;
135:   ilocal = NULL;
136:   if (!ctx->contiguousLeaves) PetscCall(PetscCalloc1(nLeaves + 1, &ilocal));
137:   PetscCall(PetscMalloc1(nLeaves, &iremote));
138:   PetscCall(PetscSFCreate(ctx->comm, &sf));
139:   for (r = 0, j = 0; r < ctx->size; r++) {
140:     for (k = 0; k < ctx->nLeavesPerRank; k++, j++) {
141:       if (!ctx->contiguousLeaves) ilocal[j + 1] = ilocal[j] + ctx->leaveStep;
142:       iremote[j].rank  = r;
143:       iremote[j].index = k;
144:     }
145:   }
146:   PetscCheck(j == nLeaves, PETSC_COMM_SELF, PETSC_ERR_PLIB, "j != nLeaves");
147:   PetscCall(PetscSFSetGraph(sf, nroots, nLeaves, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
148:   if (ctx->contiguousLeaves) {
149:     const PetscInt *tlocal;

151:     PetscCall(PetscSFGetGraph(sf, NULL, NULL, &tlocal, NULL));
152:     PetscCheck(!tlocal, PETSC_COMM_SELF, PETSC_ERR_PLIB, "ilocal=NULL expected for contiguous case");
153:   }
154:   *sf1 = sf;
155:   PetscFunctionReturn(PETSC_SUCCESS);
156: }

158: int main(int argc, char **argv)
159: {
160:   AppCtx   ctx;
161:   PetscSF  sf0, sf1;
162:   MPI_Comm comm;

164:   PetscFunctionBeginUser;
165:   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
166:   comm = PETSC_COMM_WORLD;
167:   PetscCall(GetOptions(comm, &ctx));

169:   PetscCall(CreateSF0(&ctx, &sf0));
170:   PetscCall(CreateSF1(&ctx, &sf1));
171:   PetscCall(PetscSFViewFromOptions(sf0, NULL, "-sf0_view"));
172:   PetscCall(PetscSFViewFromOptions(sf1, NULL, "-sf1_view"));
173:   PetscCall(PetscSFCheckEqual_Private(sf0, sf1));

175:   if (ctx.localmode != PETSC_OWN_POINTER) PetscCall(PetscFree(ctx.ilocal));
176:   if (ctx.remotemode != PETSC_OWN_POINTER) PetscCall(PetscFree(ctx.iremote));
177:   PetscCall(PetscSFDestroy(&sf0));
178:   PetscCall(PetscSFDestroy(&sf1));
179:   PetscCall(PetscFinalize());
180:   return 0;
181: }

183: /*TEST
184:   testset:
185:     suffix: 1
186:     nsize: {{1 3}}
187:     args: -n_leaves_per_rank {{0 5}} -leave_step {{1 3}}
188:     test:
189:       suffix: a
190:       args: -localmode {{COPY_VALUES OWN_POINTER}} -remotemode {{COPY_VALUES OWN_POINTER}}
191:     test:
192:       suffix: b
193:       args: -localmode USE_POINTER -remotemode {{COPY_VALUES OWN_POINTER USE_POINTER}}
194: TEST*/