Actual source code: plexpreallocate.c
petsc-3.10.5 2019-03-28
Report Typos and Errors

      1:  #include <petsc/private/dmpleximpl.h>
      2:  #include <petsc/private/isimpl.h>
      3:  #include <petscsf.h>
      4:  #include <petscds.h>

      6: /* get adjacencies due to point-to-point constraints that can't be found with DMPlexGetAdjacency() */
      7: static PetscErrorCode DMPlexComputeAnchorAdjacencies(DM dm, PetscBool useCone, PetscBool useClosure, PetscSection *anchorSectionAdj, PetscInt *anchorAdj[])
      8: {
      9:   PetscInt       pStart, pEnd;
     10:   PetscSection   section, sectionGlobal, adjSec, aSec;
     11:   IS             aIS;

     15:   DMGetSection(dm, &section);
     16:   DMGetGlobalSection(dm, &sectionGlobal);
     17:   PetscSectionCreate(PetscObjectComm((PetscObject) section), &adjSec);
     18:   PetscSectionGetChart(section,&pStart,&pEnd);
     19:   PetscSectionSetChart(adjSec,pStart,pEnd);

     21:   DMPlexGetAnchors(dm,&aSec,&aIS);
     22:   if (aSec) {
     23:     const PetscInt *anchors;
     24:     PetscInt       p, q, a, aSize, *offsets, aStart, aEnd, *inverse, iSize, *adj, adjSize;
     25:     PetscInt       *tmpAdjP = NULL, *tmpAdjQ = NULL;
     26:     PetscSection   inverseSec;

     28:     /* invert the constraint-to-anchor map */
     29:     PetscSectionCreate(PetscObjectComm((PetscObject)aSec),&inverseSec);
     30:     PetscSectionSetChart(inverseSec,pStart,pEnd);
     31:     ISGetLocalSize(aIS, &aSize);
     32:     ISGetIndices(aIS, &anchors);

     34:     for (p = 0; p < aSize; p++) {
     35:       PetscInt a = anchors[p];

     37:       PetscSectionAddDof(inverseSec,a,1);
     38:     }
     39:     PetscSectionSetUp(inverseSec);
     40:     PetscSectionGetStorageSize(inverseSec,&iSize);
     41:     PetscMalloc1(iSize,&inverse);
     42:     PetscCalloc1(pEnd-pStart,&offsets);
     43:     PetscSectionGetChart(aSec,&aStart,&aEnd);
     44:     for (p = aStart; p < aEnd; p++) {
     45:       PetscInt dof, off;

     47:       PetscSectionGetDof(aSec, p, &dof);
     48:       PetscSectionGetOffset(aSec, p, &off);

     50:       for (q = 0; q < dof; q++) {
     51:         PetscInt iOff;

     53:         a = anchors[off + q];
     54:         PetscSectionGetOffset(inverseSec, a, &iOff);
     55:         inverse[iOff + offsets[a-pStart]++] = p;
     56:       }
     57:     }
     58:     ISRestoreIndices(aIS, &anchors);
     59:     PetscFree(offsets);

     61:     /* construct anchorAdj and adjSec
     62:      *
     63:      * loop over anchors:
     64:      *   construct anchor adjacency
     65:      *   loop over constrained:
     66:      *     construct constrained adjacency
     67:      *     if not in anchor adjacency, add to dofs
     68:      * setup adjSec, allocate anchorAdj
     69:      * loop over anchors:
     70:      *   construct anchor adjacency
     71:      *   loop over constrained:
     72:      *     construct constrained adjacency
     73:      *     if not in anchor adjacency
     74:      *       if not already in list, put in list
     75:      *   sort, unique, reduce dof count
     76:      * optional: compactify
     77:      */
     78:     for (p = pStart; p < pEnd; p++) {
     79:       PetscInt iDof, iOff, i, r, s, numAdjP = PETSC_DETERMINE;

     81:       PetscSectionGetDof(inverseSec,p,&iDof);
     82:       if (!iDof) continue;
     83:       PetscSectionGetOffset(inverseSec,p,&iOff);
     84:       DMPlexGetAdjacency_Internal(dm,p,useCone,useClosure,PETSC_TRUE,&numAdjP,&tmpAdjP);
     85:       for (i = 0; i < iDof; i++) {
     86:         PetscInt iNew = 0, qAdj, qAdjDof, qAdjCDof, numAdjQ = PETSC_DETERMINE;

     88:         q = inverse[iOff + i];
     89:         DMPlexGetAdjacency_Internal(dm,q,useCone,useClosure,PETSC_TRUE,&numAdjQ,&tmpAdjQ);
     90:         for (r = 0; r < numAdjQ; r++) {
     91:           qAdj = tmpAdjQ[r];
     92:           if ((qAdj < pStart) || (qAdj >= pEnd)) continue;
     93:           for (s = 0; s < numAdjP; s++) {
     94:             if (qAdj == tmpAdjP[s]) break;
     95:           }
     96:           if (s < numAdjP) continue;
     97:           PetscSectionGetDof(section,qAdj,&qAdjDof);
     98:           PetscSectionGetConstraintDof(section,qAdj,&qAdjCDof);
     99:           iNew += qAdjDof - qAdjCDof;
    100:         }
    101:         PetscSectionAddDof(adjSec,p,iNew);
    102:       }
    103:     }

    105:     PetscSectionSetUp(adjSec);
    106:     PetscSectionGetStorageSize(adjSec,&adjSize);
    107:     PetscMalloc1(adjSize,&adj);

    109:     for (p = pStart; p < pEnd; p++) {
    110:       PetscInt iDof, iOff, i, r, s, aOff, aOffOrig, aDof, numAdjP = PETSC_DETERMINE;

    112:       PetscSectionGetDof(inverseSec,p,&iDof);
    113:       if (!iDof) continue;
    114:       PetscSectionGetOffset(inverseSec,p,&iOff);
    115:       DMPlexGetAdjacency_Internal(dm,p,useCone,useClosure,PETSC_TRUE,&numAdjP,&tmpAdjP);
    116:       PetscSectionGetDof(adjSec,p,&aDof);
    117:       PetscSectionGetOffset(adjSec,p,&aOff);
    118:       aOffOrig = aOff;
    119:       for (i = 0; i < iDof; i++) {
    120:         PetscInt qAdj, qAdjDof, qAdjCDof, qAdjOff, nd, numAdjQ = PETSC_DETERMINE;

    122:         q = inverse[iOff + i];
    123:         DMPlexGetAdjacency_Internal(dm,q,useCone,useClosure,PETSC_TRUE,&numAdjQ,&tmpAdjQ);
    124:         for (r = 0; r < numAdjQ; r++) {
    125:           qAdj = tmpAdjQ[r];
    126:           if ((qAdj < pStart) || (qAdj >= pEnd)) continue;
    127:           for (s = 0; s < numAdjP; s++) {
    128:             if (qAdj == tmpAdjP[s]) break;
    129:           }
    130:           if (s < numAdjP) continue;
    131:           PetscSectionGetDof(section,qAdj,&qAdjDof);
    132:           PetscSectionGetConstraintDof(section,qAdj,&qAdjCDof);
    133:           PetscSectionGetOffset(sectionGlobal,qAdj,&qAdjOff);
    134:           for (nd = 0; nd < qAdjDof-qAdjCDof; ++nd) {
    135:             adj[aOff++] = (qAdjOff < 0 ? -(qAdjOff+1) : qAdjOff) + nd;
    136:           }
    137:         }
    138:       }
    139:       PetscSortRemoveDupsInt(&aDof,&adj[aOffOrig]);
    140:       PetscSectionSetDof(adjSec,p,aDof);
    141:     }
    142:     *anchorAdj = adj;

    144:     /* clean up */
    145:     PetscSectionDestroy(&inverseSec);
    146:     PetscFree(inverse);
    147:     PetscFree(tmpAdjP);
    148:     PetscFree(tmpAdjQ);
    149:   }
    150:   else {
    151:     *anchorAdj = NULL;
    152:     PetscSectionSetUp(adjSec);
    153:   }
    154:   *anchorSectionAdj = adjSec;
    155:   return(0);
    156: }

    158: static PetscErrorCode DMPlexCreateAdjacencySection_Static(DM dm, PetscInt bs, PetscSF sfDof, PetscBool useCone, PetscBool useClosure, PetscBool useAnchors, PetscSection *sA, PetscInt **colIdx)
    159: {
    160:   MPI_Comm           comm;
    161:   PetscMPIInt        size;
    162:   PetscBool          doCommLocal, doComm, debug = PETSC_FALSE;
    163:   PetscSF            sf, sfAdj;
    164:   PetscSection       section, sectionGlobal, leafSectionAdj, rootSectionAdj, sectionAdj, anchorSectionAdj;
    165:   PetscInt           nroots, nleaves, l, p, r;
    166:   const PetscInt    *leaves;
    167:   const PetscSFNode *remotes;
    168:   PetscInt           dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
    169:   PetscInt          *tmpAdj = NULL, *adj, *rootAdj, *anchorAdj = NULL, *cols, *remoteOffsets;
    170:   PetscInt           adjSize;
    171:   PetscErrorCode     ierr;

    174:   PetscObjectGetComm((PetscObject) dm, &comm);
    175:   PetscOptionsGetBool(NULL,NULL, "-dm_view_preallocation", &debug, NULL);
    176:   MPI_Comm_size(comm, &size);
    177:   DMGetDimension(dm, &dim);
    178:   DMGetPointSF(dm, &sf);
    179:   DMGetSection(dm, &section);
    180:   DMGetGlobalSection(dm, &sectionGlobal);
    181:   PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);
    182:   doCommLocal = (size > 1) && (nroots >= 0) ? PETSC_TRUE : PETSC_FALSE;
    183:   MPIU_Allreduce(&doCommLocal, &doComm, 1, MPIU_BOOL, MPI_LAND, comm);
    184:   /* Create section for dof adjacency (dof ==> # adj dof) */
    185:   PetscSectionGetChart(section, &pStart, &pEnd);
    186:   PetscSectionGetStorageSize(section, &numDof);
    187:   PetscSectionCreate(comm, &leafSectionAdj);
    188:   PetscSectionSetChart(leafSectionAdj, 0, numDof);
    189:   PetscSectionCreate(comm, &rootSectionAdj);
    190:   PetscSectionSetChart(rootSectionAdj, 0, numDof);
    191:   /*   Fill in the ghost dofs on the interface */
    192:   PetscSFGetGraph(sf, NULL, &nleaves, &leaves, &remotes);
    193:   /*
    194:    section        - maps points to (# dofs, local dofs)
    195:    sectionGlobal  - maps points to (# dofs, global dofs)
    196:    leafSectionAdj - maps unowned local dofs to # adj dofs
    197:    rootSectionAdj - maps   owned local dofs to # adj dofs
    198:    adj            - adj global dofs indexed by leafSectionAdj
    199:    rootAdj        - adj global dofs indexed by rootSectionAdj
    200:    sf    - describes shared points across procs
    201:    sfDof - describes shared dofs across procs
    202:    sfAdj - describes shared adjacent dofs across procs
    203:    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
    204:   (0). If there are point-to-point constraints, add the adjacencies of constrained points to anchors in anchorAdj
    205:        (This is done in DMPlexComputeAnchorAdjacencies())
    206:     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
    207:        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
    208:     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
    209:        Create sfAdj connecting rootSectionAdj and leafSectionAdj
    210:     3. Visit unowned points on interface, write adjacencies to adj
    211:        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
    212:     4. Visit owned points on interface, write adjacencies to rootAdj
    213:        Remove redundancy in rootAdj
    214:    ** The last two traversals use transitive closure
    215:     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
    216:        Allocate memory addressed by sectionAdj (cols)
    217:     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
    218:    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
    219:   */
    220:   DMPlexComputeAnchorAdjacencies(dm, useCone, useClosure, &anchorSectionAdj, &anchorAdj);
    221:   for (l = 0; l < nleaves; ++l) {
    222:     PetscInt dof, off, d, q, anDof;
    223:     PetscInt p = leaves[l], numAdj = PETSC_DETERMINE;

    225:     if ((p < pStart) || (p >= pEnd)) continue;
    226:     PetscSectionGetDof(section, p, &dof);
    227:     PetscSectionGetOffset(section, p, &off);
    228:     DMPlexGetAdjacency_Internal(dm, p, useCone, useClosure, useAnchors, &numAdj, &tmpAdj);
    229:     for (q = 0; q < numAdj; ++q) {
    230:       const PetscInt padj = tmpAdj[q];
    231:       PetscInt ndof, ncdof;

    233:       if ((padj < pStart) || (padj >= pEnd)) continue;
    234:       PetscSectionGetDof(section, padj, &ndof);
    235:       PetscSectionGetConstraintDof(section, padj, &ncdof);
    236:       for (d = off; d < off+dof; ++d) {
    237:         PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);
    238:       }
    239:     }
    240:     PetscSectionGetDof(anchorSectionAdj, p, &anDof);
    241:     if (anDof) {
    242:       for (d = off; d < off+dof; ++d) {
    243:         PetscSectionAddDof(leafSectionAdj, d, anDof);
    244:       }
    245:     }
    246:   }
    247:   PetscSectionSetUp(leafSectionAdj);
    248:   if (debug) {
    249:     PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");
    250:     PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);
    251:   }
    252:   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
    253:   if (doComm) {
    254:     PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);
    255:     PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);
    256:   }
    257:   if (debug) {
    258:     PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");
    259:     PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);
    260:   }
    261:   /* Add in local adjacency sizes for owned dofs on interface (roots) */
    262:   for (p = pStart; p < pEnd; ++p) {
    263:     PetscInt numAdj = PETSC_DETERMINE, adof, dof, off, d, q, anDof;

    265:     PetscSectionGetDof(section, p, &dof);
    266:     PetscSectionGetOffset(section, p, &off);
    267:     if (!dof) continue;
    268:     PetscSectionGetDof(rootSectionAdj, off, &adof);
    269:     if (adof <= 0) continue;
    270:     DMPlexGetAdjacency_Internal(dm, p, useCone, useClosure, useAnchors, &numAdj, &tmpAdj);
    271:     for (q = 0; q < numAdj; ++q) {
    272:       const PetscInt padj = tmpAdj[q];
    273:       PetscInt ndof, ncdof;

    275:       if ((padj < pStart) || (padj >= pEnd)) continue;
    276:       PetscSectionGetDof(section, padj, &ndof);
    277:       PetscSectionGetConstraintDof(section, padj, &ncdof);
    278:       for (d = off; d < off+dof; ++d) {
    279:         PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);
    280:       }
    281:     }
    282:     PetscSectionGetDof(anchorSectionAdj, p, &anDof);
    283:     if (anDof) {
    284:       for (d = off; d < off+dof; ++d) {
    285:         PetscSectionAddDof(rootSectionAdj, d, anDof);
    286:       }
    287:     }
    288:   }
    289:   PetscSectionSetUp(rootSectionAdj);
    290:   if (debug) {
    291:     PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");
    292:     PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);
    293:   }
    294:   /* Create adj SF based on dof SF */
    295:   PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);
    296:   PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);
    297:   PetscFree(remoteOffsets);
    298:   if (debug && size > 1) {
    299:     PetscPrintf(comm, "Adjacency SF for Preallocation:\n");
    300:     PetscSFView(sfAdj, NULL);
    301:   }
    302:   /* Create leaf adjacency */
    303:   PetscSectionSetUp(leafSectionAdj);
    304:   PetscSectionGetStorageSize(leafSectionAdj, &adjSize);
    305:   PetscCalloc1(adjSize, &adj);
    306:   for (l = 0; l < nleaves; ++l) {
    307:     PetscInt dof, off, d, q, anDof, anOff;
    308:     PetscInt p = leaves[l], numAdj = PETSC_DETERMINE;

    310:     if ((p < pStart) || (p >= pEnd)) continue;
    311:     PetscSectionGetDof(section, p, &dof);
    312:     PetscSectionGetOffset(section, p, &off);
    313:     DMPlexGetAdjacency_Internal(dm, p, useCone, useClosure, useAnchors, &numAdj, &tmpAdj);
    314:     PetscSectionGetDof(anchorSectionAdj, p, &anDof);
    315:     PetscSectionGetOffset(anchorSectionAdj, p, &anOff);
    316:     for (d = off; d < off+dof; ++d) {
    317:       PetscInt aoff, i = 0;

    319:       PetscSectionGetOffset(leafSectionAdj, d, &aoff);
    320:       for (q = 0; q < numAdj; ++q) {
    321:         const PetscInt padj = tmpAdj[q];
    322:         PetscInt ndof, ncdof, ngoff, nd;

    324:         if ((padj < pStart) || (padj >= pEnd)) continue;
    325:         PetscSectionGetDof(section, padj, &ndof);
    326:         PetscSectionGetConstraintDof(section, padj, &ncdof);
    327:         PetscSectionGetOffset(sectionGlobal, padj, &ngoff);
    328:         for (nd = 0; nd < ndof-ncdof; ++nd) {
    329:           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
    330:           ++i;
    331:         }
    332:       }
    333:       for (q = 0; q < anDof; q++) {
    334:         adj[aoff+i] = anchorAdj[anOff+q];
    335:         ++i;
    336:       }
    337:     }
    338:   }
    339:   /* Debugging */
    340:   if (debug) {
    341:     IS tmp;
    342:     PetscPrintf(comm, "Leaf adjacency indices\n");
    343:     ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);
    344:     ISView(tmp, NULL);
    345:     ISDestroy(&tmp);
    346:   }
    347:   /* Gather adjacent indices to root */
    348:   PetscSectionGetStorageSize(rootSectionAdj, &adjSize);
    349:   PetscMalloc1(adjSize, &rootAdj);
    350:   for (r = 0; r < adjSize; ++r) rootAdj[r] = -1;
    351:   if (doComm) {
    352:     const PetscInt *indegree;
    353:     PetscInt       *remoteadj, radjsize = 0;

    355:     PetscSFComputeDegreeBegin(sfAdj, &indegree);
    356:     PetscSFComputeDegreeEnd(sfAdj, &indegree);
    357:     for (p = 0; p < adjSize; ++p) radjsize += indegree[p];
    358:     PetscMalloc1(radjsize, &remoteadj);
    359:     PetscSFGatherBegin(sfAdj, MPIU_INT, adj, remoteadj);
    360:     PetscSFGatherEnd(sfAdj, MPIU_INT, adj, remoteadj);
    361:     for (p = 0, l = 0, r = 0; p < adjSize; ++p, l = PetscMax(p, l + indegree[p-1])) {
    362:       PetscInt s;
    363:       for (s = 0; s < indegree[p]; ++s, ++r) rootAdj[l+s] = remoteadj[r];
    364:     }
    365:     if (r != radjsize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistency in communication %d != %d", r, radjsize);
    366:     if (l != adjSize)  SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistency in communication %d != %d", l, adjSize);
    367:     PetscFree(remoteadj);
    368:   }
    369:   PetscSFDestroy(&sfAdj);
    370:   PetscFree(adj);
    371:   /* Debugging */
    372:   if (debug) {
    373:     IS tmp;
    374:     PetscPrintf(comm, "Root adjacency indices after gather\n");
    375:     ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);
    376:     ISView(tmp, NULL);
    377:     ISDestroy(&tmp);
    378:   }
    379:   /* Add in local adjacency indices for owned dofs on interface (roots) */
    380:   for (p = pStart; p < pEnd; ++p) {
    381:     PetscInt numAdj = PETSC_DETERMINE, adof, dof, off, d, q, anDof, anOff;

    383:     PetscSectionGetDof(section, p, &dof);
    384:     PetscSectionGetOffset(section, p, &off);
    385:     if (!dof) continue;
    386:     PetscSectionGetDof(rootSectionAdj, off, &adof);
    387:     if (adof <= 0) continue;
    388:     DMPlexGetAdjacency_Internal(dm, p, useCone, useClosure, useAnchors, &numAdj, &tmpAdj);
    389:     PetscSectionGetDof(anchorSectionAdj, p, &anDof);
    390:     PetscSectionGetOffset(anchorSectionAdj, p, &anOff);
    391:     for (d = off; d < off+dof; ++d) {
    392:       PetscInt adof, aoff, i;

    394:       PetscSectionGetDof(rootSectionAdj, d, &adof);
    395:       PetscSectionGetOffset(rootSectionAdj, d, &aoff);
    396:       i    = adof-1;
    397:       for (q = 0; q < anDof; q++) {
    398:         rootAdj[aoff+i] = anchorAdj[anOff+q];
    399:         --i;
    400:       }
    401:       for (q = 0; q < numAdj; ++q) {
    402:         const PetscInt padj = tmpAdj[q];
    403:         PetscInt ndof, ncdof, ngoff, nd;

    405:         if ((padj < pStart) || (padj >= pEnd)) continue;
    406:         PetscSectionGetDof(section, padj, &ndof);
    407:         PetscSectionGetConstraintDof(section, padj, &ncdof);
    408:         PetscSectionGetOffset(sectionGlobal, padj, &ngoff);
    409:         for (nd = 0; nd < ndof-ncdof; ++nd) {
    410:           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
    411:           --i;
    412:         }
    413:       }
    414:     }
    415:   }
    416:   /* Debugging */
    417:   if (debug) {
    418:     IS tmp;
    419:     PetscPrintf(comm, "Root adjacency indices\n");
    420:     ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);
    421:     ISView(tmp, NULL);
    422:     ISDestroy(&tmp);
    423:   }
    424:   /* Compress indices */
    425:   PetscSectionSetUp(rootSectionAdj);
    426:   for (p = pStart; p < pEnd; ++p) {
    427:     PetscInt dof, cdof, off, d;
    428:     PetscInt adof, aoff;

    430:     PetscSectionGetDof(section, p, &dof);
    431:     PetscSectionGetConstraintDof(section, p, &cdof);
    432:     PetscSectionGetOffset(section, p, &off);
    433:     if (!dof) continue;
    434:     PetscSectionGetDof(rootSectionAdj, off, &adof);
    435:     if (adof <= 0) continue;
    436:     for (d = off; d < off+dof-cdof; ++d) {
    437:       PetscSectionGetDof(rootSectionAdj, d, &adof);
    438:       PetscSectionGetOffset(rootSectionAdj, d, &aoff);
    439:       PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);
    440:       PetscSectionSetDof(rootSectionAdj, d, adof);
    441:     }
    442:   }
    443:   /* Debugging */
    444:   if (debug) {
    445:     IS tmp;
    446:     PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");
    447:     PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);
    448:     PetscPrintf(comm, "Root adjacency indices after compression\n");
    449:     ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);
    450:     ISView(tmp, NULL);
    451:     ISDestroy(&tmp);
    452:   }
    453:   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
    454:   PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);
    455:   PetscSectionCreate(comm, &sectionAdj);
    456:   PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);
    457:   for (p = pStart; p < pEnd; ++p) {
    458:     PetscInt  numAdj = PETSC_DETERMINE, dof, cdof, off, goff, d, q, anDof;
    459:     PetscBool found  = PETSC_TRUE;

    461:     PetscSectionGetDof(section, p, &dof);
    462:     PetscSectionGetConstraintDof(section, p, &cdof);
    463:     PetscSectionGetOffset(section, p, &off);
    464:     PetscSectionGetOffset(sectionGlobal, p, &goff);
    465:     for (d = 0; d < dof-cdof; ++d) {
    466:       PetscInt ldof, rdof;

    468:       PetscSectionGetDof(leafSectionAdj, off+d, &ldof);
    469:       PetscSectionGetDof(rootSectionAdj, off+d, &rdof);
    470:       if (ldof > 0) {
    471:         /* We do not own this point */
    472:       } else if (rdof > 0) {
    473:         PetscSectionSetDof(sectionAdj, goff+d, rdof);
    474:       } else {
    475:         found = PETSC_FALSE;
    476:       }
    477:     }
    478:     if (found) continue;
    479:     PetscSectionGetDof(section, p, &dof);
    480:     PetscSectionGetOffset(sectionGlobal, p, &goff);
    481:     DMPlexGetAdjacency_Internal(dm, p, useCone, useClosure, useAnchors, &numAdj, &tmpAdj);
    482:     for (q = 0; q < numAdj; ++q) {
    483:       const PetscInt padj = tmpAdj[q];
    484:       PetscInt ndof, ncdof, noff;

    486:       if ((padj < pStart) || (padj >= pEnd)) continue;
    487:       PetscSectionGetDof(section, padj, &ndof);
    488:       PetscSectionGetConstraintDof(section, padj, &ncdof);
    489:       PetscSectionGetOffset(section, padj, &noff);
    490:       for (d = goff; d < goff+dof-cdof; ++d) {
    491:         PetscSectionAddDof(sectionAdj, d, ndof-ncdof);
    492:       }
    493:     }
    494:     PetscSectionGetDof(anchorSectionAdj, p, &anDof);
    495:     if (anDof) {
    496:       for (d = goff; d < goff+dof-cdof; ++d) {
    497:         PetscSectionAddDof(sectionAdj, d, anDof);
    498:       }
    499:     }
    500:   }
    501:   PetscSectionSetUp(sectionAdj);
    502:   if (debug) {
    503:     PetscPrintf(comm, "Adjacency Section for Preallocation:\n");
    504:     PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);
    505:   }
    506:   /* Get adjacent indices */
    507:   PetscSectionGetStorageSize(sectionAdj, &numCols);
    508:   PetscMalloc1(numCols, &cols);
    509:   for (p = pStart; p < pEnd; ++p) {
    510:     PetscInt  numAdj = PETSC_DETERMINE, dof, cdof, off, goff, d, q, anDof, anOff;
    511:     PetscBool found  = PETSC_TRUE;

    513:     PetscSectionGetDof(section, p, &dof);
    514:     PetscSectionGetConstraintDof(section, p, &cdof);
    515:     PetscSectionGetOffset(section, p, &off);
    516:     PetscSectionGetOffset(sectionGlobal, p, &goff);
    517:     for (d = 0; d < dof-cdof; ++d) {
    518:       PetscInt ldof, rdof;

    520:       PetscSectionGetDof(leafSectionAdj, off+d, &ldof);
    521:       PetscSectionGetDof(rootSectionAdj, off+d, &rdof);
    522:       if (ldof > 0) {
    523:         /* We do not own this point */
    524:       } else if (rdof > 0) {
    525:         PetscInt aoff, roff;

    527:         PetscSectionGetOffset(sectionAdj, goff+d, &aoff);
    528:         PetscSectionGetOffset(rootSectionAdj, off+d, &roff);
    529:         PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));
    530:       } else {
    531:         found = PETSC_FALSE;
    532:       }
    533:     }
    534:     if (found) continue;
    535:     DMPlexGetAdjacency_Internal(dm, p, useCone, useClosure, useAnchors, &numAdj, &tmpAdj);
    536:     PetscSectionGetDof(anchorSectionAdj, p, &anDof);
    537:     PetscSectionGetOffset(anchorSectionAdj, p, &anOff);
    538:     for (d = goff; d < goff+dof-cdof; ++d) {
    539:       PetscInt adof, aoff, i = 0;

    541:       PetscSectionGetDof(sectionAdj, d, &adof);
    542:       PetscSectionGetOffset(sectionAdj, d, &aoff);
    543:       for (q = 0; q < numAdj; ++q) {
    544:         const PetscInt  padj = tmpAdj[q];
    545:         PetscInt        ndof, ncdof, ngoff, nd;
    546:         const PetscInt *ncind;

    548:         /* Adjacent points may not be in the section chart */
    549:         if ((padj < pStart) || (padj >= pEnd)) continue;
    550:         PetscSectionGetDof(section, padj, &ndof);
    551:         PetscSectionGetConstraintDof(section, padj, &ncdof);
    552:         PetscSectionGetConstraintIndices(section, padj, &ncind);
    553:         PetscSectionGetOffset(sectionGlobal, padj, &ngoff);
    554:         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
    555:           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
    556:         }
    557:       }
    558:       for (q = 0; q < anDof; q++, i++) {
    559:         cols[aoff+i] = anchorAdj[anOff + q];
    560:       }
    561:       if (i != adof) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of entries %D != %D for dof %D (point %D)", i, adof, d, p);
    562:     }
    563:   }
    564:   PetscSectionDestroy(&anchorSectionAdj);
    565:   PetscSectionDestroy(&leafSectionAdj);
    566:   PetscSectionDestroy(&rootSectionAdj);
    567:   PetscFree(anchorAdj);
    568:   PetscFree(rootAdj);
    569:   PetscFree(tmpAdj);
    570:   /* Debugging */
    571:   if (debug) {
    572:     IS tmp;
    573:     PetscPrintf(comm, "Column indices\n");
    574:     ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);
    575:     ISView(tmp, NULL);
    576:     ISDestroy(&tmp);
    577:   }

    579:   *sA     = sectionAdj;
    580:   *colIdx = cols;
    581:   return(0);
    582: }

    584: static PetscErrorCode DMPlexUpdateAllocation_Static(DM dm, PetscLayout rLayout, PetscInt bs, PetscInt f, PetscSection sectionAdj, const PetscInt cols[], PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[])
    585: {
    586:   PetscSection   section;
    587:   PetscInt       rStart, rEnd, r, pStart, pEnd, p;

    591:   /* This loop needs to change to a loop over points, then field dofs, which means we need to look both sections */
    592:   PetscLayoutGetRange(rLayout, &rStart, &rEnd);
    593:   if (rStart%bs || rEnd%bs) SETERRQ3(PetscObjectComm((PetscObject) rLayout), PETSC_ERR_ARG_WRONG, "Invalid layout [%d, %d) for matrix, must be divisible by block size %d", rStart, rEnd, bs);
    594:   if (f >= 0 && bs == 1) {
    595:     DMGetSection(dm, &section);
    596:     PetscSectionGetChart(section, &pStart, &pEnd);
    597:     for (p = pStart; p < pEnd; ++p) {
    598:       PetscInt rS, rE;

    600:       DMGetGlobalFieldOffset_Private(dm, p, f, &rS, &rE);
    601:       for (r = rS; r < rE; ++r) {
    602:         PetscInt numCols, cStart, c;

    604:         PetscSectionGetDof(sectionAdj, r, &numCols);
    605:         PetscSectionGetOffset(sectionAdj, r, &cStart);
    606:         for (c = cStart; c < cStart+numCols; ++c) {
    607:           if ((cols[c] >= rStart) && (cols[c] < rEnd)) {
    608:             ++dnz[r-rStart];
    609:             if (cols[c] >= r) ++dnzu[r-rStart];
    610:           } else {
    611:             ++onz[r-rStart];
    612:             if (cols[c] >= r) ++onzu[r-rStart];
    613:           }
    614:         }
    615:       }
    616:     }
    617:   } else {
    618:     /* Only loop over blocks of rows */
    619:     for (r = rStart/bs; r < rEnd/bs; ++r) {
    620:       const PetscInt row = r*bs;
    621:       PetscInt       numCols, cStart, c;

    623:       PetscSectionGetDof(sectionAdj, row, &numCols);
    624:       PetscSectionGetOffset(sectionAdj, row, &cStart);
    625:       for (c = cStart; c < cStart+numCols; ++c) {
    626:         if ((cols[c] >= rStart) && (cols[c] < rEnd)) {
    627:           ++dnz[r-rStart/bs];
    628:           if (cols[c] >= row) ++dnzu[r-rStart/bs];
    629:         } else {
    630:           ++onz[r-rStart/bs];
    631:           if (cols[c] >= row) ++onzu[r-rStart/bs];
    632:         }
    633:       }
    634:     }
    635:     for (r = 0; r < (rEnd - rStart)/bs; ++r) {
    636:       dnz[r]  /= bs;
    637:       onz[r]  /= bs;
    638:       dnzu[r] /= bs;
    639:       onzu[r] /= bs;
    640:     }
    641:   }
    642:   return(0);
    643: }

    645: static PetscErrorCode DMPlexFillMatrix_Static(DM dm, PetscLayout rLayout, PetscInt bs, PetscInt f, PetscSection sectionAdj, const PetscInt cols[], Mat A)
    646: {
    647:   PetscSection   section;
    648:   PetscScalar   *values;
    649:   PetscInt       rStart, rEnd, r, pStart, pEnd, p, len, maxRowLen = 0;

    653:   PetscLayoutGetRange(rLayout, &rStart, &rEnd);
    654:   for (r = rStart; r < rEnd; ++r) {
    655:     PetscSectionGetDof(sectionAdj, r, &len);
    656:     maxRowLen = PetscMax(maxRowLen, len);
    657:   }
    658:   PetscCalloc1(maxRowLen, &values);
    659:   if (f >=0 && bs == 1) {
    660:     DMGetSection(dm, &section);
    661:     PetscSectionGetChart(section, &pStart, &pEnd);
    662:     for (p = pStart; p < pEnd; ++p) {
    663:       PetscInt rS, rE;

    665:       DMGetGlobalFieldOffset_Private(dm, p, f, &rS, &rE);
    666:       for (r = rS; r < rE; ++r) {
    667:         PetscInt numCols, cStart;

    669:         PetscSectionGetDof(sectionAdj, r, &numCols);
    670:         PetscSectionGetOffset(sectionAdj, r, &cStart);
    671:         MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);
    672:       }
    673:     }
    674:   } else {
    675:     for (r = rStart; r < rEnd; ++r) {
    676:       PetscInt numCols, cStart;

    678:       PetscSectionGetDof(sectionAdj, r, &numCols);
    679:       PetscSectionGetOffset(sectionAdj, r, &cStart);
    680:       MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);
    681:     }
    682:   }
    683:   PetscFree(values);
    684:   return(0);
    685: }

    687: /*@C
    688:   DMPlexPreallocateOperator - Calculate the matrix nonzero pattern based upon the information in the DM,
    689:   the PetscDS it contains, and the default PetscSection.

    691:   Collective

    693:   Input Arguments:
    694: + dm   - The DMPlex
    695: . bs   - The matrix blocksize
    696: . dnz  - An array to hold the number of nonzeros in the diagonal block
    697: . onz  - An array to hold the number of nonzeros in the off-diagonal block
    698: . dnzu - An array to hold the number of nonzeros in the upper triangle of the diagonal block
    699: . onzu - An array to hold the number of nonzeros in the upper triangle of the off-diagonal block
    700: . fillMatrix - If PETSC_TRUE, fill the matrix with zeros

    702:   Ouput Argument:
    703: . A - The preallocated matrix

    705:   Level: advanced

    707: .seealso: DMCreateMatrix()
    708: @*/
    709: PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
    710: {
    711:   MPI_Comm       comm;
    712:   PetscDS        prob;
    713:   MatType        mtype;
    714:   PetscSF        sf, sfDof;
    715:   PetscSection   section;
    716:   PetscInt      *remoteOffsets;
    717:   PetscSection   sectionAdj[4] = {NULL, NULL, NULL, NULL};
    718:   PetscInt      *cols[4]       = {NULL, NULL, NULL, NULL};
    719:   PetscBool      useCone, useClosure;
    720:   PetscInt       Nf, f, idx, locRows;
    721:   PetscLayout    rLayout;
    722:   PetscBool      isSymBlock, isSymSeqBlock, isSymMPIBlock, debug = PETSC_FALSE;
    723:   PetscMPIInt    size;

    731:   DMGetDS(dm, &prob);
    732:   DMGetPointSF(dm, &sf);
    733:   DMGetSection(dm, &section);
    734:   PetscOptionsGetBool(NULL,NULL, "-dm_view_preallocation", &debug, NULL);
    735:   PetscObjectGetComm((PetscObject) dm, &comm);
    736:   MPI_Comm_size(comm, &size);
    737:   PetscLogEventBegin(DMPLEX_Preallocate,dm,0,0,0);
    738:   /* Create dof SF based on point SF */
    739:   if (debug) {
    740:     PetscSection section, sectionGlobal;
    741:     PetscSF      sf;

    743:     DMGetPointSF(dm, &sf);
    744:     DMGetSection(dm, &section);
    745:     DMGetGlobalSection(dm, &sectionGlobal);
    746:     PetscPrintf(comm, "Input Section for Preallocation:\n");
    747:     PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);
    748:     PetscPrintf(comm, "Input Global Section for Preallocation:\n");
    749:     PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);
    750:     if (size > 1) {
    751:       PetscPrintf(comm, "Input SF for Preallocation:\n");
    752:       PetscSFView(sf, NULL);
    753:     }
    754:   }
    755:   PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);
    756:   PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);
    757:   PetscFree(remoteOffsets);
    758:   if (debug && size > 1) {
    759:     PetscPrintf(comm, "Dof SF for Preallocation:\n");
    760:     PetscSFView(sfDof, NULL);
    761:   }
    762:   /* Create allocation vectors from adjacency graph */
    763:   MatGetLocalSize(A, &locRows, NULL);
    764:   PetscLayoutCreate(comm, &rLayout);
    765:   PetscLayoutSetLocalSize(rLayout, locRows);
    766:   PetscLayoutSetBlockSize(rLayout, 1);
    767:   PetscLayoutSetUp(rLayout);
    768:   /* There are 4 types of adjacency */
    769:   PetscSectionGetNumFields(section, &Nf);
    770:   if (Nf < 1 || bs > 1) {
    771:     DMPlexGetAdjacencyUseCone(dm, &useCone);
    772:     DMPlexGetAdjacencyUseClosure(dm, &useClosure);
    773:     idx  = (useCone ? 1 : 0) + (useClosure ? 2 : 0);
    774:     DMPlexCreateAdjacencySection_Static(dm, bs, sfDof, useCone, useClosure, PETSC_TRUE, &sectionAdj[idx], &cols[idx]);
    775:     DMPlexUpdateAllocation_Static(dm, rLayout, bs, -1, sectionAdj[idx], cols[idx], dnz, onz, dnzu, onzu);
    776:   } else {
    777:     for (f = 0; f < Nf; ++f) {
    778:       PetscDSGetAdjacency(prob, f, &useCone, &useClosure);
    779:       idx  = (useCone ? 1 : 0) + (useClosure ? 2 : 0);
    780:       if (!sectionAdj[idx]) {DMPlexCreateAdjacencySection_Static(dm, bs, sfDof, useCone, useClosure, PETSC_TRUE, &sectionAdj[idx], &cols[idx]);}
    781:       DMPlexUpdateAllocation_Static(dm, rLayout, bs, f, sectionAdj[idx], cols[idx], dnz, onz, dnzu, onzu);
    782:     }
    783:   }
    784:   PetscSFDestroy(&sfDof);
    785:   /* Set matrix pattern */
    786:   MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);
    787:   MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);
    788:   /* Check for symmetric storage */
    789:   MatGetType(A, &mtype);
    790:   PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
    791:   PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
    792:   PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
    793:   if (isSymBlock || isSymSeqBlock || isSymMPIBlock) {MatSetOption(A, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);}
    794:   /* Fill matrix with zeros */
    795:   if (fillMatrix) {
    796:     if (Nf < 1 || bs > 1) {
    797:       DMPlexGetAdjacencyUseCone(dm, &useCone);
    798:       DMPlexGetAdjacencyUseClosure(dm, &useClosure);
    799:       idx  = (useCone ? 1 : 0) + (useClosure ? 2 : 0);
    800:       DMPlexFillMatrix_Static(dm, rLayout, bs, -1, sectionAdj[idx], cols[idx], A);
    801:     } else {
    802:       for (f = 0; f < Nf; ++f) {
    803:         PetscDSGetAdjacency(prob, f, &useCone, &useClosure);
    804:         idx  = (useCone ? 1 : 0) + (useClosure ? 2 : 0);
    805:         DMPlexFillMatrix_Static(dm, rLayout, bs, f, sectionAdj[idx], cols[idx], A);
    806:       }
    807:     }
    808:     MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);
    809:     MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);
    810:   }
    811:   PetscLayoutDestroy(&rLayout);
    812:   for (idx = 0; idx < 4; ++idx) {PetscSectionDestroy(&sectionAdj[idx]); PetscFree(cols[idx]);}
    813:   PetscLogEventEnd(DMPLEX_Preallocate,dm,0,0,0);
    814:   return(0);
    815: }

    817: #if 0
    818: PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
    819: {
    820:   PetscInt       *tmpClosure,*tmpAdj,*visits;
    821:   PetscInt        c,cStart,cEnd,pStart,pEnd;
    822:   PetscErrorCode  ierr;

    825:   DMGetDimension(dm, &dim);
    826:   DMPlexGetDepth(dm, &depth);
    827:   DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);

    829:   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth+1),PetscPowInt(mesh->maxSupportSize,depth+1));

    831:   PetscSectionGetChart(section, &pStart, &pEnd);
    832:   npoints = pEnd - pStart;

    834:   PetscMalloc3(maxClosureSize,&tmpClosure,npoints,&lvisits,npoints,&visits);
    835:   PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));
    836:   PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));
    837:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    838:   for (c=cStart; c<cEnd; c++) {
    839:     PetscInt *support = tmpClosure;
    840:     DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);
    841:     for (p=0; p<supportSize; p++) lvisits[support[p]]++;
    842:   }
    843:   PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);
    844:   PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);
    845:   PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);
    846:   PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);

    848:   PetscSFGetRanks();

    851:   PetscMalloc2(maxClosureSize*maxClosureSize,&cellmat,npoints,&owner);
    852:   for (c=cStart; c<cEnd; c++) {
    853:     PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));
    854:     /*
    855:      Depth-first walk of transitive closure.
    856:      At each leaf frame f of transitive closure that we see, add 1/visits[f] to each pair (p,q) not marked as done in cellmat.
    857:      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
    858:      */
    859:   }

    861:   PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);
    862:   PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);
    863:   return(0);
    864: }
    865: #endif