Date: 2025-03-28T21:11:20+00:00

Actual source code: aobasic.c

      1: /*
      2:     The most basic AO application ordering routines. These store the
      3:   entire orderings on each processor to be efficient but can require excessive memory
      4: */

      6: #include <../src/vec/is/ao/aoimpl.h>

      8: typedef struct {
      9:   PetscInt *app;   /* app[i] is the partner for the ith PETSc slot */
     10:   PetscInt *petsc; /* petsc[j] is the partner for the jth app slot */
     11: } AO_Basic;

     13: /*
     14:        All processors have the same data so processor 1 prints it
     15: */
     16: static PetscErrorCode AOView_Basic(AO ao, PetscViewer viewer)
     17: {
     18:   PetscMPIInt rank;
     19:   PetscInt    i;
     20:   AO_Basic   *aobasic = (AO_Basic *)ao->data;
     21:   PetscBool   iascii;

     23:   PetscFunctionBegin;
     24:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)ao), &rank));
     25:   if (rank == 0) {
     26:     PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
     27:     if (iascii) {
     28:       PetscCall(PetscViewerASCIIPrintf(viewer, "Number of elements in ordering %" PetscInt_FMT "\n", ao->N));
     29:       PetscCall(PetscViewerASCIIPrintf(viewer, "PETSc->App  App->PETSc\n"));
     30:       for (i = 0; i < ao->N; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT "  %3" PetscInt_FMT "    %3" PetscInt_FMT "  %3" PetscInt_FMT "\n", i, aobasic->app[i], i, aobasic->petsc[i]));
     31:     }
     32:   }
     33:   PetscCall(PetscViewerFlush(viewer));
     34:   PetscFunctionReturn(PETSC_SUCCESS);
     35: }

     37: static PetscErrorCode AODestroy_Basic(AO ao)
     38: {
     39:   AO_Basic *aobasic = (AO_Basic *)ao->data;

     41:   PetscFunctionBegin;
     42:   PetscCall(PetscFree2(aobasic->app, aobasic->petsc));
     43:   PetscCall(PetscFree(aobasic));
     44:   PetscFunctionReturn(PETSC_SUCCESS);
     45: }

     47: static PetscErrorCode AOPetscToApplication_Basic(AO ao, PetscInt n, PetscInt *ia)
     48: {
     49:   PetscInt  i, N = ao->N;
     50:   AO_Basic *aobasic = (AO_Basic *)ao->data;

     52:   PetscFunctionBegin;
     53:   for (i = 0; i < n; i++) {
     54:     if (ia[i] >= 0 && ia[i] < N) {
     55:       ia[i] = aobasic->app[ia[i]];
     56:     } else {
     57:       ia[i] = -1;
     58:     }
     59:   }
     60:   PetscFunctionReturn(PETSC_SUCCESS);
     61: }

     63: static PetscErrorCode AOApplicationToPetsc_Basic(AO ao, PetscInt n, PetscInt *ia)
     64: {
     65:   PetscInt  i, N = ao->N;
     66:   AO_Basic *aobasic = (AO_Basic *)ao->data;

     68:   PetscFunctionBegin;
     69:   for (i = 0; i < n; i++) {
     70:     if (ia[i] >= 0 && ia[i] < N) {
     71:       ia[i] = aobasic->petsc[ia[i]];
     72:     } else {
     73:       ia[i] = -1;
     74:     }
     75:   }
     76:   PetscFunctionReturn(PETSC_SUCCESS);
     77: }

     79: static PetscErrorCode AOPetscToApplicationPermuteInt_Basic(AO ao, PetscInt block, PetscInt *array)
     80: {
     81:   AO_Basic *aobasic = (AO_Basic *)ao->data;
     82:   PetscInt *temp;
     83:   PetscInt  i, j;

     85:   PetscFunctionBegin;
     86:   PetscCall(PetscMalloc1(ao->N * block, &temp));
     87:   for (i = 0; i < ao->N; i++) {
     88:     for (j = 0; j < block; j++) temp[i * block + j] = array[aobasic->petsc[i] * block + j];
     89:   }
     90:   PetscCall(PetscArraycpy(array, temp, ao->N * block));
     91:   PetscCall(PetscFree(temp));
     92:   PetscFunctionReturn(PETSC_SUCCESS);
     93: }

     95: static PetscErrorCode AOApplicationToPetscPermuteInt_Basic(AO ao, PetscInt block, PetscInt *array)
     96: {
     97:   AO_Basic *aobasic = (AO_Basic *)ao->data;
     98:   PetscInt *temp;
     99:   PetscInt  i, j;

    101:   PetscFunctionBegin;
    102:   PetscCall(PetscMalloc1(ao->N * block, &temp));
    103:   for (i = 0; i < ao->N; i++) {
    104:     for (j = 0; j < block; j++) temp[i * block + j] = array[aobasic->app[i] * block + j];
    105:   }
    106:   PetscCall(PetscArraycpy(array, temp, ao->N * block));
    107:   PetscCall(PetscFree(temp));
    108:   PetscFunctionReturn(PETSC_SUCCESS);
    109: }

    111: static PetscErrorCode AOPetscToApplicationPermuteReal_Basic(AO ao, PetscInt block, PetscReal *array)
    112: {
    113:   AO_Basic  *aobasic = (AO_Basic *)ao->data;
    114:   PetscReal *temp;
    115:   PetscInt   i, j;

    117:   PetscFunctionBegin;
    118:   PetscCall(PetscMalloc1(ao->N * block, &temp));
    119:   for (i = 0; i < ao->N; i++) {
    120:     for (j = 0; j < block; j++) temp[i * block + j] = array[aobasic->petsc[i] * block + j];
    121:   }
    122:   PetscCall(PetscArraycpy(array, temp, ao->N * block));
    123:   PetscCall(PetscFree(temp));
    124:   PetscFunctionReturn(PETSC_SUCCESS);
    125: }

    127: static PetscErrorCode AOApplicationToPetscPermuteReal_Basic(AO ao, PetscInt block, PetscReal *array)
    128: {
    129:   AO_Basic  *aobasic = (AO_Basic *)ao->data;
    130:   PetscReal *temp;
    131:   PetscInt   i, j;

    133:   PetscFunctionBegin;
    134:   PetscCall(PetscMalloc1(ao->N * block, &temp));
    135:   for (i = 0; i < ao->N; i++) {
    136:     for (j = 0; j < block; j++) temp[i * block + j] = array[aobasic->app[i] * block + j];
    137:   }
    138:   PetscCall(PetscArraycpy(array, temp, ao->N * block));
    139:   PetscCall(PetscFree(temp));
    140:   PetscFunctionReturn(PETSC_SUCCESS);
    141: }

    143: static const struct _AOOps AOOps_Basic = {
    144:   PetscDesignatedInitializer(view, AOView_Basic),
    145:   PetscDesignatedInitializer(destroy, AODestroy_Basic),
    146:   PetscDesignatedInitializer(petsctoapplication, AOPetscToApplication_Basic),
    147:   PetscDesignatedInitializer(applicationtopetsc, AOApplicationToPetsc_Basic),
    148:   PetscDesignatedInitializer(petsctoapplicationpermuteint, AOPetscToApplicationPermuteInt_Basic),
    149:   PetscDesignatedInitializer(applicationtopetscpermuteint, AOApplicationToPetscPermuteInt_Basic),
    150:   PetscDesignatedInitializer(petsctoapplicationpermutereal, AOPetscToApplicationPermuteReal_Basic),
    151:   PetscDesignatedInitializer(applicationtopetscpermutereal, AOApplicationToPetscPermuteReal_Basic),
    152: };

    154: PETSC_INTERN PetscErrorCode AOCreate_Basic(AO ao)
    155: {
    156:   AO_Basic       *aobasic;
    157:   PetscMPIInt     size, rank, count, *lens, *disp;
    158:   PetscInt        napp, *allpetsc, *allapp, ip, ia, N, i, *petsc = NULL, start;
    159:   IS              isapp = ao->isapp, ispetsc = ao->ispetsc;
    160:   MPI_Comm        comm;
    161:   const PetscInt *myapp, *mypetsc = NULL;

    163:   PetscFunctionBegin;
    164:   /* create special struct aobasic */
    165:   PetscCall(PetscNew(&aobasic));
    166:   ao->data   = (void *)aobasic;
    167:   ao->ops[0] = AOOps_Basic;
    168:   PetscCall(PetscObjectChangeTypeName((PetscObject)ao, AOBASIC));

    170:   PetscCall(ISGetLocalSize(isapp, &napp));
    171:   PetscCall(ISGetIndices(isapp, &myapp));

    173:   PetscCall(PetscMPIIntCast(napp, &count));

    175:   /* transmit all lengths to all processors */
    176:   PetscCall(PetscObjectGetComm((PetscObject)isapp, &comm));
    177:   PetscCallMPI(MPI_Comm_size(comm, &size));
    178:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
    179:   PetscCall(PetscMalloc2(size, &lens, size, &disp));
    180:   PetscCallMPI(MPI_Allgather(&count, 1, MPI_INT, lens, 1, MPI_INT, comm));
    181:   N = 0;
    182:   for (i = 0; i < size; i++) {
    183:     PetscCall(PetscMPIIntCast(N, disp + i)); /* = sum(lens[j]), j< i */
    184:     N += lens[i];
    185:   }
    186:   ao->N = N;
    187:   ao->n = N;

    189:   /* If mypetsc is 0 then use "natural" numbering */
    190:   if (napp) {
    191:     if (!ispetsc) {
    192:       start = disp[rank];
    193:       PetscCall(PetscMalloc1(napp + 1, &petsc));
    194:       for (i = 0; i < napp; i++) petsc[i] = start + i;
    195:     } else {
    196:       PetscCall(ISGetIndices(ispetsc, &mypetsc));
    197:       petsc = (PetscInt *)mypetsc;
    198:     }
    199:   }

    201:   /* get all indices on all processors */
    202:   PetscCall(PetscMalloc2(N, &allpetsc, N, &allapp));
    203:   PetscCallMPI(MPI_Allgatherv(petsc, count, MPIU_INT, allpetsc, lens, disp, MPIU_INT, comm));
    204:   PetscCallMPI(MPI_Allgatherv((void *)myapp, count, MPIU_INT, allapp, lens, disp, MPIU_INT, comm));
    205:   PetscCall(PetscFree2(lens, disp));

    207:   if (PetscDefined(USE_DEBUG)) {
    208:     PetscInt *sorted;
    209:     PetscCall(PetscMalloc1(N, &sorted));

    211:     PetscCall(PetscArraycpy(sorted, allpetsc, N));
    212:     PetscCall(PetscSortInt(N, sorted));
    213:     for (i = 0; i < N; i++) PetscCheck(sorted[i] == i, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PETSc ordering requires a permutation of numbers 0 to N-1, it is missing %" PetscInt_FMT " has %" PetscInt_FMT, i, sorted[i]);

    215:     PetscCall(PetscArraycpy(sorted, allapp, N));
    216:     PetscCall(PetscSortInt(N, sorted));
    217:     for (i = 0; i < N; i++) PetscCheck(sorted[i] == i, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Application ordering requires a permutation of numbers 0 to N-1, it is missing %" PetscInt_FMT " has %" PetscInt_FMT, i, sorted[i]);

    219:     PetscCall(PetscFree(sorted));
    220:   }

    222:   /* generate a list of application and PETSc node numbers */
    223:   PetscCall(PetscCalloc2(N, &aobasic->app, N, &aobasic->petsc));
    224:   for (i = 0; i < N; i++) {
    225:     ip = allpetsc[i];
    226:     ia = allapp[i];
    227:     /* check there are no duplicates */
    228:     PetscCheck(!aobasic->app[ip], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Duplicate in PETSc ordering at position %" PetscInt_FMT ". Already mapped to %" PetscInt_FMT ", not %" PetscInt_FMT ".", i, aobasic->app[ip] - 1, ia);
    229:     aobasic->app[ip] = ia + 1;
    230:     PetscCheck(!aobasic->petsc[ia], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Duplicate in Application ordering at position %" PetscInt_FMT ". Already mapped to %" PetscInt_FMT ", not %" PetscInt_FMT ".", i, aobasic->petsc[ia] - 1, ip);
    231:     aobasic->petsc[ia] = ip + 1;
    232:   }
    233:   if (napp && !mypetsc) PetscCall(PetscFree(petsc));
    234:   PetscCall(PetscFree2(allpetsc, allapp));
    235:   /* shift indices down by one */
    236:   for (i = 0; i < N; i++) {
    237:     aobasic->app[i]--;
    238:     aobasic->petsc[i]--;
    239:   }

    241:   PetscCall(ISRestoreIndices(isapp, &myapp));
    242:   if (napp) {
    243:     if (ispetsc) {
    244:       PetscCall(ISRestoreIndices(ispetsc, &mypetsc));
    245:     } else {
    246:       PetscCall(PetscFree(petsc));
    247:     }
    248:   }
    249:   PetscFunctionReturn(PETSC_SUCCESS);
    250: }

    252: /*@
    253:   AOCreateBasic - Creates a basic application ordering using two integer arrays.

    255:   Collective

    257:   Input Parameters:
    258: + comm    - MPI communicator that is to share `AO`
    259: . napp    - size of `myapp` and `mypetsc`
    260: . myapp   - integer array that defines an ordering
    261: - mypetsc - integer array that defines another ordering (may be `NULL` to
    262:             indicate the natural ordering, that is 0,1,2,3,...)

    264:   Output Parameter:
    265: . aoout - the new application ordering

    267:   Level: beginner

    269:   Note:
    270:   The arrays `myapp` and `mypetsc` must contain the all the integers 0 to `napp`-1 with no duplicates; that is there cannot be any "holes"
    271:   in the indices. Use `AOCreateMapping()` or `AOCreateMappingIS()` if you wish to have "holes" in the indices.

    273: .seealso: [](sec_ao), [](sec_scatter), `AO`, `AOCreateBasicIS()`, `AODestroy()`, `AOPetscToApplication()`, `AOApplicationToPetsc()`
    274: @*/
    275: PetscErrorCode AOCreateBasic(MPI_Comm comm, PetscInt napp, const PetscInt myapp[], const PetscInt mypetsc[], AO *aoout)
    276: {
    277:   IS              isapp, ispetsc;
    278:   const PetscInt *app = myapp, *petsc = mypetsc;

    280:   PetscFunctionBegin;
    281:   PetscCall(ISCreateGeneral(comm, napp, app, PETSC_USE_POINTER, &isapp));
    282:   if (mypetsc) {
    283:     PetscCall(ISCreateGeneral(comm, napp, petsc, PETSC_USE_POINTER, &ispetsc));
    284:   } else {
    285:     ispetsc = NULL;
    286:   }
    287:   PetscCall(AOCreateBasicIS(isapp, ispetsc, aoout));
    288:   PetscCall(ISDestroy(&isapp));
    289:   if (mypetsc) PetscCall(ISDestroy(&ispetsc));
    290:   PetscFunctionReturn(PETSC_SUCCESS);
    291: }

    293: /*@
    294:   AOCreateBasicIS - Creates a basic application ordering using two `IS` index sets.

    296:   Collective

    298:   Input Parameters:
    299: + isapp   - index set that defines an ordering
    300: - ispetsc - index set that defines another ordering (may be `NULL` to use the natural ordering)

    302:   Output Parameter:
    303: . aoout - the new application ordering

    305:   Level: beginner

    307:   Note:
    308:   The index sets `isapp` and `ispetsc` must contain the all the integers 0 to napp-1 (where napp is the length of the index sets) with no duplicates;
    309:   that is there cannot be any "holes"

    311: .seealso: [](sec_ao), [](sec_scatter), `IS`, `AO`, `AOCreateBasic()`, `AODestroy()`
    312: @*/
    313: PetscErrorCode AOCreateBasicIS(IS isapp, IS ispetsc, AO *aoout)
    314: {
    315:   MPI_Comm comm;
    316:   AO       ao;

    318:   PetscFunctionBegin;
    319:   PetscCall(PetscObjectGetComm((PetscObject)isapp, &comm));
    320:   PetscCall(AOCreate(comm, &ao));
    321:   PetscCall(AOSetIS(ao, isapp, ispetsc));
    322:   PetscCall(AOSetType(ao, AOBASIC));
    323:   PetscCall(AOViewFromOptions(ao, NULL, "-ao_view"));
    324:   *aoout = ao;
    325:   PetscFunctionReturn(PETSC_SUCCESS);
    326: }