Date: 2025-03-29T05:58:23+00:00

Actual source code: dmredundant.c

      1: #include <petsc/private/dmimpl.h>
      2: #include <petscdmredundant.h>

      4: typedef struct {
      5:   PetscMPIInt rank; /* owner */
      6:   PetscInt    N;    /* total number of dofs */
      7:   PetscInt    n;    /* owned number of dofs, n=N on owner, n=0 on non-owners */
      8: } DM_Redundant;

     10: static PetscErrorCode DMCreateMatrix_Redundant(DM dm, Mat *J)
     11: {
     12:   DM_Redundant          *red = (DM_Redundant *)dm->data;
     13:   ISLocalToGlobalMapping ltog;
     14:   PetscInt               i, rstart, rend, *cols;
     15:   PetscScalar           *vals;

     17:   PetscFunctionBegin;
     18:   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J));
     19:   PetscCall(MatSetSizes(*J, red->n, red->n, red->N, red->N));
     20:   PetscCall(MatSetType(*J, dm->mattype));
     21:   PetscCall(MatSeqAIJSetPreallocation(*J, red->n, NULL));
     22:   PetscCall(MatSeqBAIJSetPreallocation(*J, 1, red->n, NULL));
     23:   PetscCall(MatMPIAIJSetPreallocation(*J, red->n, NULL, red->N - red->n, NULL));
     24:   PetscCall(MatMPIBAIJSetPreallocation(*J, 1, red->n, NULL, red->N - red->n, NULL));

     26:   PetscCall(DMGetLocalToGlobalMapping(dm, &ltog));
     27:   PetscCall(MatSetLocalToGlobalMapping(*J, ltog, ltog));
     28:   PetscCall(MatSetDM(*J, dm));

     30:   PetscCall(PetscMalloc2(red->N, &cols, red->N, &vals));
     31:   for (i = 0; i < red->N; i++) {
     32:     cols[i] = i;
     33:     vals[i] = 0.0;
     34:   }
     35:   PetscCall(MatGetOwnershipRange(*J, &rstart, &rend));
     36:   for (i = rstart; i < rend; i++) PetscCall(MatSetValues(*J, 1, &i, red->N, cols, vals, INSERT_VALUES));
     37:   PetscCall(PetscFree2(cols, vals));
     38:   PetscCall(MatAssemblyBegin(*J, MAT_FINAL_ASSEMBLY));
     39:   PetscCall(MatAssemblyEnd(*J, MAT_FINAL_ASSEMBLY));
     40:   PetscFunctionReturn(PETSC_SUCCESS);
     41: }

     43: static PetscErrorCode DMDestroy_Redundant(DM dm)
     44: {
     45:   PetscFunctionBegin;
     46:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMRedundantSetSize_C", NULL));
     47:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMRedundantGetSize_C", NULL));
     48:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL));
     49:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
     50:   PetscCall(PetscFree(dm->data));
     51:   PetscFunctionReturn(PETSC_SUCCESS);
     52: }

     54: static PetscErrorCode DMCreateGlobalVector_Redundant(DM dm, Vec *gvec)
     55: {
     56:   DM_Redundant          *red = (DM_Redundant *)dm->data;
     57:   ISLocalToGlobalMapping ltog;

     59:   PetscFunctionBegin;
     61:   PetscAssertPointer(gvec, 2);
     62:   *gvec = NULL;
     63:   PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), gvec));
     64:   PetscCall(VecSetSizes(*gvec, red->n, red->N));
     65:   PetscCall(VecSetType(*gvec, dm->vectype));
     66:   PetscCall(DMGetLocalToGlobalMapping(dm, &ltog));
     67:   PetscCall(VecSetLocalToGlobalMapping(*gvec, ltog));
     68:   PetscCall(VecSetDM(*gvec, dm));
     69:   PetscFunctionReturn(PETSC_SUCCESS);
     70: }

     72: static PetscErrorCode DMCreateLocalVector_Redundant(DM dm, Vec *lvec)
     73: {
     74:   DM_Redundant *red = (DM_Redundant *)dm->data;

     76:   PetscFunctionBegin;
     78:   PetscAssertPointer(lvec, 2);
     79:   *lvec = NULL;
     80:   PetscCall(VecCreate(PETSC_COMM_SELF, lvec));
     81:   PetscCall(VecSetSizes(*lvec, red->N, red->N));
     82:   PetscCall(VecSetType(*lvec, dm->vectype));
     83:   PetscCall(VecSetDM(*lvec, dm));
     84:   PetscFunctionReturn(PETSC_SUCCESS);
     85: }

     87: static PetscErrorCode DMLocalToGlobalBegin_Redundant(DM dm, Vec l, InsertMode imode, Vec g)
     88: {
     89:   DM_Redundant      *red = (DM_Redundant *)dm->data;
     90:   const PetscScalar *lv;
     91:   PetscScalar       *gv;
     92:   PetscMPIInt        rank, iN;

     94:   PetscFunctionBegin;
     95:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
     96:   PetscCall(VecGetArrayRead(l, &lv));
     97:   PetscCall(VecGetArray(g, &gv));
     98:   switch (imode) {
     99:   case ADD_VALUES:
    100:   case MAX_VALUES: {
    101:     void        *source;
    102:     PetscScalar *buffer;
    103:     PetscInt     i;
    104:     if (rank == red->rank) {
    105:       buffer = gv;
    106:       source = MPI_IN_PLACE;
    107:       if (imode == ADD_VALUES)
    108:         for (i = 0; i < red->N; i++) buffer[i] = gv[i] + lv[i];
    109: #if !defined(PETSC_USE_COMPLEX)
    110:       if (imode == MAX_VALUES)
    111:         for (i = 0; i < red->N; i++) buffer[i] = PetscMax(gv[i], lv[i]);
    112: #endif
    113:     } else source = (void *)lv;
    114:     PetscCall(PetscMPIIntCast(red->N, &iN));
    115:     PetscCallMPI(MPI_Reduce(source, gv, iN, MPIU_SCALAR, (imode == ADD_VALUES) ? MPIU_SUM : MPIU_MAX, red->rank, PetscObjectComm((PetscObject)dm)));
    116:   } break;
    117:   case INSERT_VALUES:
    118:     PetscCall(PetscArraycpy(gv, lv, red->n));
    119:     break;
    120:   default:
    121:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "InsertMode not supported");
    122:   }
    123:   PetscCall(VecRestoreArrayRead(l, &lv));
    124:   PetscCall(VecRestoreArray(g, &gv));
    125:   PetscFunctionReturn(PETSC_SUCCESS);
    126: }

    128: static PetscErrorCode DMLocalToGlobalEnd_Redundant(DM dm, Vec l, InsertMode imode, Vec g)
    129: {
    130:   PetscFunctionBegin;
    131:   PetscFunctionReturn(PETSC_SUCCESS);
    132: }

    134: static PetscErrorCode DMGlobalToLocalBegin_Redundant(DM dm, Vec g, InsertMode imode, Vec l)
    135: {
    136:   DM_Redundant      *red = (DM_Redundant *)dm->data;
    137:   const PetscScalar *gv;
    138:   PetscScalar       *lv;
    139:   PetscMPIInt        iN;

    141:   PetscFunctionBegin;
    142:   PetscCall(VecGetArrayRead(g, &gv));
    143:   PetscCall(VecGetArray(l, &lv));
    144:   switch (imode) {
    145:   case INSERT_VALUES:
    146:     if (red->n) PetscCall(PetscArraycpy(lv, gv, red->n));
    147:     PetscCall(PetscMPIIntCast(red->N, &iN));
    148:     PetscCallMPI(MPI_Bcast(lv, iN, MPIU_SCALAR, red->rank, PetscObjectComm((PetscObject)dm)));
    149:     break;
    150:   default:
    151:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "InsertMode not supported");
    152:   }
    153:   PetscCall(VecRestoreArrayRead(g, &gv));
    154:   PetscCall(VecRestoreArray(l, &lv));
    155:   PetscFunctionReturn(PETSC_SUCCESS);
    156: }

    158: static PetscErrorCode DMGlobalToLocalEnd_Redundant(DM dm, Vec g, InsertMode imode, Vec l)
    159: {
    160:   PetscFunctionBegin;
    161:   PetscFunctionReturn(PETSC_SUCCESS);
    162: }

    164: static PetscErrorCode DMView_Redundant(DM dm, PetscViewer viewer)
    165: {
    166:   DM_Redundant *red = (DM_Redundant *)dm->data;
    167:   PetscBool     iascii;

    169:   PetscFunctionBegin;
    170:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
    171:   if (iascii) PetscCall(PetscViewerASCIIPrintf(viewer, "redundant: rank=%d N=%" PetscInt_FMT "\n", red->rank, red->N));
    172:   PetscFunctionReturn(PETSC_SUCCESS);
    173: }

    175: static PetscErrorCode DMCreateColoring_Redundant(DM dm, ISColoringType ctype, ISColoring *coloring)
    176: {
    177:   DM_Redundant    *red = (DM_Redundant *)dm->data;
    178:   PetscInt         i, nloc;
    179:   ISColoringValue *colors;

    181:   PetscFunctionBegin;
    182:   switch (ctype) {
    183:   case IS_COLORING_GLOBAL:
    184:     nloc = red->n;
    185:     break;
    186:   case IS_COLORING_LOCAL:
    187:     nloc = red->N;
    188:     break;
    189:   default:
    190:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown ISColoringType %d", (int)ctype);
    191:   }
    192:   PetscCall(PetscMalloc1(nloc, &colors));
    193:   for (i = 0; i < nloc; i++) PetscCall(ISColoringValueCast(i, colors + i));
    194:   PetscCall(ISColoringCreate(PetscObjectComm((PetscObject)dm), red->N, nloc, colors, PETSC_OWN_POINTER, coloring));
    195:   PetscCall(ISColoringSetType(*coloring, ctype));
    196:   PetscFunctionReturn(PETSC_SUCCESS);
    197: }

    199: static PetscErrorCode DMRefine_Redundant(DM dmc, MPI_Comm comm, DM *dmf)
    200: {
    201:   PetscMPIInt   flag;
    202:   DM_Redundant *redc = (DM_Redundant *)dmc->data;

    204:   PetscFunctionBegin;
    205:   if (comm == MPI_COMM_NULL) PetscCall(PetscObjectGetComm((PetscObject)dmc, &comm));
    206:   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dmc), comm, &flag));
    207:   PetscCheck(flag == MPI_CONGRUENT || flag == MPI_IDENT, PetscObjectComm((PetscObject)dmc), PETSC_ERR_SUP, "cannot change communicators");
    208:   PetscCall(DMRedundantCreate(comm, redc->rank, redc->N, dmf));
    209:   PetscFunctionReturn(PETSC_SUCCESS);
    210: }

    212: static PetscErrorCode DMCoarsen_Redundant(DM dmf, MPI_Comm comm, DM *dmc)
    213: {
    214:   PetscMPIInt   flag;
    215:   DM_Redundant *redf = (DM_Redundant *)dmf->data;

    217:   PetscFunctionBegin;
    218:   if (comm == MPI_COMM_NULL) PetscCall(PetscObjectGetComm((PetscObject)dmf, &comm));
    219:   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dmf), comm, &flag));
    220:   PetscCheck(flag == MPI_CONGRUENT || flag == MPI_IDENT, PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "cannot change communicators");
    221:   PetscCall(DMRedundantCreate(comm, redf->rank, redf->N, dmc));
    222:   PetscFunctionReturn(PETSC_SUCCESS);
    223: }

    225: static PetscErrorCode DMCreateInterpolation_Redundant(DM dmc, DM dmf, Mat *P, Vec *scale)
    226: {
    227:   DM_Redundant *redc = (DM_Redundant *)dmc->data;
    228:   DM_Redundant *redf = (DM_Redundant *)dmf->data;
    229:   PetscMPIInt   flag;
    230:   PetscInt      i, rstart, rend;

    232:   PetscFunctionBegin;
    233:   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dmc), PetscObjectComm((PetscObject)dmf), &flag));
    234:   PetscCheck(flag == MPI_CONGRUENT || flag == MPI_IDENT, PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "cannot change communicators");
    235:   PetscCheck(redc->rank == redf->rank, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_INCOMP, "Owning rank does not match");
    236:   PetscCheck(redc->N == redf->N, PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_INCOMP, "Global size does not match");
    237:   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmc), P));
    238:   PetscCall(MatSetSizes(*P, redc->n, redc->n, redc->N, redc->N));
    239:   PetscCall(MatSetType(*P, MATAIJ));
    240:   PetscCall(MatSeqAIJSetPreallocation(*P, 1, NULL));
    241:   PetscCall(MatMPIAIJSetPreallocation(*P, 1, NULL, 0, NULL));
    242:   PetscCall(MatGetOwnershipRange(*P, &rstart, &rend));
    243:   for (i = rstart; i < rend; i++) PetscCall(MatSetValue(*P, i, i, 1.0, INSERT_VALUES));
    244:   PetscCall(MatAssemblyBegin(*P, MAT_FINAL_ASSEMBLY));
    245:   PetscCall(MatAssemblyEnd(*P, MAT_FINAL_ASSEMBLY));
    246:   if (scale) PetscCall(DMCreateInterpolationScale(dmc, dmf, *P, scale));
    247:   PetscFunctionReturn(PETSC_SUCCESS);
    248: }

    250: /*@
    251:   DMRedundantSetSize - Sets the size of a densely coupled redundant object

    253:   Collective

    255:   Input Parameters:
    256: + dm   - `DM` object of type `DMREDUNDANT`
    257: . rank - rank of process to own the redundant degrees of freedom
    258: - N    - total number of redundant degrees of freedom

    260:   Level: advanced

    262: .seealso: `DM`, `DMREDUNDANT`, `DMDestroy()`, `DMCreateGlobalVector()`, `DMRedundantCreate()`, `DMRedundantGetSize()`
    263: @*/
    264: PetscErrorCode DMRedundantSetSize(DM dm, PetscMPIInt rank, PetscInt N)
    265: {
    266:   PetscFunctionBegin;
    271:   PetscTryMethod(dm, "DMRedundantSetSize_C", (DM, PetscMPIInt, PetscInt), (dm, rank, N));
    272:   PetscFunctionReturn(PETSC_SUCCESS);
    273: }

    275: /*@
    276:   DMRedundantGetSize - Gets the size of a densely coupled redundant object

    278:   Not Collective

    280:   Input Parameter:
    281: . dm - `DM` object of type `DMREDUNDANT`

    283:   Output Parameters:
    284: + rank - rank of process to own the redundant degrees of freedom (or `NULL`)
    285: - N    - total number of redundant degrees of freedom (or `NULL`)

    287:   Level: advanced

    289: .seealso: `DM`, `DMREDUNDANT`, `DMDestroy()`, `DMCreateGlobalVector()`, `DMRedundantCreate()`, `DMRedundantSetSize()`
    290: @*/
    291: PetscErrorCode DMRedundantGetSize(DM dm, PetscMPIInt *rank, PetscInt *N)
    292: {
    293:   PetscFunctionBegin;
    296:   PetscUseMethod(dm, "DMRedundantGetSize_C", (DM, PetscMPIInt *, PetscInt *), (dm, rank, N));
    297:   PetscFunctionReturn(PETSC_SUCCESS);
    298: }

    300: static PetscErrorCode DMRedundantSetSize_Redundant(DM dm, PetscMPIInt rank, PetscInt N)
    301: {
    302:   DM_Redundant *red = (DM_Redundant *)dm->data;
    303:   PetscMPIInt   myrank;
    304:   PetscInt      i, *globals;

    306:   PetscFunctionBegin;
    307:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &myrank));
    308:   red->rank = rank;
    309:   red->N    = N;
    310:   red->n    = (myrank == rank) ? N : 0;

    312:   /* mapping is setup here */
    313:   PetscCall(PetscMalloc1(red->N, &globals));
    314:   for (i = 0; i < red->N; i++) globals[i] = i;
    315:   PetscCall(ISLocalToGlobalMappingDestroy(&dm->ltogmap));
    316:   PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), 1, red->N, globals, PETSC_OWN_POINTER, &dm->ltogmap));
    317:   PetscFunctionReturn(PETSC_SUCCESS);
    318: }

    320: static PetscErrorCode DMRedundantGetSize_Redundant(DM dm, PetscInt *rank, PetscInt *N)
    321: {
    322:   DM_Redundant *red = (DM_Redundant *)dm->data;

    324:   PetscFunctionBegin;
    325:   if (rank) *rank = red->rank;
    326:   if (N) *N = red->N;
    327:   PetscFunctionReturn(PETSC_SUCCESS);
    328: }

    330: static PetscErrorCode DMSetUpGLVisViewer_Redundant(PetscObject odm, PetscViewer viewer)
    331: {
    332:   PetscFunctionBegin;
    333:   PetscFunctionReturn(PETSC_SUCCESS);
    334: }

    336: /*MC
    337:    DMREDUNDANT = "redundant" - A DM object that is used to manage data for a small set of dense globally coupled variables.
    338:          In the global representation of the vector the variables are all stored on a single MPI process (all the other MPI processes have
    339:          no variables) in the local representation all the variables are stored on ALL the MPI processes (because they are all needed for each
    340:          processes local computations).

    342:          This DM is generally used inside a DMCOMPOSITE object. For example, it may be used to store continuation parameters for a bifurcation problem.

    344:   Level: intermediate

    346: .seealso: `DMType`, `DMCOMPOSITE`, `DMCreate()`, `DMRedundantSetSize()`, `DMRedundantGetSize()`
    347: M*/

    349: PETSC_EXTERN PetscErrorCode DMCreate_Redundant(DM dm)
    350: {
    351:   DM_Redundant *red;

    353:   PetscFunctionBegin;
    354:   PetscCall(PetscNew(&red));
    355:   dm->data = red;

    357:   dm->ops->view                = DMView_Redundant;
    358:   dm->ops->createglobalvector  = DMCreateGlobalVector_Redundant;
    359:   dm->ops->createlocalvector   = DMCreateLocalVector_Redundant;
    360:   dm->ops->creatematrix        = DMCreateMatrix_Redundant;
    361:   dm->ops->destroy             = DMDestroy_Redundant;
    362:   dm->ops->globaltolocalbegin  = DMGlobalToLocalBegin_Redundant;
    363:   dm->ops->globaltolocalend    = DMGlobalToLocalEnd_Redundant;
    364:   dm->ops->localtoglobalbegin  = DMLocalToGlobalBegin_Redundant;
    365:   dm->ops->localtoglobalend    = DMLocalToGlobalEnd_Redundant;
    366:   dm->ops->refine              = DMRefine_Redundant;
    367:   dm->ops->coarsen             = DMCoarsen_Redundant;
    368:   dm->ops->createinterpolation = DMCreateInterpolation_Redundant;
    369:   dm->ops->getcoloring         = DMCreateColoring_Redundant;

    371:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMRedundantSetSize_C", DMRedundantSetSize_Redundant));
    372:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMRedundantGetSize_C", DMRedundantGetSize_Redundant));
    373:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", DMSetUpGLVisViewer_Redundant));
    374:   PetscFunctionReturn(PETSC_SUCCESS);
    375: }

    377: /*@
    378:   DMRedundantCreate - Creates a `DM` object, used to manage data for dense globally coupled variables

    380:   Collective

    382:   Input Parameters:
    383: + comm - the processors that will share the global vector
    384: . rank - the MPI rank to own the redundant values
    385: - N    - total number of degrees of freedom

    387:   Output Parameter:
    388: . dm - the `DM` object of type `DMREDUNDANT`

    390:   Level: advanced

    392: .seealso: `DM`, `DMREDUNDANT`, `DMDestroy()`, `DMCreateGlobalVector()`, `DMCreateMatrix()`, `DMCompositeAddDM()`, `DMSetType()`, `DMRedundantSetSize()`, `DMRedundantGetSize()`
    393: @*/
    394: PetscErrorCode DMRedundantCreate(MPI_Comm comm, PetscMPIInt rank, PetscInt N, DM *dm)
    395: {
    396:   PetscFunctionBegin;
    397:   PetscAssertPointer(dm, 4);
    398:   PetscCall(DMCreate(comm, dm));
    399:   PetscCall(DMSetType(*dm, DMREDUNDANT));
    400:   PetscCall(DMRedundantSetSize(*dm, rank, N));
    401:   PetscCall(DMSetUp(*dm));
    402:   PetscFunctionReturn(PETSC_SUCCESS);
    403: }