Date: 2025-03-28T21:10:48+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 DMSetUp_Redundant(DM dm)
    165: {
    166:   PetscFunctionBegin;
    167:   PetscFunctionReturn(PETSC_SUCCESS);
    168: }

    170: static PetscErrorCode DMView_Redundant(DM dm, PetscViewer viewer)
    171: {
    172:   DM_Redundant *red = (DM_Redundant *)dm->data;
    173:   PetscBool     iascii;

    175:   PetscFunctionBegin;
    176:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
    177:   if (iascii) PetscCall(PetscViewerASCIIPrintf(viewer, "redundant: rank=%d N=%" PetscInt_FMT "\n", red->rank, red->N));
    178:   PetscFunctionReturn(PETSC_SUCCESS);
    179: }

    181: static PetscErrorCode DMCreateColoring_Redundant(DM dm, ISColoringType ctype, ISColoring *coloring)
    182: {
    183:   DM_Redundant    *red = (DM_Redundant *)dm->data;
    184:   PetscInt         i, nloc;
    185:   ISColoringValue *colors;

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

    205: static PetscErrorCode DMRefine_Redundant(DM dmc, MPI_Comm comm, DM *dmf)
    206: {
    207:   PetscMPIInt   flag;
    208:   DM_Redundant *redc = (DM_Redundant *)dmc->data;

    210:   PetscFunctionBegin;
    211:   if (comm == MPI_COMM_NULL) PetscCall(PetscObjectGetComm((PetscObject)dmc, &comm));
    212:   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dmc), comm, &flag));
    213:   PetscCheck(flag == MPI_CONGRUENT || flag == MPI_IDENT, PetscObjectComm((PetscObject)dmc), PETSC_ERR_SUP, "cannot change communicators");
    214:   PetscCall(DMRedundantCreate(comm, redc->rank, redc->N, dmf));
    215:   PetscFunctionReturn(PETSC_SUCCESS);
    216: }

    218: static PetscErrorCode DMCoarsen_Redundant(DM dmf, MPI_Comm comm, DM *dmc)
    219: {
    220:   PetscMPIInt   flag;
    221:   DM_Redundant *redf = (DM_Redundant *)dmf->data;

    223:   PetscFunctionBegin;
    224:   if (comm == MPI_COMM_NULL) PetscCall(PetscObjectGetComm((PetscObject)dmf, &comm));
    225:   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dmf), comm, &flag));
    226:   PetscCheck(flag == MPI_CONGRUENT || flag == MPI_IDENT, PetscObjectComm((PetscObject)dmf), PETSC_ERR_SUP, "cannot change communicators");
    227:   PetscCall(DMRedundantCreate(comm, redf->rank, redf->N, dmc));
    228:   PetscFunctionReturn(PETSC_SUCCESS);
    229: }

    231: static PetscErrorCode DMCreateInterpolation_Redundant(DM dmc, DM dmf, Mat *P, Vec *scale)
    232: {
    233:   DM_Redundant *redc = (DM_Redundant *)dmc->data;
    234:   DM_Redundant *redf = (DM_Redundant *)dmf->data;
    235:   PetscMPIInt   flag;
    236:   PetscInt      i, rstart, rend;

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

    256: /*@
    257:   DMRedundantSetSize - Sets the size of a densely coupled redundant object

    259:   Collective

    261:   Input Parameters:
    262: + dm   - `DM` object of type `DMREDUNDANT`
    263: . rank - rank of process to own the redundant degrees of freedom
    264: - N    - total number of redundant degrees of freedom

    266:   Level: advanced

    268: .seealso: `DM`, `DMREDUNDANT`, `DMDestroy()`, `DMCreateGlobalVector()`, `DMRedundantCreate()`, `DMRedundantGetSize()`
    269: @*/
    270: PetscErrorCode DMRedundantSetSize(DM dm, PetscMPIInt rank, PetscInt N)
    271: {
    272:   PetscFunctionBegin;
    277:   PetscTryMethod(dm, "DMRedundantSetSize_C", (DM, PetscMPIInt, PetscInt), (dm, rank, N));
    278:   PetscFunctionReturn(PETSC_SUCCESS);
    279: }

    281: /*@
    282:   DMRedundantGetSize - Gets the size of a densely coupled redundant object

    284:   Not Collective

    286:   Input Parameter:
    287: . dm - `DM` object of type `DMREDUNDANT`

    289:   Output Parameters:
    290: + rank - rank of process to own the redundant degrees of freedom (or `NULL`)
    291: - N    - total number of redundant degrees of freedom (or `NULL`)

    293:   Level: advanced

    295: .seealso: `DM`, `DMREDUNDANT`, `DMDestroy()`, `DMCreateGlobalVector()`, `DMRedundantCreate()`, `DMRedundantSetSize()`
    296: @*/
    297: PetscErrorCode DMRedundantGetSize(DM dm, PetscMPIInt *rank, PetscInt *N)
    298: {
    299:   PetscFunctionBegin;
    302:   PetscUseMethod(dm, "DMRedundantGetSize_C", (DM, PetscMPIInt *, PetscInt *), (dm, rank, N));
    303:   PetscFunctionReturn(PETSC_SUCCESS);
    304: }

    306: static PetscErrorCode DMRedundantSetSize_Redundant(DM dm, PetscMPIInt rank, PetscInt N)
    307: {
    308:   DM_Redundant *red = (DM_Redundant *)dm->data;
    309:   PetscMPIInt   myrank;
    310:   PetscInt      i, *globals;

    312:   PetscFunctionBegin;
    313:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &myrank));
    314:   red->rank = rank;
    315:   red->N    = N;
    316:   red->n    = (myrank == rank) ? N : 0;

    318:   /* mapping is setup here */
    319:   PetscCall(PetscMalloc1(red->N, &globals));
    320:   for (i = 0; i < red->N; i++) globals[i] = i;
    321:   PetscCall(ISLocalToGlobalMappingDestroy(&dm->ltogmap));
    322:   PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), 1, red->N, globals, PETSC_OWN_POINTER, &dm->ltogmap));
    323:   PetscFunctionReturn(PETSC_SUCCESS);
    324: }

    326: static PetscErrorCode DMRedundantGetSize_Redundant(DM dm, PetscInt *rank, PetscInt *N)
    327: {
    328:   DM_Redundant *red = (DM_Redundant *)dm->data;

    330:   PetscFunctionBegin;
    331:   if (rank) *rank = red->rank;
    332:   if (N) *N = red->N;
    333:   PetscFunctionReturn(PETSC_SUCCESS);
    334: }

    336: static PetscErrorCode DMSetUpGLVisViewer_Redundant(PetscObject odm, PetscViewer viewer)
    337: {
    338:   PetscFunctionBegin;
    339:   PetscFunctionReturn(PETSC_SUCCESS);
    340: }

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

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

    350:   Level: intermediate

    352: .seealso: `DMType`, `DMCOMPOSITE`, `DMCreate()`, `DMRedundantSetSize()`, `DMRedundantGetSize()`
    353: M*/

    355: PETSC_EXTERN PetscErrorCode DMCreate_Redundant(DM dm)
    356: {
    357:   DM_Redundant *red;

    359:   PetscFunctionBegin;
    360:   PetscCall(PetscNew(&red));
    361:   dm->data = red;

    363:   dm->ops->setup               = DMSetUp_Redundant;
    364:   dm->ops->view                = DMView_Redundant;
    365:   dm->ops->createglobalvector  = DMCreateGlobalVector_Redundant;
    366:   dm->ops->createlocalvector   = DMCreateLocalVector_Redundant;
    367:   dm->ops->creatematrix        = DMCreateMatrix_Redundant;
    368:   dm->ops->destroy             = DMDestroy_Redundant;
    369:   dm->ops->globaltolocalbegin  = DMGlobalToLocalBegin_Redundant;
    370:   dm->ops->globaltolocalend    = DMGlobalToLocalEnd_Redundant;
    371:   dm->ops->localtoglobalbegin  = DMLocalToGlobalBegin_Redundant;
    372:   dm->ops->localtoglobalend    = DMLocalToGlobalEnd_Redundant;
    373:   dm->ops->refine              = DMRefine_Redundant;
    374:   dm->ops->coarsen             = DMCoarsen_Redundant;
    375:   dm->ops->createinterpolation = DMCreateInterpolation_Redundant;
    376:   dm->ops->getcoloring         = DMCreateColoring_Redundant;

    378:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMRedundantSetSize_C", DMRedundantSetSize_Redundant));
    379:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMRedundantGetSize_C", DMRedundantGetSize_Redundant));
    380:   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", DMSetUpGLVisViewer_Redundant));
    381:   PetscFunctionReturn(PETSC_SUCCESS);
    382: }

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

    387:   Collective

    389:   Input Parameters:
    390: + comm - the processors that will share the global vector
    391: . rank - the MPI rank to own the redundant values
    392: - N    - total number of degrees of freedom

    394:   Output Parameter:
    395: . dm - the `DM` object of type `DMREDUNDANT`

    397:   Level: advanced

    399: .seealso: `DM`, `DMREDUNDANT`, `DMDestroy()`, `DMCreateGlobalVector()`, `DMCreateMatrix()`, `DMCompositeAddDM()`, `DMSetType()`, `DMRedundantSetSize()`, `DMRedundantGetSize()`
    400: @*/
    401: PetscErrorCode DMRedundantCreate(MPI_Comm comm, PetscMPIInt rank, PetscInt N, DM *dm)
    402: {
    403:   PetscFunctionBegin;
    404:   PetscAssertPointer(dm, 4);
    405:   PetscCall(DMCreate(comm, dm));
    406:   PetscCall(DMSetType(*dm, DMREDUNDANT));
    407:   PetscCall(DMRedundantSetSize(*dm, rank, N));
    408:   PetscCall(DMSetUp(*dm));
    409:   PetscFunctionReturn(PETSC_SUCCESS);
    410: }