Date: 2015-10-02T22:15:05+00:00

Actual source code: plexpreallocate.c
petsc-3.6.2 2015-10-02
Report Typos and Errors

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

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

     17:   DMGetDefaultSection(dm, &section);
     18:   DMGetDefaultGlobalSection(dm, &sectionGlobal);
     19:   PetscSectionCreate(PetscObjectComm((PetscObject) section), &adjSec);
     20:   PetscSectionGetChart(section,&pStart,&pEnd);
     21:   PetscSectionSetChart(adjSec,pStart,pEnd);

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

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

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

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

     49:       PetscSectionGetDof(aSec, p, &dof);
     50:       PetscSectionGetOffset(aSec, p, &off);

     52:       for (q = 0; q < dof; q++) {
     53:         PetscInt iOff;

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

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

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

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

    107:     PetscSectionSetUp(adjSec);
    108:     PetscSectionGetStorageSize(adjSec,&adjSize);
    109:     PetscMalloc1(adjSize,&adj);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    582:   *sA     = sectionAdj;
    583:   *colIdx = cols;
    584:   return(0);
    585: }

    589: PetscErrorCode DMPlexUpdateAllocation_Static(DM dm, PetscLayout rLayout, PetscInt bs, PetscInt f, PetscSection sectionAdj, const PetscInt cols[], PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[])
    590: {
    591:   PetscSection   section;
    592:   PetscInt       rStart, rEnd, r, pStart, pEnd, p;

    596:   /* This loop needs to change to a loop over points, then field dofs, which means we need to look both sections */
    597:   PetscLayoutGetRange(rLayout, &rStart, &rEnd);
    598:   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);
    599:   if (f >= 0 && bs == 1) {
    600:     DMGetDefaultSection(dm, &section);
    601:     PetscSectionGetChart(section, &pStart, &pEnd);
    602:     for (p = pStart; p < pEnd; ++p) {
    603:       PetscInt rS, rE;

    605:       DMPlexGetGlobalFieldOffset_Private(dm, p, f, &rS, &rE);
    606:       for (r = rS; r < rE; ++r) {
    607:         PetscInt numCols, cStart, c;

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

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

    652: PetscErrorCode DMPlexFillMatrix_Static(DM dm, PetscLayout rLayout, PetscInt bs, PetscInt f, PetscSection sectionAdj, const PetscInt cols[], Mat A)
    653: {
    654:   PetscSection   section;
    655:   PetscScalar   *values;
    656:   PetscInt       rStart, rEnd, r, pStart, pEnd, p, len, maxRowLen = 0;

    660:   PetscLayoutGetRange(rLayout, &rStart, &rEnd);
    661:   for (r = rStart; r < rEnd; ++r) {
    662:     PetscSectionGetDof(sectionAdj, r, &len);
    663:     maxRowLen = PetscMax(maxRowLen, len);
    664:   }
    665:   PetscCalloc1(maxRowLen, &values);
    666:   if (f >=0 && bs == 1) {
    667:     DMGetDefaultSection(dm, &section);
    668:     PetscSectionGetChart(section, &pStart, &pEnd);
    669:     for (p = pStart; p < pEnd; ++p) {
    670:       PetscInt rS, rE;

    672:       DMPlexGetGlobalFieldOffset_Private(dm, p, f, &rS, &rE);
    673:       for (r = rS; r < rE; ++r) {
    674:         PetscInt numCols, cStart;

    676:         PetscSectionGetDof(sectionAdj, r, &numCols);
    677:         PetscSectionGetOffset(sectionAdj, r, &cStart);
    678:         MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);
    679:       }
    680:     }
    681:   } else {
    682:     for (r = rStart; r < rEnd; ++r) {
    683:       PetscInt numCols, cStart;

    685:       PetscSectionGetDof(sectionAdj, r, &numCols);
    686:       PetscSectionGetOffset(sectionAdj, r, &cStart);
    687:       MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);
    688:     }
    689:   }
    690:   PetscFree(values);
    691:   return(0);
    692: }

    696: PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
    697: {
    698:   MPI_Comm       comm;
    699:   PetscDS        prob;
    700:   MatType        mtype;
    701:   PetscSF        sf, sfDof;
    702:   PetscSection   section;
    703:   PetscInt      *remoteOffsets;
    704:   PetscSection   sectionAdj[4] = {NULL, NULL, NULL, NULL};
    705:   PetscInt      *cols[4]       = {NULL, NULL, NULL, NULL};
    706:   PetscBool      useCone, useClosure;
    707:   PetscInt       Nf, f, idx, locRows;
    708:   PetscLayout    rLayout;
    709:   PetscBool      isSymBlock, isSymSeqBlock, isSymMPIBlock, debug = PETSC_FALSE;

    717:   DMGetDS(dm, &prob);
    718:   DMGetPointSF(dm, &sf);
    719:   DMGetDefaultSection(dm, &section);
    720:   PetscOptionsGetBool(NULL, "-dm_view_preallocation", &debug, NULL);
    721:   PetscObjectGetComm((PetscObject) dm, &comm);
    722:   PetscLogEventBegin(DMPLEX_Preallocate,dm,0,0,0);
    723:   /* Create dof SF based on point SF */
    724:   if (debug) {
    725:     PetscSection section, sectionGlobal;
    726:     PetscSF      sf;

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

    799: #if 0
    802: PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
    803: {
    804:   PetscInt       *tmpClosure,*tmpAdj,*visits;
    805:   PetscInt        c,cStart,cEnd,pStart,pEnd;
    806:   PetscErrorCode  ierr;

    809:   DMGetDimension(dm, &dim);
    810:   DMPlexGetDepth(dm, &depth);
    811:   DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);

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

    815:   PetscSectionGetChart(section, &pStart, &pEnd);
    816:   npoints = pEnd - pStart;

    818:   PetscMalloc3(maxClosureSize,&tmpClosure,npoints,&lvisits,npoints,&visits);
    819:   PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));
    820:   PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));
    821:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    822:   for (c=cStart; c<cEnd; c++) {
    823:     PetscInt *support = tmpClosure;
    824:     DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);
    825:     for (p=0; p<supportSize; p++) lvisits[support[p]]++;
    826:   }
    827:   PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);
    828:   PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);
    829:   PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);
    830:   PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);

    832:   PetscSFGetRanks();

    835:   PetscMalloc2(maxClosureSize*maxClosureSize,&cellmat,npoints,&owner);
    836:   for (c=cStart; c<cEnd; c++) {
    837:     PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));
    838:     /*
    839:      Depth-first walk of transitive closure.
    840:      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.
    841:      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
    842:      */
    843:   }

    845:   PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);
    846:   PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);
    847:   return(0);
    848: }
    849: #endif