Actual source code: ex19.c

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

  3: #include <petscsf.h>

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

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

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

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

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

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

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

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

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

 94:   PetscFunctionBegin;
 95:   PetscCall(PetscMalloc1(nLeaves + 1, &ctx->ilocal));
 96:   PetscCall(PetscMalloc1(nLeaves, &ctx->iremote));
 97:   ilocal          = ctx->ilocal;
 98:   iremote         = ctx->iremote;
 99:   ilocal[nLeaves] = -ctx->leaveStep;
100:   PetscCall(PetscSFCreate(ctx->comm, &sf));
101:   j = nLeaves - 1;
102:   for (PetscMPIInt r = 0; 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;
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:   j = 0;
140:   for (PetscMPIInt r = 0; r < ctx->size; r++) {
141:     for (k = 0; k < ctx->nLeavesPerRank; k++, j++) {
142:       if (!ctx->contiguousLeaves) ilocal[j + 1] = ilocal[j] + ctx->leaveStep;
143:       iremote[j].rank  = r;
144:       iremote[j].index = k;
145:     }
146:   }
147:   PetscCheck(j == nLeaves, PETSC_COMM_SELF, PETSC_ERR_PLIB, "j != nLeaves");
148:   PetscCall(PetscSFSetGraph(sf, nroots, nLeaves, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
149:   if (ctx->contiguousLeaves) {
150:     const PetscInt *tlocal;

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

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

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

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

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

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