xref: /petsc/src/ksp/pc/impls/patch/pcpatch.c (revision f1580f4e3ce5d5b2393648fd039d0d41b440385d)
14bbf5ea8SMatthew G. Knepley #include <petsc/private/pcpatchimpl.h> /*I "petscpc.h" I*/
254ab768cSLawrence Mitchell #include <petsc/private/kspimpl.h>     /* For ksp->setfromoptionscalled */
39d4fc724SLawrence Mitchell #include <petsc/private/vecimpl.h>     /* For vec->map */
45f824522SMatthew G. Knepley #include <petsc/private/dmpleximpl.h>  /* For DMPlexComputeJacobian_Patch_Internal() */
54bbf5ea8SMatthew G. Knepley #include <petscsf.h>
64bbf5ea8SMatthew G. Knepley #include <petscbt.h>
75f824522SMatthew G. Knepley #include <petscds.h>
8c73d2cf6SLawrence Mitchell #include <../src/mat/impls/dense/seq/dense.h> /*I "petscmat.h" I*/
94bbf5ea8SMatthew G. Knepley 
109d4fc724SLawrence Mitchell PetscLogEvent PC_Patch_CreatePatches, PC_Patch_ComputeOp, PC_Patch_Solve, PC_Patch_Apply, PC_Patch_Prealloc;
114bbf5ea8SMatthew G. Knepley 
129371c9d4SSatish Balay static inline PetscErrorCode ObjectView(PetscObject obj, PetscViewer viewer, PetscViewerFormat format) {
139566063dSJacob Faibussowitsch   PetscCall(PetscViewerPushFormat(viewer, format));
149566063dSJacob Faibussowitsch   PetscCall(PetscObjectView(obj, viewer));
159566063dSJacob Faibussowitsch   PetscCall(PetscViewerPopFormat(viewer));
167974b488SMatthew G. Knepley   return (0);
175f824522SMatthew G. Knepley }
185f824522SMatthew G. Knepley 
199371c9d4SSatish Balay static PetscErrorCode PCPatchConstruct_Star(void *vpatch, DM dm, PetscInt point, PetscHSetI ht) {
204bbf5ea8SMatthew G. Knepley   PetscInt  starSize;
214bbf5ea8SMatthew G. Knepley   PetscInt *star = NULL, si;
224bbf5ea8SMatthew G. Knepley 
234bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
249566063dSJacob Faibussowitsch   PetscCall(PetscHSetIClear(ht));
254bbf5ea8SMatthew G. Knepley   /* To start with, add the point we care about */
269566063dSJacob Faibussowitsch   PetscCall(PetscHSetIAdd(ht, point));
274bbf5ea8SMatthew G. Knepley   /* Loop over all the points that this point connects to */
289566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &starSize, &star));
299566063dSJacob Faibussowitsch   for (si = 0; si < starSize * 2; si += 2) PetscCall(PetscHSetIAdd(ht, star[si]));
309566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &starSize, &star));
314bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
324bbf5ea8SMatthew G. Knepley }
334bbf5ea8SMatthew G. Knepley 
349371c9d4SSatish Balay static PetscErrorCode PCPatchConstruct_Vanka(void *vpatch, DM dm, PetscInt point, PetscHSetI ht) {
354bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)vpatch;
364bbf5ea8SMatthew G. Knepley   PetscInt  starSize;
374bbf5ea8SMatthew G. Knepley   PetscInt *star         = NULL;
384bbf5ea8SMatthew G. Knepley   PetscBool shouldIgnore = PETSC_FALSE;
394bbf5ea8SMatthew G. Knepley   PetscInt  cStart, cEnd, iStart, iEnd, si;
404bbf5ea8SMatthew G. Knepley 
414bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
429566063dSJacob Faibussowitsch   PetscCall(PetscHSetIClear(ht));
434bbf5ea8SMatthew G. Knepley   /* To start with, add the point we care about */
449566063dSJacob Faibussowitsch   PetscCall(PetscHSetIAdd(ht, point));
454bbf5ea8SMatthew G. Knepley   /* Should we ignore any points of a certain dimension? */
464bbf5ea8SMatthew G. Knepley   if (patch->vankadim >= 0) {
474bbf5ea8SMatthew G. Knepley     shouldIgnore = PETSC_TRUE;
489566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, patch->vankadim, &iStart, &iEnd));
494bbf5ea8SMatthew G. Knepley   }
509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
514bbf5ea8SMatthew G. Knepley   /* Loop over all the cells that this point connects to */
529566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &starSize, &star));
535f824522SMatthew G. Knepley   for (si = 0; si < starSize * 2; si += 2) {
544bbf5ea8SMatthew G. Knepley     const PetscInt cell = star[si];
554bbf5ea8SMatthew G. Knepley     PetscInt       closureSize;
564bbf5ea8SMatthew G. Knepley     PetscInt      *closure = NULL, ci;
574bbf5ea8SMatthew G. Knepley 
584bbf5ea8SMatthew G. Knepley     if (cell < cStart || cell >= cEnd) continue;
594bbf5ea8SMatthew G. Knepley     /* now loop over all entities in the closure of that cell */
609566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure));
615f824522SMatthew G. Knepley     for (ci = 0; ci < closureSize * 2; ci += 2) {
624bbf5ea8SMatthew G. Knepley       const PetscInt newpoint = closure[ci];
634bbf5ea8SMatthew G. Knepley 
644bbf5ea8SMatthew G. Knepley       /* We've been told to ignore entities of this type.*/
654bbf5ea8SMatthew G. Knepley       if (shouldIgnore && newpoint >= iStart && newpoint < iEnd) continue;
669566063dSJacob Faibussowitsch       PetscCall(PetscHSetIAdd(ht, newpoint));
674bbf5ea8SMatthew G. Knepley     }
689566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure));
694bbf5ea8SMatthew G. Knepley   }
709566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &starSize, &star));
714bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
724bbf5ea8SMatthew G. Knepley }
734bbf5ea8SMatthew G. Knepley 
749371c9d4SSatish Balay static PetscErrorCode PCPatchConstruct_Pardecomp(void *vpatch, DM dm, PetscInt point, PetscHSetI ht) {
75b525f888SPatrick Farrell   PC_PATCH       *patch = (PC_PATCH *)vpatch;
760a390943SPatrick Farrell   DMLabel         ghost = NULL;
770a390943SPatrick Farrell   const PetscInt *leaves;
780a390943SPatrick Farrell   PetscInt        nleaves, pStart, pEnd, loc;
790a390943SPatrick Farrell   PetscBool       isFiredrake;
800a390943SPatrick Farrell   PetscBool       flg;
81b525f888SPatrick Farrell   PetscInt        starSize;
82b525f888SPatrick Farrell   PetscInt       *star = NULL;
8325fd193aSPatrick Farrell   PetscInt        opoint, overlapi;
840a390943SPatrick Farrell 
850a390943SPatrick Farrell   PetscFunctionBegin;
869566063dSJacob Faibussowitsch   PetscCall(PetscHSetIClear(ht));
870a390943SPatrick Farrell 
889566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
890a390943SPatrick Farrell 
909566063dSJacob Faibussowitsch   PetscCall(DMHasLabel(dm, "pyop2_ghost", &isFiredrake));
910a390943SPatrick Farrell   if (isFiredrake) {
929566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(dm, "pyop2_ghost", &ghost));
939566063dSJacob Faibussowitsch     PetscCall(DMLabelCreateIndex(ghost, pStart, pEnd));
940a390943SPatrick Farrell   } else {
950a390943SPatrick Farrell     PetscSF sf;
969566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(dm, &sf));
979566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL));
980a390943SPatrick Farrell     nleaves = PetscMax(nleaves, 0);
990a390943SPatrick Farrell   }
1000a390943SPatrick Farrell 
10125fd193aSPatrick Farrell   for (opoint = pStart; opoint < pEnd; ++opoint) {
1029566063dSJacob Faibussowitsch     if (ghost) PetscCall(DMLabelHasPoint(ghost, opoint, &flg));
1039371c9d4SSatish Balay     else {
1049371c9d4SSatish Balay       PetscCall(PetscFindInt(opoint, nleaves, leaves, &loc));
1059371c9d4SSatish Balay       flg = loc >= 0 ? PETSC_TRUE : PETSC_FALSE;
1069371c9d4SSatish Balay     }
1070a390943SPatrick Farrell     /* Not an owned entity, don't make a cell patch. */
1080a390943SPatrick Farrell     if (flg) continue;
1099566063dSJacob Faibussowitsch     PetscCall(PetscHSetIAdd(ht, opoint));
1100a390943SPatrick Farrell   }
1110a390943SPatrick Farrell 
112b525f888SPatrick Farrell   /* Now build the overlap for the patch */
11325fd193aSPatrick Farrell   for (overlapi = 0; overlapi < patch->pardecomp_overlap; ++overlapi) {
114b525f888SPatrick Farrell     PetscInt  index    = 0;
115b525f888SPatrick Farrell     PetscInt *htpoints = NULL;
116b525f888SPatrick Farrell     PetscInt  htsize;
11725fd193aSPatrick Farrell     PetscInt  i;
118b525f888SPatrick Farrell 
1199566063dSJacob Faibussowitsch     PetscCall(PetscHSetIGetSize(ht, &htsize));
1209566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(htsize, &htpoints));
1219566063dSJacob Faibussowitsch     PetscCall(PetscHSetIGetElems(ht, &index, htpoints));
122b525f888SPatrick Farrell 
12325fd193aSPatrick Farrell     for (i = 0; i < htsize; ++i) {
12425fd193aSPatrick Farrell       PetscInt hpoint = htpoints[i];
12525fd193aSPatrick Farrell       PetscInt si;
126b525f888SPatrick Farrell 
1279566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, hpoint, PETSC_FALSE, &starSize, &star));
12825fd193aSPatrick Farrell       for (si = 0; si < starSize * 2; si += 2) {
129b525f888SPatrick Farrell         const PetscInt starp = star[si];
130b525f888SPatrick Farrell         PetscInt       closureSize;
131b525f888SPatrick Farrell         PetscInt      *closure = NULL, ci;
132b525f888SPatrick Farrell 
133b525f888SPatrick Farrell         /* now loop over all entities in the closure of starp */
1349566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm, starp, PETSC_TRUE, &closureSize, &closure));
13525fd193aSPatrick Farrell         for (ci = 0; ci < closureSize * 2; ci += 2) {
136b525f888SPatrick Farrell           const PetscInt closstarp = closure[ci];
1379566063dSJacob Faibussowitsch           PetscCall(PetscHSetIAdd(ht, closstarp));
138b525f888SPatrick Farrell         }
1399566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, starp, PETSC_TRUE, &closureSize, &closure));
140b525f888SPatrick Farrell       }
1419566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, hpoint, PETSC_FALSE, &starSize, &star));
142b525f888SPatrick Farrell     }
1439566063dSJacob Faibussowitsch     PetscCall(PetscFree(htpoints));
144b525f888SPatrick Farrell   }
145b525f888SPatrick Farrell 
1460a390943SPatrick Farrell   PetscFunctionReturn(0);
1470a390943SPatrick Farrell }
1480a390943SPatrick Farrell 
1494bbf5ea8SMatthew G. Knepley /* The user's already set the patches in patch->userIS. Build the hash tables */
1509371c9d4SSatish Balay static PetscErrorCode PCPatchConstruct_User(void *vpatch, DM dm, PetscInt point, PetscHSetI ht) {
1514bbf5ea8SMatthew G. Knepley   PC_PATCH       *patch   = (PC_PATCH *)vpatch;
1524bbf5ea8SMatthew G. Knepley   IS              patchis = patch->userIS[point];
1534bbf5ea8SMatthew G. Knepley   PetscInt        n;
1544bbf5ea8SMatthew G. Knepley   const PetscInt *patchdata;
1554bbf5ea8SMatthew G. Knepley   PetscInt        pStart, pEnd, i;
1564bbf5ea8SMatthew G. Knepley 
1574bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
1589566063dSJacob Faibussowitsch   PetscCall(PetscHSetIClear(ht));
1599566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
1609566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(patchis, &n));
1619566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(patchis, &patchdata));
1624bbf5ea8SMatthew G. Knepley   for (i = 0; i < n; ++i) {
1634bbf5ea8SMatthew G. Knepley     const PetscInt ownedpoint = patchdata[i];
1644bbf5ea8SMatthew G. Knepley 
1657a46b595SBarry Smith     PetscCheck(ownedpoint >= pStart && ownedpoint < pEnd, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " was not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", ownedpoint, pStart, pEnd);
1669566063dSJacob Faibussowitsch     PetscCall(PetscHSetIAdd(ht, ownedpoint));
1674bbf5ea8SMatthew G. Knepley   }
1689566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(patchis, &patchdata));
1694bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
1704bbf5ea8SMatthew G. Knepley }
1714bbf5ea8SMatthew G. Knepley 
1729371c9d4SSatish Balay static PetscErrorCode PCPatchCreateDefaultSF_Private(PC pc, PetscInt n, const PetscSF *sf, const PetscInt *bs) {
1734bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
1744bbf5ea8SMatthew G. Knepley   PetscInt  i;
1754bbf5ea8SMatthew G. Knepley 
1764bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
1774bbf5ea8SMatthew G. Knepley   if (n == 1 && bs[0] == 1) {
1781bb6d2a8SBarry Smith     patch->sectionSF = sf[0];
1799566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)patch->sectionSF));
1804bbf5ea8SMatthew G. Knepley   } else {
1814bbf5ea8SMatthew G. Knepley     PetscInt     allRoots = 0, allLeaves = 0;
1824bbf5ea8SMatthew G. Knepley     PetscInt     leafOffset    = 0;
1834bbf5ea8SMatthew G. Knepley     PetscInt    *ilocal        = NULL;
1844bbf5ea8SMatthew G. Knepley     PetscSFNode *iremote       = NULL;
1854bbf5ea8SMatthew G. Knepley     PetscInt    *remoteOffsets = NULL;
1864bbf5ea8SMatthew G. Knepley     PetscInt     index         = 0;
1871b68eb51SMatthew G. Knepley     PetscHMapI   rankToIndex;
1884bbf5ea8SMatthew G. Knepley     PetscInt     numRanks = 0;
1894bbf5ea8SMatthew G. Knepley     PetscSFNode *remote   = NULL;
1904bbf5ea8SMatthew G. Knepley     PetscSF      rankSF;
1914bbf5ea8SMatthew G. Knepley     PetscInt    *ranks   = NULL;
1924bbf5ea8SMatthew G. Knepley     PetscInt    *offsets = NULL;
1934bbf5ea8SMatthew G. Knepley     MPI_Datatype contig;
1941b68eb51SMatthew G. Knepley     PetscHSetI   ranksUniq;
1954bbf5ea8SMatthew G. Knepley 
1964bbf5ea8SMatthew G. Knepley     /* First figure out how many dofs there are in the concatenated numbering.
197*f1580f4eSBarry Smith        allRoots: number of owned global dofs;
198*f1580f4eSBarry Smith        allLeaves: number of visible dofs (global + ghosted).
1994bbf5ea8SMatthew G. Knepley     */
2004bbf5ea8SMatthew G. Knepley     for (i = 0; i < n; ++i) {
2014bbf5ea8SMatthew G. Knepley       PetscInt nroots, nleaves;
2024bbf5ea8SMatthew G. Knepley 
2039566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGraph(sf[i], &nroots, &nleaves, NULL, NULL));
2044bbf5ea8SMatthew G. Knepley       allRoots += nroots * bs[i];
2054bbf5ea8SMatthew G. Knepley       allLeaves += nleaves * bs[i];
2064bbf5ea8SMatthew G. Knepley     }
2079566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(allLeaves, &ilocal));
2089566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(allLeaves, &iremote));
2094bbf5ea8SMatthew G. Knepley     /* Now build an SF that just contains process connectivity. */
2109566063dSJacob Faibussowitsch     PetscCall(PetscHSetICreate(&ranksUniq));
2114bbf5ea8SMatthew G. Knepley     for (i = 0; i < n; ++i) {
2124bbf5ea8SMatthew G. Knepley       const PetscMPIInt *ranks = NULL;
2134bbf5ea8SMatthew G. Knepley       PetscInt           nranks, j;
2144bbf5ea8SMatthew G. Knepley 
2159566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(sf[i]));
2169566063dSJacob Faibussowitsch       PetscCall(PetscSFGetRootRanks(sf[i], &nranks, &ranks, NULL, NULL, NULL));
2174bbf5ea8SMatthew G. Knepley       /* These are all the ranks who communicate with me. */
21848a46eb9SPierre Jolivet       for (j = 0; j < nranks; ++j) PetscCall(PetscHSetIAdd(ranksUniq, (PetscInt)ranks[j]));
2194bbf5ea8SMatthew G. Knepley     }
2209566063dSJacob Faibussowitsch     PetscCall(PetscHSetIGetSize(ranksUniq, &numRanks));
2219566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numRanks, &remote));
2229566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numRanks, &ranks));
2239566063dSJacob Faibussowitsch     PetscCall(PetscHSetIGetElems(ranksUniq, &index, ranks));
2244bbf5ea8SMatthew G. Knepley 
2259566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&rankToIndex));
2264bbf5ea8SMatthew G. Knepley     for (i = 0; i < numRanks; ++i) {
2274bbf5ea8SMatthew G. Knepley       remote[i].rank  = ranks[i];
2284bbf5ea8SMatthew G. Knepley       remote[i].index = 0;
2299566063dSJacob Faibussowitsch       PetscCall(PetscHMapISet(rankToIndex, ranks[i], i));
2304bbf5ea8SMatthew G. Knepley     }
2319566063dSJacob Faibussowitsch     PetscCall(PetscFree(ranks));
2329566063dSJacob Faibussowitsch     PetscCall(PetscHSetIDestroy(&ranksUniq));
2339566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)pc), &rankSF));
2349566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(rankSF, 1, numRanks, NULL, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER));
2359566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(rankSF));
236*f1580f4eSBarry Smith     /* OK, use it to communicate the root offset on the remote processes for each subspace. */
2379566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &offsets));
2389566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n * numRanks, &remoteOffsets));
2394bbf5ea8SMatthew G. Knepley 
2404bbf5ea8SMatthew G. Knepley     offsets[0] = 0;
2414bbf5ea8SMatthew G. Knepley     for (i = 1; i < n; ++i) {
2424bbf5ea8SMatthew G. Knepley       PetscInt nroots;
2434bbf5ea8SMatthew G. Knepley 
2449566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGraph(sf[i - 1], &nroots, NULL, NULL, NULL));
2454bbf5ea8SMatthew G. Knepley       offsets[i] = offsets[i - 1] + nroots * bs[i - 1];
2464bbf5ea8SMatthew G. Knepley     }
247*f1580f4eSBarry Smith     /* Offsets are the offsets on the current process of the global dof numbering for the subspaces. */
2489566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_contiguous(n, MPIU_INT, &contig));
2499566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&contig));
2504bbf5ea8SMatthew G. Knepley 
2519566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(rankSF, contig, offsets, remoteOffsets, MPI_REPLACE));
2529566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(rankSF, contig, offsets, remoteOffsets, MPI_REPLACE));
2539566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&contig));
2549566063dSJacob Faibussowitsch     PetscCall(PetscFree(offsets));
2559566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&rankSF));
2564bbf5ea8SMatthew G. Knepley     /* Now remoteOffsets contains the offsets on the remote
257*f1580f4eSBarry Smith       processes who communicate with me.  So now we can
258*f1580f4eSBarry Smith       concatenate the list of SFs into a single one. */
2594bbf5ea8SMatthew G. Knepley     index = 0;
2604bbf5ea8SMatthew G. Knepley     for (i = 0; i < n; ++i) {
2614bbf5ea8SMatthew G. Knepley       const PetscSFNode *remote = NULL;
2624bbf5ea8SMatthew G. Knepley       const PetscInt    *local  = NULL;
2634bbf5ea8SMatthew G. Knepley       PetscInt           nroots, nleaves, j;
2644bbf5ea8SMatthew G. Knepley 
2659566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGraph(sf[i], &nroots, &nleaves, &local, &remote));
2664bbf5ea8SMatthew G. Knepley       for (j = 0; j < nleaves; ++j) {
2674bbf5ea8SMatthew G. Knepley         PetscInt rank = remote[j].rank;
2684bbf5ea8SMatthew G. Knepley         PetscInt idx, rootOffset, k;
2694bbf5ea8SMatthew G. Knepley 
2709566063dSJacob Faibussowitsch         PetscCall(PetscHMapIGet(rankToIndex, rank, &idx));
27108401ef6SPierre Jolivet         PetscCheck(idx != -1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Didn't find rank, huh?");
2724bbf5ea8SMatthew G. Knepley         /* Offset on given rank for ith subspace */
2734bbf5ea8SMatthew G. Knepley         rootOffset = remoteOffsets[n * idx + i];
2744bbf5ea8SMatthew G. Knepley         for (k = 0; k < bs[i]; ++k) {
27573ec7555SLawrence Mitchell           ilocal[index]        = (local ? local[j] : j) * bs[i] + k + leafOffset;
2764bbf5ea8SMatthew G. Knepley           iremote[index].rank  = remote[j].rank;
2774bbf5ea8SMatthew G. Knepley           iremote[index].index = remote[j].index * bs[i] + k + rootOffset;
2784bbf5ea8SMatthew G. Knepley           ++index;
2794bbf5ea8SMatthew G. Knepley         }
2804bbf5ea8SMatthew G. Knepley       }
2814bbf5ea8SMatthew G. Knepley       leafOffset += nleaves * bs[i];
2824bbf5ea8SMatthew G. Knepley     }
2839566063dSJacob Faibussowitsch     PetscCall(PetscHMapIDestroy(&rankToIndex));
2849566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsets));
2859566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)pc), &patch->sectionSF));
2869566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(patch->sectionSF, allRoots, allLeaves, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
2874bbf5ea8SMatthew G. Knepley   }
2884bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
2894bbf5ea8SMatthew G. Knepley }
2904bbf5ea8SMatthew G. Knepley 
2919371c9d4SSatish Balay PetscErrorCode PCPatchSetDenseInverse(PC pc, PetscBool flg) {
292c73d2cf6SLawrence Mitchell   PC_PATCH *patch = (PC_PATCH *)pc->data;
293c73d2cf6SLawrence Mitchell   PetscFunctionBegin;
294c73d2cf6SLawrence Mitchell   patch->denseinverse = flg;
295c73d2cf6SLawrence Mitchell   PetscFunctionReturn(0);
296c73d2cf6SLawrence Mitchell }
297c73d2cf6SLawrence Mitchell 
2989371c9d4SSatish Balay PetscErrorCode PCPatchGetDenseInverse(PC pc, PetscBool *flg) {
299c73d2cf6SLawrence Mitchell   PC_PATCH *patch = (PC_PATCH *)pc->data;
300c73d2cf6SLawrence Mitchell   PetscFunctionBegin;
301c73d2cf6SLawrence Mitchell   *flg = patch->denseinverse;
302c73d2cf6SLawrence Mitchell   PetscFunctionReturn(0);
303c73d2cf6SLawrence Mitchell }
304c73d2cf6SLawrence Mitchell 
3054bbf5ea8SMatthew G. Knepley /* TODO: Docs */
3069371c9d4SSatish Balay PetscErrorCode PCPatchSetIgnoreDim(PC pc, PetscInt dim) {
3075f824522SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
3085f824522SMatthew G. Knepley   PetscFunctionBegin;
3095f824522SMatthew G. Knepley   patch->ignoredim = dim;
3105f824522SMatthew G. Knepley   PetscFunctionReturn(0);
3115f824522SMatthew G. Knepley }
3125f824522SMatthew G. Knepley 
3135f824522SMatthew G. Knepley /* TODO: Docs */
3149371c9d4SSatish Balay PetscErrorCode PCPatchGetIgnoreDim(PC pc, PetscInt *dim) {
3155f824522SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
3165f824522SMatthew G. Knepley   PetscFunctionBegin;
3175f824522SMatthew G. Knepley   *dim = patch->ignoredim;
3185f824522SMatthew G. Knepley   PetscFunctionReturn(0);
3195f824522SMatthew G. Knepley }
3205f824522SMatthew G. Knepley 
3215f824522SMatthew G. Knepley /* TODO: Docs */
3229371c9d4SSatish Balay PetscErrorCode PCPatchSetSaveOperators(PC pc, PetscBool flg) {
3234bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
3244bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
3254bbf5ea8SMatthew G. Knepley   patch->save_operators = flg;
3264bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
3274bbf5ea8SMatthew G. Knepley }
3284bbf5ea8SMatthew G. Knepley 
3294bbf5ea8SMatthew G. Knepley /* TODO: Docs */
3309371c9d4SSatish Balay PetscErrorCode PCPatchGetSaveOperators(PC pc, PetscBool *flg) {
3314bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
3324bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
3334bbf5ea8SMatthew G. Knepley   *flg = patch->save_operators;
3344bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
3354bbf5ea8SMatthew G. Knepley }
3364bbf5ea8SMatthew G. Knepley 
3374bbf5ea8SMatthew G. Knepley /* TODO: Docs */
3389371c9d4SSatish Balay PetscErrorCode PCPatchSetPrecomputeElementTensors(PC pc, PetscBool flg) {
339fa84ea4cSLawrence Mitchell   PC_PATCH *patch = (PC_PATCH *)pc->data;
340fa84ea4cSLawrence Mitchell   PetscFunctionBegin;
341fa84ea4cSLawrence Mitchell   patch->precomputeElementTensors = flg;
342fa84ea4cSLawrence Mitchell   PetscFunctionReturn(0);
343fa84ea4cSLawrence Mitchell }
344fa84ea4cSLawrence Mitchell 
345fa84ea4cSLawrence Mitchell /* TODO: Docs */
3469371c9d4SSatish Balay PetscErrorCode PCPatchGetPrecomputeElementTensors(PC pc, PetscBool *flg) {
347fa84ea4cSLawrence Mitchell   PC_PATCH *patch = (PC_PATCH *)pc->data;
348fa84ea4cSLawrence Mitchell   PetscFunctionBegin;
349fa84ea4cSLawrence Mitchell   *flg = patch->precomputeElementTensors;
350fa84ea4cSLawrence Mitchell   PetscFunctionReturn(0);
351fa84ea4cSLawrence Mitchell }
352fa84ea4cSLawrence Mitchell 
353fa84ea4cSLawrence Mitchell /* TODO: Docs */
3549371c9d4SSatish Balay PetscErrorCode PCPatchSetPartitionOfUnity(PC pc, PetscBool flg) {
3554bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
3564bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
3574bbf5ea8SMatthew G. Knepley   patch->partition_of_unity = flg;
3584bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
3594bbf5ea8SMatthew G. Knepley }
3604bbf5ea8SMatthew G. Knepley 
3614bbf5ea8SMatthew G. Knepley /* TODO: Docs */
3629371c9d4SSatish Balay PetscErrorCode PCPatchGetPartitionOfUnity(PC pc, PetscBool *flg) {
3634bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
3644bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
3654bbf5ea8SMatthew G. Knepley   *flg = patch->partition_of_unity;
3664bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
3674bbf5ea8SMatthew G. Knepley }
3684bbf5ea8SMatthew G. Knepley 
3694bbf5ea8SMatthew G. Knepley /* TODO: Docs */
3709371c9d4SSatish Balay PetscErrorCode PCPatchSetLocalComposition(PC pc, PCCompositeType type) {
371c2e6f3c0SFlorian Wechsung   PC_PATCH *patch = (PC_PATCH *)pc->data;
372c2e6f3c0SFlorian Wechsung   PetscFunctionBegin;
3732472a847SBarry Smith   PetscCheck(type == PC_COMPOSITE_ADDITIVE || type == PC_COMPOSITE_MULTIPLICATIVE, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Only supports additive or multiplicative as the local type");
37461c4b389SFlorian Wechsung   patch->local_composition_type = type;
375c2e6f3c0SFlorian Wechsung   PetscFunctionReturn(0);
376c2e6f3c0SFlorian Wechsung }
377c2e6f3c0SFlorian Wechsung 
378c2e6f3c0SFlorian Wechsung /* TODO: Docs */
3799371c9d4SSatish Balay PetscErrorCode PCPatchGetLocalComposition(PC pc, PCCompositeType *type) {
380c2e6f3c0SFlorian Wechsung   PC_PATCH *patch = (PC_PATCH *)pc->data;
381c2e6f3c0SFlorian Wechsung   PetscFunctionBegin;
38261c4b389SFlorian Wechsung   *type = patch->local_composition_type;
383c2e6f3c0SFlorian Wechsung   PetscFunctionReturn(0);
384c2e6f3c0SFlorian Wechsung }
385c2e6f3c0SFlorian Wechsung 
386c2e6f3c0SFlorian Wechsung /* TODO: Docs */
3879371c9d4SSatish Balay PetscErrorCode PCPatchSetSubMatType(PC pc, MatType sub_mat_type) {
3884bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
3894bbf5ea8SMatthew G. Knepley 
3904bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
3919566063dSJacob Faibussowitsch   if (patch->sub_mat_type) PetscCall(PetscFree(patch->sub_mat_type));
3929566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(sub_mat_type, (char **)&patch->sub_mat_type));
3934bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
3944bbf5ea8SMatthew G. Knepley }
3954bbf5ea8SMatthew G. Knepley 
3964bbf5ea8SMatthew G. Knepley /* TODO: Docs */
3979371c9d4SSatish Balay PetscErrorCode PCPatchGetSubMatType(PC pc, MatType *sub_mat_type) {
3984bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
3994bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
4004bbf5ea8SMatthew G. Knepley   *sub_mat_type = patch->sub_mat_type;
4014bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
4024bbf5ea8SMatthew G. Knepley }
4034bbf5ea8SMatthew G. Knepley 
4044bbf5ea8SMatthew G. Knepley /* TODO: Docs */
4059371c9d4SSatish Balay PetscErrorCode PCPatchSetCellNumbering(PC pc, PetscSection cellNumbering) {
4064bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
4074bbf5ea8SMatthew G. Knepley 
4084bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
4094bbf5ea8SMatthew G. Knepley   patch->cellNumbering = cellNumbering;
4109566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)cellNumbering));
4114bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
4124bbf5ea8SMatthew G. Knepley }
4134bbf5ea8SMatthew G. Knepley 
4144bbf5ea8SMatthew G. Knepley /* TODO: Docs */
4159371c9d4SSatish Balay PetscErrorCode PCPatchGetCellNumbering(PC pc, PetscSection *cellNumbering) {
4164bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
4174bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
4184bbf5ea8SMatthew G. Knepley   *cellNumbering = patch->cellNumbering;
4194bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
4204bbf5ea8SMatthew G. Knepley }
4214bbf5ea8SMatthew G. Knepley 
4224bbf5ea8SMatthew G. Knepley /* TODO: Docs */
4239371c9d4SSatish Balay PetscErrorCode PCPatchSetConstructType(PC pc, PCPatchConstructType ctype, PetscErrorCode (*func)(PC, PetscInt *, IS **, IS *, void *), void *ctx) {
4244bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
4254bbf5ea8SMatthew G. Knepley 
4264bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
4274bbf5ea8SMatthew G. Knepley   patch->ctype = ctype;
4284bbf5ea8SMatthew G. Knepley   switch (ctype) {
4294bbf5ea8SMatthew G. Knepley   case PC_PATCH_STAR:
43040c17a03SPatrick Farrell     patch->user_patches     = PETSC_FALSE;
4314bbf5ea8SMatthew G. Knepley     patch->patchconstructop = PCPatchConstruct_Star;
4324bbf5ea8SMatthew G. Knepley     break;
4334bbf5ea8SMatthew G. Knepley   case PC_PATCH_VANKA:
43440c17a03SPatrick Farrell     patch->user_patches     = PETSC_FALSE;
4354bbf5ea8SMatthew G. Knepley     patch->patchconstructop = PCPatchConstruct_Vanka;
4364bbf5ea8SMatthew G. Knepley     break;
437e5b9877fSPatrick Farrell   case PC_PATCH_PARDECOMP:
4380a390943SPatrick Farrell     patch->user_patches     = PETSC_FALSE;
439e5b9877fSPatrick Farrell     patch->patchconstructop = PCPatchConstruct_Pardecomp;
4400a390943SPatrick Farrell     break;
4414bbf5ea8SMatthew G. Knepley   case PC_PATCH_USER:
4424bbf5ea8SMatthew G. Knepley   case PC_PATCH_PYTHON:
4434bbf5ea8SMatthew G. Knepley     patch->user_patches     = PETSC_TRUE;
4444bbf5ea8SMatthew G. Knepley     patch->patchconstructop = PCPatchConstruct_User;
445bdd9e0cdSPatrick Farrell     if (func) {
4464bbf5ea8SMatthew G. Knepley       patch->userpatchconstructionop = func;
4474bbf5ea8SMatthew G. Knepley       patch->userpatchconstructctx   = ctx;
448bdd9e0cdSPatrick Farrell     }
4494bbf5ea8SMatthew G. Knepley     break;
4509371c9d4SSatish Balay   default: SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "Unknown patch construction type %" PetscInt_FMT, (PetscInt)patch->ctype);
4514bbf5ea8SMatthew G. Knepley   }
4524bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
4534bbf5ea8SMatthew G. Knepley }
4544bbf5ea8SMatthew G. Knepley 
4554bbf5ea8SMatthew G. Knepley /* TODO: Docs */
4569371c9d4SSatish Balay PetscErrorCode PCPatchGetConstructType(PC pc, PCPatchConstructType *ctype, PetscErrorCode (**func)(PC, PetscInt *, IS **, IS *, void *), void **ctx) {
4574bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
4584bbf5ea8SMatthew G. Knepley 
4594bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
4604bbf5ea8SMatthew G. Knepley   *ctype = patch->ctype;
4614bbf5ea8SMatthew G. Knepley   switch (patch->ctype) {
4624bbf5ea8SMatthew G. Knepley   case PC_PATCH_STAR:
4634bbf5ea8SMatthew G. Knepley   case PC_PATCH_VANKA:
4649371c9d4SSatish Balay   case PC_PATCH_PARDECOMP: break;
4654bbf5ea8SMatthew G. Knepley   case PC_PATCH_USER:
4664bbf5ea8SMatthew G. Knepley   case PC_PATCH_PYTHON:
4674bbf5ea8SMatthew G. Knepley     *func = patch->userpatchconstructionop;
4684bbf5ea8SMatthew G. Knepley     *ctx  = patch->userpatchconstructctx;
4694bbf5ea8SMatthew G. Knepley     break;
4709371c9d4SSatish Balay   default: SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "Unknown patch construction type %" PetscInt_FMT, (PetscInt)patch->ctype);
4714bbf5ea8SMatthew G. Knepley   }
4724bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
4734bbf5ea8SMatthew G. Knepley }
4744bbf5ea8SMatthew G. Knepley 
4754bbf5ea8SMatthew G. Knepley /* TODO: Docs */
4769371c9d4SSatish Balay PetscErrorCode PCPatchSetDiscretisationInfo(PC pc, PetscInt nsubspaces, DM *dms, PetscInt *bs, PetscInt *nodesPerCell, const PetscInt **cellNodeMap, const PetscInt *subspaceOffsets, PetscInt numGhostBcs, const PetscInt *ghostBcNodes, PetscInt numGlobalBcs, const PetscInt *globalBcNodes) {
4774bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
478b6bb21d1SLawrence Mitchell   DM        dm, plex;
4794bbf5ea8SMatthew G. Knepley   PetscSF  *sfs;
4805f824522SMatthew G. Knepley   PetscInt  cStart, cEnd, i, j;
4814bbf5ea8SMatthew G. Knepley 
4824bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
4839566063dSJacob Faibussowitsch   PetscCall(PCGetDM(pc, &dm));
4849566063dSJacob Faibussowitsch   PetscCall(DMConvert(dm, DMPLEX, &plex));
485b6bb21d1SLawrence Mitchell   dm = plex;
4869566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
4879566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nsubspaces, &sfs));
4889566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nsubspaces, &patch->dofSection));
4899566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nsubspaces, &patch->bs));
4909566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nsubspaces, &patch->nodesPerCell));
4919566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nsubspaces, &patch->cellNodeMap));
4929566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nsubspaces + 1, &patch->subspaceOffsets));
4934bbf5ea8SMatthew G. Knepley 
4944bbf5ea8SMatthew G. Knepley   patch->nsubspaces       = nsubspaces;
4954bbf5ea8SMatthew G. Knepley   patch->totalDofsPerCell = 0;
4964bbf5ea8SMatthew G. Knepley   for (i = 0; i < nsubspaces; ++i) {
4979566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dms[i], &patch->dofSection[i]));
4989566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)patch->dofSection[i]));
4999566063dSJacob Faibussowitsch     PetscCall(DMGetSectionSF(dms[i], &sfs[i]));
5004bbf5ea8SMatthew G. Knepley     patch->bs[i]           = bs[i];
5014bbf5ea8SMatthew G. Knepley     patch->nodesPerCell[i] = nodesPerCell[i];
5024bbf5ea8SMatthew G. Knepley     patch->totalDofsPerCell += nodesPerCell[i] * bs[i];
5039566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1((cEnd - cStart) * nodesPerCell[i], &patch->cellNodeMap[i]));
50480e8a965SFlorian Wechsung     for (j = 0; j < (cEnd - cStart) * nodesPerCell[i]; ++j) patch->cellNodeMap[i][j] = cellNodeMap[i][j];
5054bbf5ea8SMatthew G. Knepley     patch->subspaceOffsets[i] = subspaceOffsets[i];
5064bbf5ea8SMatthew G. Knepley   }
5079566063dSJacob Faibussowitsch   PetscCall(PCPatchCreateDefaultSF_Private(pc, nsubspaces, sfs, patch->bs));
5089566063dSJacob Faibussowitsch   PetscCall(PetscFree(sfs));
5094bbf5ea8SMatthew G. Knepley 
5104bbf5ea8SMatthew G. Knepley   patch->subspaceOffsets[nsubspaces] = subspaceOffsets[nsubspaces];
5119566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numGhostBcs, ghostBcNodes, PETSC_COPY_VALUES, &patch->ghostBcNodes));
5129566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numGlobalBcs, globalBcNodes, PETSC_COPY_VALUES, &patch->globalBcNodes));
5139566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dm));
5144bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
5154bbf5ea8SMatthew G. Knepley }
5164bbf5ea8SMatthew G. Knepley 
5174bbf5ea8SMatthew G. Knepley /* TODO: Docs */
5189371c9d4SSatish Balay PetscErrorCode PCPatchSetDiscretisationInfoCombined(PC pc, DM dm, PetscInt *nodesPerCell, const PetscInt **cellNodeMap, PetscInt numGhostBcs, const PetscInt *ghostBcNodes, PetscInt numGlobalBcs, const PetscInt *globalBcNodes) {
5195f824522SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
5205f824522SMatthew G. Knepley   PetscInt  cStart, cEnd, i, j;
5215f824522SMatthew G. Knepley 
5225f824522SMatthew G. Knepley   PetscFunctionBegin;
5235f824522SMatthew G. Knepley   patch->combined = PETSC_TRUE;
5249566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
5259566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &patch->nsubspaces));
5269566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(patch->nsubspaces, &patch->dofSection));
5279566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(patch->nsubspaces, &patch->bs));
5289566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(patch->nsubspaces, &patch->nodesPerCell));
5299566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(patch->nsubspaces, &patch->cellNodeMap));
5309566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(patch->nsubspaces + 1, &patch->subspaceOffsets));
5319566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &patch->dofSection[0]));
5329566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)patch->dofSection[0]));
5339566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(patch->dofSection[0], &patch->subspaceOffsets[patch->nsubspaces]));
5345f824522SMatthew G. Knepley   patch->totalDofsPerCell = 0;
5355f824522SMatthew G. Knepley   for (i = 0; i < patch->nsubspaces; ++i) {
5365f824522SMatthew G. Knepley     patch->bs[i]           = 1;
5375f824522SMatthew G. Knepley     patch->nodesPerCell[i] = nodesPerCell[i];
5385f824522SMatthew G. Knepley     patch->totalDofsPerCell += nodesPerCell[i];
5399566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1((cEnd - cStart) * nodesPerCell[i], &patch->cellNodeMap[i]));
5405f824522SMatthew G. Knepley     for (j = 0; j < (cEnd - cStart) * nodesPerCell[i]; ++j) patch->cellNodeMap[i][j] = cellNodeMap[i][j];
5415f824522SMatthew G. Knepley   }
5429566063dSJacob Faibussowitsch   PetscCall(DMGetSectionSF(dm, &patch->sectionSF));
5439566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)patch->sectionSF));
5449566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numGhostBcs, ghostBcNodes, PETSC_COPY_VALUES, &patch->ghostBcNodes));
5459566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numGlobalBcs, globalBcNodes, PETSC_COPY_VALUES, &patch->globalBcNodes));
5465f824522SMatthew G. Knepley   PetscFunctionReturn(0);
5475f824522SMatthew G. Knepley }
5485f824522SMatthew G. Knepley 
5495f824522SMatthew G. Knepley /*@C
5505f824522SMatthew G. Knepley 
55192d50984SMatthew G. Knepley   PCPatchSetComputeFunction - Set the callback used to compute patch residuals
55292d50984SMatthew G. Knepley 
553*f1580f4eSBarry Smith   Logically collective on pc
55499b7e5c6SPatrick Farrell 
55592d50984SMatthew G. Knepley   Input Parameters:
55692d50984SMatthew G. Knepley + pc   - The PC
55792d50984SMatthew G. Knepley . func - The callback
55892d50984SMatthew G. Knepley - ctx  - The user context
55992d50984SMatthew G. Knepley 
5607a50e09dSPatrick Farrell   Calling sequence of func:
5617a50e09dSPatrick Farrell $   func (PC pc,PetscInt point,Vec x,Vec f,IS cellIS,PetscInt n,const PetscInt* dofsArray,const PetscInt* dofsArrayWithAll,void* ctx)
5627a50e09dSPatrick Farrell 
5637a50e09dSPatrick Farrell +  pc               - The PC
5647a50e09dSPatrick Farrell .  point            - The point
5657a50e09dSPatrick Farrell .  x                - The input solution (not used in linear problems)
5667a50e09dSPatrick Farrell .  f                - The patch residual vector
5677a50e09dSPatrick Farrell .  cellIS           - An array of the cell numbers
5687a50e09dSPatrick Farrell .  n                - The size of dofsArray
5697a50e09dSPatrick Farrell .  dofsArray        - The dofmap for the dofs to be solved for
5707a50e09dSPatrick Farrell .  dofsArrayWithAll - The dofmap for all dofs on the patch
5717a50e09dSPatrick Farrell -  ctx              - The user context
5727a50e09dSPatrick Farrell 
57392d50984SMatthew G. Knepley   Level: advanced
57492d50984SMatthew G. Knepley 
575*f1580f4eSBarry Smith   Note:
57626dc5b63SLawrence Mitchell   The entries of F (the output residual vector) have been set to zero before the call.
57792d50984SMatthew G. Knepley 
578db781477SPatrick Sanan .seealso: `PCPatchSetComputeOperator()`, `PCPatchGetComputeOperator()`, `PCPatchSetDiscretisationInfo()`, `PCPatchSetComputeFunctionInteriorFacets()`
57992d50984SMatthew G. Knepley @*/
5809371c9d4SSatish Balay PetscErrorCode PCPatchSetComputeFunction(PC pc, PetscErrorCode (*func)(PC, PetscInt, Vec, Vec, IS, PetscInt, const PetscInt *, const PetscInt *, void *), void *ctx) {
58192d50984SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
58292d50984SMatthew G. Knepley 
58392d50984SMatthew G. Knepley   PetscFunctionBegin;
58492d50984SMatthew G. Knepley   patch->usercomputef    = func;
58592d50984SMatthew G. Knepley   patch->usercomputefctx = ctx;
58692d50984SMatthew G. Knepley   PetscFunctionReturn(0);
58792d50984SMatthew G. Knepley }
58892d50984SMatthew G. Knepley 
58992d50984SMatthew G. Knepley /*@C
59092d50984SMatthew G. Knepley 
59159109abcSLawrence Mitchell   PCPatchSetComputeFunctionInteriorFacets - Set the callback used to compute facet integrals for patch residuals
59259109abcSLawrence Mitchell 
593*f1580f4eSBarry Smith   Logically collective on pc
5947a50e09dSPatrick Farrell 
59559109abcSLawrence Mitchell   Input Parameters:
59659109abcSLawrence Mitchell + pc   - The PC
59759109abcSLawrence Mitchell . func - The callback
59859109abcSLawrence Mitchell - ctx  - The user context
59959109abcSLawrence Mitchell 
6007a50e09dSPatrick Farrell   Calling sequence of func:
6017a50e09dSPatrick Farrell $   func (PC pc,PetscInt point,Vec x,Vec f,IS facetIS,PetscInt n,const PetscInt* dofsArray,const PetscInt* dofsArrayWithAll,void* ctx)
6027a50e09dSPatrick Farrell 
6037a50e09dSPatrick Farrell +  pc               - The PC
6047a50e09dSPatrick Farrell .  point            - The point
6057a50e09dSPatrick Farrell .  x                - The input solution (not used in linear problems)
6067a50e09dSPatrick Farrell .  f                - The patch residual vector
6077a50e09dSPatrick Farrell .  facetIS          - An array of the facet numbers
6087a50e09dSPatrick Farrell .  n                - The size of dofsArray
6097a50e09dSPatrick Farrell .  dofsArray        - The dofmap for the dofs to be solved for
6107a50e09dSPatrick Farrell .  dofsArrayWithAll - The dofmap for all dofs on the patch
6117a50e09dSPatrick Farrell -  ctx              - The user context
6127a50e09dSPatrick Farrell 
61359109abcSLawrence Mitchell   Level: advanced
61459109abcSLawrence Mitchell 
615*f1580f4eSBarry Smith   Note:
61626dc5b63SLawrence Mitchell   The entries of F (the output residual vector) have been set to zero before the call.
61759109abcSLawrence Mitchell 
618db781477SPatrick Sanan .seealso: `PCPatchSetComputeOperator()`, `PCPatchGetComputeOperator()`, `PCPatchSetDiscretisationInfo()`, `PCPatchSetComputeFunction()`
61959109abcSLawrence Mitchell @*/
6209371c9d4SSatish Balay PetscErrorCode PCPatchSetComputeFunctionInteriorFacets(PC pc, PetscErrorCode (*func)(PC, PetscInt, Vec, Vec, IS, PetscInt, const PetscInt *, const PetscInt *, void *), void *ctx) {
62159109abcSLawrence Mitchell   PC_PATCH *patch = (PC_PATCH *)pc->data;
62259109abcSLawrence Mitchell 
62359109abcSLawrence Mitchell   PetscFunctionBegin;
62459109abcSLawrence Mitchell   patch->usercomputefintfacet    = func;
62559109abcSLawrence Mitchell   patch->usercomputefintfacetctx = ctx;
62659109abcSLawrence Mitchell   PetscFunctionReturn(0);
62759109abcSLawrence Mitchell }
62859109abcSLawrence Mitchell 
62959109abcSLawrence Mitchell /*@C
63059109abcSLawrence Mitchell 
6315f824522SMatthew G. Knepley   PCPatchSetComputeOperator - Set the callback used to compute patch matrices
6325f824522SMatthew G. Knepley 
633*f1580f4eSBarry Smith   Logically collective on pc
6347a50e09dSPatrick Farrell 
6355f824522SMatthew G. Knepley   Input Parameters:
6365f824522SMatthew G. Knepley + pc   - The PC
6375f824522SMatthew G. Knepley . func - The callback
6385f824522SMatthew G. Knepley - ctx  - The user context
6395f824522SMatthew G. Knepley 
6407a50e09dSPatrick Farrell   Calling sequence of func:
6417a50e09dSPatrick Farrell $   func (PC pc,PetscInt point,Vec x,Mat mat,IS facetIS,PetscInt n,const PetscInt* dofsArray,const PetscInt* dofsArrayWithAll,void* ctx)
6427a50e09dSPatrick Farrell 
6437a50e09dSPatrick Farrell +  pc               - The PC
6447a50e09dSPatrick Farrell .  point            - The point
6457a50e09dSPatrick Farrell .  x                - The input solution (not used in linear problems)
6467a50e09dSPatrick Farrell .  mat              - The patch matrix
6477a50e09dSPatrick Farrell .  cellIS           - An array of the cell numbers
6487a50e09dSPatrick Farrell .  n                - The size of dofsArray
6497a50e09dSPatrick Farrell .  dofsArray        - The dofmap for the dofs to be solved for
6507a50e09dSPatrick Farrell .  dofsArrayWithAll - The dofmap for all dofs on the patch
6517a50e09dSPatrick Farrell -  ctx              - The user context
6527a50e09dSPatrick Farrell 
6535f824522SMatthew G. Knepley   Level: advanced
6545f824522SMatthew G. Knepley 
655*f1580f4eSBarry Smith   Note:
6567a50e09dSPatrick Farrell   The matrix entries have been set to zero before the call.
6575f824522SMatthew G. Knepley 
658db781477SPatrick Sanan .seealso: `PCPatchGetComputeOperator()`, `PCPatchSetComputeFunction()`, `PCPatchSetDiscretisationInfo()`
6595f824522SMatthew G. Knepley @*/
6609371c9d4SSatish Balay PetscErrorCode PCPatchSetComputeOperator(PC pc, PetscErrorCode (*func)(PC, PetscInt, Vec, Mat, IS, PetscInt, const PetscInt *, const PetscInt *, void *), void *ctx) {
6614bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
6624bbf5ea8SMatthew G. Knepley 
6634bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
6644bbf5ea8SMatthew G. Knepley   patch->usercomputeop    = func;
665723f9013SMatthew G. Knepley   patch->usercomputeopctx = ctx;
6664bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
6674bbf5ea8SMatthew G. Knepley }
6684bbf5ea8SMatthew G. Knepley 
66959109abcSLawrence Mitchell /*@C
67059109abcSLawrence Mitchell 
6717a50e09dSPatrick Farrell   PCPatchSetComputeOperatorInteriorFacets - Set the callback used to compute facet integrals for patch matrices
67259109abcSLawrence Mitchell 
673*f1580f4eSBarry Smith   Logically collective on pc
67499b7e5c6SPatrick Farrell 
67559109abcSLawrence Mitchell   Input Parameters:
67659109abcSLawrence Mitchell + pc   - The PC
67759109abcSLawrence Mitchell . func - The callback
67859109abcSLawrence Mitchell - ctx  - The user context
67959109abcSLawrence Mitchell 
6807a50e09dSPatrick Farrell   Calling sequence of func:
6817a50e09dSPatrick Farrell $   func (PC pc,PetscInt point,Vec x,Mat mat,IS facetIS,PetscInt n,const PetscInt* dofsArray,const PetscInt* dofsArrayWithAll,void* ctx)
6827a50e09dSPatrick Farrell 
6837a50e09dSPatrick Farrell +  pc               - The PC
6847a50e09dSPatrick Farrell .  point            - The point
6857a50e09dSPatrick Farrell .  x                - The input solution (not used in linear problems)
6867a50e09dSPatrick Farrell .  mat              - The patch matrix
6877a50e09dSPatrick Farrell .  facetIS          - An array of the facet numbers
6887a50e09dSPatrick Farrell .  n                - The size of dofsArray
6897a50e09dSPatrick Farrell .  dofsArray        - The dofmap for the dofs to be solved for
6907a50e09dSPatrick Farrell .  dofsArrayWithAll - The dofmap for all dofs on the patch
6917a50e09dSPatrick Farrell -  ctx              - The user context
6927a50e09dSPatrick Farrell 
69359109abcSLawrence Mitchell   Level: advanced
69459109abcSLawrence Mitchell 
695*f1580f4eSBarry Smith   Note:
6967a50e09dSPatrick Farrell   The matrix entries have been set to zero before the call.
69759109abcSLawrence Mitchell 
698db781477SPatrick Sanan .seealso: `PCPatchGetComputeOperator()`, `PCPatchSetComputeFunction()`, `PCPatchSetDiscretisationInfo()`
69959109abcSLawrence Mitchell @*/
7009371c9d4SSatish Balay PetscErrorCode PCPatchSetComputeOperatorInteriorFacets(PC pc, PetscErrorCode (*func)(PC, PetscInt, Vec, Mat, IS, PetscInt, const PetscInt *, const PetscInt *, void *), void *ctx) {
70159109abcSLawrence Mitchell   PC_PATCH *patch = (PC_PATCH *)pc->data;
70259109abcSLawrence Mitchell 
70359109abcSLawrence Mitchell   PetscFunctionBegin;
70459109abcSLawrence Mitchell   patch->usercomputeopintfacet    = func;
70559109abcSLawrence Mitchell   patch->usercomputeopintfacetctx = ctx;
70659109abcSLawrence Mitchell   PetscFunctionReturn(0);
70759109abcSLawrence Mitchell }
70859109abcSLawrence Mitchell 
7094bbf5ea8SMatthew G. Knepley /* On entry, ht contains the topological entities whose dofs we are responsible for solving for;
7104bbf5ea8SMatthew G. Knepley    on exit, cht contains all the topological entities we need to compute their residuals.
7114bbf5ea8SMatthew G. Knepley    In full generality this should incorporate knowledge of the sparsity pattern of the matrix;
7124bbf5ea8SMatthew G. Knepley    here we assume a standard FE sparsity pattern.*/
7134bbf5ea8SMatthew G. Knepley /* TODO: Use DMPlexGetAdjacency() */
7149371c9d4SSatish Balay static PetscErrorCode PCPatchCompleteCellPatch(PC pc, PetscHSetI ht, PetscHSetI cht) {
715b6bb21d1SLawrence Mitchell   DM            dm, plex;
716bc7fa33aSFlorian Wechsung   PC_PATCH     *patch = (PC_PATCH *)pc->data;
7171b68eb51SMatthew G. Knepley   PetscHashIter hi;
7184bbf5ea8SMatthew G. Knepley   PetscInt      point;
7194bbf5ea8SMatthew G. Knepley   PetscInt     *star = NULL, *closure = NULL;
7204c954380SMatthew G. Knepley   PetscInt      ignoredim, iStart = 0, iEnd = -1, starSize, closureSize, si, ci;
721bc7fa33aSFlorian Wechsung   PetscInt     *fStar = NULL, *fClosure = NULL;
722bc7fa33aSFlorian Wechsung   PetscInt      fBegin, fEnd, fsi, fci, fStarSize, fClosureSize;
7234bbf5ea8SMatthew G. Knepley 
7244bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
7259566063dSJacob Faibussowitsch   PetscCall(PCGetDM(pc, &dm));
7269566063dSJacob Faibussowitsch   PetscCall(DMConvert(dm, DMPLEX, &plex));
727b6bb21d1SLawrence Mitchell   dm = plex;
7289566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 1, &fBegin, &fEnd));
7299566063dSJacob Faibussowitsch   PetscCall(PCPatchGetIgnoreDim(pc, &ignoredim));
7309566063dSJacob Faibussowitsch   if (ignoredim >= 0) PetscCall(DMPlexGetDepthStratum(dm, ignoredim, &iStart, &iEnd));
7319566063dSJacob Faibussowitsch   PetscCall(PetscHSetIClear(cht));
7321b68eb51SMatthew G. Knepley   PetscHashIterBegin(ht, hi);
7331b68eb51SMatthew G. Knepley   while (!PetscHashIterAtEnd(ht, hi)) {
7341b68eb51SMatthew G. Knepley     PetscHashIterGetKey(ht, hi, point);
7351b68eb51SMatthew G. Knepley     PetscHashIterNext(ht, hi);
7364bbf5ea8SMatthew G. Knepley 
7374bbf5ea8SMatthew G. Knepley     /* Loop over all the cells that this point connects to */
7389566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &starSize, &star));
7395f824522SMatthew G. Knepley     for (si = 0; si < starSize * 2; si += 2) {
7404c954380SMatthew G. Knepley       const PetscInt ownedpoint = star[si];
7415f824522SMatthew G. Knepley       /* TODO Check for point in cht before running through closure again */
7424bbf5ea8SMatthew G. Knepley       /* now loop over all entities in the closure of that cell */
7439566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(dm, ownedpoint, PETSC_TRUE, &closureSize, &closure));
7445f824522SMatthew G. Knepley       for (ci = 0; ci < closureSize * 2; ci += 2) {
7454c954380SMatthew G. Knepley         const PetscInt seenpoint = closure[ci];
7465f824522SMatthew G. Knepley         if (ignoredim >= 0 && seenpoint >= iStart && seenpoint < iEnd) continue;
7479566063dSJacob Faibussowitsch         PetscCall(PetscHSetIAdd(cht, seenpoint));
748bc7fa33aSFlorian Wechsung         /* Facet integrals couple dofs across facets, so in that case for each of
749*f1580f4eSBarry Smith           the facets we need to add all dofs on the other side of the facet to
750*f1580f4eSBarry Smith           the seen dofs. */
751bc7fa33aSFlorian Wechsung         if (patch->usercomputeopintfacet) {
752bc7fa33aSFlorian Wechsung           if (fBegin <= seenpoint && seenpoint < fEnd) {
7539566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTransitiveClosure(dm, seenpoint, PETSC_FALSE, &fStarSize, &fStar));
754bc7fa33aSFlorian Wechsung             for (fsi = 0; fsi < fStarSize * 2; fsi += 2) {
7559566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTransitiveClosure(dm, fStar[fsi], PETSC_TRUE, &fClosureSize, &fClosure));
75648a46eb9SPierre Jolivet               for (fci = 0; fci < fClosureSize * 2; fci += 2) PetscCall(PetscHSetIAdd(cht, fClosure[fci]));
7579566063dSJacob Faibussowitsch               PetscCall(DMPlexRestoreTransitiveClosure(dm, fStar[fsi], PETSC_TRUE, NULL, &fClosure));
758bc7fa33aSFlorian Wechsung             }
7599566063dSJacob Faibussowitsch             PetscCall(DMPlexRestoreTransitiveClosure(dm, seenpoint, PETSC_FALSE, NULL, &fStar));
760bc7fa33aSFlorian Wechsung           }
761bc7fa33aSFlorian Wechsung         }
7624bbf5ea8SMatthew G. Knepley       }
7639566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(dm, ownedpoint, PETSC_TRUE, NULL, &closure));
7644bbf5ea8SMatthew G. Knepley     }
7659566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, NULL, &star));
7664bbf5ea8SMatthew G. Knepley   }
7679566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dm));
7685f824522SMatthew G. Knepley   PetscFunctionReturn(0);
7695f824522SMatthew G. Knepley }
7705f824522SMatthew G. Knepley 
7719371c9d4SSatish Balay static PetscErrorCode PCPatchGetGlobalDofs(PC pc, PetscSection dofSection[], PetscInt f, PetscBool combined, PetscInt p, PetscInt *dof, PetscInt *off) {
7725f824522SMatthew G. Knepley   PetscFunctionBegin;
7735f824522SMatthew G. Knepley   if (combined) {
7745f824522SMatthew G. Knepley     if (f < 0) {
7759566063dSJacob Faibussowitsch       if (dof) PetscCall(PetscSectionGetDof(dofSection[0], p, dof));
7769566063dSJacob Faibussowitsch       if (off) PetscCall(PetscSectionGetOffset(dofSection[0], p, off));
7775f824522SMatthew G. Knepley     } else {
7789566063dSJacob Faibussowitsch       if (dof) PetscCall(PetscSectionGetFieldDof(dofSection[0], p, f, dof));
7799566063dSJacob Faibussowitsch       if (off) PetscCall(PetscSectionGetFieldOffset(dofSection[0], p, f, off));
7805f824522SMatthew G. Knepley     }
7815f824522SMatthew G. Knepley   } else {
7825f824522SMatthew G. Knepley     if (f < 0) {
7835f824522SMatthew G. Knepley       PC_PATCH *patch = (PC_PATCH *)pc->data;
7845f824522SMatthew G. Knepley       PetscInt  fdof, g;
7855f824522SMatthew G. Knepley 
7865f824522SMatthew G. Knepley       if (dof) {
7875f824522SMatthew G. Knepley         *dof = 0;
7885f824522SMatthew G. Knepley         for (g = 0; g < patch->nsubspaces; ++g) {
7899566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(dofSection[g], p, &fdof));
7905f824522SMatthew G. Knepley           *dof += fdof;
7915f824522SMatthew G. Knepley         }
7925f824522SMatthew G. Knepley       }
793624e31c3SLawrence Mitchell       if (off) {
794624e31c3SLawrence Mitchell         *off = 0;
795624e31c3SLawrence Mitchell         for (g = 0; g < patch->nsubspaces; ++g) {
7969566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(dofSection[g], p, &fdof));
797624e31c3SLawrence Mitchell           *off += fdof;
798624e31c3SLawrence Mitchell         }
799624e31c3SLawrence Mitchell       }
8005f824522SMatthew G. Knepley     } else {
8019566063dSJacob Faibussowitsch       if (dof) PetscCall(PetscSectionGetDof(dofSection[f], p, dof));
8029566063dSJacob Faibussowitsch       if (off) PetscCall(PetscSectionGetOffset(dofSection[f], p, off));
8035f824522SMatthew G. Knepley     }
8045f824522SMatthew G. Knepley   }
8054bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
8064bbf5ea8SMatthew G. Knepley }
8074bbf5ea8SMatthew G. Knepley 
8084bbf5ea8SMatthew G. Knepley /* Given a hash table with a set of topological entities (pts), compute the degrees of
8094bbf5ea8SMatthew G. Knepley    freedom in global concatenated numbering on those entities.
8104bbf5ea8SMatthew G. Knepley    For Vanka smoothing, this needs to do something special: ignore dofs of the
8114bbf5ea8SMatthew G. Knepley    constraint subspace on entities that aren't the base entity we're building the patch
8124bbf5ea8SMatthew G. Knepley    around. */
8139371c9d4SSatish Balay static PetscErrorCode PCPatchGetPointDofs(PC pc, PetscHSetI pts, PetscHSetI dofs, PetscInt base, PetscHSetI *subspaces_to_exclude) {
8145f824522SMatthew G. Knepley   PC_PATCH     *patch = (PC_PATCH *)pc->data;
8151b68eb51SMatthew G. Knepley   PetscHashIter hi;
8164bbf5ea8SMatthew G. Knepley   PetscInt      ldof, loff;
8174bbf5ea8SMatthew G. Knepley   PetscInt      k, p;
8184bbf5ea8SMatthew G. Knepley 
8194bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
8209566063dSJacob Faibussowitsch   PetscCall(PetscHSetIClear(dofs));
8214bbf5ea8SMatthew G. Knepley   for (k = 0; k < patch->nsubspaces; ++k) {
8224bbf5ea8SMatthew G. Knepley     PetscInt subspaceOffset = patch->subspaceOffsets[k];
8234bbf5ea8SMatthew G. Knepley     PetscInt bs             = patch->bs[k];
8244bbf5ea8SMatthew G. Knepley     PetscInt j, l;
8254bbf5ea8SMatthew G. Knepley 
826e4c66b91SPatrick Farrell     if (subspaces_to_exclude != NULL) {
827e4c66b91SPatrick Farrell       PetscBool should_exclude_k = PETSC_FALSE;
8289566063dSJacob Faibussowitsch       PetscCall(PetscHSetIHas(*subspaces_to_exclude, k, &should_exclude_k));
829e4c66b91SPatrick Farrell       if (should_exclude_k) {
8304bbf5ea8SMatthew G. Knepley         /* only get this subspace dofs at the base entity, not any others */
8319566063dSJacob Faibussowitsch         PetscCall(PCPatchGetGlobalDofs(pc, patch->dofSection, k, patch->combined, base, &ldof, &loff));
8324bbf5ea8SMatthew G. Knepley         if (0 == ldof) continue;
8334bbf5ea8SMatthew G. Knepley         for (j = loff; j < ldof + loff; ++j) {
8344bbf5ea8SMatthew G. Knepley           for (l = 0; l < bs; ++l) {
8354bbf5ea8SMatthew G. Knepley             PetscInt dof = bs * j + l + subspaceOffset;
8369566063dSJacob Faibussowitsch             PetscCall(PetscHSetIAdd(dofs, dof));
8374bbf5ea8SMatthew G. Knepley           }
8384bbf5ea8SMatthew G. Knepley         }
8394bbf5ea8SMatthew G. Knepley         continue; /* skip the other dofs of this subspace */
8404bbf5ea8SMatthew G. Knepley       }
841e4c66b91SPatrick Farrell     }
8424bbf5ea8SMatthew G. Knepley 
8431b68eb51SMatthew G. Knepley     PetscHashIterBegin(pts, hi);
8441b68eb51SMatthew G. Knepley     while (!PetscHashIterAtEnd(pts, hi)) {
8451b68eb51SMatthew G. Knepley       PetscHashIterGetKey(pts, hi, p);
8461b68eb51SMatthew G. Knepley       PetscHashIterNext(pts, hi);
8479566063dSJacob Faibussowitsch       PetscCall(PCPatchGetGlobalDofs(pc, patch->dofSection, k, patch->combined, p, &ldof, &loff));
8484bbf5ea8SMatthew G. Knepley       if (0 == ldof) continue;
8494bbf5ea8SMatthew G. Knepley       for (j = loff; j < ldof + loff; ++j) {
8504bbf5ea8SMatthew G. Knepley         for (l = 0; l < bs; ++l) {
8514bbf5ea8SMatthew G. Knepley           PetscInt dof = bs * j + l + subspaceOffset;
8529566063dSJacob Faibussowitsch           PetscCall(PetscHSetIAdd(dofs, dof));
8534bbf5ea8SMatthew G. Knepley         }
8544bbf5ea8SMatthew G. Knepley       }
8554bbf5ea8SMatthew G. Knepley     }
8564bbf5ea8SMatthew G. Knepley   }
8574bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
8584bbf5ea8SMatthew G. Knepley }
8594bbf5ea8SMatthew G. Knepley 
8604bbf5ea8SMatthew G. Knepley /* Given two hash tables A and B, compute the keys in B that are not in A, and put them in C */
8619371c9d4SSatish Balay static PetscErrorCode PCPatchComputeSetDifference_Private(PetscHSetI A, PetscHSetI B, PetscHSetI C) {
8621b68eb51SMatthew G. Knepley   PetscHashIter hi;
8631b68eb51SMatthew G. Knepley   PetscInt      key;
8644bbf5ea8SMatthew G. Knepley   PetscBool     flg;
8654bbf5ea8SMatthew G. Knepley 
8664bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
8679566063dSJacob Faibussowitsch   PetscCall(PetscHSetIClear(C));
8681b68eb51SMatthew G. Knepley   PetscHashIterBegin(B, hi);
8691b68eb51SMatthew G. Knepley   while (!PetscHashIterAtEnd(B, hi)) {
8701b68eb51SMatthew G. Knepley     PetscHashIterGetKey(B, hi, key);
8711b68eb51SMatthew G. Knepley     PetscHashIterNext(B, hi);
8729566063dSJacob Faibussowitsch     PetscCall(PetscHSetIHas(A, key, &flg));
8739566063dSJacob Faibussowitsch     if (!flg) PetscCall(PetscHSetIAdd(C, key));
8744bbf5ea8SMatthew G. Knepley   }
8754bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
8764bbf5ea8SMatthew G. Knepley }
8774bbf5ea8SMatthew G. Knepley 
8784bbf5ea8SMatthew G. Knepley /*
879*f1580f4eSBarry Smith   PCPatchCreateCellPatches - create patches.
880*f1580f4eSBarry Smith 
881*f1580f4eSBarry Smith   Input Parameter:
882*f1580f4eSBarry Smith   . dm - The DMPlex object defining the mesh
883*f1580f4eSBarry Smith 
884*f1580f4eSBarry Smith   Output Parameters:
885*f1580f4eSBarry Smith   + cellCounts  - Section with counts of cells around each vertex
886*f1580f4eSBarry Smith   . cells       - IS of the cell point indices of cells in each patch
887*f1580f4eSBarry Smith   . pointCounts - Section with counts of cells around each vertex
888*f1580f4eSBarry Smith   - point       - IS of the cell point indices of cells in each patch
8894bbf5ea8SMatthew G. Knepley  */
8909371c9d4SSatish Balay static PetscErrorCode PCPatchCreateCellPatches(PC pc) {
8914bbf5ea8SMatthew G. Knepley   PC_PATCH       *patch = (PC_PATCH *)pc->data;
8925f824522SMatthew G. Knepley   DMLabel         ghost = NULL;
8934bbf5ea8SMatthew G. Knepley   DM              dm, plex;
89476ce8f1aSJose E. Roman   PetscHSetI      ht = NULL, cht = NULL;
8950e126c0bSLawrence Mitchell   PetscSection    cellCounts, pointCounts, intFacetCounts, extFacetCounts;
896eb62eeaaSLawrence Mitchell   PetscInt       *cellsArray, *pointsArray, *intFacetsArray, *extFacetsArray, *intFacetsToPatchCell;
8970e126c0bSLawrence Mitchell   PetscInt        numCells, numPoints, numIntFacets, numExtFacets;
8985f824522SMatthew G. Knepley   const PetscInt *leaves;
89933cbca70SPatrick Farrell   PetscInt        nleaves, pStart, pEnd, cStart, cEnd, vStart, vEnd, fStart, fEnd, v;
9005f824522SMatthew G. Knepley   PetscBool       isFiredrake;
9014bbf5ea8SMatthew G. Knepley 
9024bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
9034bbf5ea8SMatthew G. Knepley   /* Used to keep track of the cells in the patch. */
9049566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&ht));
9059566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&cht));
9064bbf5ea8SMatthew G. Knepley 
9079566063dSJacob Faibussowitsch   PetscCall(PCGetDM(pc, &dm));
90828b400f6SJacob Faibussowitsch   PetscCheck(dm, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "DM not yet set on patch PC");
9099566063dSJacob Faibussowitsch   PetscCall(DMConvert(dm, DMPLEX, &plex));
910b6bb21d1SLawrence Mitchell   dm = plex;
9119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
9129566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
9134bbf5ea8SMatthew G. Knepley 
9144bbf5ea8SMatthew G. Knepley   if (patch->user_patches) {
9159566063dSJacob Faibussowitsch     PetscCall(patch->userpatchconstructionop(pc, &patch->npatch, &patch->userIS, &patch->iterationSet, patch->userpatchconstructctx));
9169371c9d4SSatish Balay     vStart = 0;
9179371c9d4SSatish Balay     vEnd   = patch->npatch;
918e5b9877fSPatrick Farrell   } else if (patch->ctype == PC_PATCH_PARDECOMP) {
9199371c9d4SSatish Balay     vStart = 0;
9209371c9d4SSatish Balay     vEnd   = 1;
9215f824522SMatthew G. Knepley   } else if (patch->codim < 0) {
9229566063dSJacob Faibussowitsch     if (patch->dim < 0) PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
9239566063dSJacob Faibussowitsch     else PetscCall(DMPlexGetDepthStratum(dm, patch->dim, &vStart, &vEnd));
9249566063dSJacob Faibussowitsch   } else PetscCall(DMPlexGetHeightStratum(dm, patch->codim, &vStart, &vEnd));
9255f824522SMatthew G. Knepley   patch->npatch = vEnd - vStart;
9264bbf5ea8SMatthew G. Knepley 
9274bbf5ea8SMatthew G. Knepley   /* These labels mark the owned points.  We only create patches around points that this process owns. */
9289566063dSJacob Faibussowitsch   PetscCall(DMHasLabel(dm, "pyop2_ghost", &isFiredrake));
9295f824522SMatthew G. Knepley   if (isFiredrake) {
9309566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(dm, "pyop2_ghost", &ghost));
9319566063dSJacob Faibussowitsch     PetscCall(DMLabelCreateIndex(ghost, pStart, pEnd));
9325f824522SMatthew G. Knepley   } else {
9335f824522SMatthew G. Knepley     PetscSF sf;
9345f824522SMatthew G. Knepley 
9359566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(dm, &sf));
9369566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL));
9375f824522SMatthew G. Knepley     nleaves = PetscMax(nleaves, 0);
9385f824522SMatthew G. Knepley   }
9394bbf5ea8SMatthew G. Knepley 
9409566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &patch->cellCounts));
9419566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)patch->cellCounts, "Patch Cell Layout"));
9424bbf5ea8SMatthew G. Knepley   cellCounts = patch->cellCounts;
9439566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(cellCounts, vStart, vEnd));
9449566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &patch->pointCounts));
9459566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)patch->pointCounts, "Patch Point Layout"));
9465f824522SMatthew G. Knepley   pointCounts = patch->pointCounts;
9479566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(pointCounts, vStart, vEnd));
9489566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &patch->extFacetCounts));
9499566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)patch->extFacetCounts, "Patch Exterior Facet Layout"));
9500e126c0bSLawrence Mitchell   extFacetCounts = patch->extFacetCounts;
9519566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(extFacetCounts, vStart, vEnd));
9529566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &patch->intFacetCounts));
9539566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)patch->intFacetCounts, "Patch Interior Facet Layout"));
9540e126c0bSLawrence Mitchell   intFacetCounts = patch->intFacetCounts;
9559566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(intFacetCounts, vStart, vEnd));
9565f824522SMatthew G. Knepley   /* Count cells and points in the patch surrounding each entity */
9579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
9584bbf5ea8SMatthew G. Knepley   for (v = vStart; v < vEnd; ++v) {
9591b68eb51SMatthew G. Knepley     PetscHashIter hi;
9605f824522SMatthew G. Knepley     PetscInt      chtSize, loc = -1;
9615f824522SMatthew G. Knepley     PetscBool     flg;
9624bbf5ea8SMatthew G. Knepley 
963b525f888SPatrick Farrell     if (!patch->user_patches && patch->ctype != PC_PATCH_PARDECOMP) {
9649566063dSJacob Faibussowitsch       if (ghost) PetscCall(DMLabelHasPoint(ghost, v, &flg));
9659371c9d4SSatish Balay       else {
9669371c9d4SSatish Balay         PetscCall(PetscFindInt(v, nleaves, leaves, &loc));
9679371c9d4SSatish Balay         flg = loc >= 0 ? PETSC_TRUE : PETSC_FALSE;
9689371c9d4SSatish Balay       }
9694bbf5ea8SMatthew G. Knepley       /* Not an owned entity, don't make a cell patch. */
9704bbf5ea8SMatthew G. Knepley       if (flg) continue;
9714bbf5ea8SMatthew G. Knepley     }
9724bbf5ea8SMatthew G. Knepley 
9739566063dSJacob Faibussowitsch     PetscCall(patch->patchconstructop((void *)patch, dm, v, ht));
9749566063dSJacob Faibussowitsch     PetscCall(PCPatchCompleteCellPatch(pc, ht, cht));
9759566063dSJacob Faibussowitsch     PetscCall(PetscHSetIGetSize(cht, &chtSize));
9764bbf5ea8SMatthew G. Knepley     /* empty patch, continue */
9774bbf5ea8SMatthew G. Knepley     if (chtSize == 0) continue;
9784bbf5ea8SMatthew G. Knepley 
9794bbf5ea8SMatthew G. Knepley     /* safe because size(cht) > 0 from above */
9801b68eb51SMatthew G. Knepley     PetscHashIterBegin(cht, hi);
9811b68eb51SMatthew G. Knepley     while (!PetscHashIterAtEnd(cht, hi)) {
9825f824522SMatthew G. Knepley       PetscInt point, pdof;
9834bbf5ea8SMatthew G. Knepley 
9841b68eb51SMatthew G. Knepley       PetscHashIterGetKey(cht, hi, point);
9850e126c0bSLawrence Mitchell       if (fStart <= point && point < fEnd) {
9860e126c0bSLawrence Mitchell         const PetscInt *support;
9870e126c0bSLawrence Mitchell         PetscInt        supportSize, p;
9880e126c0bSLawrence Mitchell         PetscBool       interior = PETSC_TRUE;
9899566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupport(dm, point, &support));
9909566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupportSize(dm, point, &supportSize));
9910e126c0bSLawrence Mitchell         if (supportSize == 1) {
9920e126c0bSLawrence Mitchell           interior = PETSC_FALSE;
9930e126c0bSLawrence Mitchell         } else {
9940e126c0bSLawrence Mitchell           for (p = 0; p < supportSize; p++) {
9950e126c0bSLawrence Mitchell             PetscBool found;
9960e126c0bSLawrence Mitchell             /* FIXME: can I do this while iterating over cht? */
9979566063dSJacob Faibussowitsch             PetscCall(PetscHSetIHas(cht, support[p], &found));
9980e126c0bSLawrence Mitchell             if (!found) {
9990e126c0bSLawrence Mitchell               interior = PETSC_FALSE;
10000e126c0bSLawrence Mitchell               break;
10010e126c0bSLawrence Mitchell             }
10020e126c0bSLawrence Mitchell           }
10030e126c0bSLawrence Mitchell         }
10040e126c0bSLawrence Mitchell         if (interior) {
10059566063dSJacob Faibussowitsch           PetscCall(PetscSectionAddDof(intFacetCounts, v, 1));
10060e126c0bSLawrence Mitchell         } else {
10079566063dSJacob Faibussowitsch           PetscCall(PetscSectionAddDof(extFacetCounts, v, 1));
10080e126c0bSLawrence Mitchell         }
10090e126c0bSLawrence Mitchell       }
10109566063dSJacob Faibussowitsch       PetscCall(PCPatchGetGlobalDofs(pc, patch->dofSection, -1, patch->combined, point, &pdof, NULL));
10119566063dSJacob Faibussowitsch       if (pdof) PetscCall(PetscSectionAddDof(pointCounts, v, 1));
10129566063dSJacob Faibussowitsch       if (point >= cStart && point < cEnd) PetscCall(PetscSectionAddDof(cellCounts, v, 1));
10131b68eb51SMatthew G. Knepley       PetscHashIterNext(cht, hi);
10144bbf5ea8SMatthew G. Knepley     }
10154bbf5ea8SMatthew G. Knepley   }
10169566063dSJacob Faibussowitsch   if (isFiredrake) PetscCall(DMLabelDestroyIndex(ghost));
10174bbf5ea8SMatthew G. Knepley 
10189566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(cellCounts));
10199566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(cellCounts, &numCells));
10209566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numCells, &cellsArray));
10219566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(pointCounts));
10229566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(pointCounts, &numPoints));
10239566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numPoints, &pointsArray));
10244bbf5ea8SMatthew G. Knepley 
10259566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(intFacetCounts));
10269566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(extFacetCounts));
10279566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(intFacetCounts, &numIntFacets));
10289566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(extFacetCounts, &numExtFacets));
10299566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numIntFacets, &intFacetsArray));
10309566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numIntFacets * 2, &intFacetsToPatchCell));
10319566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numExtFacets, &extFacetsArray));
10320e126c0bSLawrence Mitchell 
10334bbf5ea8SMatthew G. Knepley   /* Now that we know how much space we need, run through again and actually remember the cells. */
10344bbf5ea8SMatthew G. Knepley   for (v = vStart; v < vEnd; v++) {
10351b68eb51SMatthew G. Knepley     PetscHashIter hi;
10360e126c0bSLawrence Mitchell     PetscInt      dof, off, cdof, coff, efdof, efoff, ifdof, ifoff, pdof, n = 0, cn = 0, ifn = 0, efn = 0;
10374bbf5ea8SMatthew G. Knepley 
10389566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(pointCounts, v, &dof));
10399566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(pointCounts, v, &off));
10409566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(cellCounts, v, &cdof));
10419566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(cellCounts, v, &coff));
10429566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(intFacetCounts, v, &ifdof));
10439566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(intFacetCounts, v, &ifoff));
10449566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(extFacetCounts, v, &efdof));
10459566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(extFacetCounts, v, &efoff));
10465f824522SMatthew G. Knepley     if (dof <= 0) continue;
10479566063dSJacob Faibussowitsch     PetscCall(patch->patchconstructop((void *)patch, dm, v, ht));
10489566063dSJacob Faibussowitsch     PetscCall(PCPatchCompleteCellPatch(pc, ht, cht));
10491b68eb51SMatthew G. Knepley     PetscHashIterBegin(cht, hi);
10501b68eb51SMatthew G. Knepley     while (!PetscHashIterAtEnd(cht, hi)) {
10514bbf5ea8SMatthew G. Knepley       PetscInt point;
10524bbf5ea8SMatthew G. Knepley 
10531b68eb51SMatthew G. Knepley       PetscHashIterGetKey(cht, hi, point);
10540e126c0bSLawrence Mitchell       if (fStart <= point && point < fEnd) {
10550e126c0bSLawrence Mitchell         const PetscInt *support;
10560e126c0bSLawrence Mitchell         PetscInt        supportSize, p;
10570e126c0bSLawrence Mitchell         PetscBool       interior = PETSC_TRUE;
10589566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupport(dm, point, &support));
10599566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupportSize(dm, point, &supportSize));
10600e126c0bSLawrence Mitchell         if (supportSize == 1) {
10610e126c0bSLawrence Mitchell           interior = PETSC_FALSE;
10620e126c0bSLawrence Mitchell         } else {
10630e126c0bSLawrence Mitchell           for (p = 0; p < supportSize; p++) {
10640e126c0bSLawrence Mitchell             PetscBool found;
10650e126c0bSLawrence Mitchell             /* FIXME: can I do this while iterating over cht? */
10669566063dSJacob Faibussowitsch             PetscCall(PetscHSetIHas(cht, support[p], &found));
10670e126c0bSLawrence Mitchell             if (!found) {
10680e126c0bSLawrence Mitchell               interior = PETSC_FALSE;
10690e126c0bSLawrence Mitchell               break;
10700e126c0bSLawrence Mitchell             }
10710e126c0bSLawrence Mitchell           }
10720e126c0bSLawrence Mitchell         }
10730e126c0bSLawrence Mitchell         if (interior) {
107444b625f7SLawrence Mitchell           intFacetsToPatchCell[2 * (ifoff + ifn)]     = support[0];
107544b625f7SLawrence Mitchell           intFacetsToPatchCell[2 * (ifoff + ifn) + 1] = support[1];
10760e126c0bSLawrence Mitchell           intFacetsArray[ifoff + ifn++]               = point;
10770e126c0bSLawrence Mitchell         } else {
10780e126c0bSLawrence Mitchell           extFacetsArray[efoff + efn++] = point;
10790e126c0bSLawrence Mitchell         }
10800e126c0bSLawrence Mitchell       }
10819566063dSJacob Faibussowitsch       PetscCall(PCPatchGetGlobalDofs(pc, patch->dofSection, -1, patch->combined, point, &pdof, NULL));
1082ad540459SPierre Jolivet       if (pdof) pointsArray[off + n++] = point;
1083ad540459SPierre Jolivet       if (point >= cStart && point < cEnd) cellsArray[coff + cn++] = point;
10841b68eb51SMatthew G. Knepley       PetscHashIterNext(cht, hi);
10854bbf5ea8SMatthew G. Knepley     }
108663a3b9bcSJacob Faibussowitsch     PetscCheck(ifn == ifdof, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of interior facets in patch %" PetscInt_FMT " is %" PetscInt_FMT ", but should be %" PetscInt_FMT, v, ifn, ifdof);
108763a3b9bcSJacob Faibussowitsch     PetscCheck(efn == efdof, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of exterior facets in patch %" PetscInt_FMT " is %" PetscInt_FMT ", but should be %" PetscInt_FMT, v, efn, efdof);
108863a3b9bcSJacob Faibussowitsch     PetscCheck(cn == cdof, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of cells in patch %" PetscInt_FMT " is %" PetscInt_FMT ", but should be %" PetscInt_FMT, v, cn, cdof);
108963a3b9bcSJacob Faibussowitsch     PetscCheck(n == dof, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of points in patch %" PetscInt_FMT " is %" PetscInt_FMT ", but should be %" PetscInt_FMT, v, n, dof);
1090eb62eeaaSLawrence Mitchell 
1091eb62eeaaSLawrence Mitchell     for (ifn = 0; ifn < ifdof; ifn++) {
109244b625f7SLawrence Mitchell       PetscInt  cell0  = intFacetsToPatchCell[2 * (ifoff + ifn)];
109344b625f7SLawrence Mitchell       PetscInt  cell1  = intFacetsToPatchCell[2 * (ifoff + ifn) + 1];
1094eb62eeaaSLawrence Mitchell       PetscBool found0 = PETSC_FALSE, found1 = PETSC_FALSE;
1095eb62eeaaSLawrence Mitchell       for (n = 0; n < cdof; n++) {
10967c54fef0SLawrence Mitchell         if (!found0 && cell0 == cellsArray[coff + n]) {
1097c3faab33SLawrence Mitchell           intFacetsToPatchCell[2 * (ifoff + ifn)] = n;
1098eb62eeaaSLawrence Mitchell           found0                                  = PETSC_TRUE;
1099eb62eeaaSLawrence Mitchell         }
11007c54fef0SLawrence Mitchell         if (!found1 && cell1 == cellsArray[coff + n]) {
1101c3faab33SLawrence Mitchell           intFacetsToPatchCell[2 * (ifoff + ifn) + 1] = n;
110280fc4459SLawrence Mitchell           found1                                      = PETSC_TRUE;
1103eb62eeaaSLawrence Mitchell         }
1104eb62eeaaSLawrence Mitchell         if (found0 && found1) break;
1105eb62eeaaSLawrence Mitchell       }
11067827d75bSBarry Smith       PetscCheck(found0 && found1, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Didn't manage to find local point numbers for facet support");
1107eb62eeaaSLawrence Mitchell     }
11084bbf5ea8SMatthew G. Knepley   }
11099566063dSJacob Faibussowitsch   PetscCall(PetscHSetIDestroy(&ht));
11109566063dSJacob Faibussowitsch   PetscCall(PetscHSetIDestroy(&cht));
11115f824522SMatthew G. Knepley 
11129566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numCells, cellsArray, PETSC_OWN_POINTER, &patch->cells));
11139566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)patch->cells, "Patch Cells"));
11145f824522SMatthew G. Knepley   if (patch->viewCells) {
11159566063dSJacob Faibussowitsch     PetscCall(ObjectView((PetscObject)patch->cellCounts, patch->viewerCells, patch->formatCells));
11169566063dSJacob Faibussowitsch     PetscCall(ObjectView((PetscObject)patch->cells, patch->viewerCells, patch->formatCells));
11175f824522SMatthew G. Knepley   }
11189566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numIntFacets, intFacetsArray, PETSC_OWN_POINTER, &patch->intFacets));
11199566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)patch->intFacets, "Patch Interior Facets"));
11209566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 2 * numIntFacets, intFacetsToPatchCell, PETSC_OWN_POINTER, &patch->intFacetsToPatchCell));
11219566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)patch->intFacetsToPatchCell, "Patch Interior Facets local support"));
11220e126c0bSLawrence Mitchell   if (patch->viewIntFacets) {
11239566063dSJacob Faibussowitsch     PetscCall(ObjectView((PetscObject)patch->intFacetCounts, patch->viewerIntFacets, patch->formatIntFacets));
11249566063dSJacob Faibussowitsch     PetscCall(ObjectView((PetscObject)patch->intFacets, patch->viewerIntFacets, patch->formatIntFacets));
11259566063dSJacob Faibussowitsch     PetscCall(ObjectView((PetscObject)patch->intFacetsToPatchCell, patch->viewerIntFacets, patch->formatIntFacets));
11260e126c0bSLawrence Mitchell   }
11279566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numExtFacets, extFacetsArray, PETSC_OWN_POINTER, &patch->extFacets));
11289566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)patch->extFacets, "Patch Exterior Facets"));
11290e126c0bSLawrence Mitchell   if (patch->viewExtFacets) {
11309566063dSJacob Faibussowitsch     PetscCall(ObjectView((PetscObject)patch->extFacetCounts, patch->viewerExtFacets, patch->formatExtFacets));
11319566063dSJacob Faibussowitsch     PetscCall(ObjectView((PetscObject)patch->extFacets, patch->viewerExtFacets, patch->formatExtFacets));
11320e126c0bSLawrence Mitchell   }
11339566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numPoints, pointsArray, PETSC_OWN_POINTER, &patch->points));
11349566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)patch->points, "Patch Points"));
11355f824522SMatthew G. Knepley   if (patch->viewPoints) {
11369566063dSJacob Faibussowitsch     PetscCall(ObjectView((PetscObject)patch->pointCounts, patch->viewerPoints, patch->formatPoints));
11379566063dSJacob Faibussowitsch     PetscCall(ObjectView((PetscObject)patch->points, patch->viewerPoints, patch->formatPoints));
11385f824522SMatthew G. Knepley   }
11399566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dm));
11404bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
11414bbf5ea8SMatthew G. Knepley }
11424bbf5ea8SMatthew G. Knepley 
11434bbf5ea8SMatthew G. Knepley /*
1144*f1580f4eSBarry Smith   PCPatchCreateCellPatchDiscretisationInfo - Build the dof maps for cell patches
1145*f1580f4eSBarry Smith 
1146*f1580f4eSBarry Smith   Input Parameters:
1147*f1580f4eSBarry Smith   + dm - The DMPlex object defining the mesh
1148*f1580f4eSBarry Smith   . cellCounts - Section with counts of cells around each vertex
1149*f1580f4eSBarry Smith   . cells - IS of the cell point indices of cells in each patch
1150*f1580f4eSBarry Smith   . cellNumbering - Section mapping plex cell points to Firedrake cell indices.
1151*f1580f4eSBarry Smith   . nodesPerCell - number of nodes per cell.
1152*f1580f4eSBarry Smith   - cellNodeMap - map from cells to node indices (nodesPerCell * numCells)
1153*f1580f4eSBarry Smith 
1154*f1580f4eSBarry Smith   Output Parameters:
1155*f1580f4eSBarry Smith   + dofs - IS of local dof numbers of each cell in the patch, where local is a patch local numbering
1156*f1580f4eSBarry Smith   . gtolCounts - Section with counts of dofs per cell patch
1157*f1580f4eSBarry Smith   - gtol - IS mapping from global dofs to local dofs for each patch.
11584bbf5ea8SMatthew G. Knepley  */
11599371c9d4SSatish Balay static PetscErrorCode PCPatchCreateCellPatchDiscretisationInfo(PC pc) {
11604bbf5ea8SMatthew G. Knepley   PC_PATCH       *patch       = (PC_PATCH *)pc->data;
11614bbf5ea8SMatthew G. Knepley   PetscSection    cellCounts  = patch->cellCounts;
11625f824522SMatthew G. Knepley   PetscSection    pointCounts = patch->pointCounts;
11630904074fSPatrick Farrell   PetscSection    gtolCounts, gtolCountsWithArtificial = NULL, gtolCountsWithAll = NULL;
11644bbf5ea8SMatthew G. Knepley   IS              cells         = patch->cells;
11655f824522SMatthew G. Knepley   IS              points        = patch->points;
11664bbf5ea8SMatthew G. Knepley   PetscSection    cellNumbering = patch->cellNumbering;
11675f824522SMatthew G. Knepley   PetscInt        Nf            = patch->nsubspaces;
11685f824522SMatthew G. Knepley   PetscInt        numCells, numPoints;
11694bbf5ea8SMatthew G. Knepley   PetscInt        numDofs;
11700904074fSPatrick Farrell   PetscInt        numGlobalDofs, numGlobalDofsWithArtificial, numGlobalDofsWithAll;
11714bbf5ea8SMatthew G. Knepley   PetscInt        totalDofsPerCell = patch->totalDofsPerCell;
11724bbf5ea8SMatthew G. Knepley   PetscInt        vStart, vEnd, v;
11735f824522SMatthew G. Knepley   const PetscInt *cellsArray, *pointsArray;
11744bbf5ea8SMatthew G. Knepley   PetscInt       *newCellsArray                 = NULL;
11754bbf5ea8SMatthew G. Knepley   PetscInt       *dofsArray                     = NULL;
1176c2e6f3c0SFlorian Wechsung   PetscInt       *dofsArrayWithArtificial       = NULL;
11770904074fSPatrick Farrell   PetscInt       *dofsArrayWithAll              = NULL;
11785f824522SMatthew G. Knepley   PetscInt       *offsArray                     = NULL;
1179c2e6f3c0SFlorian Wechsung   PetscInt       *offsArrayWithArtificial       = NULL;
11800904074fSPatrick Farrell   PetscInt       *offsArrayWithAll              = NULL;
11814bbf5ea8SMatthew G. Knepley   PetscInt       *asmArray                      = NULL;
1182c2e6f3c0SFlorian Wechsung   PetscInt       *asmArrayWithArtificial        = NULL;
11830904074fSPatrick Farrell   PetscInt       *asmArrayWithAll               = NULL;
11844bbf5ea8SMatthew G. Knepley   PetscInt       *globalDofsArray               = NULL;
1185c2e6f3c0SFlorian Wechsung   PetscInt       *globalDofsArrayWithArtificial = NULL;
11860904074fSPatrick Farrell   PetscInt       *globalDofsArrayWithAll        = NULL;
11874bbf5ea8SMatthew G. Knepley   PetscInt        globalIndex                   = 0;
11884bbf5ea8SMatthew G. Knepley   PetscInt        key                           = 0;
11894bbf5ea8SMatthew G. Knepley   PetscInt        asmKey                        = 0;
1190b6bb21d1SLawrence Mitchell   DM              dm                            = NULL, plex;
1191557beb66SLawrence Mitchell   const PetscInt *bcNodes                       = NULL;
11921b68eb51SMatthew G. Knepley   PetscHMapI      ht;
1193c2e6f3c0SFlorian Wechsung   PetscHMapI      htWithArtificial;
11940904074fSPatrick Farrell   PetscHMapI      htWithAll;
11951b68eb51SMatthew G. Knepley   PetscHSetI      globalBcs;
1196557beb66SLawrence Mitchell   PetscInt        numBcs;
11971b68eb51SMatthew G. Knepley   PetscHSetI      ownedpts, seenpts, owneddofs, seendofs, artificialbcs;
1198cda239d9SMatthew G. Knepley   PetscInt        pStart, pEnd, p, i;
119910534d48SPatrick Farrell   char            option[PETSC_MAX_PATH_LEN];
120039fd2e8aSPatrick Farrell   PetscBool       isNonlinear;
12014bbf5ea8SMatthew G. Knepley 
12024bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
1203557beb66SLawrence Mitchell 
12049566063dSJacob Faibussowitsch   PetscCall(PCGetDM(pc, &dm));
12059566063dSJacob Faibussowitsch   PetscCall(DMConvert(dm, DMPLEX, &plex));
1206b6bb21d1SLawrence Mitchell   dm = plex;
12074bbf5ea8SMatthew G. Knepley   /* dofcounts section is cellcounts section * dofPerCell */
12089566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(cellCounts, &numCells));
12099566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(patch->pointCounts, &numPoints));
12104bbf5ea8SMatthew G. Knepley   numDofs = numCells * totalDofsPerCell;
12119566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numDofs, &dofsArray));
12129566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numPoints * Nf, &offsArray));
12139566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numDofs, &asmArray));
12149566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numCells, &newCellsArray));
12159566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(cellCounts, &vStart, &vEnd));
12169566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &patch->gtolCounts));
12174bbf5ea8SMatthew G. Knepley   gtolCounts = patch->gtolCounts;
12189566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(gtolCounts, vStart, vEnd));
12199566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)patch->gtolCounts, "Patch Global Index Section"));
12204bbf5ea8SMatthew G. Knepley 
1221b6bb21d1SLawrence Mitchell   if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
12229566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPoints * Nf, &offsArrayWithArtificial));
12239566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numDofs, &asmArrayWithArtificial));
12249566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numDofs, &dofsArrayWithArtificial));
12259566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &patch->gtolCountsWithArtificial));
1226c2e6f3c0SFlorian Wechsung     gtolCountsWithArtificial = patch->gtolCountsWithArtificial;
12279566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(gtolCountsWithArtificial, vStart, vEnd));
12289566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)patch->gtolCountsWithArtificial, "Patch Global Index Section Including Artificial BCs"));
1229c2e6f3c0SFlorian Wechsung   }
1230c2e6f3c0SFlorian Wechsung 
12310904074fSPatrick Farrell   isNonlinear = patch->isNonlinear;
1232b6bb21d1SLawrence Mitchell   if (isNonlinear) {
12339566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numPoints * Nf, &offsArrayWithAll));
12349566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numDofs, &asmArrayWithAll));
12359566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numDofs, &dofsArrayWithAll));
12369566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &patch->gtolCountsWithAll));
12370904074fSPatrick Farrell     gtolCountsWithAll = patch->gtolCountsWithAll;
12389566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(gtolCountsWithAll, vStart, vEnd));
12399566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)patch->gtolCountsWithAll, "Patch Global Index Section Including All BCs"));
12400904074fSPatrick Farrell   }
12410904074fSPatrick Farrell 
1242557beb66SLawrence Mitchell   /* Outside the patch loop, get the dofs that are globally-enforced Dirichlet
1243557beb66SLawrence Mitchell    conditions */
12449566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&globalBcs));
12459566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(patch->ghostBcNodes, &bcNodes));
12469566063dSJacob Faibussowitsch   PetscCall(ISGetSize(patch->ghostBcNodes, &numBcs));
12479371c9d4SSatish Balay   for (i = 0; i < numBcs; ++i) { PetscCall(PetscHSetIAdd(globalBcs, bcNodes[i])); /* these are already in concatenated numbering */ }
12489566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(patch->ghostBcNodes, &bcNodes));
12499566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&patch->ghostBcNodes)); /* memory optimisation */
1250557beb66SLawrence Mitchell 
1251557beb66SLawrence Mitchell   /* Hash tables for artificial BC construction */
12529566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&ownedpts));
12539566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&seenpts));
12549566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&owneddofs));
12559566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&seendofs));
12569566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&artificialbcs));
1257557beb66SLawrence Mitchell 
12589566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(cells, &cellsArray));
12599566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(points, &pointsArray));
12609566063dSJacob Faibussowitsch   PetscCall(PetscHMapICreate(&ht));
12619566063dSJacob Faibussowitsch   PetscCall(PetscHMapICreate(&htWithArtificial));
12629566063dSJacob Faibussowitsch   PetscCall(PetscHMapICreate(&htWithAll));
12634bbf5ea8SMatthew G. Knepley   for (v = vStart; v < vEnd; ++v) {
12644bbf5ea8SMatthew G. Knepley     PetscInt localIndex               = 0;
1265c2e6f3c0SFlorian Wechsung     PetscInt localIndexWithArtificial = 0;
12660904074fSPatrick Farrell     PetscInt localIndexWithAll        = 0;
12674bbf5ea8SMatthew G. Knepley     PetscInt dof, off, i, j, k, l;
12684bbf5ea8SMatthew G. Knepley 
12699566063dSJacob Faibussowitsch     PetscCall(PetscHMapIClear(ht));
12709566063dSJacob Faibussowitsch     PetscCall(PetscHMapIClear(htWithArtificial));
12719566063dSJacob Faibussowitsch     PetscCall(PetscHMapIClear(htWithAll));
12729566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(cellCounts, v, &dof));
12739566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(cellCounts, v, &off));
12744bbf5ea8SMatthew G. Knepley     if (dof <= 0) continue;
12754bbf5ea8SMatthew G. Knepley 
1276557beb66SLawrence Mitchell     /* Calculate the global numbers of the artificial BC dofs here first */
12779566063dSJacob Faibussowitsch     PetscCall(patch->patchconstructop((void *)patch, dm, v, ownedpts));
12789566063dSJacob Faibussowitsch     PetscCall(PCPatchCompleteCellPatch(pc, ownedpts, seenpts));
12799566063dSJacob Faibussowitsch     PetscCall(PCPatchGetPointDofs(pc, ownedpts, owneddofs, v, &patch->subspaces_to_exclude));
12809566063dSJacob Faibussowitsch     PetscCall(PCPatchGetPointDofs(pc, seenpts, seendofs, v, NULL));
12819566063dSJacob Faibussowitsch     PetscCall(PCPatchComputeSetDifference_Private(owneddofs, seendofs, artificialbcs));
12828135ed82SLawrence Mitchell     if (patch->viewPatches) {
12831b68eb51SMatthew G. Knepley       PetscHSetI    globalbcdofs;
12841b68eb51SMatthew G. Knepley       PetscHashIter hi;
12858135ed82SLawrence Mitchell       MPI_Comm      comm = PetscObjectComm((PetscObject)pc);
12861b68eb51SMatthew G. Knepley 
12879566063dSJacob Faibussowitsch       PetscCall(PetscHSetICreate(&globalbcdofs));
128863a3b9bcSJacob Faibussowitsch       PetscCall(PetscSynchronizedPrintf(comm, "Patch %" PetscInt_FMT ": owned dofs:\n", v));
12891b68eb51SMatthew G. Knepley       PetscHashIterBegin(owneddofs, hi);
12901b68eb51SMatthew G. Knepley       while (!PetscHashIterAtEnd(owneddofs, hi)) {
12918135ed82SLawrence Mitchell         PetscInt globalDof;
12928135ed82SLawrence Mitchell 
12931b68eb51SMatthew G. Knepley         PetscHashIterGetKey(owneddofs, hi, globalDof);
12941b68eb51SMatthew G. Knepley         PetscHashIterNext(owneddofs, hi);
129563a3b9bcSJacob Faibussowitsch         PetscCall(PetscSynchronizedPrintf(comm, "%" PetscInt_FMT " ", globalDof));
12968135ed82SLawrence Mitchell       }
12979566063dSJacob Faibussowitsch       PetscCall(PetscSynchronizedPrintf(comm, "\n"));
129863a3b9bcSJacob Faibussowitsch       PetscCall(PetscSynchronizedPrintf(comm, "Patch %" PetscInt_FMT ": seen dofs:\n", v));
12991b68eb51SMatthew G. Knepley       PetscHashIterBegin(seendofs, hi);
13001b68eb51SMatthew G. Knepley       while (!PetscHashIterAtEnd(seendofs, hi)) {
13018135ed82SLawrence Mitchell         PetscInt  globalDof;
13028135ed82SLawrence Mitchell         PetscBool flg;
13038135ed82SLawrence Mitchell 
13041b68eb51SMatthew G. Knepley         PetscHashIterGetKey(seendofs, hi, globalDof);
13051b68eb51SMatthew G. Knepley         PetscHashIterNext(seendofs, hi);
130663a3b9bcSJacob Faibussowitsch         PetscCall(PetscSynchronizedPrintf(comm, "%" PetscInt_FMT " ", globalDof));
13078135ed82SLawrence Mitchell 
13089566063dSJacob Faibussowitsch         PetscCall(PetscHSetIHas(globalBcs, globalDof, &flg));
13099566063dSJacob Faibussowitsch         if (flg) PetscCall(PetscHSetIAdd(globalbcdofs, globalDof));
13108135ed82SLawrence Mitchell       }
13119566063dSJacob Faibussowitsch       PetscCall(PetscSynchronizedPrintf(comm, "\n"));
131263a3b9bcSJacob Faibussowitsch       PetscCall(PetscSynchronizedPrintf(comm, "Patch %" PetscInt_FMT ": global BCs:\n", v));
13139566063dSJacob Faibussowitsch       PetscCall(PetscHSetIGetSize(globalbcdofs, &numBcs));
13148135ed82SLawrence Mitchell       if (numBcs > 0) {
13151b68eb51SMatthew G. Knepley         PetscHashIterBegin(globalbcdofs, hi);
13161b68eb51SMatthew G. Knepley         while (!PetscHashIterAtEnd(globalbcdofs, hi)) {
13178135ed82SLawrence Mitchell           PetscInt globalDof;
13181b68eb51SMatthew G. Knepley           PetscHashIterGetKey(globalbcdofs, hi, globalDof);
13191b68eb51SMatthew G. Knepley           PetscHashIterNext(globalbcdofs, hi);
132063a3b9bcSJacob Faibussowitsch           PetscCall(PetscSynchronizedPrintf(comm, "%" PetscInt_FMT " ", globalDof));
13218135ed82SLawrence Mitchell         }
13228135ed82SLawrence Mitchell       }
13239566063dSJacob Faibussowitsch       PetscCall(PetscSynchronizedPrintf(comm, "\n"));
132463a3b9bcSJacob Faibussowitsch       PetscCall(PetscSynchronizedPrintf(comm, "Patch %" PetscInt_FMT ": artificial BCs:\n", v));
13259566063dSJacob Faibussowitsch       PetscCall(PetscHSetIGetSize(artificialbcs, &numBcs));
13268135ed82SLawrence Mitchell       if (numBcs > 0) {
13271b68eb51SMatthew G. Knepley         PetscHashIterBegin(artificialbcs, hi);
13281b68eb51SMatthew G. Knepley         while (!PetscHashIterAtEnd(artificialbcs, hi)) {
13298135ed82SLawrence Mitchell           PetscInt globalDof;
13301b68eb51SMatthew G. Knepley           PetscHashIterGetKey(artificialbcs, hi, globalDof);
13311b68eb51SMatthew G. Knepley           PetscHashIterNext(artificialbcs, hi);
133263a3b9bcSJacob Faibussowitsch           PetscCall(PetscSynchronizedPrintf(comm, "%" PetscInt_FMT " ", globalDof));
13338135ed82SLawrence Mitchell         }
13348135ed82SLawrence Mitchell       }
13359566063dSJacob Faibussowitsch       PetscCall(PetscSynchronizedPrintf(comm, "\n\n"));
13369566063dSJacob Faibussowitsch       PetscCall(PetscHSetIDestroy(&globalbcdofs));
13378135ed82SLawrence Mitchell     }
13384bbf5ea8SMatthew G. Knepley     for (k = 0; k < patch->nsubspaces; ++k) {
13394bbf5ea8SMatthew G. Knepley       const PetscInt *cellNodeMap    = patch->cellNodeMap[k];
13404bbf5ea8SMatthew G. Knepley       PetscInt        nodesPerCell   = patch->nodesPerCell[k];
13414bbf5ea8SMatthew G. Knepley       PetscInt        subspaceOffset = patch->subspaceOffsets[k];
13424bbf5ea8SMatthew G. Knepley       PetscInt        bs             = patch->bs[k];
13434bbf5ea8SMatthew G. Knepley 
13444bbf5ea8SMatthew G. Knepley       for (i = off; i < off + dof; ++i) {
13454bbf5ea8SMatthew G. Knepley         /* Walk over the cells in this patch. */
13464bbf5ea8SMatthew G. Knepley         const PetscInt c    = cellsArray[i];
13475f824522SMatthew G. Knepley         PetscInt       cell = c;
13484bbf5ea8SMatthew G. Knepley 
13495f824522SMatthew G. Knepley         /* TODO Change this to an IS */
13505f824522SMatthew G. Knepley         if (cellNumbering) {
13519566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(cellNumbering, c, &cell));
135263a3b9bcSJacob Faibussowitsch           PetscCheck(cell > 0, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " doesn't appear in cell numbering map", c);
13539566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetOffset(cellNumbering, c, &cell));
13545f824522SMatthew G. Knepley         }
13554bbf5ea8SMatthew G. Knepley         newCellsArray[i] = cell;
13564bbf5ea8SMatthew G. Knepley         for (j = 0; j < nodesPerCell; ++j) {
13574bbf5ea8SMatthew G. Knepley           /* For each global dof, map it into contiguous local storage. */
13584bbf5ea8SMatthew G. Knepley           const PetscInt globalDof = cellNodeMap[cell * nodesPerCell + j] * bs + subspaceOffset;
13594bbf5ea8SMatthew G. Knepley           /* finally, loop over block size */
13604bbf5ea8SMatthew G. Knepley           for (l = 0; l < bs; ++l) {
13611b68eb51SMatthew G. Knepley             PetscInt  localDof;
13621b68eb51SMatthew G. Knepley             PetscBool isGlobalBcDof, isArtificialBcDof;
13634bbf5ea8SMatthew G. Knepley 
1364557beb66SLawrence Mitchell             /* first, check if this is either a globally enforced or locally enforced BC dof */
13659566063dSJacob Faibussowitsch             PetscCall(PetscHSetIHas(globalBcs, globalDof + l, &isGlobalBcDof));
13669566063dSJacob Faibussowitsch             PetscCall(PetscHSetIHas(artificialbcs, globalDof + l, &isArtificialBcDof));
1367557beb66SLawrence Mitchell 
1368557beb66SLawrence Mitchell             /* if it's either, don't ever give it a local dof number */
13691b68eb51SMatthew G. Knepley             if (isGlobalBcDof || isArtificialBcDof) {
1370c2e6f3c0SFlorian Wechsung               dofsArray[globalIndex] = -1; /* don't use this in assembly in this patch */
1371557beb66SLawrence Mitchell             } else {
13729566063dSJacob Faibussowitsch               PetscCall(PetscHMapIGet(ht, globalDof + l, &localDof));
13734bbf5ea8SMatthew G. Knepley               if (localDof == -1) {
13744bbf5ea8SMatthew G. Knepley                 localDof = localIndex++;
13759566063dSJacob Faibussowitsch                 PetscCall(PetscHMapISet(ht, globalDof + l, localDof));
13764bbf5ea8SMatthew G. Knepley               }
137763a3b9bcSJacob Faibussowitsch               PetscCheck(globalIndex < numDofs, PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Found more dofs %" PetscInt_FMT " than expected %" PetscInt_FMT, globalIndex + 1, numDofs);
13784bbf5ea8SMatthew G. Knepley               /* And store. */
1379c2e6f3c0SFlorian Wechsung               dofsArray[globalIndex] = localDof;
13804bbf5ea8SMatthew G. Knepley             }
1381c2e6f3c0SFlorian Wechsung 
13820904074fSPatrick Farrell             if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
1383c2e6f3c0SFlorian Wechsung               if (isGlobalBcDof) {
1384e047a90bSFlorian Wechsung                 dofsArrayWithArtificial[globalIndex] = -1; /* don't use this in assembly in this patch */
1385c2e6f3c0SFlorian Wechsung               } else {
13869566063dSJacob Faibussowitsch                 PetscCall(PetscHMapIGet(htWithArtificial, globalDof + l, &localDof));
1387c2e6f3c0SFlorian Wechsung                 if (localDof == -1) {
1388c2e6f3c0SFlorian Wechsung                   localDof = localIndexWithArtificial++;
13899566063dSJacob Faibussowitsch                   PetscCall(PetscHMapISet(htWithArtificial, globalDof + l, localDof));
1390c2e6f3c0SFlorian Wechsung                 }
139163a3b9bcSJacob Faibussowitsch                 PetscCheck(globalIndex < numDofs, PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Found more dofs %" PetscInt_FMT " than expected %" PetscInt_FMT, globalIndex + 1, numDofs);
1392c2e6f3c0SFlorian Wechsung                 /* And store.*/
1393c2e6f3c0SFlorian Wechsung                 dofsArrayWithArtificial[globalIndex] = localDof;
1394c2e6f3c0SFlorian Wechsung               }
1395c2e6f3c0SFlorian Wechsung             }
13960904074fSPatrick Farrell 
13970904074fSPatrick Farrell             if (isNonlinear) {
13980904074fSPatrick Farrell               /* Build the dofmap for the function space with _all_ dofs,
13990904074fSPatrick Farrell    including those in any kind of boundary condition */
14009566063dSJacob Faibussowitsch               PetscCall(PetscHMapIGet(htWithAll, globalDof + l, &localDof));
14010904074fSPatrick Farrell               if (localDof == -1) {
14020904074fSPatrick Farrell                 localDof = localIndexWithAll++;
14039566063dSJacob Faibussowitsch                 PetscCall(PetscHMapISet(htWithAll, globalDof + l, localDof));
14040904074fSPatrick Farrell               }
140563a3b9bcSJacob Faibussowitsch               PetscCheck(globalIndex < numDofs, PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Found more dofs %" PetscInt_FMT " than expected %" PetscInt_FMT, globalIndex + 1, numDofs);
14060904074fSPatrick Farrell               /* And store.*/
14070904074fSPatrick Farrell               dofsArrayWithAll[globalIndex] = localDof;
14080904074fSPatrick Farrell             }
1409c2e6f3c0SFlorian Wechsung             globalIndex++;
14104bbf5ea8SMatthew G. Knepley           }
14114bbf5ea8SMatthew G. Knepley         }
14124bbf5ea8SMatthew G. Knepley       }
1413557beb66SLawrence Mitchell     }
14144bbf5ea8SMatthew G. Knepley     /*How many local dofs in this patch? */
14150904074fSPatrick Farrell     if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
14169566063dSJacob Faibussowitsch       PetscCall(PetscHMapIGetSize(htWithArtificial, &dof));
14179566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(gtolCountsWithArtificial, v, dof));
1418c2e6f3c0SFlorian Wechsung     }
14190904074fSPatrick Farrell     if (isNonlinear) {
14209566063dSJacob Faibussowitsch       PetscCall(PetscHMapIGetSize(htWithAll, &dof));
14219566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(gtolCountsWithAll, v, dof));
14220904074fSPatrick Farrell     }
14239566063dSJacob Faibussowitsch     PetscCall(PetscHMapIGetSize(ht, &dof));
14249566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(gtolCounts, v, dof));
14254bbf5ea8SMatthew G. Knepley   }
1426b6bb21d1SLawrence Mitchell 
14279566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dm));
142863a3b9bcSJacob Faibussowitsch   PetscCheck(globalIndex == numDofs, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Expected number of dofs (%" PetscInt_FMT ") doesn't match found number (%" PetscInt_FMT ")", numDofs, globalIndex);
14299566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(gtolCounts));
14309566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(gtolCounts, &numGlobalDofs));
14319566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numGlobalDofs, &globalDofsArray));
14324bbf5ea8SMatthew G. Knepley 
14330904074fSPatrick Farrell   if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
14349566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(gtolCountsWithArtificial));
14359566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(gtolCountsWithArtificial, &numGlobalDofsWithArtificial));
14369566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numGlobalDofsWithArtificial, &globalDofsArrayWithArtificial));
1437c2e6f3c0SFlorian Wechsung   }
14380904074fSPatrick Farrell   if (isNonlinear) {
14399566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(gtolCountsWithAll));
14409566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetStorageSize(gtolCountsWithAll, &numGlobalDofsWithAll));
14419566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numGlobalDofsWithAll, &globalDofsArrayWithAll));
14420904074fSPatrick Farrell   }
14434bbf5ea8SMatthew G. Knepley   /* Now populate the global to local map.  This could be merged into the above loop if we were willing to deal with reallocs. */
14444bbf5ea8SMatthew G. Knepley   for (v = vStart; v < vEnd; ++v) {
14451b68eb51SMatthew G. Knepley     PetscHashIter hi;
14465f824522SMatthew G. Knepley     PetscInt      dof, off, Np, ooff, i, j, k, l;
14474bbf5ea8SMatthew G. Knepley 
14489566063dSJacob Faibussowitsch     PetscCall(PetscHMapIClear(ht));
14499566063dSJacob Faibussowitsch     PetscCall(PetscHMapIClear(htWithArtificial));
14509566063dSJacob Faibussowitsch     PetscCall(PetscHMapIClear(htWithAll));
14519566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(cellCounts, v, &dof));
14529566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(cellCounts, v, &off));
14539566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(pointCounts, v, &Np));
14549566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(pointCounts, v, &ooff));
14554bbf5ea8SMatthew G. Knepley     if (dof <= 0) continue;
14564bbf5ea8SMatthew G. Knepley 
14574bbf5ea8SMatthew G. Knepley     for (k = 0; k < patch->nsubspaces; ++k) {
14584bbf5ea8SMatthew G. Knepley       const PetscInt *cellNodeMap    = patch->cellNodeMap[k];
14594bbf5ea8SMatthew G. Knepley       PetscInt        nodesPerCell   = patch->nodesPerCell[k];
14604bbf5ea8SMatthew G. Knepley       PetscInt        subspaceOffset = patch->subspaceOffsets[k];
14614bbf5ea8SMatthew G. Knepley       PetscInt        bs             = patch->bs[k];
1462d490bb3dSLawrence Mitchell       PetscInt        goff;
14634bbf5ea8SMatthew G. Knepley 
14644bbf5ea8SMatthew G. Knepley       for (i = off; i < off + dof; ++i) {
14654bbf5ea8SMatthew G. Knepley         /* Reconstruct mapping of global-to-local on this patch. */
14664bbf5ea8SMatthew G. Knepley         const PetscInt c    = cellsArray[i];
14675f824522SMatthew G. Knepley         PetscInt       cell = c;
14684bbf5ea8SMatthew G. Knepley 
14699566063dSJacob Faibussowitsch         if (cellNumbering) PetscCall(PetscSectionGetOffset(cellNumbering, c, &cell));
14704bbf5ea8SMatthew G. Knepley         for (j = 0; j < nodesPerCell; ++j) {
14714bbf5ea8SMatthew G. Knepley           for (l = 0; l < bs; ++l) {
14725f824522SMatthew G. Knepley             const PetscInt globalDof = cellNodeMap[cell * nodesPerCell + j] * bs + l + subspaceOffset;
1473c2e6f3c0SFlorian Wechsung             const PetscInt localDof  = dofsArray[key];
14749566063dSJacob Faibussowitsch             if (localDof >= 0) PetscCall(PetscHMapISet(ht, globalDof, localDof));
14750904074fSPatrick Farrell             if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
1476c2e6f3c0SFlorian Wechsung               const PetscInt localDofWithArtificial = dofsArrayWithArtificial[key];
147748a46eb9SPierre Jolivet               if (localDofWithArtificial >= 0) PetscCall(PetscHMapISet(htWithArtificial, globalDof, localDofWithArtificial));
1478c2e6f3c0SFlorian Wechsung             }
14790904074fSPatrick Farrell             if (isNonlinear) {
14800904074fSPatrick Farrell               const PetscInt localDofWithAll = dofsArrayWithAll[key];
148148a46eb9SPierre Jolivet               if (localDofWithAll >= 0) PetscCall(PetscHMapISet(htWithAll, globalDof, localDofWithAll));
14820904074fSPatrick Farrell             }
1483c2e6f3c0SFlorian Wechsung             key++;
14844bbf5ea8SMatthew G. Knepley           }
14854bbf5ea8SMatthew G. Knepley         }
14864bbf5ea8SMatthew G. Knepley       }
1487557beb66SLawrence Mitchell 
14884bbf5ea8SMatthew G. Knepley       /* Shove it in the output data structure. */
14899566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(gtolCounts, v, &goff));
14901b68eb51SMatthew G. Knepley       PetscHashIterBegin(ht, hi);
14911b68eb51SMatthew G. Knepley       while (!PetscHashIterAtEnd(ht, hi)) {
14924bbf5ea8SMatthew G. Knepley         PetscInt globalDof, localDof;
14934bbf5ea8SMatthew G. Knepley 
14941b68eb51SMatthew G. Knepley         PetscHashIterGetKey(ht, hi, globalDof);
14951b68eb51SMatthew G. Knepley         PetscHashIterGetVal(ht, hi, localDof);
14964bbf5ea8SMatthew G. Knepley         if (globalDof >= 0) globalDofsArray[goff + localDof] = globalDof;
14971b68eb51SMatthew G. Knepley         PetscHashIterNext(ht, hi);
14984bbf5ea8SMatthew G. Knepley       }
14995f824522SMatthew G. Knepley 
15000904074fSPatrick Farrell       if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
15019566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(gtolCountsWithArtificial, v, &goff));
1502c2e6f3c0SFlorian Wechsung         PetscHashIterBegin(htWithArtificial, hi);
1503c2e6f3c0SFlorian Wechsung         while (!PetscHashIterAtEnd(htWithArtificial, hi)) {
1504c2e6f3c0SFlorian Wechsung           PetscInt globalDof, localDof;
1505c2e6f3c0SFlorian Wechsung           PetscHashIterGetKey(htWithArtificial, hi, globalDof);
1506c2e6f3c0SFlorian Wechsung           PetscHashIterGetVal(htWithArtificial, hi, localDof);
1507c2e6f3c0SFlorian Wechsung           if (globalDof >= 0) globalDofsArrayWithArtificial[goff + localDof] = globalDof;
1508c2e6f3c0SFlorian Wechsung           PetscHashIterNext(htWithArtificial, hi);
1509c2e6f3c0SFlorian Wechsung         }
1510c2e6f3c0SFlorian Wechsung       }
15110904074fSPatrick Farrell       if (isNonlinear) {
15129566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(gtolCountsWithAll, v, &goff));
15130904074fSPatrick Farrell         PetscHashIterBegin(htWithAll, hi);
15140904074fSPatrick Farrell         while (!PetscHashIterAtEnd(htWithAll, hi)) {
15150904074fSPatrick Farrell           PetscInt globalDof, localDof;
15160904074fSPatrick Farrell           PetscHashIterGetKey(htWithAll, hi, globalDof);
15170904074fSPatrick Farrell           PetscHashIterGetVal(htWithAll, hi, localDof);
15180904074fSPatrick Farrell           if (globalDof >= 0) globalDofsArrayWithAll[goff + localDof] = globalDof;
15190904074fSPatrick Farrell           PetscHashIterNext(htWithAll, hi);
15200904074fSPatrick Farrell         }
15210904074fSPatrick Farrell       }
1522c2e6f3c0SFlorian Wechsung 
15235f824522SMatthew G. Knepley       for (p = 0; p < Np; ++p) {
15245f824522SMatthew G. Knepley         const PetscInt point = pointsArray[ooff + p];
15255f824522SMatthew G. Knepley         PetscInt       globalDof, localDof;
15265f824522SMatthew G. Knepley 
15279566063dSJacob Faibussowitsch         PetscCall(PCPatchGetGlobalDofs(pc, patch->dofSection, k, patch->combined, point, NULL, &globalDof));
15289566063dSJacob Faibussowitsch         PetscCall(PetscHMapIGet(ht, globalDof, &localDof));
15295f824522SMatthew G. Knepley         offsArray[(ooff + p) * Nf + k] = localDof;
15300904074fSPatrick Farrell         if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
15319566063dSJacob Faibussowitsch           PetscCall(PetscHMapIGet(htWithArtificial, globalDof, &localDof));
1532c2e6f3c0SFlorian Wechsung           offsArrayWithArtificial[(ooff + p) * Nf + k] = localDof;
1533c2e6f3c0SFlorian Wechsung         }
15340904074fSPatrick Farrell         if (isNonlinear) {
15359566063dSJacob Faibussowitsch           PetscCall(PetscHMapIGet(htWithAll, globalDof, &localDof));
15360904074fSPatrick Farrell           offsArrayWithAll[(ooff + p) * Nf + k] = localDof;
15370904074fSPatrick Farrell         }
15385f824522SMatthew G. Knepley       }
15394bbf5ea8SMatthew G. Knepley     }
15404bbf5ea8SMatthew G. Knepley 
15419566063dSJacob Faibussowitsch     PetscCall(PetscHSetIDestroy(&globalBcs));
15429566063dSJacob Faibussowitsch     PetscCall(PetscHSetIDestroy(&ownedpts));
15439566063dSJacob Faibussowitsch     PetscCall(PetscHSetIDestroy(&seenpts));
15449566063dSJacob Faibussowitsch     PetscCall(PetscHSetIDestroy(&owneddofs));
15459566063dSJacob Faibussowitsch     PetscCall(PetscHSetIDestroy(&seendofs));
15469566063dSJacob Faibussowitsch     PetscCall(PetscHSetIDestroy(&artificialbcs));
1547557beb66SLawrence Mitchell 
15484bbf5ea8SMatthew G. Knepley     /* At this point, we have a hash table ht built that maps globalDof -> localDof.
15494bbf5ea8SMatthew G. Knepley    We need to create the dof table laid out cellwise first, then by subspace,
15504bbf5ea8SMatthew G. Knepley    as the assembler assembles cell-wise and we need to stuff the different
15514bbf5ea8SMatthew G. Knepley    contributions of the different function spaces to the right places. So we loop
15524bbf5ea8SMatthew G. Knepley    over cells, then over subspaces. */
15534bbf5ea8SMatthew G. Knepley     if (patch->nsubspaces > 1) { /* for nsubspaces = 1, data we need is already in dofsArray */
15544bbf5ea8SMatthew G. Knepley       for (i = off; i < off + dof; ++i) {
15554bbf5ea8SMatthew G. Knepley         const PetscInt c    = cellsArray[i];
15565f824522SMatthew G. Knepley         PetscInt       cell = c;
15574bbf5ea8SMatthew G. Knepley 
15589566063dSJacob Faibussowitsch         if (cellNumbering) PetscCall(PetscSectionGetOffset(cellNumbering, c, &cell));
15594bbf5ea8SMatthew G. Knepley         for (k = 0; k < patch->nsubspaces; ++k) {
15604bbf5ea8SMatthew G. Knepley           const PetscInt *cellNodeMap    = patch->cellNodeMap[k];
15614bbf5ea8SMatthew G. Knepley           PetscInt        nodesPerCell   = patch->nodesPerCell[k];
15624bbf5ea8SMatthew G. Knepley           PetscInt        subspaceOffset = patch->subspaceOffsets[k];
15634bbf5ea8SMatthew G. Knepley           PetscInt        bs             = patch->bs[k];
15644bbf5ea8SMatthew G. Knepley 
15654bbf5ea8SMatthew G. Knepley           for (j = 0; j < nodesPerCell; ++j) {
15664bbf5ea8SMatthew G. Knepley             for (l = 0; l < bs; ++l) {
15675f824522SMatthew G. Knepley               const PetscInt globalDof = cellNodeMap[cell * nodesPerCell + j] * bs + l + subspaceOffset;
15684bbf5ea8SMatthew G. Knepley               PetscInt       localDof;
15694bbf5ea8SMatthew G. Knepley 
15709566063dSJacob Faibussowitsch               PetscCall(PetscHMapIGet(ht, globalDof, &localDof));
1571557beb66SLawrence Mitchell               /* If it's not in the hash table, i.e. is a BC dof,
15721b68eb51SMatthew G. Knepley    then the PetscHSetIMap above gives -1, which matches
1573557beb66SLawrence Mitchell    exactly the convention for PETSc's matrix assembly to
1574557beb66SLawrence Mitchell    ignore the dof. So we don't need to do anything here */
1575c2e6f3c0SFlorian Wechsung               asmArray[asmKey] = localDof;
15760904074fSPatrick Farrell               if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
15779566063dSJacob Faibussowitsch                 PetscCall(PetscHMapIGet(htWithArtificial, globalDof, &localDof));
1578c2e6f3c0SFlorian Wechsung                 asmArrayWithArtificial[asmKey] = localDof;
1579c2e6f3c0SFlorian Wechsung               }
15800904074fSPatrick Farrell               if (isNonlinear) {
15819566063dSJacob Faibussowitsch                 PetscCall(PetscHMapIGet(htWithAll, globalDof, &localDof));
15820904074fSPatrick Farrell                 asmArrayWithAll[asmKey] = localDof;
15830904074fSPatrick Farrell               }
1584c2e6f3c0SFlorian Wechsung               asmKey++;
15854bbf5ea8SMatthew G. Knepley             }
15864bbf5ea8SMatthew G. Knepley           }
15874bbf5ea8SMatthew G. Knepley         }
15884bbf5ea8SMatthew G. Knepley       }
15894bbf5ea8SMatthew G. Knepley     }
15904bbf5ea8SMatthew G. Knepley   }
1591c2e6f3c0SFlorian Wechsung   if (1 == patch->nsubspaces) {
15929566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(asmArray, dofsArray, numDofs));
159348a46eb9SPierre Jolivet     if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) PetscCall(PetscArraycpy(asmArrayWithArtificial, dofsArrayWithArtificial, numDofs));
15941baa6e33SBarry Smith     if (isNonlinear) PetscCall(PetscArraycpy(asmArrayWithAll, dofsArrayWithAll, numDofs));
1595c2e6f3c0SFlorian Wechsung   }
15964bbf5ea8SMatthew G. Knepley 
15979566063dSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&ht));
15989566063dSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&htWithArtificial));
15999566063dSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&htWithAll));
16009566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(cells, &cellsArray));
16019566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(points, &pointsArray));
16029566063dSJacob Faibussowitsch   PetscCall(PetscFree(dofsArray));
160348a46eb9SPierre Jolivet   if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) PetscCall(PetscFree(dofsArrayWithArtificial));
16041baa6e33SBarry Smith   if (isNonlinear) PetscCall(PetscFree(dofsArrayWithAll));
16055f824522SMatthew G. Knepley   /* Create placeholder section for map from points to patch dofs */
16069566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &patch->patchSection));
16079566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetNumFields(patch->patchSection, patch->nsubspaces));
16081e5fa6bbSLawrence Mitchell   if (patch->combined) {
16091e5fa6bbSLawrence Mitchell     PetscInt numFields;
16109566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetNumFields(patch->dofSection[0], &numFields));
161163a3b9bcSJacob Faibussowitsch     PetscCheck(numFields == patch->nsubspaces, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "Mismatch between number of section fields %" PetscInt_FMT " and number of subspaces %" PetscInt_FMT, numFields, patch->nsubspaces);
16129566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(patch->dofSection[0], &pStart, &pEnd));
16139566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(patch->patchSection, pStart, pEnd));
16145f824522SMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
16155f824522SMatthew G. Knepley       PetscInt dof, fdof, f;
16165f824522SMatthew G. Knepley 
16179566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(patch->dofSection[0], p, &dof));
16189566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(patch->patchSection, p, dof));
16195f824522SMatthew G. Knepley       for (f = 0; f < patch->nsubspaces; ++f) {
16209566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldDof(patch->dofSection[0], p, f, &fdof));
16219566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetFieldDof(patch->patchSection, p, f, fdof));
16225f824522SMatthew G. Knepley       }
16231e5fa6bbSLawrence Mitchell     }
16241e5fa6bbSLawrence Mitchell   } else {
16251e5fa6bbSLawrence Mitchell     PetscInt pStartf, pEndf, f;
16261e5fa6bbSLawrence Mitchell     pStart = PETSC_MAX_INT;
16271e5fa6bbSLawrence Mitchell     pEnd   = PETSC_MIN_INT;
16281e5fa6bbSLawrence Mitchell     for (f = 0; f < patch->nsubspaces; ++f) {
16299566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetChart(patch->dofSection[f], &pStartf, &pEndf));
16301e5fa6bbSLawrence Mitchell       pStart = PetscMin(pStart, pStartf);
16311e5fa6bbSLawrence Mitchell       pEnd   = PetscMax(pEnd, pEndf);
16321e5fa6bbSLawrence Mitchell     }
16339566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(patch->patchSection, pStart, pEnd));
16341e5fa6bbSLawrence Mitchell     for (f = 0; f < patch->nsubspaces; ++f) {
16359566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetChart(patch->dofSection[f], &pStartf, &pEndf));
16361e5fa6bbSLawrence Mitchell       for (p = pStartf; p < pEndf; ++p) {
16371e5fa6bbSLawrence Mitchell         PetscInt fdof;
16389566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(patch->dofSection[f], p, &fdof));
16399566063dSJacob Faibussowitsch         PetscCall(PetscSectionAddDof(patch->patchSection, p, fdof));
16409566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetFieldDof(patch->patchSection, p, f, fdof));
1641bdd9e0cdSPatrick Farrell       }
1642bdd9e0cdSPatrick Farrell     }
16435f824522SMatthew G. Knepley   }
16449566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(patch->patchSection));
16459566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUseFieldOffsets(patch->patchSection, PETSC_TRUE));
16464bbf5ea8SMatthew G. Knepley   /* Replace cell indices with firedrake-numbered ones. */
16479566063dSJacob Faibussowitsch   PetscCall(ISGeneralSetIndices(cells, numCells, (const PetscInt *)newCellsArray, PETSC_OWN_POINTER));
16489566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numGlobalDofs, globalDofsArray, PETSC_OWN_POINTER, &patch->gtol));
16499566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)patch->gtol, "Global Indices"));
16509566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_g2l_view", patch->classname));
16519566063dSJacob Faibussowitsch   PetscCall(PetscSectionViewFromOptions(patch->gtolCounts, (PetscObject)pc, option));
16529566063dSJacob Faibussowitsch   PetscCall(ISViewFromOptions(patch->gtol, (PetscObject)pc, option));
16539566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numDofs, asmArray, PETSC_OWN_POINTER, &patch->dofs));
16549566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numPoints * Nf, offsArray, PETSC_OWN_POINTER, &patch->offs));
16550904074fSPatrick Farrell   if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
16569566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numGlobalDofsWithArtificial, globalDofsArrayWithArtificial, PETSC_OWN_POINTER, &patch->gtolWithArtificial));
16579566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numDofs, asmArrayWithArtificial, PETSC_OWN_POINTER, &patch->dofsWithArtificial));
16589566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numPoints * Nf, offsArrayWithArtificial, PETSC_OWN_POINTER, &patch->offsWithArtificial));
1659c2e6f3c0SFlorian Wechsung   }
16600904074fSPatrick Farrell   if (isNonlinear) {
16619566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numGlobalDofsWithAll, globalDofsArrayWithAll, PETSC_OWN_POINTER, &patch->gtolWithAll));
16629566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numDofs, asmArrayWithAll, PETSC_OWN_POINTER, &patch->dofsWithAll));
16639566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numPoints * Nf, offsArrayWithAll, PETSC_OWN_POINTER, &patch->offsWithAll));
16640904074fSPatrick Farrell   }
16654bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
16664bbf5ea8SMatthew G. Knepley }
16674bbf5ea8SMatthew G. Knepley 
16689371c9d4SSatish Balay static PetscErrorCode PCPatchCreateMatrix_Private(PC pc, PetscInt point, Mat *mat, PetscBool withArtificial) {
16694bbf5ea8SMatthew G. Knepley   PC_PATCH   *patch = (PC_PATCH *)pc->data;
16704bbf5ea8SMatthew G. Knepley   PetscBool   flg;
16714bbf5ea8SMatthew G. Knepley   PetscInt    csize, rsize;
16724bbf5ea8SMatthew G. Knepley   const char *prefix = NULL;
16734bbf5ea8SMatthew G. Knepley 
16744bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
1675c2e6f3c0SFlorian Wechsung   if (withArtificial) {
1676e047a90bSFlorian Wechsung     /* would be nice if we could create a rectangular matrix of size numDofsWithArtificial x numDofs here */
16779d4fc724SLawrence Mitchell     PetscInt pStart;
16789566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(patch->gtolCountsWithArtificial, &pStart, NULL));
16799566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(patch->gtolCountsWithArtificial, point + pStart, &rsize));
16809d4fc724SLawrence Mitchell     csize = rsize;
1681ff201f6aSFlorian Wechsung   } else {
16829d4fc724SLawrence Mitchell     PetscInt pStart;
16839566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(patch->gtolCounts, &pStart, NULL));
16849566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(patch->gtolCounts, point + pStart, &rsize));
16859d4fc724SLawrence Mitchell     csize = rsize;
1686c2e6f3c0SFlorian Wechsung   }
1687c2e6f3c0SFlorian Wechsung 
16889566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_SELF, mat));
16899566063dSJacob Faibussowitsch   PetscCall(PCGetOptionsPrefix(pc, &prefix));
16909566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(*mat, prefix));
16919566063dSJacob Faibussowitsch   PetscCall(MatAppendOptionsPrefix(*mat, "pc_patch_sub_"));
16929566063dSJacob Faibussowitsch   if (patch->sub_mat_type) PetscCall(MatSetType(*mat, patch->sub_mat_type));
16939566063dSJacob Faibussowitsch   else if (!patch->sub_mat_type) PetscCall(MatSetType(*mat, MATDENSE));
16949566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*mat, rsize, csize, rsize, csize));
16959566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)*mat, MATDENSE, &flg));
16969566063dSJacob Faibussowitsch   if (!flg) PetscCall(PetscObjectTypeCompare((PetscObject)*mat, MATSEQDENSE, &flg));
16974bbf5ea8SMatthew G. Knepley   /* Sparse patch matrices */
16984bbf5ea8SMatthew G. Knepley   if (!flg) {
16994bbf5ea8SMatthew G. Knepley     PetscBT         bt;
17004bbf5ea8SMatthew G. Knepley     PetscInt       *dnnz      = NULL;
17014bbf5ea8SMatthew G. Knepley     const PetscInt *dofsArray = NULL;
17024bbf5ea8SMatthew G. Knepley     PetscInt        pStart, pEnd, ncell, offset, c, i, j;
17034bbf5ea8SMatthew G. Knepley 
1704c2e6f3c0SFlorian Wechsung     if (withArtificial) {
17059566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(patch->dofsWithArtificial, &dofsArray));
1706ff201f6aSFlorian Wechsung     } else {
17079566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(patch->dofs, &dofsArray));
1708c2e6f3c0SFlorian Wechsung     }
17099566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(patch->cellCounts, &pStart, &pEnd));
17104bbf5ea8SMatthew G. Knepley     point += pStart;
171163a3b9bcSJacob Faibussowitsch     PetscCheck(point < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Operator point %" PetscInt_FMT " not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, pStart, pEnd);
17129566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(patch->cellCounts, point, &ncell));
17139566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(patch->cellCounts, point, &offset));
17149566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(PC_Patch_Prealloc, pc, 0, 0, 0));
1715b2866507SPatrick Farrell     /* A PetscBT uses N^2 bits to store the sparsity pattern on a
17164bbf5ea8SMatthew G. Knepley    * patch. This is probably OK if the patches are not too big,
1717b2866507SPatrick Farrell    * but uses too much memory. We therefore switch based on rsize. */
1718b2866507SPatrick Farrell     if (rsize < 3000) { /* FIXME: I picked this switch value out of my hat */
1719d63cebbaSPatrick Farrell       PetscScalar *zeroes;
1720d63cebbaSPatrick Farrell       PetscInt     rows;
1721d63cebbaSPatrick Farrell 
17229566063dSJacob Faibussowitsch       PetscCall(PetscCalloc1(rsize, &dnnz));
17239566063dSJacob Faibussowitsch       PetscCall(PetscBTCreate(rsize * rsize, &bt));
17244bbf5ea8SMatthew G. Knepley       for (c = 0; c < ncell; ++c) {
17254bbf5ea8SMatthew G. Knepley         const PetscInt *idx = dofsArray + (offset + c) * patch->totalDofsPerCell;
17264bbf5ea8SMatthew G. Knepley         for (i = 0; i < patch->totalDofsPerCell; ++i) {
17274bbf5ea8SMatthew G. Knepley           const PetscInt row = idx[i];
1728557beb66SLawrence Mitchell           if (row < 0) continue;
17294bbf5ea8SMatthew G. Knepley           for (j = 0; j < patch->totalDofsPerCell; ++j) {
17304bbf5ea8SMatthew G. Knepley             const PetscInt col = idx[j];
17314bbf5ea8SMatthew G. Knepley             const PetscInt key = row * rsize + col;
1732557beb66SLawrence Mitchell             if (col < 0) continue;
17334bbf5ea8SMatthew G. Knepley             if (!PetscBTLookupSet(bt, key)) ++dnnz[row];
17344bbf5ea8SMatthew G. Knepley           }
17354bbf5ea8SMatthew G. Knepley         }
17364bbf5ea8SMatthew G. Knepley       }
1737d63cebbaSPatrick Farrell 
1738d63cebbaSPatrick Farrell       if (patch->usercomputeopintfacet) {
1739d63cebbaSPatrick Farrell         const PetscInt *intFacetsArray = NULL;
1740d63cebbaSPatrick Farrell         PetscInt        i, numIntFacets, intFacetOffset;
1741d63cebbaSPatrick Farrell         const PetscInt *facetCells = NULL;
1742d63cebbaSPatrick Farrell 
17439566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(patch->intFacetCounts, point, &numIntFacets));
17449566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(patch->intFacetCounts, point, &intFacetOffset));
17459566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(patch->intFacetsToPatchCell, &facetCells));
17469566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(patch->intFacets, &intFacetsArray));
1747d63cebbaSPatrick Farrell         for (i = 0; i < numIntFacets; i++) {
1748d63cebbaSPatrick Farrell           const PetscInt cell0 = facetCells[2 * (intFacetOffset + i) + 0];
1749d63cebbaSPatrick Farrell           const PetscInt cell1 = facetCells[2 * (intFacetOffset + i) + 1];
1750d63cebbaSPatrick Farrell           PetscInt       celli, cellj;
1751d63cebbaSPatrick Farrell 
1752d63cebbaSPatrick Farrell           for (celli = 0; celli < patch->totalDofsPerCell; celli++) {
1753d63cebbaSPatrick Farrell             const PetscInt row = dofsArray[(offset + cell0) * patch->totalDofsPerCell + celli];
1754b5c64f08SPatrick Farrell             if (row < 0) continue;
1755d63cebbaSPatrick Farrell             for (cellj = 0; cellj < patch->totalDofsPerCell; cellj++) {
1756d63cebbaSPatrick Farrell               const PetscInt col = dofsArray[(offset + cell1) * patch->totalDofsPerCell + cellj];
1757d63cebbaSPatrick Farrell               const PetscInt key = row * rsize + col;
1758d63cebbaSPatrick Farrell               if (col < 0) continue;
1759d63cebbaSPatrick Farrell               if (!PetscBTLookupSet(bt, key)) ++dnnz[row];
1760d63cebbaSPatrick Farrell             }
1761d63cebbaSPatrick Farrell           }
1762d63cebbaSPatrick Farrell 
1763d63cebbaSPatrick Farrell           for (celli = 0; celli < patch->totalDofsPerCell; celli++) {
1764d63cebbaSPatrick Farrell             const PetscInt row = dofsArray[(offset + cell1) * patch->totalDofsPerCell + celli];
1765b5c64f08SPatrick Farrell             if (row < 0) continue;
1766d63cebbaSPatrick Farrell             for (cellj = 0; cellj < patch->totalDofsPerCell; cellj++) {
1767d63cebbaSPatrick Farrell               const PetscInt col = dofsArray[(offset + cell0) * patch->totalDofsPerCell + cellj];
1768d63cebbaSPatrick Farrell               const PetscInt key = row * rsize + col;
1769d63cebbaSPatrick Farrell               if (col < 0) continue;
1770d63cebbaSPatrick Farrell               if (!PetscBTLookupSet(bt, key)) ++dnnz[row];
1771d63cebbaSPatrick Farrell             }
1772d63cebbaSPatrick Farrell           }
1773d63cebbaSPatrick Farrell         }
1774d63cebbaSPatrick Farrell       }
17759566063dSJacob Faibussowitsch       PetscCall(PetscBTDestroy(&bt));
17769566063dSJacob Faibussowitsch       PetscCall(MatXAIJSetPreallocation(*mat, 1, dnnz, NULL, NULL, NULL));
17779566063dSJacob Faibussowitsch       PetscCall(PetscFree(dnnz));
1778d63cebbaSPatrick Farrell 
17799566063dSJacob Faibussowitsch       PetscCall(PetscCalloc1(patch->totalDofsPerCell * patch->totalDofsPerCell, &zeroes));
1780d63cebbaSPatrick Farrell       for (c = 0; c < ncell; ++c) {
1781d63cebbaSPatrick Farrell         const PetscInt *idx = &dofsArray[(offset + c) * patch->totalDofsPerCell];
17829566063dSJacob Faibussowitsch         PetscCall(MatSetValues(*mat, patch->totalDofsPerCell, idx, patch->totalDofsPerCell, idx, zeroes, INSERT_VALUES));
1783d63cebbaSPatrick Farrell       }
17849566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(*mat, &rows, NULL));
178548a46eb9SPierre Jolivet       for (i = 0; i < rows; ++i) PetscCall(MatSetValues(*mat, 1, &i, 1, &i, zeroes, INSERT_VALUES));
1786d63cebbaSPatrick Farrell 
1787d63cebbaSPatrick Farrell       if (patch->usercomputeopintfacet) {
1788d63cebbaSPatrick Farrell         const PetscInt *intFacetsArray = NULL;
1789d63cebbaSPatrick Farrell         PetscInt        i, numIntFacets, intFacetOffset;
1790d63cebbaSPatrick Farrell         const PetscInt *facetCells = NULL;
1791d63cebbaSPatrick Farrell 
17929566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(patch->intFacetCounts, point, &numIntFacets));
17939566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(patch->intFacetCounts, point, &intFacetOffset));
17949566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(patch->intFacetsToPatchCell, &facetCells));
17959566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(patch->intFacets, &intFacetsArray));
1796d63cebbaSPatrick Farrell         for (i = 0; i < numIntFacets; i++) {
1797d63cebbaSPatrick Farrell           const PetscInt  cell0    = facetCells[2 * (intFacetOffset + i) + 0];
1798d63cebbaSPatrick Farrell           const PetscInt  cell1    = facetCells[2 * (intFacetOffset + i) + 1];
1799d63cebbaSPatrick Farrell           const PetscInt *cell0idx = &dofsArray[(offset + cell0) * patch->totalDofsPerCell];
1800d63cebbaSPatrick Farrell           const PetscInt *cell1idx = &dofsArray[(offset + cell1) * patch->totalDofsPerCell];
18019566063dSJacob Faibussowitsch           PetscCall(MatSetValues(*mat, patch->totalDofsPerCell, cell0idx, patch->totalDofsPerCell, cell1idx, zeroes, INSERT_VALUES));
18029566063dSJacob Faibussowitsch           PetscCall(MatSetValues(*mat, patch->totalDofsPerCell, cell1idx, patch->totalDofsPerCell, cell0idx, zeroes, INSERT_VALUES));
1803d63cebbaSPatrick Farrell         }
1804d63cebbaSPatrick Farrell       }
1805d63cebbaSPatrick Farrell 
18069566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY));
18079566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY));
1808d63cebbaSPatrick Farrell 
18099566063dSJacob Faibussowitsch       PetscCall(PetscFree(zeroes));
1810d63cebbaSPatrick Farrell 
1811b2866507SPatrick Farrell     } else { /* rsize too big, use MATPREALLOCATOR */
1812b2866507SPatrick Farrell       Mat          preallocator;
1813b2866507SPatrick Farrell       PetscScalar *vals;
1814b2866507SPatrick Farrell 
18159566063dSJacob Faibussowitsch       PetscCall(PetscCalloc1(patch->totalDofsPerCell * patch->totalDofsPerCell, &vals));
18169566063dSJacob Faibussowitsch       PetscCall(MatCreate(PETSC_COMM_SELF, &preallocator));
18179566063dSJacob Faibussowitsch       PetscCall(MatSetType(preallocator, MATPREALLOCATOR));
18189566063dSJacob Faibussowitsch       PetscCall(MatSetSizes(preallocator, rsize, rsize, rsize, rsize));
18199566063dSJacob Faibussowitsch       PetscCall(MatSetUp(preallocator));
182011bcd083SPatrick Farrell 
1821b2866507SPatrick Farrell       for (c = 0; c < ncell; ++c) {
1822b2866507SPatrick Farrell         const PetscInt *idx = dofsArray + (offset + c) * patch->totalDofsPerCell;
18239566063dSJacob Faibussowitsch         PetscCall(MatSetValues(preallocator, patch->totalDofsPerCell, idx, patch->totalDofsPerCell, idx, vals, INSERT_VALUES));
1824b2866507SPatrick Farrell       }
182511bcd083SPatrick Farrell 
182611bcd083SPatrick Farrell       if (patch->usercomputeopintfacet) {
182711bcd083SPatrick Farrell         const PetscInt *intFacetsArray = NULL;
182811bcd083SPatrick Farrell         PetscInt        i, numIntFacets, intFacetOffset;
182911bcd083SPatrick Farrell         const PetscInt *facetCells = NULL;
183011bcd083SPatrick Farrell 
18319566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(patch->intFacetCounts, point, &numIntFacets));
18329566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(patch->intFacetCounts, point, &intFacetOffset));
18339566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(patch->intFacetsToPatchCell, &facetCells));
18349566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(patch->intFacets, &intFacetsArray));
183511bcd083SPatrick Farrell         for (i = 0; i < numIntFacets; i++) {
183611bcd083SPatrick Farrell           const PetscInt  cell0    = facetCells[2 * (intFacetOffset + i) + 0];
183711bcd083SPatrick Farrell           const PetscInt  cell1    = facetCells[2 * (intFacetOffset + i) + 1];
183811bcd083SPatrick Farrell           const PetscInt *cell0idx = &dofsArray[(offset + cell0) * patch->totalDofsPerCell];
183911bcd083SPatrick Farrell           const PetscInt *cell1idx = &dofsArray[(offset + cell1) * patch->totalDofsPerCell];
18409566063dSJacob Faibussowitsch           PetscCall(MatSetValues(preallocator, patch->totalDofsPerCell, cell0idx, patch->totalDofsPerCell, cell1idx, vals, INSERT_VALUES));
18419566063dSJacob Faibussowitsch           PetscCall(MatSetValues(preallocator, patch->totalDofsPerCell, cell1idx, patch->totalDofsPerCell, cell0idx, vals, INSERT_VALUES));
184211bcd083SPatrick Farrell         }
184311bcd083SPatrick Farrell       }
184411bcd083SPatrick Farrell 
18459566063dSJacob Faibussowitsch       PetscCall(PetscFree(vals));
18469566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY));
18479566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY));
18489566063dSJacob Faibussowitsch       PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_TRUE, *mat));
18499566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&preallocator));
1850b2866507SPatrick Farrell     }
18519566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(PC_Patch_Prealloc, pc, 0, 0, 0));
1852fe117d09SFlorian Wechsung     if (withArtificial) {
18539566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(patch->dofsWithArtificial, &dofsArray));
1854fe117d09SFlorian Wechsung     } else {
18559566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(patch->dofs, &dofsArray));
18564bbf5ea8SMatthew G. Knepley     }
1857fe117d09SFlorian Wechsung   }
18589566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*mat));
18594bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
18604bbf5ea8SMatthew G. Knepley }
18614bbf5ea8SMatthew G. Knepley 
18629371c9d4SSatish Balay static PetscErrorCode PCPatchComputeFunction_DMPlex_Private(PC pc, PetscInt patchNum, Vec x, Vec F, IS cellIS, PetscInt n, const PetscInt *l2p, const PetscInt *l2pWithAll, void *ctx) {
186392d50984SMatthew G. Knepley   PC_PATCH       *patch = (PC_PATCH *)pc->data;
1864b6bb21d1SLawrence Mitchell   DM              dm, plex;
186592d50984SMatthew G. Knepley   PetscSection    s;
186692d50984SMatthew G. Knepley   const PetscInt *parray, *oarray;
186792d50984SMatthew G. Knepley   PetscInt        Nf = patch->nsubspaces, Np, poff, p, f;
186892d50984SMatthew G. Knepley 
186992d50984SMatthew G. Knepley   PetscFunctionBegin;
187028b400f6SJacob Faibussowitsch   PetscCheck(!patch->precomputeElementTensors, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Precomputing element tensors not implemented with DMPlex compute operator");
18719566063dSJacob Faibussowitsch   PetscCall(PCGetDM(pc, &dm));
18729566063dSJacob Faibussowitsch   PetscCall(DMConvert(dm, DMPLEX, &plex));
1873b6bb21d1SLawrence Mitchell   dm = plex;
18749566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
187592d50984SMatthew G. Knepley   /* Set offset into patch */
18769566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(patch->pointCounts, patchNum, &Np));
18779566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(patch->pointCounts, patchNum, &poff));
18789566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(patch->points, &parray));
18799566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(patch->offs, &oarray));
188092d50984SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
188192d50984SMatthew G. Knepley     for (p = 0; p < Np; ++p) {
188292d50984SMatthew G. Knepley       const PetscInt point = parray[poff + p];
188392d50984SMatthew G. Knepley       PetscInt       dof;
188492d50984SMatthew G. Knepley 
18859566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(patch->patchSection, point, f, &dof));
18869566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetFieldOffset(patch->patchSection, point, f, oarray[(poff + p) * Nf + f]));
18879566063dSJacob Faibussowitsch       if (patch->nsubspaces == 1) PetscCall(PetscSectionSetOffset(patch->patchSection, point, oarray[(poff + p) * Nf + f]));
18889566063dSJacob Faibussowitsch       else PetscCall(PetscSectionSetOffset(patch->patchSection, point, -1));
188992d50984SMatthew G. Knepley     }
189092d50984SMatthew G. Knepley   }
18919566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(patch->points, &parray));
18929566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(patch->offs, &oarray));
18939566063dSJacob Faibussowitsch   if (patch->viewSection) PetscCall(ObjectView((PetscObject)patch->patchSection, patch->viewerSection, patch->formatSection));
18949566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeResidual_Patch_Internal(dm, patch->patchSection, cellIS, 0.0, x, NULL, F, ctx));
18959566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dm));
189692d50984SMatthew G. Knepley   PetscFunctionReturn(0);
189792d50984SMatthew G. Knepley }
189892d50984SMatthew G. Knepley 
18999371c9d4SSatish Balay PetscErrorCode PCPatchComputeFunction_Internal(PC pc, Vec x, Vec F, PetscInt point) {
190092d50984SMatthew G. Knepley   PC_PATCH       *patch = (PC_PATCH *)pc->data;
190192d50984SMatthew G. Knepley   const PetscInt *dofsArray;
19020904074fSPatrick Farrell   const PetscInt *dofsArrayWithAll;
190392d50984SMatthew G. Knepley   const PetscInt *cellsArray;
190492d50984SMatthew G. Knepley   PetscInt        ncell, offset, pStart, pEnd;
190592d50984SMatthew G. Knepley 
190692d50984SMatthew G. Knepley   PetscFunctionBegin;
19079566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_Patch_ComputeOp, pc, 0, 0, 0));
1908ef1023bdSBarry Smith   PetscCheck(patch->usercomputeop, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call PCPatchSetComputeOperator() to set callback");
19099566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(patch->dofs, &dofsArray));
19109566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(patch->dofsWithAll, &dofsArrayWithAll));
19119566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(patch->cells, &cellsArray));
19129566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(patch->cellCounts, &pStart, &pEnd));
191392d50984SMatthew G. Knepley 
191492d50984SMatthew G. Knepley   point += pStart;
191563a3b9bcSJacob Faibussowitsch   PetscCheck(point < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Operator point %" PetscInt_FMT " not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, pStart, pEnd);
191692d50984SMatthew G. Knepley 
19179566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(patch->cellCounts, point, &ncell));
19189566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(patch->cellCounts, point, &offset));
191992d50984SMatthew G. Knepley   if (ncell <= 0) {
19209566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(PC_Patch_ComputeOp, pc, 0, 0, 0));
192192d50984SMatthew G. Knepley     PetscFunctionReturn(0);
192292d50984SMatthew G. Knepley   }
19239566063dSJacob Faibussowitsch   PetscCall(VecSet(F, 0.0));
192492d50984SMatthew G. Knepley   /* Cannot reuse the same IS because the geometry info is being cached in it */
19259566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncell, cellsArray + offset, PETSC_USE_POINTER, &patch->cellIS));
1926792fecdfSBarry Smith   PetscCallBack("PCPatch callback", patch->usercomputef(pc, point, x, F, patch->cellIS, ncell * patch->totalDofsPerCell, dofsArray + offset * patch->totalDofsPerCell, dofsArrayWithAll + offset * patch->totalDofsPerCell, patch->usercomputefctx));
19279566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&patch->cellIS));
19289566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(patch->dofs, &dofsArray));
19299566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(patch->dofsWithAll, &dofsArrayWithAll));
19309566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(patch->cells, &cellsArray));
193192d50984SMatthew G. Knepley   if (patch->viewMatrix) {
193292d50984SMatthew G. Knepley     char name[PETSC_MAX_PATH_LEN];
193392d50984SMatthew G. Knepley 
193463a3b9bcSJacob Faibussowitsch     PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN - 1, "Patch vector for Point %" PetscInt_FMT, point));
19359566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)F, name));
19369566063dSJacob Faibussowitsch     PetscCall(ObjectView((PetscObject)F, patch->viewerMatrix, patch->formatMatrix));
193792d50984SMatthew G. Knepley   }
19389566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_Patch_ComputeOp, pc, 0, 0, 0));
193992d50984SMatthew G. Knepley   PetscFunctionReturn(0);
194092d50984SMatthew G. Knepley }
194192d50984SMatthew G. Knepley 
19429371c9d4SSatish Balay static PetscErrorCode PCPatchComputeOperator_DMPlex_Private(PC pc, PetscInt patchNum, Vec x, Mat J, IS cellIS, PetscInt n, const PetscInt *l2p, const PetscInt *l2pWithAll, void *ctx) {
19435f824522SMatthew G. Knepley   PC_PATCH       *patch = (PC_PATCH *)pc->data;
1944b6bb21d1SLawrence Mitchell   DM              dm, plex;
19455f824522SMatthew G. Knepley   PetscSection    s;
19465f824522SMatthew G. Knepley   const PetscInt *parray, *oarray;
19475f824522SMatthew G. Knepley   PetscInt        Nf = patch->nsubspaces, Np, poff, p, f;
19485f824522SMatthew G. Knepley 
19495f824522SMatthew G. Knepley   PetscFunctionBegin;
19509566063dSJacob Faibussowitsch   PetscCall(PCGetDM(pc, &dm));
19519566063dSJacob Faibussowitsch   PetscCall(DMConvert(dm, DMPLEX, &plex));
1952b6bb21d1SLawrence Mitchell   dm = plex;
19539566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
19545f824522SMatthew G. Knepley   /* Set offset into patch */
19559566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(patch->pointCounts, patchNum, &Np));
19569566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(patch->pointCounts, patchNum, &poff));
19579566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(patch->points, &parray));
19589566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(patch->offs, &oarray));
19595f824522SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
19605f824522SMatthew G. Knepley     for (p = 0; p < Np; ++p) {
19615f824522SMatthew G. Knepley       const PetscInt point = parray[poff + p];
19625f824522SMatthew G. Knepley       PetscInt       dof;
19635f824522SMatthew G. Knepley 
19649566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(patch->patchSection, point, f, &dof));
19659566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetFieldOffset(patch->patchSection, point, f, oarray[(poff + p) * Nf + f]));
19669566063dSJacob Faibussowitsch       if (patch->nsubspaces == 1) PetscCall(PetscSectionSetOffset(patch->patchSection, point, oarray[(poff + p) * Nf + f]));
19679566063dSJacob Faibussowitsch       else PetscCall(PetscSectionSetOffset(patch->patchSection, point, -1));
19685f824522SMatthew G. Knepley     }
19695f824522SMatthew G. Knepley   }
19709566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(patch->points, &parray));
19719566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(patch->offs, &oarray));
19729566063dSJacob Faibussowitsch   if (patch->viewSection) PetscCall(ObjectView((PetscObject)patch->patchSection, patch->viewerSection, patch->formatSection));
19735f824522SMatthew G. Knepley   /* TODO Shut off MatViewFromOptions() in MatAssemblyEnd() here */
19749566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeJacobian_Patch_Internal(dm, patch->patchSection, patch->patchSection, cellIS, 0.0, 0.0, x, NULL, J, J, ctx));
19759566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dm));
19765f824522SMatthew G. Knepley   PetscFunctionReturn(0);
19775f824522SMatthew G. Knepley }
19785f824522SMatthew G. Knepley 
1979a685ae26SLawrence Mitchell /* This function zeros mat on entry */
19809371c9d4SSatish Balay PetscErrorCode PCPatchComputeOperator_Internal(PC pc, Vec x, Mat mat, PetscInt point, PetscBool withArtificial) {
19814bbf5ea8SMatthew G. Knepley   PC_PATCH       *patch = (PC_PATCH *)pc->data;
19824bbf5ea8SMatthew G. Knepley   const PetscInt *dofsArray;
19830904074fSPatrick Farrell   const PetscInt *dofsArrayWithAll = NULL;
19844bbf5ea8SMatthew G. Knepley   const PetscInt *cellsArray;
1985eb62eeaaSLawrence Mitchell   PetscInt        ncell, offset, pStart, pEnd, numIntFacets, intFacetOffset;
19864d04e9f1SPatrick Farrell   PetscBool       isNonlinear;
19874bbf5ea8SMatthew G. Knepley 
19884bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
19899566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_Patch_ComputeOp, pc, 0, 0, 0));
1990debbdec3SPatrick Farrell   isNonlinear = patch->isNonlinear;
1991ef1023bdSBarry Smith   PetscCheck(patch->usercomputeop, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call PCPatchSetComputeOperator() to set callback");
1992c2e6f3c0SFlorian Wechsung   if (withArtificial) {
19939566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(patch->dofsWithArtificial, &dofsArray));
1994c2e6f3c0SFlorian Wechsung   } else {
19959566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(patch->dofs, &dofsArray));
1996c2e6f3c0SFlorian Wechsung   }
199748a46eb9SPierre Jolivet   if (isNonlinear) PetscCall(ISGetIndices(patch->dofsWithAll, &dofsArrayWithAll));
19989566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(patch->cells, &cellsArray));
19999566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(patch->cellCounts, &pStart, &pEnd));
20004bbf5ea8SMatthew G. Knepley 
20014bbf5ea8SMatthew G. Knepley   point += pStart;
200263a3b9bcSJacob Faibussowitsch   PetscCheck(point < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Operator point %" PetscInt_FMT " not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, pStart, pEnd);
20034bbf5ea8SMatthew G. Knepley 
20049566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetDof(patch->cellCounts, point, &ncell));
20059566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetOffset(patch->cellCounts, point, &offset));
20064bbf5ea8SMatthew G. Knepley   if (ncell <= 0) {
20079566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(PC_Patch_ComputeOp, pc, 0, 0, 0));
20084bbf5ea8SMatthew G. Knepley     PetscFunctionReturn(0);
20094bbf5ea8SMatthew G. Knepley   }
20109566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(mat));
2011fa84ea4cSLawrence Mitchell   if (patch->precomputeElementTensors) {
2012fa84ea4cSLawrence Mitchell     PetscInt           i;
2013fa84ea4cSLawrence Mitchell     PetscInt           ndof = patch->totalDofsPerCell;
2014fa84ea4cSLawrence Mitchell     const PetscScalar *elementTensors;
2015fa84ea4cSLawrence Mitchell 
20169566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(patch->cellMats, &elementTensors));
2017fa84ea4cSLawrence Mitchell     for (i = 0; i < ncell; i++) {
2018fa84ea4cSLawrence Mitchell       const PetscInt     cell = cellsArray[i + offset];
2019fa84ea4cSLawrence Mitchell       const PetscInt    *idx  = dofsArray + (offset + i) * ndof;
2020fe988be2SFlorian Wechsung       const PetscScalar *v    = elementTensors + patch->precomputedTensorLocations[cell] * ndof * ndof;
20219566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat, ndof, idx, ndof, idx, v, ADD_VALUES));
2022fa84ea4cSLawrence Mitchell     }
20239566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(patch->cellMats, &elementTensors));
20249566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
20259566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
2026fa84ea4cSLawrence Mitchell   } else {
20272aa6f319SMatthew G. Knepley     /* Cannot reuse the same IS because the geometry info is being cached in it */
20289566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncell, cellsArray + offset, PETSC_USE_POINTER, &patch->cellIS));
20299371c9d4SSatish Balay     PetscCallBack("PCPatch callback",
20309371c9d4SSatish Balay                   patch->usercomputeop(pc, point, x, mat, patch->cellIS, ncell * patch->totalDofsPerCell, dofsArray + offset * patch->totalDofsPerCell, dofsArrayWithAll ? dofsArrayWithAll + offset * patch->totalDofsPerCell : NULL, patch->usercomputeopctx));
2031fa84ea4cSLawrence Mitchell   }
203259109abcSLawrence Mitchell   if (patch->usercomputeopintfacet) {
20339566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(patch->intFacetCounts, point, &numIntFacets));
20349566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(patch->intFacetCounts, point, &intFacetOffset));
2035eb62eeaaSLawrence Mitchell     if (numIntFacets > 0) {
2036eb62eeaaSLawrence Mitchell       /* For each interior facet, grab the two cells (in local numbering, and concatenate dof numberings for those cells) */
2037eb62eeaaSLawrence Mitchell       PetscInt       *facetDofs = NULL, *facetDofsWithAll = NULL;
2038eb62eeaaSLawrence Mitchell       const PetscInt *intFacetsArray = NULL;
2039eb62eeaaSLawrence Mitchell       PetscInt        idx            = 0;
2040eb62eeaaSLawrence Mitchell       PetscInt        i, c, d;
2041de2d1767SPatrick Farrell       PetscInt        fStart;
2042b6bb21d1SLawrence Mitchell       DM              dm, plex;
2043eb62eeaaSLawrence Mitchell       IS              facetIS    = NULL;
2044eb62eeaaSLawrence Mitchell       const PetscInt *facetCells = NULL;
20457a50e09dSPatrick Farrell 
20469566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(patch->intFacetsToPatchCell, &facetCells));
20479566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(patch->intFacets, &intFacetsArray));
20489566063dSJacob Faibussowitsch       PetscCall(PCGetDM(pc, &dm));
20499566063dSJacob Faibussowitsch       PetscCall(DMConvert(dm, DMPLEX, &plex));
2050b6bb21d1SLawrence Mitchell       dm = plex;
20519566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, NULL));
2052eb62eeaaSLawrence Mitchell       /* FIXME: Pull this malloc out. */
20539566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(2 * patch->totalDofsPerCell * numIntFacets, &facetDofs));
205448a46eb9SPierre Jolivet       if (dofsArrayWithAll) PetscCall(PetscMalloc1(2 * patch->totalDofsPerCell * numIntFacets, &facetDofsWithAll));
2055f98464cbSLawrence Mitchell       if (patch->precomputeElementTensors) {
2056f98464cbSLawrence Mitchell         PetscInt           nFacetDof = 2 * patch->totalDofsPerCell;
2057f98464cbSLawrence Mitchell         const PetscScalar *elementTensors;
2058f98464cbSLawrence Mitchell 
20599566063dSJacob Faibussowitsch         PetscCall(VecGetArrayRead(patch->intFacetMats, &elementTensors));
2060f98464cbSLawrence Mitchell 
2061f98464cbSLawrence Mitchell         for (i = 0; i < numIntFacets; i++) {
2062f98464cbSLawrence Mitchell           const PetscInt     facet = intFacetsArray[i + intFacetOffset];
2063de2d1767SPatrick Farrell           const PetscScalar *v     = elementTensors + patch->precomputedIntFacetTensorLocations[facet - fStart] * nFacetDof * nFacetDof;
2064f98464cbSLawrence Mitchell           idx                      = 0;
2065f98464cbSLawrence Mitchell           /*
2066*f1580f4eSBarry Smith      0--1
2067*f1580f4eSBarry Smith      |\-|
2068*f1580f4eSBarry Smith      |+\|
2069*f1580f4eSBarry Smith      2--3
2070*f1580f4eSBarry Smith      [0, 2, 3, 0, 1, 3]
2071f98464cbSLawrence Mitchell    */
2072f98464cbSLawrence Mitchell           for (c = 0; c < 2; c++) {
2073f98464cbSLawrence Mitchell             const PetscInt cell = facetCells[2 * (intFacetOffset + i) + c];
2074f98464cbSLawrence Mitchell             for (d = 0; d < patch->totalDofsPerCell; d++) {
2075f98464cbSLawrence Mitchell               facetDofs[idx] = dofsArray[(offset + cell) * patch->totalDofsPerCell + d];
2076f98464cbSLawrence Mitchell               idx++;
2077f98464cbSLawrence Mitchell             }
2078f98464cbSLawrence Mitchell           }
20799566063dSJacob Faibussowitsch           PetscCall(MatSetValues(mat, nFacetDof, facetDofs, nFacetDof, facetDofs, v, ADD_VALUES));
2080f98464cbSLawrence Mitchell         }
20819566063dSJacob Faibussowitsch         PetscCall(VecRestoreArrayRead(patch->intFacetMats, &elementTensors));
2082f98464cbSLawrence Mitchell       } else {
2083eb62eeaaSLawrence Mitchell         /*
2084*f1580f4eSBarry Smith      0--1
2085*f1580f4eSBarry Smith      |\-|
2086*f1580f4eSBarry Smith      |+\|
2087*f1580f4eSBarry Smith      2--3
2088*f1580f4eSBarry Smith      [0, 2, 3, 0, 1, 3]
2089eb62eeaaSLawrence Mitchell    */
2090eb62eeaaSLawrence Mitchell         for (i = 0; i < numIntFacets; i++) {
2091eb62eeaaSLawrence Mitchell           for (c = 0; c < 2; c++) {
2092eb62eeaaSLawrence Mitchell             const PetscInt cell = facetCells[2 * (intFacetOffset + i) + c];
2093eb62eeaaSLawrence Mitchell             for (d = 0; d < patch->totalDofsPerCell; d++) {
2094eb62eeaaSLawrence Mitchell               facetDofs[idx] = dofsArray[(offset + cell) * patch->totalDofsPerCell + d];
2095ad540459SPierre Jolivet               if (dofsArrayWithAll) facetDofsWithAll[idx] = dofsArrayWithAll[(offset + cell) * patch->totalDofsPerCell + d];
2096eb62eeaaSLawrence Mitchell               idx++;
2097eb62eeaaSLawrence Mitchell             }
2098eb62eeaaSLawrence Mitchell           }
2099eb62eeaaSLawrence Mitchell         }
21009566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numIntFacets, intFacetsArray + intFacetOffset, PETSC_USE_POINTER, &facetIS));
21019566063dSJacob Faibussowitsch         PetscCall(patch->usercomputeopintfacet(pc, point, x, mat, facetIS, 2 * numIntFacets * patch->totalDofsPerCell, facetDofs, facetDofsWithAll, patch->usercomputeopintfacetctx));
21029566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&facetIS));
2103f98464cbSLawrence Mitchell       }
21049566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(patch->intFacetsToPatchCell, &facetCells));
21059566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(patch->intFacets, &intFacetsArray));
21069566063dSJacob Faibussowitsch       PetscCall(PetscFree(facetDofs));
21079566063dSJacob Faibussowitsch       PetscCall(PetscFree(facetDofsWithAll));
21089566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&dm));
2109eb62eeaaSLawrence Mitchell     }
211059109abcSLawrence Mitchell   }
21116710cc29SPatrick Farrell 
21129566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
21139566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
21146710cc29SPatrick Farrell 
2115c73d2cf6SLawrence Mitchell   if (!(withArtificial || isNonlinear) && patch->denseinverse) {
2116c73d2cf6SLawrence Mitchell     MatFactorInfo info;
2117c73d2cf6SLawrence Mitchell     PetscBool     flg;
21189566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)mat, MATSEQDENSE, &flg));
211928b400f6SJacob Faibussowitsch     PetscCheck(flg, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Invalid Mat type for dense inverse");
21209566063dSJacob Faibussowitsch     PetscCall(MatFactorInfoInitialize(&info));
21219566063dSJacob Faibussowitsch     PetscCall(MatLUFactor(mat, NULL, NULL, &info));
21229566063dSJacob Faibussowitsch     PetscCall(MatSeqDenseInvertFactors_Private(mat));
2123c73d2cf6SLawrence Mitchell   }
21249566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&patch->cellIS));
21254d04e9f1SPatrick Farrell   if (withArtificial) {
21269566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(patch->dofsWithArtificial, &dofsArray));
2127c2e6f3c0SFlorian Wechsung   } else {
21289566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(patch->dofs, &dofsArray));
2129c2e6f3c0SFlorian Wechsung   }
213048a46eb9SPierre Jolivet   if (isNonlinear) PetscCall(ISRestoreIndices(patch->dofsWithAll, &dofsArrayWithAll));
21319566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(patch->cells, &cellsArray));
21322aa6f319SMatthew G. Knepley   if (patch->viewMatrix) {
21332aa6f319SMatthew G. Knepley     char name[PETSC_MAX_PATH_LEN];
21342aa6f319SMatthew G. Knepley 
213563a3b9bcSJacob Faibussowitsch     PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN - 1, "Patch matrix for Point %" PetscInt_FMT, point));
21369566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetName((PetscObject)mat, name));
21379566063dSJacob Faibussowitsch     PetscCall(ObjectView((PetscObject)mat, patch->viewerMatrix, patch->formatMatrix));
21382aa6f319SMatthew G. Knepley   }
21399566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_Patch_ComputeOp, pc, 0, 0, 0));
21404bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
21414bbf5ea8SMatthew G. Knepley }
21424bbf5ea8SMatthew G. Knepley 
21439371c9d4SSatish Balay static PetscErrorCode MatSetValues_PCPatch_Private(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], const PetscScalar *v, InsertMode addv) {
2144fa84ea4cSLawrence Mitchell   Vec          data;
2145fa84ea4cSLawrence Mitchell   PetscScalar *array;
2146fe988be2SFlorian Wechsung   PetscInt     bs, nz, i, j, cell;
2147fa84ea4cSLawrence Mitchell 
21489566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(mat, &data));
21499566063dSJacob Faibussowitsch   PetscCall(VecGetBlockSize(data, &bs));
21509566063dSJacob Faibussowitsch   PetscCall(VecGetSize(data, &nz));
21519566063dSJacob Faibussowitsch   PetscCall(VecGetArray(data, &array));
215208401ef6SPierre Jolivet   PetscCheck(m == n, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "Only for square insertion");
215333cbca70SPatrick Farrell   cell = (PetscInt)(idxm[0] / bs); /* use the fact that this is called once per cell */
2154fa84ea4cSLawrence Mitchell   for (i = 0; i < m; i++) {
215508401ef6SPierre Jolivet     PetscCheck(idxm[i] == idxn[i], PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "Row and column indices must match!");
2156fa84ea4cSLawrence Mitchell     for (j = 0; j < n; j++) {
2157fa84ea4cSLawrence Mitchell       const PetscScalar v_ = v[i * bs + j];
2158fa84ea4cSLawrence Mitchell       /* Indexing is special to the data structure we have! */
2159fa84ea4cSLawrence Mitchell       if (addv == INSERT_VALUES) {
2160fe988be2SFlorian Wechsung         array[cell * bs * bs + i * bs + j] = v_;
2161fa84ea4cSLawrence Mitchell       } else {
2162fe988be2SFlorian Wechsung         array[cell * bs * bs + i * bs + j] += v_;
2163fa84ea4cSLawrence Mitchell       }
2164fa84ea4cSLawrence Mitchell     }
2165fa84ea4cSLawrence Mitchell   }
21669566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(data, &array));
2167fa84ea4cSLawrence Mitchell   PetscFunctionReturn(0);
2168fa84ea4cSLawrence Mitchell }
2169fa84ea4cSLawrence Mitchell 
21709371c9d4SSatish Balay static PetscErrorCode PCPatchPrecomputePatchTensors_Private(PC pc) {
2171fa84ea4cSLawrence Mitchell   PC_PATCH       *patch = (PC_PATCH *)pc->data;
2172fa84ea4cSLawrence Mitchell   const PetscInt *cellsArray;
2173fa84ea4cSLawrence Mitchell   PetscInt        ncell, offset;
2174fa84ea4cSLawrence Mitchell   const PetscInt *dofMapArray;
2175fa84ea4cSLawrence Mitchell   PetscInt        i, j;
2176fa84ea4cSLawrence Mitchell   IS              dofMap;
2177fa84ea4cSLawrence Mitchell   IS              cellIS;
2178fa84ea4cSLawrence Mitchell   const PetscInt  ndof = patch->totalDofsPerCell;
2179fa84ea4cSLawrence Mitchell   Mat             vecMat;
2180fe988be2SFlorian Wechsung   PetscInt        cStart, cEnd;
2181fe988be2SFlorian Wechsung   DM              dm, plex;
2182fe988be2SFlorian Wechsung 
21839566063dSJacob Faibussowitsch   PetscCall(ISGetSize(patch->cells, &ncell));
2184e9c2c94bSFlorian Wechsung   if (!ncell) { /* No cells to assemble over -> skip */
2185e9c2c94bSFlorian Wechsung     PetscFunctionReturn(0);
2186e9c2c94bSFlorian Wechsung   }
2187e9c2c94bSFlorian Wechsung 
21889566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_Patch_ComputeOp, pc, 0, 0, 0));
2189fa84ea4cSLawrence Mitchell 
21909566063dSJacob Faibussowitsch   PetscCall(PCGetDM(pc, &dm));
21919566063dSJacob Faibussowitsch   PetscCall(DMConvert(dm, DMPLEX, &plex));
2192b6bb21d1SLawrence Mitchell   dm = plex;
2193fa84ea4cSLawrence Mitchell   if (!patch->allCells) {
2194fa84ea4cSLawrence Mitchell     PetscHSetI    cells;
2195fa84ea4cSLawrence Mitchell     PetscHashIter hi;
2196fa84ea4cSLawrence Mitchell     PetscInt      pStart, pEnd;
2197fa84ea4cSLawrence Mitchell     PetscInt     *allCells = NULL;
21989566063dSJacob Faibussowitsch     PetscCall(PetscHSetICreate(&cells));
21999566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(patch->cells, &cellsArray));
22009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(patch->cellCounts, &pStart, &pEnd));
2201fa84ea4cSLawrence Mitchell     for (i = pStart; i < pEnd; i++) {
22029566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(patch->cellCounts, i, &ncell));
22039566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(patch->cellCounts, i, &offset));
2204fa84ea4cSLawrence Mitchell       if (ncell <= 0) continue;
220548a46eb9SPierre Jolivet       for (j = 0; j < ncell; j++) PetscCall(PetscHSetIAdd(cells, cellsArray[offset + j]));
2206fa84ea4cSLawrence Mitchell     }
22079566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(patch->cells, &cellsArray));
22089566063dSJacob Faibussowitsch     PetscCall(PetscHSetIGetSize(cells, &ncell));
22099566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(ncell, &allCells));
22109566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
22119566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(cEnd - cStart, &patch->precomputedTensorLocations));
2212fa84ea4cSLawrence Mitchell     i = 0;
2213fa84ea4cSLawrence Mitchell     PetscHashIterBegin(cells, hi);
2214fa84ea4cSLawrence Mitchell     while (!PetscHashIterAtEnd(cells, hi)) {
2215fe988be2SFlorian Wechsung       PetscHashIterGetKey(cells, hi, allCells[i]);
2216fe988be2SFlorian Wechsung       patch->precomputedTensorLocations[allCells[i]] = i;
2217fa84ea4cSLawrence Mitchell       PetscHashIterNext(cells, hi);
2218fe988be2SFlorian Wechsung       i++;
2219fa84ea4cSLawrence Mitchell     }
22209566063dSJacob Faibussowitsch     PetscCall(PetscHSetIDestroy(&cells));
22219566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncell, allCells, PETSC_OWN_POINTER, &patch->allCells));
2222fa84ea4cSLawrence Mitchell   }
22239566063dSJacob Faibussowitsch   PetscCall(ISGetSize(patch->allCells, &ncell));
2224fa84ea4cSLawrence Mitchell   if (!patch->cellMats) {
22259566063dSJacob Faibussowitsch     PetscCall(VecCreateSeq(PETSC_COMM_SELF, ncell * ndof * ndof, &patch->cellMats));
22269566063dSJacob Faibussowitsch     PetscCall(VecSetBlockSize(patch->cellMats, ndof));
2227fa84ea4cSLawrence Mitchell   }
22289566063dSJacob Faibussowitsch   PetscCall(VecSet(patch->cellMats, 0));
2229fa84ea4cSLawrence Mitchell 
2230d0609cedSBarry Smith   PetscCall(MatCreateShell(PETSC_COMM_SELF, ncell * ndof, ncell * ndof, ncell * ndof, ncell * ndof, (void *)patch->cellMats, &vecMat));
22319566063dSJacob Faibussowitsch   PetscCall(MatShellSetOperation(vecMat, MATOP_SET_VALUES, (void (*)(void)) & MatSetValues_PCPatch_Private));
22329566063dSJacob Faibussowitsch   PetscCall(ISGetSize(patch->allCells, &ncell));
22339566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, ndof * ncell, 0, 1, &dofMap));
22349566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(dofMap, &dofMapArray));
22359566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(patch->allCells, &cellsArray));
22369566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncell, cellsArray, PETSC_USE_POINTER, &cellIS));
2237fa84ea4cSLawrence Mitchell   /* TODO: Fix for DMPlex compute op, this bypasses a lot of the machinery and just assembles every element tensor. */
2238792fecdfSBarry Smith   PetscCallBack("PCPatch callback", patch->usercomputeop(pc, -1, NULL, vecMat, cellIS, ndof * ncell, dofMapArray, NULL, patch->usercomputeopctx));
22399566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cellIS));
22409566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&vecMat));
22419566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(patch->allCells, &cellsArray));
22429566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(dofMap, &dofMapArray));
22439566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&dofMap));
2244f98464cbSLawrence Mitchell 
2245f98464cbSLawrence Mitchell   if (patch->usercomputeopintfacet) {
2246f98464cbSLawrence Mitchell     PetscInt        nIntFacets;
2247f98464cbSLawrence Mitchell     IS              intFacetsIS;
2248f98464cbSLawrence Mitchell     const PetscInt *intFacetsArray = NULL;
2249f98464cbSLawrence Mitchell     if (!patch->allIntFacets) {
2250f98464cbSLawrence Mitchell       PetscHSetI    facets;
2251f98464cbSLawrence Mitchell       PetscHashIter hi;
2252f98464cbSLawrence Mitchell       PetscInt      pStart, pEnd, fStart, fEnd;
2253f98464cbSLawrence Mitchell       PetscInt     *allIntFacets = NULL;
22549566063dSJacob Faibussowitsch       PetscCall(PetscHSetICreate(&facets));
22559566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(patch->intFacets, &intFacetsArray));
22569566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetChart(patch->intFacetCounts, &pStart, &pEnd));
22579566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
2258f98464cbSLawrence Mitchell       for (i = pStart; i < pEnd; i++) {
22599566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(patch->intFacetCounts, i, &nIntFacets));
22609566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(patch->intFacetCounts, i, &offset));
2261f98464cbSLawrence Mitchell         if (nIntFacets <= 0) continue;
226248a46eb9SPierre Jolivet         for (j = 0; j < nIntFacets; j++) PetscCall(PetscHSetIAdd(facets, intFacetsArray[offset + j]));
2263f98464cbSLawrence Mitchell       }
22649566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(patch->intFacets, &intFacetsArray));
22659566063dSJacob Faibussowitsch       PetscCall(PetscHSetIGetSize(facets, &nIntFacets));
22669566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nIntFacets, &allIntFacets));
22679566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(fEnd - fStart, &patch->precomputedIntFacetTensorLocations));
2268f98464cbSLawrence Mitchell       i = 0;
2269f98464cbSLawrence Mitchell       PetscHashIterBegin(facets, hi);
2270f98464cbSLawrence Mitchell       while (!PetscHashIterAtEnd(facets, hi)) {
2271f98464cbSLawrence Mitchell         PetscHashIterGetKey(facets, hi, allIntFacets[i]);
2272de2d1767SPatrick Farrell         patch->precomputedIntFacetTensorLocations[allIntFacets[i] - fStart] = i;
2273f98464cbSLawrence Mitchell         PetscHashIterNext(facets, hi);
2274f98464cbSLawrence Mitchell         i++;
2275f98464cbSLawrence Mitchell       }
22769566063dSJacob Faibussowitsch       PetscCall(PetscHSetIDestroy(&facets));
22779566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nIntFacets, allIntFacets, PETSC_OWN_POINTER, &patch->allIntFacets));
2278f98464cbSLawrence Mitchell     }
22799566063dSJacob Faibussowitsch     PetscCall(ISGetSize(patch->allIntFacets, &nIntFacets));
2280f98464cbSLawrence Mitchell     if (!patch->intFacetMats) {
22819566063dSJacob Faibussowitsch       PetscCall(VecCreateSeq(PETSC_COMM_SELF, nIntFacets * ndof * ndof * 4, &patch->intFacetMats));
22829566063dSJacob Faibussowitsch       PetscCall(VecSetBlockSize(patch->intFacetMats, ndof * 2));
2283f98464cbSLawrence Mitchell     }
22849566063dSJacob Faibussowitsch     PetscCall(VecSet(patch->intFacetMats, 0));
2285f98464cbSLawrence Mitchell 
2286d0609cedSBarry Smith     PetscCall(MatCreateShell(PETSC_COMM_SELF, nIntFacets * ndof * 2, nIntFacets * ndof * 2, nIntFacets * ndof * 2, nIntFacets * ndof * 2, (void *)patch->intFacetMats, &vecMat));
22879566063dSJacob Faibussowitsch     PetscCall(MatShellSetOperation(vecMat, MATOP_SET_VALUES, (void (*)(void)) & MatSetValues_PCPatch_Private));
22889566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, 2 * ndof * nIntFacets, 0, 1, &dofMap));
22899566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(dofMap, &dofMapArray));
22909566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(patch->allIntFacets, &intFacetsArray));
22919566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nIntFacets, intFacetsArray, PETSC_USE_POINTER, &intFacetsIS));
2292f98464cbSLawrence Mitchell     /* TODO: Fix for DMPlex compute op, this bypasses a lot of the machinery and just assembles every element tensor. */
2293792fecdfSBarry Smith     PetscCallBack("PCPatch callback (interior facets)", patch->usercomputeopintfacet(pc, -1, NULL, vecMat, intFacetsIS, 2 * ndof * nIntFacets, dofMapArray, NULL, patch->usercomputeopintfacetctx));
22949566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&intFacetsIS));
22959566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&vecMat));
22969566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(patch->allIntFacets, &intFacetsArray));
22979566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(dofMap, &dofMapArray));
22989566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&dofMap));
2299f98464cbSLawrence Mitchell   }
23009566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dm));
23019566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_Patch_ComputeOp, pc, 0, 0, 0));
2302fa84ea4cSLawrence Mitchell 
2303fa84ea4cSLawrence Mitchell   PetscFunctionReturn(0);
2304fa84ea4cSLawrence Mitchell }
2305fa84ea4cSLawrence Mitchell 
23069371c9d4SSatish Balay PetscErrorCode PCPatch_ScatterLocal_Private(PC pc, PetscInt p, Vec x, Vec y, InsertMode mode, ScatterMode scat, PatchScatterType scattertype) {
23074bbf5ea8SMatthew G. Knepley   PC_PATCH          *patch     = (PC_PATCH *)pc->data;
23084bbf5ea8SMatthew G. Knepley   const PetscScalar *xArray    = NULL;
23094bbf5ea8SMatthew G. Knepley   PetscScalar       *yArray    = NULL;
23104bbf5ea8SMatthew G. Knepley   const PetscInt    *gtolArray = NULL;
23114bbf5ea8SMatthew G. Knepley   PetscInt           dof, offset, lidx;
23124bbf5ea8SMatthew G. Knepley 
23134bbf5ea8SMatthew G. Knepley   PetscFunctionBeginHot;
23149566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x, &xArray));
23159566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &yArray));
23160904074fSPatrick Farrell   if (scattertype == SCATTER_WITHARTIFICIAL) {
23179566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(patch->gtolCountsWithArtificial, p, &dof));
23189566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(patch->gtolCountsWithArtificial, p, &offset));
23199566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(patch->gtolWithArtificial, &gtolArray));
23200904074fSPatrick Farrell   } else if (scattertype == SCATTER_WITHALL) {
23219566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(patch->gtolCountsWithAll, p, &dof));
23229566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(patch->gtolCountsWithAll, p, &offset));
23239566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(patch->gtolWithAll, &gtolArray));
2324c2e6f3c0SFlorian Wechsung   } else {
23259566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(patch->gtolCounts, p, &dof));
23269566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(patch->gtolCounts, p, &offset));
23279566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(patch->gtol, &gtolArray));
2328c2e6f3c0SFlorian Wechsung   }
23292472a847SBarry Smith   PetscCheck(mode != INSERT_VALUES || scat == SCATTER_FORWARD, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Can't insert if not scattering forward");
23302472a847SBarry Smith   PetscCheck(mode != ADD_VALUES || scat == SCATTER_REVERSE, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Can't add if not scattering reverse");
23314bbf5ea8SMatthew G. Knepley   for (lidx = 0; lidx < dof; ++lidx) {
23324bbf5ea8SMatthew G. Knepley     const PetscInt gidx = gtolArray[offset + lidx];
23334bbf5ea8SMatthew G. Knepley 
23344bbf5ea8SMatthew G. Knepley     if (mode == INSERT_VALUES) yArray[lidx] = xArray[gidx]; /* Forward */
23354bbf5ea8SMatthew G. Knepley     else yArray[gidx] += xArray[lidx];                      /* Reverse */
23364bbf5ea8SMatthew G. Knepley   }
23370904074fSPatrick Farrell   if (scattertype == SCATTER_WITHARTIFICIAL) {
23389566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(patch->gtolWithArtificial, &gtolArray));
23390904074fSPatrick Farrell   } else if (scattertype == SCATTER_WITHALL) {
23409566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(patch->gtolWithAll, &gtolArray));
2341c2e6f3c0SFlorian Wechsung   } else {
23429566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(patch->gtol, &gtolArray));
2343c2e6f3c0SFlorian Wechsung   }
23449566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x, &xArray));
23459566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &yArray));
23464bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
23474bbf5ea8SMatthew G. Knepley }
23484bbf5ea8SMatthew G. Knepley 
23499371c9d4SSatish Balay static PetscErrorCode PCSetUp_PATCH_Linear(PC pc) {
2350dadc69c5SMatthew G. Knepley   PC_PATCH   *patch = (PC_PATCH *)pc->data;
2351dadc69c5SMatthew G. Knepley   const char *prefix;
2352dadc69c5SMatthew G. Knepley   PetscInt    i;
2353dadc69c5SMatthew G. Knepley 
2354dadc69c5SMatthew G. Knepley   PetscFunctionBegin;
2355dadc69c5SMatthew G. Knepley   if (!pc->setupcalled) {
23567827d75bSBarry Smith     PetscCheck(patch->save_operators || !patch->denseinverse, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Can't have dense inverse without save operators");
2357c73d2cf6SLawrence Mitchell     if (!patch->denseinverse) {
23589566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(patch->npatch, &patch->solver));
23599566063dSJacob Faibussowitsch       PetscCall(PCGetOptionsPrefix(pc, &prefix));
2360dadc69c5SMatthew G. Knepley       for (i = 0; i < patch->npatch; ++i) {
2361dadc69c5SMatthew G. Knepley         KSP ksp;
2362dadc69c5SMatthew G. Knepley         PC  subpc;
2363dadc69c5SMatthew G. Knepley 
23649566063dSJacob Faibussowitsch         PetscCall(KSPCreate(PETSC_COMM_SELF, &ksp));
23659566063dSJacob Faibussowitsch         PetscCall(KSPSetErrorIfNotConverged(ksp, pc->erroriffailure));
23669566063dSJacob Faibussowitsch         PetscCall(KSPSetOptionsPrefix(ksp, prefix));
23679566063dSJacob Faibussowitsch         PetscCall(KSPAppendOptionsPrefix(ksp, "sub_"));
23689566063dSJacob Faibussowitsch         PetscCall(PetscObjectIncrementTabLevel((PetscObject)ksp, (PetscObject)pc, 1));
23699566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(ksp, &subpc));
23709566063dSJacob Faibussowitsch         PetscCall(PetscObjectIncrementTabLevel((PetscObject)subpc, (PetscObject)pc, 1));
23719566063dSJacob Faibussowitsch         PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)ksp));
2372dadc69c5SMatthew G. Knepley         patch->solver[i] = (PetscObject)ksp;
2373dadc69c5SMatthew G. Knepley       }
2374dadc69c5SMatthew G. Knepley     }
2375c73d2cf6SLawrence Mitchell   }
2376dadc69c5SMatthew G. Knepley   if (patch->save_operators) {
23771baa6e33SBarry Smith     if (patch->precomputeElementTensors) PetscCall(PCPatchPrecomputePatchTensors_Private(pc));
2378dadc69c5SMatthew G. Knepley     for (i = 0; i < patch->npatch; ++i) {
23799566063dSJacob Faibussowitsch       PetscCall(PCPatchComputeOperator_Internal(pc, NULL, patch->mat[i], i, PETSC_FALSE));
2380c73d2cf6SLawrence Mitchell       if (!patch->denseinverse) {
23819566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators((KSP)patch->solver[i], patch->mat[i], patch->mat[i]));
23829d4fc724SLawrence Mitchell       } else if (patch->mat[i] && !patch->densesolve) {
23839d4fc724SLawrence Mitchell         /* Setup matmult callback */
23849566063dSJacob Faibussowitsch         PetscCall(MatGetOperation(patch->mat[i], MATOP_MULT, (void (**)(void)) & patch->densesolve));
2385dadc69c5SMatthew G. Knepley       }
2386dadc69c5SMatthew G. Knepley     }
2387c73d2cf6SLawrence Mitchell   }
238834d8b122SPatrick Farrell   if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
238934d8b122SPatrick Farrell     for (i = 0; i < patch->npatch; ++i) {
23901202d238SPatrick Farrell       /* Instead of padding patch->patchUpdate with zeros to get */
23911202d238SPatrick Farrell       /* patch->patchUpdateWithArtificial and then multiplying with the matrix, */
239234d8b122SPatrick Farrell       /* just get rid of the columns that correspond to the dofs with */
239334d8b122SPatrick Farrell       /* artificial bcs. That's of course fairly inefficient, hopefully we */
239434d8b122SPatrick Farrell       /* can just assemble the rectangular matrix in the first place. */
239534d8b122SPatrick Farrell       Mat      matSquare;
239634d8b122SPatrick Farrell       IS       rowis;
239734d8b122SPatrick Farrell       PetscInt dof;
239834d8b122SPatrick Farrell 
23999566063dSJacob Faibussowitsch       PetscCall(MatGetSize(patch->mat[i], &dof, NULL));
240034d8b122SPatrick Farrell       if (dof == 0) {
240134d8b122SPatrick Farrell         patch->matWithArtificial[i] = NULL;
240234d8b122SPatrick Farrell         continue;
240334d8b122SPatrick Farrell       }
240434d8b122SPatrick Farrell 
24059566063dSJacob Faibussowitsch       PetscCall(PCPatchCreateMatrix_Private(pc, i, &matSquare, PETSC_TRUE));
24069566063dSJacob Faibussowitsch       PetscCall(PCPatchComputeOperator_Internal(pc, NULL, matSquare, i, PETSC_TRUE));
240734d8b122SPatrick Farrell 
24089566063dSJacob Faibussowitsch       PetscCall(MatGetSize(matSquare, &dof, NULL));
24099566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF, dof, 0, 1, &rowis));
241034d8b122SPatrick Farrell       if (pc->setupcalled) {
24119566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(matSquare, rowis, patch->dofMappingWithoutToWithArtificial[i], MAT_REUSE_MATRIX, &patch->matWithArtificial[i]));
241234d8b122SPatrick Farrell       } else {
24139566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(matSquare, rowis, patch->dofMappingWithoutToWithArtificial[i], MAT_INITIAL_MATRIX, &patch->matWithArtificial[i]));
241434d8b122SPatrick Farrell       }
24159566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&rowis));
24169566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&matSquare));
241734d8b122SPatrick Farrell     }
241834d8b122SPatrick Farrell   }
2419dadc69c5SMatthew G. Knepley   PetscFunctionReturn(0);
2420dadc69c5SMatthew G. Knepley }
2421dadc69c5SMatthew G. Knepley 
24229371c9d4SSatish Balay static PetscErrorCode PCSetUp_PATCH(PC pc) {
24234bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
2424557beb66SLawrence Mitchell   PetscInt  i;
242539fd2e8aSPatrick Farrell   PetscBool isNonlinear;
24269d4fc724SLawrence Mitchell   PetscInt  maxDof = -1, maxDofWithArtificial = -1;
24274bbf5ea8SMatthew G. Knepley 
24284bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
24294bbf5ea8SMatthew G. Knepley   if (!pc->setupcalled) {
24304bbf5ea8SMatthew G. Knepley     PetscInt pStart, pEnd, p;
24314bbf5ea8SMatthew G. Knepley     PetscInt localSize;
24324bbf5ea8SMatthew G. Knepley 
24339566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(PC_Patch_CreatePatches, pc, 0, 0, 0));
24344bbf5ea8SMatthew G. Knepley 
2435debbdec3SPatrick Farrell     isNonlinear = patch->isNonlinear;
24365f824522SMatthew G. Knepley     if (!patch->nsubspaces) {
2437b6bb21d1SLawrence Mitchell       DM           dm, plex;
24385f824522SMatthew G. Knepley       PetscSection s;
2439bd026e97SJed Brown       PetscInt     cStart, cEnd, c, Nf, f, numGlobalBcs = 0, *globalBcs, *Nb, **cellDofs;
24405f824522SMatthew G. Knepley 
24419566063dSJacob Faibussowitsch       PetscCall(PCGetDM(pc, &dm));
244228b400f6SJacob Faibussowitsch       PetscCheck(dm, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "Must set DM for PCPATCH or call PCPatchSetDiscretisationInfo()");
24439566063dSJacob Faibussowitsch       PetscCall(DMConvert(dm, DMPLEX, &plex));
2444b6bb21d1SLawrence Mitchell       dm = plex;
24459566063dSJacob Faibussowitsch       PetscCall(DMGetLocalSection(dm, &s));
24469566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetNumFields(s, &Nf));
24479566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
24485f824522SMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
24495f824522SMatthew G. Knepley         PetscInt cdof;
24509566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
24515f824522SMatthew G. Knepley         numGlobalBcs += cdof;
24525f824522SMatthew G. Knepley       }
24539566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
24549566063dSJacob Faibussowitsch       PetscCall(PetscMalloc3(Nf, &Nb, Nf, &cellDofs, numGlobalBcs, &globalBcs));
24555f824522SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
24565f824522SMatthew G. Knepley         PetscFE        fe;
24575f824522SMatthew G. Knepley         PetscDualSpace sp;
24585f824522SMatthew G. Knepley         PetscInt       cdoff = 0;
24595f824522SMatthew G. Knepley 
24609566063dSJacob Faibussowitsch         PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe));
24619566063dSJacob Faibussowitsch         /* PetscCall(PetscFEGetNumComponents(fe, &Nc[f])); */
24629566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace(fe, &sp));
24639566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetDimension(sp, &Nb[f]));
24645f824522SMatthew G. Knepley 
24659566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1((cEnd - cStart) * Nb[f], &cellDofs[f]));
24665f824522SMatthew G. Knepley         for (c = cStart; c < cEnd; ++c) {
24675f824522SMatthew G. Knepley           PetscInt *closure = NULL;
24685f824522SMatthew G. Knepley           PetscInt  clSize  = 0, cl;
24695f824522SMatthew G. Knepley 
24709566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
24715f824522SMatthew G. Knepley           for (cl = 0; cl < clSize * 2; cl += 2) {
24725f824522SMatthew G. Knepley             const PetscInt p = closure[cl];
24735f824522SMatthew G. Knepley             PetscInt       fdof, d, foff;
24745f824522SMatthew G. Knepley 
24759566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldDof(s, p, f, &fdof));
24769566063dSJacob Faibussowitsch             PetscCall(PetscSectionGetFieldOffset(s, p, f, &foff));
24775f824522SMatthew G. Knepley             for (d = 0; d < fdof; ++d, ++cdoff) cellDofs[f][cdoff] = foff + d;
24785f824522SMatthew G. Knepley           }
24799566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure));
24805f824522SMatthew G. Knepley         }
248163a3b9bcSJacob Faibussowitsch         PetscCheck(cdoff == (cEnd - cStart) * Nb[f], PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_SIZ, "Total number of cellDofs %" PetscInt_FMT " for field %" PetscInt_FMT " should be Nc (%" PetscInt_FMT ") * cellDof (%" PetscInt_FMT ")", cdoff, f, cEnd - cStart, Nb[f]);
24825f824522SMatthew G. Knepley       }
24835f824522SMatthew G. Knepley       numGlobalBcs = 0;
24845f824522SMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
24855f824522SMatthew G. Knepley         const PetscInt *ind;
24865f824522SMatthew G. Knepley         PetscInt        off, cdof, d;
24875f824522SMatthew G. Knepley 
24889566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(s, p, &off));
24899566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
24909566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetConstraintIndices(s, p, &ind));
24915f824522SMatthew G. Knepley         for (d = 0; d < cdof; ++d) globalBcs[numGlobalBcs++] = off + ind[d];
24925f824522SMatthew G. Knepley       }
24935f824522SMatthew G. Knepley 
24949566063dSJacob Faibussowitsch       PetscCall(PCPatchSetDiscretisationInfoCombined(pc, dm, Nb, (const PetscInt **)cellDofs, numGlobalBcs, globalBcs, numGlobalBcs, globalBcs));
249548a46eb9SPierre Jolivet       for (f = 0; f < Nf; ++f) PetscCall(PetscFree(cellDofs[f]));
24969566063dSJacob Faibussowitsch       PetscCall(PetscFree3(Nb, cellDofs, globalBcs));
24979566063dSJacob Faibussowitsch       PetscCall(PCPatchSetComputeFunction(pc, PCPatchComputeFunction_DMPlex_Private, NULL));
24989566063dSJacob Faibussowitsch       PetscCall(PCPatchSetComputeOperator(pc, PCPatchComputeOperator_DMPlex_Private, NULL));
24999566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&dm));
25005f824522SMatthew G. Knepley     }
25015f824522SMatthew G. Knepley 
25024bbf5ea8SMatthew G. Knepley     localSize = patch->subspaceOffsets[patch->nsubspaces];
25039566063dSJacob Faibussowitsch     PetscCall(VecCreateSeq(PETSC_COMM_SELF, localSize, &patch->localRHS));
25049566063dSJacob Faibussowitsch     PetscCall(VecSetUp(patch->localRHS));
25059566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(patch->localRHS, &patch->localUpdate));
25069566063dSJacob Faibussowitsch     PetscCall(PCPatchCreateCellPatches(pc));
25079566063dSJacob Faibussowitsch     PetscCall(PCPatchCreateCellPatchDiscretisationInfo(pc));
25084bbf5ea8SMatthew G. Knepley 
25094bbf5ea8SMatthew G. Knepley     /* OK, now build the work vectors */
25109566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(patch->gtolCounts, &pStart, &pEnd));
2511c2e6f3c0SFlorian Wechsung 
251248a46eb9SPierre Jolivet     if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) PetscCall(PetscMalloc1(patch->npatch, &patch->dofMappingWithoutToWithArtificial));
251348a46eb9SPierre Jolivet     if (isNonlinear) PetscCall(PetscMalloc1(patch->npatch, &patch->dofMappingWithoutToWithAll));
25144bbf5ea8SMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
25154bbf5ea8SMatthew G. Knepley       PetscInt dof;
25164bbf5ea8SMatthew G. Knepley 
25179566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(patch->gtolCounts, p, &dof));
25182f613bf5SBarry Smith       maxDof = PetscMax(maxDof, dof);
25190904074fSPatrick Farrell       if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
25203bb0e8f7SKarl Rupp         const PetscInt *gtolArray, *gtolArrayWithArtificial = NULL;
25213bb0e8f7SKarl Rupp         PetscInt        numPatchDofs, offset;
25223bb0e8f7SKarl Rupp         PetscInt        numPatchDofsWithArtificial, offsetWithArtificial;
25233bb0e8f7SKarl Rupp         PetscInt        dofWithoutArtificialCounter = 0;
25243bb0e8f7SKarl Rupp         PetscInt       *patchWithoutArtificialToWithArtificialArray;
25253bb0e8f7SKarl Rupp 
25269566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(patch->gtolCountsWithArtificial, p, &dof));
25279d4fc724SLawrence Mitchell         maxDofWithArtificial = PetscMax(maxDofWithArtificial, dof);
2528c2e6f3c0SFlorian Wechsung 
2529e047a90bSFlorian Wechsung         /* Now build the mapping that for a dof in a patch WITHOUT dofs that have artificial bcs gives the */
2530e047a90bSFlorian Wechsung         /* the index in the patch with all dofs */
25319566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(patch->gtol, &gtolArray));
253263deea8eSPatrick Farrell 
25339566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(patch->gtolCounts, p, &numPatchDofs));
253447aca4a6SPatrick Farrell         if (numPatchDofs == 0) {
253547aca4a6SPatrick Farrell           patch->dofMappingWithoutToWithArtificial[p - pStart] = NULL;
253647aca4a6SPatrick Farrell           continue;
253747aca4a6SPatrick Farrell         }
253863deea8eSPatrick Farrell 
25399566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(patch->gtolCounts, p, &offset));
25409566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(patch->gtolWithArtificial, &gtolArrayWithArtificial));
25419566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(patch->gtolCountsWithArtificial, p, &numPatchDofsWithArtificial));
25429566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(patch->gtolCountsWithArtificial, p, &offsetWithArtificial));
2543c2e6f3c0SFlorian Wechsung 
25449566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(numPatchDofs, &patchWithoutArtificialToWithArtificialArray));
2545b0c21b6aSKarl Rupp         for (i = 0; i < numPatchDofsWithArtificial; i++) {
2546e047a90bSFlorian Wechsung           if (gtolArrayWithArtificial[i + offsetWithArtificial] == gtolArray[offset + dofWithoutArtificialCounter]) {
2547c2e6f3c0SFlorian Wechsung             patchWithoutArtificialToWithArtificialArray[dofWithoutArtificialCounter] = i;
2548c2e6f3c0SFlorian Wechsung             dofWithoutArtificialCounter++;
25499371c9d4SSatish Balay             if (dofWithoutArtificialCounter == numPatchDofs) break;
2550c2e6f3c0SFlorian Wechsung           }
2551c2e6f3c0SFlorian Wechsung         }
25529566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numPatchDofs, patchWithoutArtificialToWithArtificialArray, PETSC_OWN_POINTER, &patch->dofMappingWithoutToWithArtificial[p - pStart]));
25539566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(patch->gtol, &gtolArray));
25549566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(patch->gtolWithArtificial, &gtolArrayWithArtificial));
2555c2e6f3c0SFlorian Wechsung       }
25560997d788SPatrick Farrell     }
25570997d788SPatrick Farrell     for (p = pStart; p < pEnd; ++p) {
25580904074fSPatrick Farrell       if (isNonlinear) {
25590904074fSPatrick Farrell         const PetscInt *gtolArray, *gtolArrayWithAll = NULL;
25600904074fSPatrick Farrell         PetscInt        numPatchDofs, offset;
25610904074fSPatrick Farrell         PetscInt        numPatchDofsWithAll, offsetWithAll;
25620904074fSPatrick Farrell         PetscInt        dofWithoutAllCounter = 0;
25630904074fSPatrick Farrell         PetscInt       *patchWithoutAllToWithAllArray;
25640904074fSPatrick Farrell 
25650904074fSPatrick Farrell         /* Now build the mapping that for a dof in a patch WITHOUT dofs that have artificial bcs gives the */
25660904074fSPatrick Farrell         /* the index in the patch with all dofs */
25679566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(patch->gtol, &gtolArray));
25680904074fSPatrick Farrell 
25699566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(patch->gtolCounts, p, &numPatchDofs));
257047aca4a6SPatrick Farrell         if (numPatchDofs == 0) {
2571b88cb22dSPatrick Farrell           patch->dofMappingWithoutToWithAll[p - pStart] = NULL;
257247aca4a6SPatrick Farrell           continue;
257347aca4a6SPatrick Farrell         }
25740904074fSPatrick Farrell 
25759566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(patch->gtolCounts, p, &offset));
25769566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(patch->gtolWithAll, &gtolArrayWithAll));
25779566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(patch->gtolCountsWithAll, p, &numPatchDofsWithAll));
25789566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(patch->gtolCountsWithAll, p, &offsetWithAll));
25790904074fSPatrick Farrell 
25809566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(numPatchDofs, &patchWithoutAllToWithAllArray));
25810904074fSPatrick Farrell 
25820904074fSPatrick Farrell         for (i = 0; i < numPatchDofsWithAll; i++) {
25830904074fSPatrick Farrell           if (gtolArrayWithAll[i + offsetWithAll] == gtolArray[offset + dofWithoutAllCounter]) {
25840904074fSPatrick Farrell             patchWithoutAllToWithAllArray[dofWithoutAllCounter] = i;
25850904074fSPatrick Farrell             dofWithoutAllCounter++;
25869371c9d4SSatish Balay             if (dofWithoutAllCounter == numPatchDofs) break;
25870904074fSPatrick Farrell           }
25880904074fSPatrick Farrell         }
25899566063dSJacob Faibussowitsch         PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numPatchDofs, patchWithoutAllToWithAllArray, PETSC_OWN_POINTER, &patch->dofMappingWithoutToWithAll[p - pStart]));
25909566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(patch->gtol, &gtolArray));
25919566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(patch->gtolWithAll, &gtolArrayWithAll));
25920904074fSPatrick Farrell       }
25934bbf5ea8SMatthew G. Knepley     }
259460dd46caSLawrence Mitchell     if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
25959566063dSJacob Faibussowitsch       PetscCall(VecCreateSeq(PETSC_COMM_SELF, maxDofWithArtificial, &patch->patchRHSWithArtificial));
25969566063dSJacob Faibussowitsch       PetscCall(VecSetUp(patch->patchRHSWithArtificial));
259760dd46caSLawrence Mitchell     }
25989566063dSJacob Faibussowitsch     PetscCall(VecCreateSeq(PETSC_COMM_SELF, maxDof, &patch->patchRHS));
25999566063dSJacob Faibussowitsch     PetscCall(VecSetUp(patch->patchRHS));
26009566063dSJacob Faibussowitsch     PetscCall(VecCreateSeq(PETSC_COMM_SELF, maxDof, &patch->patchUpdate));
26019566063dSJacob Faibussowitsch     PetscCall(VecSetUp(patch->patchUpdate));
26024bbf5ea8SMatthew G. Knepley     if (patch->save_operators) {
26039566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(patch->npatch, &patch->mat));
260448a46eb9SPierre Jolivet       for (i = 0; i < patch->npatch; ++i) PetscCall(PCPatchCreateMatrix_Private(pc, i, &patch->mat[i], PETSC_FALSE));
26054bbf5ea8SMatthew G. Knepley     }
26069566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(PC_Patch_CreatePatches, pc, 0, 0, 0));
26074bbf5ea8SMatthew G. Knepley 
26084bbf5ea8SMatthew G. Knepley     /* If desired, calculate weights for dof multiplicity */
26094bbf5ea8SMatthew G. Knepley     if (patch->partition_of_unity) {
26103bb0e8f7SKarl Rupp       PetscScalar *input  = NULL;
26113bb0e8f7SKarl Rupp       PetscScalar *output = NULL;
26123bb0e8f7SKarl Rupp       Vec          global;
26133bb0e8f7SKarl Rupp 
26149566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(patch->localRHS, &patch->dof_weights));
261561c4b389SFlorian Wechsung       if (patch->local_composition_type == PC_COMPOSITE_ADDITIVE) {
26164bbf5ea8SMatthew G. Knepley         for (i = 0; i < patch->npatch; ++i) {
26174bbf5ea8SMatthew G. Knepley           PetscInt dof;
26184bbf5ea8SMatthew G. Knepley 
26199566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetDof(patch->gtolCounts, i + pStart, &dof));
26204bbf5ea8SMatthew G. Knepley           if (dof <= 0) continue;
26219566063dSJacob Faibussowitsch           PetscCall(VecSet(patch->patchRHS, 1.0));
26229566063dSJacob Faibussowitsch           PetscCall(PCPatch_ScatterLocal_Private(pc, i + pStart, patch->patchRHS, patch->dof_weights, ADD_VALUES, SCATTER_REVERSE, SCATTER_INTERIOR));
26234bbf5ea8SMatthew G. Knepley         }
2624c2e6f3c0SFlorian Wechsung       } else {
2625e047a90bSFlorian Wechsung         /* multiplicative is actually only locally multiplicative and globally additive. need the pou where the mesh decomposition overlaps */
26269566063dSJacob Faibussowitsch         PetscCall(VecSet(patch->dof_weights, 1.0));
26274bbf5ea8SMatthew G. Knepley       }
2628d132cafaSFlorian Wechsung 
2629d132cafaSFlorian Wechsung       VecDuplicate(patch->dof_weights, &global);
2630d132cafaSFlorian Wechsung       VecSet(global, 0.);
2631d132cafaSFlorian Wechsung 
26329566063dSJacob Faibussowitsch       PetscCall(VecGetArray(patch->dof_weights, &input));
26339566063dSJacob Faibussowitsch       PetscCall(VecGetArray(global, &output));
26349566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(patch->sectionSF, MPIU_SCALAR, input, output, MPI_SUM));
26359566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(patch->sectionSF, MPIU_SCALAR, input, output, MPI_SUM));
26369566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(patch->dof_weights, &input));
26379566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(global, &output));
2638d132cafaSFlorian Wechsung 
26399566063dSJacob Faibussowitsch       PetscCall(VecReciprocal(global));
2640d132cafaSFlorian Wechsung 
26419566063dSJacob Faibussowitsch       PetscCall(VecGetArray(patch->dof_weights, &output));
26429566063dSJacob Faibussowitsch       PetscCall(VecGetArray(global, &input));
26439566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(patch->sectionSF, MPIU_SCALAR, input, output, MPI_REPLACE));
26449566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(patch->sectionSF, MPIU_SCALAR, input, output, MPI_REPLACE));
26459566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(patch->dof_weights, &output));
26469566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(global, &input));
26479566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&global));
26484bbf5ea8SMatthew G. Knepley     }
264948a46eb9SPierre Jolivet     if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE && patch->save_operators && !patch->isNonlinear) PetscCall(PetscMalloc1(patch->npatch, &patch->matWithArtificial));
26504bbf5ea8SMatthew G. Knepley   }
26519566063dSJacob Faibussowitsch   PetscCall((*patch->setupsolver)(pc));
2652dadc69c5SMatthew G. Knepley   PetscFunctionReturn(0);
26534bbf5ea8SMatthew G. Knepley }
2654dadc69c5SMatthew G. Knepley 
26559371c9d4SSatish Balay static PetscErrorCode PCApply_PATCH_Linear(PC pc, PetscInt i, Vec x, Vec y) {
2656dadc69c5SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
2657c73d2cf6SLawrence Mitchell   KSP       ksp;
26589d4fc724SLawrence Mitchell   Mat       op;
26599d4fc724SLawrence Mitchell   PetscInt  m, n;
2660dadc69c5SMatthew G. Knepley 
2661dadc69c5SMatthew G. Knepley   PetscFunctionBegin;
2662c73d2cf6SLawrence Mitchell   if (patch->denseinverse) {
26639566063dSJacob Faibussowitsch     PetscCall((*patch->densesolve)(patch->mat[i], x, y));
2664c73d2cf6SLawrence Mitchell     PetscFunctionReturn(0);
2665c73d2cf6SLawrence Mitchell   }
2666c73d2cf6SLawrence Mitchell   ksp = (KSP)patch->solver[i];
2667dadc69c5SMatthew G. Knepley   if (!patch->save_operators) {
2668dadc69c5SMatthew G. Knepley     Mat mat;
2669dadc69c5SMatthew G. Knepley 
26709566063dSJacob Faibussowitsch     PetscCall(PCPatchCreateMatrix_Private(pc, i, &mat, PETSC_FALSE));
2671dadc69c5SMatthew G. Knepley     /* Populate operator here. */
26729566063dSJacob Faibussowitsch     PetscCall(PCPatchComputeOperator_Internal(pc, NULL, mat, i, PETSC_FALSE));
26739566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(ksp, mat, mat));
2674dadc69c5SMatthew G. Knepley     /* Drop reference so the KSPSetOperators below will blow it away. */
26759566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&mat));
2676dadc69c5SMatthew G. Knepley   }
26779566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_Patch_Solve, pc, 0, 0, 0));
267848a46eb9SPierre Jolivet   if (!ksp->setfromoptionscalled) PetscCall(KSPSetFromOptions(ksp));
26799d4fc724SLawrence Mitchell   /* Disgusting trick to reuse work vectors */
26809566063dSJacob Faibussowitsch   PetscCall(KSPGetOperators(ksp, &op, NULL));
26819566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(op, &m, &n));
26829d4fc724SLawrence Mitchell   x->map->n = m;
26839d4fc724SLawrence Mitchell   y->map->n = n;
26849d4fc724SLawrence Mitchell   x->map->N = m;
26859d4fc724SLawrence Mitchell   y->map->N = n;
26869566063dSJacob Faibussowitsch   PetscCall(KSPSolve(ksp, x, y));
26879566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(ksp, pc, y));
26889566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_Patch_Solve, pc, 0, 0, 0));
2689dadc69c5SMatthew G. Knepley   if (!patch->save_operators) {
2690dadc69c5SMatthew G. Knepley     PC pc;
26919566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(ksp, NULL, NULL));
26929566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(ksp, &pc));
2693dadc69c5SMatthew G. Knepley     /* Destroy PC context too, otherwise the factored matrix hangs around. */
26949566063dSJacob Faibussowitsch     PetscCall(PCReset(pc));
26954bbf5ea8SMatthew G. Knepley   }
26964bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
26974bbf5ea8SMatthew G. Knepley }
26984bbf5ea8SMatthew G. Knepley 
26999371c9d4SSatish Balay static PetscErrorCode PCUpdateMultiplicative_PATCH_Linear(PC pc, PetscInt i, PetscInt pStart) {
27006c9c532dSPatrick Farrell   PC_PATCH *patch = (PC_PATCH *)pc->data;
27016c9c532dSPatrick Farrell   Mat       multMat;
27029d4fc724SLawrence Mitchell   PetscInt  n, m;
27036c9c532dSPatrick Farrell 
27044d04e9f1SPatrick Farrell   PetscFunctionBegin;
27054d04e9f1SPatrick Farrell 
27066c9c532dSPatrick Farrell   if (patch->save_operators) {
27076c9c532dSPatrick Farrell     multMat = patch->matWithArtificial[i];
27086c9c532dSPatrick Farrell   } else {
27096c9c532dSPatrick Farrell     /*Very inefficient, hopefully we can just assemble the rectangular matrix in the first place.*/
27106c9c532dSPatrick Farrell     Mat      matSquare;
27116c9c532dSPatrick Farrell     PetscInt dof;
27126c9c532dSPatrick Farrell     IS       rowis;
27139566063dSJacob Faibussowitsch     PetscCall(PCPatchCreateMatrix_Private(pc, i, &matSquare, PETSC_TRUE));
27149566063dSJacob Faibussowitsch     PetscCall(PCPatchComputeOperator_Internal(pc, NULL, matSquare, i, PETSC_TRUE));
27159566063dSJacob Faibussowitsch     PetscCall(MatGetSize(matSquare, &dof, NULL));
27169566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, dof, 0, 1, &rowis));
27179566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(matSquare, rowis, patch->dofMappingWithoutToWithArtificial[i], MAT_INITIAL_MATRIX, &multMat));
27189566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&matSquare));
27199566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&rowis));
27206c9c532dSPatrick Farrell   }
27219d4fc724SLawrence Mitchell   /* Disgusting trick to reuse work vectors */
27229566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(multMat, &m, &n));
27239d4fc724SLawrence Mitchell   patch->patchUpdate->map->n            = n;
27249d4fc724SLawrence Mitchell   patch->patchRHSWithArtificial->map->n = m;
27259d4fc724SLawrence Mitchell   patch->patchUpdate->map->N            = n;
27269d4fc724SLawrence Mitchell   patch->patchRHSWithArtificial->map->N = m;
27279566063dSJacob Faibussowitsch   PetscCall(MatMult(multMat, patch->patchUpdate, patch->patchRHSWithArtificial));
27289566063dSJacob Faibussowitsch   PetscCall(VecScale(patch->patchRHSWithArtificial, -1.0));
27299566063dSJacob Faibussowitsch   PetscCall(PCPatch_ScatterLocal_Private(pc, i + pStart, patch->patchRHSWithArtificial, patch->localRHS, ADD_VALUES, SCATTER_REVERSE, SCATTER_WITHARTIFICIAL));
273048a46eb9SPierre Jolivet   if (!patch->save_operators) PetscCall(MatDestroy(&multMat));
27314d04e9f1SPatrick Farrell   PetscFunctionReturn(0);
27326c9c532dSPatrick Farrell }
27336c9c532dSPatrick Farrell 
27349371c9d4SSatish Balay static PetscErrorCode PCApply_PATCH(PC pc, Vec x, Vec y) {
27354bbf5ea8SMatthew G. Knepley   PC_PATCH          *patch        = (PC_PATCH *)pc->data;
27361202d238SPatrick Farrell   const PetscScalar *globalRHS    = NULL;
27371202d238SPatrick Farrell   PetscScalar       *localRHS     = NULL;
27381202d238SPatrick Farrell   PetscScalar       *globalUpdate = NULL;
27394bbf5ea8SMatthew G. Knepley   const PetscInt    *bcNodes      = NULL;
27404bbf5ea8SMatthew G. Knepley   PetscInt           nsweep       = patch->symmetrise_sweep ? 2 : 1;
27414bbf5ea8SMatthew G. Knepley   PetscInt           start[2]     = {0, 0};
27424bbf5ea8SMatthew G. Knepley   PetscInt           end[2]       = {-1, -1};
27434bbf5ea8SMatthew G. Knepley   const PetscInt     inc[2]       = {1, -1};
27441202d238SPatrick Farrell   const PetscScalar *localUpdate;
27454bbf5ea8SMatthew G. Knepley   const PetscInt    *iterationSet;
27464bbf5ea8SMatthew G. Knepley   PetscInt           pStart, numBcs, n, sweep, bc, j;
27474bbf5ea8SMatthew G. Knepley 
27484bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
27499566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_Patch_Apply, pc, 0, 0, 0));
27509566063dSJacob Faibussowitsch   PetscCall(PetscOptionsPushGetViewerOff(PETSC_TRUE));
275192d50984SMatthew G. Knepley   /* start, end, inc have 2 entries to manage a second backward sweep if we symmetrize */
27524bbf5ea8SMatthew G. Knepley   end[0]   = patch->npatch;
27534bbf5ea8SMatthew G. Knepley   start[1] = patch->npatch - 1;
27544bbf5ea8SMatthew G. Knepley   if (patch->user_patches) {
27559566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(patch->iterationSet, &end[0]));
27564bbf5ea8SMatthew G. Knepley     start[1] = end[0] - 1;
27579566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(patch->iterationSet, &iterationSet));
27584bbf5ea8SMatthew G. Knepley   }
27594bbf5ea8SMatthew G. Knepley   /* Scatter from global space into overlapped local spaces */
27609566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x, &globalRHS));
27619566063dSJacob Faibussowitsch   PetscCall(VecGetArray(patch->localRHS, &localRHS));
27629566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(patch->sectionSF, MPIU_SCALAR, globalRHS, localRHS, MPI_REPLACE));
27639566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(patch->sectionSF, MPIU_SCALAR, globalRHS, localRHS, MPI_REPLACE));
27649566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x, &globalRHS));
27659566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(patch->localRHS, &localRHS));
27664bbf5ea8SMatthew G. Knepley 
27679566063dSJacob Faibussowitsch   PetscCall(VecSet(patch->localUpdate, 0.0));
27689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(patch->gtolCounts, &pStart, NULL));
27699566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PC_Patch_Solve, pc, 0, 0, 0));
27704bbf5ea8SMatthew G. Knepley   for (sweep = 0; sweep < nsweep; sweep++) {
27714bbf5ea8SMatthew G. Knepley     for (j = start[sweep]; j * inc[sweep] < end[sweep] * inc[sweep]; j += inc[sweep]) {
27724bbf5ea8SMatthew G. Knepley       PetscInt i = patch->user_patches ? iterationSet[j] : j;
27734bbf5ea8SMatthew G. Knepley       PetscInt start, len;
27744bbf5ea8SMatthew G. Knepley 
27759566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(patch->gtolCounts, i + pStart, &len));
27769566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(patch->gtolCounts, i + pStart, &start));
27774bbf5ea8SMatthew G. Knepley       /* TODO: Squash out these guys in the setup as well. */
27784bbf5ea8SMatthew G. Knepley       if (len <= 0) continue;
27794bbf5ea8SMatthew G. Knepley       /* TODO: Do we need different scatters for X and Y? */
27809566063dSJacob Faibussowitsch       PetscCall(PCPatch_ScatterLocal_Private(pc, i + pStart, patch->localRHS, patch->patchRHS, INSERT_VALUES, SCATTER_FORWARD, SCATTER_INTERIOR));
27819566063dSJacob Faibussowitsch       PetscCall((*patch->applysolver)(pc, i, patch->patchRHS, patch->patchUpdate));
27829566063dSJacob Faibussowitsch       PetscCall(PCPatch_ScatterLocal_Private(pc, i + pStart, patch->patchUpdate, patch->localUpdate, ADD_VALUES, SCATTER_REVERSE, SCATTER_INTERIOR));
278348a46eb9SPierre Jolivet       if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) PetscCall((*patch->updatemultiplicative)(pc, i, pStart));
27844bbf5ea8SMatthew G. Knepley     }
27854bbf5ea8SMatthew G. Knepley   }
27869566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_Patch_Solve, pc, 0, 0, 0));
27879566063dSJacob Faibussowitsch   if (patch->user_patches) PetscCall(ISRestoreIndices(patch->iterationSet, &iterationSet));
27884bbf5ea8SMatthew G. Knepley   /* XXX: should we do this on the global vector? */
27891baa6e33SBarry Smith   if (patch->partition_of_unity) PetscCall(VecPointwiseMult(patch->localUpdate, patch->localUpdate, patch->dof_weights));
27901202d238SPatrick Farrell   /* Now patch->localUpdate contains the solution of the patch solves, so we need to combine them all. */
27919566063dSJacob Faibussowitsch   PetscCall(VecSet(y, 0.0));
27929566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &globalUpdate));
27939566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(patch->localUpdate, &localUpdate));
27949566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(patch->sectionSF, MPIU_SCALAR, localUpdate, globalUpdate, MPI_SUM));
27959566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(patch->sectionSF, MPIU_SCALAR, localUpdate, globalUpdate, MPI_SUM));
27969566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(patch->localUpdate, &localUpdate));
27974bbf5ea8SMatthew G. Knepley 
27984bbf5ea8SMatthew G. Knepley   /* Now we need to send the global BC values through */
27999566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(x, &globalRHS));
28009566063dSJacob Faibussowitsch   PetscCall(ISGetSize(patch->globalBcNodes, &numBcs));
28019566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(patch->globalBcNodes, &bcNodes));
28029566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(x, &n));
28034bbf5ea8SMatthew G. Knepley   for (bc = 0; bc < numBcs; ++bc) {
28044bbf5ea8SMatthew G. Knepley     const PetscInt idx = bcNodes[bc];
28051202d238SPatrick Farrell     if (idx < n) globalUpdate[idx] = globalRHS[idx];
28064bbf5ea8SMatthew G. Knepley   }
28074bbf5ea8SMatthew G. Knepley 
28089566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(patch->globalBcNodes, &bcNodes));
28099566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(x, &globalRHS));
28109566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &globalUpdate));
28114bbf5ea8SMatthew G. Knepley 
28129566063dSJacob Faibussowitsch   PetscCall(PetscOptionsPopGetViewerOff());
28139566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PC_Patch_Apply, pc, 0, 0, 0));
28144bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
28154bbf5ea8SMatthew G. Knepley }
28164bbf5ea8SMatthew G. Knepley 
28179371c9d4SSatish Balay static PetscErrorCode PCReset_PATCH_Linear(PC pc) {
2818dadc69c5SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
2819dadc69c5SMatthew G. Knepley   PetscInt  i;
2820dadc69c5SMatthew G. Knepley 
2821dadc69c5SMatthew G. Knepley   PetscFunctionBegin;
2822dadc69c5SMatthew G. Knepley   if (patch->solver) {
28239566063dSJacob Faibussowitsch     for (i = 0; i < patch->npatch; ++i) PetscCall(KSPReset((KSP)patch->solver[i]));
2824dadc69c5SMatthew G. Knepley   }
2825dadc69c5SMatthew G. Knepley   PetscFunctionReturn(0);
2826dadc69c5SMatthew G. Knepley }
2827dadc69c5SMatthew G. Knepley 
28289371c9d4SSatish Balay static PetscErrorCode PCReset_PATCH(PC pc) {
28294bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
28304bbf5ea8SMatthew G. Knepley   PetscInt  i;
28314bbf5ea8SMatthew G. Knepley 
28324bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
2833fa84ea4cSLawrence Mitchell 
28349566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&patch->sectionSF));
28359566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&patch->cellCounts));
28369566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&patch->pointCounts));
28379566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&patch->cellNumbering));
28389566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&patch->gtolCounts));
28399566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&patch->gtol));
28409566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&patch->cells));
28419566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&patch->points));
28429566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&patch->dofs));
28439566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&patch->offs));
28449566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&patch->patchSection));
28459566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&patch->ghostBcNodes));
28469566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&patch->globalBcNodes));
28479566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&patch->gtolCountsWithArtificial));
28489566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&patch->gtolWithArtificial));
28499566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&patch->dofsWithArtificial));
28509566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&patch->offsWithArtificial));
28519566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&patch->gtolCountsWithAll));
28529566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&patch->gtolWithAll));
28539566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&patch->dofsWithAll));
28549566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&patch->offsWithAll));
28559566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&patch->cellMats));
28569566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&patch->intFacetMats));
28579566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&patch->allCells));
28589566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&patch->intFacets));
28599566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&patch->extFacets));
28609566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&patch->intFacetsToPatchCell));
28619566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&patch->intFacetCounts));
28629566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&patch->extFacetCounts));
28634bbf5ea8SMatthew G. Knepley 
28649371c9d4SSatish Balay   if (patch->dofSection)
28659371c9d4SSatish Balay     for (i = 0; i < patch->nsubspaces; i++) PetscCall(PetscSectionDestroy(&patch->dofSection[i]));
28669566063dSJacob Faibussowitsch   PetscCall(PetscFree(patch->dofSection));
28679566063dSJacob Faibussowitsch   PetscCall(PetscFree(patch->bs));
28689566063dSJacob Faibussowitsch   PetscCall(PetscFree(patch->nodesPerCell));
28699371c9d4SSatish Balay   if (patch->cellNodeMap)
28709371c9d4SSatish Balay     for (i = 0; i < patch->nsubspaces; i++) PetscCall(PetscFree(patch->cellNodeMap[i]));
28719566063dSJacob Faibussowitsch   PetscCall(PetscFree(patch->cellNodeMap));
28729566063dSJacob Faibussowitsch   PetscCall(PetscFree(patch->subspaceOffsets));
28734bbf5ea8SMatthew G. Knepley 
28749566063dSJacob Faibussowitsch   PetscCall((*patch->resetsolver)(pc));
28754bbf5ea8SMatthew G. Knepley 
287648a46eb9SPierre Jolivet   if (patch->subspaces_to_exclude) PetscCall(PetscHSetIDestroy(&patch->subspaces_to_exclude));
2877e4c66b91SPatrick Farrell 
28789566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&patch->localRHS));
28799566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&patch->localUpdate));
28809566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&patch->patchRHS));
28819566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&patch->patchUpdate));
28829566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&patch->dof_weights));
28834bbf5ea8SMatthew G. Knepley   if (patch->patch_dof_weights) {
28849566063dSJacob Faibussowitsch     for (i = 0; i < patch->npatch; ++i) PetscCall(VecDestroy(&patch->patch_dof_weights[i]));
28859566063dSJacob Faibussowitsch     PetscCall(PetscFree(patch->patch_dof_weights));
28864bbf5ea8SMatthew G. Knepley   }
28874bbf5ea8SMatthew G. Knepley   if (patch->mat) {
28889566063dSJacob Faibussowitsch     for (i = 0; i < patch->npatch; ++i) PetscCall(MatDestroy(&patch->mat[i]));
28899566063dSJacob Faibussowitsch     PetscCall(PetscFree(patch->mat));
28905f824522SMatthew G. Knepley   }
28910997d788SPatrick Farrell   if (patch->matWithArtificial && !patch->isNonlinear) {
28929566063dSJacob Faibussowitsch     for (i = 0; i < patch->npatch; ++i) PetscCall(MatDestroy(&patch->matWithArtificial[i]));
28939566063dSJacob Faibussowitsch     PetscCall(PetscFree(patch->matWithArtificial));
289411ac8bb0SFlorian Wechsung   }
28959566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&patch->patchRHSWithArtificial));
289696b79ebeSFlorian Wechsung   if (patch->dofMappingWithoutToWithArtificial) {
28979566063dSJacob Faibussowitsch     for (i = 0; i < patch->npatch; ++i) PetscCall(ISDestroy(&patch->dofMappingWithoutToWithArtificial[i]));
28989566063dSJacob Faibussowitsch     PetscCall(PetscFree(patch->dofMappingWithoutToWithArtificial));
289996b79ebeSFlorian Wechsung   }
29000904074fSPatrick Farrell   if (patch->dofMappingWithoutToWithAll) {
29019566063dSJacob Faibussowitsch     for (i = 0; i < patch->npatch; ++i) PetscCall(ISDestroy(&patch->dofMappingWithoutToWithAll[i]));
29029566063dSJacob Faibussowitsch     PetscCall(PetscFree(patch->dofMappingWithoutToWithAll));
29030904074fSPatrick Farrell   }
29049566063dSJacob Faibussowitsch   PetscCall(PetscFree(patch->sub_mat_type));
29055f824522SMatthew G. Knepley   if (patch->userIS) {
29069566063dSJacob Faibussowitsch     for (i = 0; i < patch->npatch; ++i) PetscCall(ISDestroy(&patch->userIS[i]));
29079566063dSJacob Faibussowitsch     PetscCall(PetscFree(patch->userIS));
29085f824522SMatthew G. Knepley   }
29099566063dSJacob Faibussowitsch   PetscCall(PetscFree(patch->precomputedTensorLocations));
29109566063dSJacob Faibussowitsch   PetscCall(PetscFree(patch->precomputedIntFacetTensorLocations));
2911f98464cbSLawrence Mitchell 
29120a545947SLisandro Dalcin   patch->bs          = NULL;
29134bbf5ea8SMatthew G. Knepley   patch->cellNodeMap = NULL;
29147974b488SMatthew G. Knepley   patch->nsubspaces  = 0;
29159566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&patch->iterationSet));
29165f824522SMatthew G. Knepley 
29179566063dSJacob Faibussowitsch   PetscCall(PetscViewerDestroy(&patch->viewerSection));
29184bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
29194bbf5ea8SMatthew G. Knepley }
29204bbf5ea8SMatthew G. Knepley 
29219371c9d4SSatish Balay static PetscErrorCode PCDestroy_PATCH_Linear(PC pc) {
29224bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
29234bbf5ea8SMatthew G. Knepley   PetscInt  i;
29244bbf5ea8SMatthew G. Knepley 
29254bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
2926dadc69c5SMatthew G. Knepley   if (patch->solver) {
29279566063dSJacob Faibussowitsch     for (i = 0; i < patch->npatch; ++i) PetscCall(KSPDestroy((KSP *)&patch->solver[i]));
29289566063dSJacob Faibussowitsch     PetscCall(PetscFree(patch->solver));
29294bbf5ea8SMatthew G. Knepley   }
2930dadc69c5SMatthew G. Knepley   PetscFunctionReturn(0);
2931dadc69c5SMatthew G. Knepley }
2932dadc69c5SMatthew G. Knepley 
29339371c9d4SSatish Balay static PetscErrorCode PCDestroy_PATCH(PC pc) {
2934dadc69c5SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *)pc->data;
2935dadc69c5SMatthew G. Knepley 
2936dadc69c5SMatthew G. Knepley   PetscFunctionBegin;
29379566063dSJacob Faibussowitsch   PetscCall(PCReset_PATCH(pc));
29389566063dSJacob Faibussowitsch   PetscCall((*patch->destroysolver)(pc));
29399566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
29404bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
29414bbf5ea8SMatthew G. Knepley }
29424bbf5ea8SMatthew G. Knepley 
29439371c9d4SSatish Balay static PetscErrorCode PCSetFromOptions_PATCH(PC pc, PetscOptionItems *PetscOptionsObject) {
29444bbf5ea8SMatthew G. Knepley   PC_PATCH            *patch                 = (PC_PATCH *)pc->data;
29454bbf5ea8SMatthew G. Knepley   PCPatchConstructType patchConstructionType = PC_PATCH_STAR;
29465f824522SMatthew G. Knepley   char                 sub_mat_type[PETSC_MAX_PATH_LEN];
294710534d48SPatrick Farrell   char                 option[PETSC_MAX_PATH_LEN];
29485f824522SMatthew G. Knepley   const char          *prefix;
29494bbf5ea8SMatthew G. Knepley   PetscBool            flg, dimflg, codimflg;
29505f824522SMatthew G. Knepley   MPI_Comm             comm;
2951a48c39c8SPatrick Farrell   PetscInt            *ifields, nfields, k;
295261c4b389SFlorian Wechsung   PCCompositeType      loctype = PC_COMPOSITE_ADDITIVE;
29534bbf5ea8SMatthew G. Knepley 
29544bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
29559566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
29569566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)pc, &prefix));
2957d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Patch solver options");
295810534d48SPatrick Farrell 
29599566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_save_operators", patch->classname));
29609566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool(option, "Store all patch operators for lifetime of object?", "PCPatchSetSaveOperators", patch->save_operators, &patch->save_operators, &flg));
296110534d48SPatrick Farrell 
29629566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_precompute_element_tensors", patch->classname));
29639566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool(option, "Compute each element tensor only once?", "PCPatchSetPrecomputeElementTensors", patch->precomputeElementTensors, &patch->precomputeElementTensors, &flg));
29649566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_partition_of_unity", patch->classname));
29659566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool(option, "Weight contributions by dof multiplicity?", "PCPatchSetPartitionOfUnity", patch->partition_of_unity, &patch->partition_of_unity, &flg));
296610534d48SPatrick Farrell 
29679566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_local_type", patch->classname));
29689566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum(option, "Type of local solver composition (additive or multiplicative)", "PCPatchSetLocalComposition", PCCompositeTypes, (PetscEnum)loctype, (PetscEnum *)&loctype, &flg));
29699566063dSJacob Faibussowitsch   if (flg) PetscCall(PCPatchSetLocalComposition(pc, loctype));
29709566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_dense_inverse", patch->classname));
29719566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool(option, "Compute inverses of patch matrices and apply directly? Ignores KSP/PC settings on patch.", "PCPatchSetDenseInverse", patch->denseinverse, &patch->denseinverse, &flg));
29729566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_construct_dim", patch->classname));
29739566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt(option, "What dimension of mesh point to construct patches by? (0 = vertices)", "PCPATCH", patch->dim, &patch->dim, &dimflg));
29749566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_construct_codim", patch->classname));
29759566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt(option, "What co-dimension of mesh point to construct patches by? (0 = cells)", "PCPATCH", patch->codim, &patch->codim, &codimflg));
297608401ef6SPierre Jolivet   PetscCheck(!dimflg || !codimflg, comm, PETSC_ERR_ARG_WRONG, "Can only set one of dimension or co-dimension");
297710534d48SPatrick Farrell 
29789566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_construct_type", patch->classname));
29799566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum(option, "How should the patches be constructed?", "PCPatchSetConstructType", PCPatchConstructTypes, (PetscEnum)patchConstructionType, (PetscEnum *)&patchConstructionType, &flg));
29809566063dSJacob Faibussowitsch   if (flg) PetscCall(PCPatchSetConstructType(pc, patchConstructionType, NULL, NULL));
298110534d48SPatrick Farrell 
29829566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_vanka_dim", patch->classname));
29839566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt(option, "Topological dimension of entities for Vanka to ignore", "PCPATCH", patch->vankadim, &patch->vankadim, &flg));
298410534d48SPatrick Farrell 
29859566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_ignore_dim", patch->classname));
29869566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt(option, "Topological dimension of entities for completion to ignore", "PCPATCH", patch->ignoredim, &patch->ignoredim, &flg));
298710534d48SPatrick Farrell 
29889566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_pardecomp_overlap", patch->classname));
29899566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt(option, "What overlap should we use in construct type pardecomp?", "PCPATCH", patch->pardecomp_overlap, &patch->pardecomp_overlap, &flg));
2990b525f888SPatrick Farrell 
29919566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_sub_mat_type", patch->classname));
29929566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList(option, "Matrix type for patch solves", "PCPatchSetSubMatType", MatList, NULL, sub_mat_type, PETSC_MAX_PATH_LEN, &flg));
29939566063dSJacob Faibussowitsch   if (flg) PetscCall(PCPatchSetSubMatType(pc, sub_mat_type));
299410534d48SPatrick Farrell 
29959566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_symmetrise_sweep", patch->classname));
29969566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool(option, "Go start->end, end->start?", "PCPATCH", patch->symmetrise_sweep, &patch->symmetrise_sweep, &flg));
2997e4c66b91SPatrick Farrell 
2998a48c39c8SPatrick Farrell   /* If the user has set the number of subspaces, use that for the buffer size,
2999a48c39c8SPatrick Farrell    otherwise use a large number */
3000a48c39c8SPatrick Farrell   if (patch->nsubspaces <= 0) {
3001a48c39c8SPatrick Farrell     nfields = 128;
3002a48c39c8SPatrick Farrell   } else {
3003a48c39c8SPatrick Farrell     nfields = patch->nsubspaces;
3004a48c39c8SPatrick Farrell   }
30059566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nfields, &ifields));
30069566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_exclude_subspaces", patch->classname));
30079566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetIntArray(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, option, ifields, &nfields, &flg));
300808401ef6SPierre Jolivet   PetscCheck(!flg || !(patchConstructionType == PC_PATCH_USER), comm, PETSC_ERR_ARG_INCOMP, "We cannot support excluding a subspace with user patches because we do not index patches with a mesh point");
3009e4c66b91SPatrick Farrell   if (flg) {
30109566063dSJacob Faibussowitsch     PetscCall(PetscHSetIClear(patch->subspaces_to_exclude));
301148a46eb9SPierre Jolivet     for (k = 0; k < nfields; k++) PetscCall(PetscHSetIAdd(patch->subspaces_to_exclude, ifields[k]));
3012e4c66b91SPatrick Farrell   }
30139566063dSJacob Faibussowitsch   PetscCall(PetscFree(ifields));
30145f824522SMatthew G. Knepley 
30159566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_patches_view", patch->classname));
30169566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool(option, "Print out information during patch construction", "PCPATCH", patch->viewPatches, &patch->viewPatches, &flg));
30179566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_cells_view", patch->classname));
30189566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetViewer(comm, ((PetscObject)pc)->options, prefix, option, &patch->viewerCells, &patch->formatCells, &patch->viewCells));
30199566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_interior_facets_view", patch->classname));
30209566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetViewer(comm, ((PetscObject)pc)->options, prefix, option, &patch->viewerIntFacets, &patch->formatIntFacets, &patch->viewIntFacets));
30219566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_exterior_facets_view", patch->classname));
30229566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetViewer(comm, ((PetscObject)pc)->options, prefix, option, &patch->viewerExtFacets, &patch->formatExtFacets, &patch->viewExtFacets));
30239566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_points_view", patch->classname));
30249566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetViewer(comm, ((PetscObject)pc)->options, prefix, option, &patch->viewerPoints, &patch->formatPoints, &patch->viewPoints));
30259566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_section_view", patch->classname));
30269566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetViewer(comm, ((PetscObject)pc)->options, prefix, option, &patch->viewerSection, &patch->formatSection, &patch->viewSection));
30279566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_mat_view", patch->classname));
30289566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetViewer(comm, ((PetscObject)pc)->options, prefix, option, &patch->viewerMatrix, &patch->formatMatrix, &patch->viewMatrix));
3029d0609cedSBarry Smith   PetscOptionsHeadEnd();
30305f824522SMatthew G. Knepley   patch->optionsSet = PETSC_TRUE;
30314bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
30324bbf5ea8SMatthew G. Knepley }
30334bbf5ea8SMatthew G. Knepley 
30349371c9d4SSatish Balay static PetscErrorCode PCSetUpOnBlocks_PATCH(PC pc) {
30354bbf5ea8SMatthew G. Knepley   PC_PATCH          *patch = (PC_PATCH *)pc->data;
30364bbf5ea8SMatthew G. Knepley   KSPConvergedReason reason;
30374bbf5ea8SMatthew G. Knepley   PetscInt           i;
30384bbf5ea8SMatthew G. Knepley 
30394bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
3040a1eac568SLawrence Mitchell   if (!patch->save_operators) {
3041a1eac568SLawrence Mitchell     /* Can't do this here because the sub KSPs don't have an operator attached yet. */
3042a1eac568SLawrence Mitchell     PetscFunctionReturn(0);
3043a1eac568SLawrence Mitchell   }
3044c73d2cf6SLawrence Mitchell   if (patch->denseinverse) {
3045c73d2cf6SLawrence Mitchell     /* No solvers */
3046c73d2cf6SLawrence Mitchell     PetscFunctionReturn(0);
3047c73d2cf6SLawrence Mitchell   }
30484bbf5ea8SMatthew G. Knepley   for (i = 0; i < patch->npatch; ++i) {
304948a46eb9SPierre Jolivet     if (!((KSP)patch->solver[i])->setfromoptionscalled) PetscCall(KSPSetFromOptions((KSP)patch->solver[i]));
30509566063dSJacob Faibussowitsch     PetscCall(KSPSetUp((KSP)patch->solver[i]));
30519566063dSJacob Faibussowitsch     PetscCall(KSPGetConvergedReason((KSP)patch->solver[i], &reason));
3052c0decd05SBarry Smith     if (reason == KSP_DIVERGED_PC_FAILED) pc->failedreason = PC_SUBPC_ERROR;
30534bbf5ea8SMatthew G. Knepley   }
30544bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
30554bbf5ea8SMatthew G. Knepley }
30564bbf5ea8SMatthew G. Knepley 
30579371c9d4SSatish Balay static PetscErrorCode PCView_PATCH(PC pc, PetscViewer viewer) {
30584bbf5ea8SMatthew G. Knepley   PC_PATCH   *patch = (PC_PATCH *)pc->data;
30594bbf5ea8SMatthew G. Knepley   PetscViewer sviewer;
30604bbf5ea8SMatthew G. Knepley   PetscBool   isascii;
30614bbf5ea8SMatthew G. Knepley   PetscMPIInt rank;
30624bbf5ea8SMatthew G. Knepley 
30634bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
30644bbf5ea8SMatthew G. Knepley   /* TODO Redo tabbing with set tbas in new style */
30659566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
30664bbf5ea8SMatthew G. Knepley   if (!isascii) PetscFunctionReturn(0);
30679566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc), &rank));
30689566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPushTab(viewer));
306963a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "Subspace Correction preconditioner with %" PetscInt_FMT " patches\n", patch->npatch));
307061c4b389SFlorian Wechsung   if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
30719566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Schwarz type: multiplicative\n"));
3072e047a90bSFlorian Wechsung   } else {
30739566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Schwarz type: additive\n"));
3074c2e6f3c0SFlorian Wechsung   }
30759566063dSJacob Faibussowitsch   if (patch->partition_of_unity) PetscCall(PetscViewerASCIIPrintf(viewer, "Weighting by partition of unity\n"));
30769566063dSJacob Faibussowitsch   else PetscCall(PetscViewerASCIIPrintf(viewer, "Not weighting by partition of unity\n"));
30779566063dSJacob Faibussowitsch   if (patch->symmetrise_sweep) PetscCall(PetscViewerASCIIPrintf(viewer, "Symmetrising sweep (start->end, then end->start)\n"));
30789566063dSJacob Faibussowitsch   else PetscCall(PetscViewerASCIIPrintf(viewer, "Not symmetrising sweep\n"));
30799566063dSJacob Faibussowitsch   if (!patch->precomputeElementTensors) PetscCall(PetscViewerASCIIPrintf(viewer, "Not precomputing element tensors (overlapping cells rebuilt in every patch assembly)\n"));
30809566063dSJacob Faibussowitsch   else PetscCall(PetscViewerASCIIPrintf(viewer, "Precomputing element tensors (each cell assembled only once)\n"));
30819566063dSJacob Faibussowitsch   if (!patch->save_operators) PetscCall(PetscViewerASCIIPrintf(viewer, "Not saving patch operators (rebuilt every PCApply)\n"));
30829566063dSJacob Faibussowitsch   else PetscCall(PetscViewerASCIIPrintf(viewer, "Saving patch operators (rebuilt every PCSetUp)\n"));
30839566063dSJacob Faibussowitsch   if (patch->patchconstructop == PCPatchConstruct_Star) PetscCall(PetscViewerASCIIPrintf(viewer, "Patch construction operator: star\n"));
30849566063dSJacob Faibussowitsch   else if (patch->patchconstructop == PCPatchConstruct_Vanka) PetscCall(PetscViewerASCIIPrintf(viewer, "Patch construction operator: Vanka\n"));
30859566063dSJacob Faibussowitsch   else if (patch->patchconstructop == PCPatchConstruct_User) PetscCall(PetscViewerASCIIPrintf(viewer, "Patch construction operator: user-specified\n"));
30869566063dSJacob Faibussowitsch   else PetscCall(PetscViewerASCIIPrintf(viewer, "Patch construction operator: unknown\n"));
30875d30859aSPatrick Farrell 
3088c73d2cf6SLawrence Mitchell   if (patch->denseinverse) {
30899566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Explicitly forming dense inverse and applying patch solver via MatMult.\n"));
3090c73d2cf6SLawrence Mitchell   } else {
30915d30859aSPatrick Farrell     if (patch->isNonlinear) {
30929566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "SNES on patches (all same):\n"));
30935d30859aSPatrick Farrell     } else {
30949566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "KSP on patches (all same):\n"));
30955d30859aSPatrick Farrell     }
3096dadc69c5SMatthew G. Knepley     if (patch->solver) {
30979566063dSJacob Faibussowitsch       PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
3098dd400576SPatrick Sanan       if (rank == 0) {
30999566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPushTab(sviewer));
31009566063dSJacob Faibussowitsch         PetscCall(PetscObjectView(patch->solver[0], sviewer));
31019566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(sviewer));
31024bbf5ea8SMatthew G. Knepley       }
31039566063dSJacob Faibussowitsch       PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
31044bbf5ea8SMatthew G. Knepley     } else {
31059566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
31069566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "Solver not yet set.\n"));
31079566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
31084bbf5ea8SMatthew G. Knepley     }
3109c73d2cf6SLawrence Mitchell   }
31109566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPopTab(viewer));
31114bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
31124bbf5ea8SMatthew G. Knepley }
31134bbf5ea8SMatthew G. Knepley 
3114e5893cccSMatthew G. Knepley /*MC
3115*f1580f4eSBarry Smith    PCPATCH - A `PC` object that encapsulates flexible definition of blocks for overlapping and non-overlapping
311698ed095eSMatthew G. Knepley    small block additive preconditioners. Block definition is based on topology from
3117*f1580f4eSBarry Smith    a `DM` and equation numbering from a `PetscSection`.
3118e5893cccSMatthew G. Knepley 
3119e5893cccSMatthew G. Knepley    Options Database Keys:
3120e5893cccSMatthew G. Knepley + -pc_patch_cells_view   - Views the process local cell numbers for each patch
3121e5893cccSMatthew G. Knepley . -pc_patch_points_view  - Views the process local mesh point numbers for each patch
3122e5893cccSMatthew G. Knepley . -pc_patch_g2l_view     - Views the map between global dofs and patch local dofs for each patch
3123e5893cccSMatthew G. Knepley . -pc_patch_patches_view - Views the global dofs associated with each patch and its boundary
3124e5893cccSMatthew G. Knepley - -pc_patch_sub_mat_view - Views the matrix associated with each patch
3125e5893cccSMatthew G. Knepley 
3126e5893cccSMatthew G. Knepley    Level: intermediate
3127e5893cccSMatthew G. Knepley 
3128*f1580f4eSBarry Smith .seealso: `PCType`, `PCCreate()`, `PCSetType()`, `PCASM`, `PCJACOBI`, `PCPBJACOBI`, `PCVPBJACOBI`, `SNESPATCH`
3129e5893cccSMatthew G. Knepley M*/
31309371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode PCCreate_Patch(PC pc) {
31314bbf5ea8SMatthew G. Knepley   PC_PATCH *patch;
31324bbf5ea8SMatthew G. Knepley 
31334bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
31349566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(pc, &patch));
31354bbf5ea8SMatthew G. Knepley 
313648a46eb9SPierre Jolivet   if (patch->subspaces_to_exclude) PetscCall(PetscHSetIDestroy(&patch->subspaces_to_exclude));
31379566063dSJacob Faibussowitsch   PetscCall(PetscHSetICreate(&patch->subspaces_to_exclude));
3138e4c66b91SPatrick Farrell 
313910534d48SPatrick Farrell   patch->classname   = "pc";
3140debbdec3SPatrick Farrell   patch->isNonlinear = PETSC_FALSE;
314110534d48SPatrick Farrell 
31424bbf5ea8SMatthew G. Knepley   /* Set some defaults */
31435f824522SMatthew G. Knepley   patch->combined                 = PETSC_FALSE;
31444bbf5ea8SMatthew G. Knepley   patch->save_operators           = PETSC_TRUE;
314561c4b389SFlorian Wechsung   patch->local_composition_type   = PC_COMPOSITE_ADDITIVE;
3146fa84ea4cSLawrence Mitchell   patch->precomputeElementTensors = PETSC_FALSE;
31474bbf5ea8SMatthew G. Knepley   patch->partition_of_unity       = PETSC_FALSE;
31484bbf5ea8SMatthew G. Knepley   patch->codim                    = -1;
31494bbf5ea8SMatthew G. Knepley   patch->dim                      = -1;
31504bbf5ea8SMatthew G. Knepley   patch->vankadim                 = -1;
31515f824522SMatthew G. Knepley   patch->ignoredim                = -1;
3152b525f888SPatrick Farrell   patch->pardecomp_overlap        = 0;
31534bbf5ea8SMatthew G. Knepley   patch->patchconstructop         = PCPatchConstruct_Star;
31544bbf5ea8SMatthew G. Knepley   patch->symmetrise_sweep         = PETSC_FALSE;
31555f824522SMatthew G. Knepley   patch->npatch                   = 0;
31564bbf5ea8SMatthew G. Knepley   patch->userIS                   = NULL;
31575f824522SMatthew G. Knepley   patch->optionsSet               = PETSC_FALSE;
31584bbf5ea8SMatthew G. Knepley   patch->iterationSet             = NULL;
31594bbf5ea8SMatthew G. Knepley   patch->user_patches             = PETSC_FALSE;
31609566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(MATDENSE, (char **)&patch->sub_mat_type));
31615f824522SMatthew G. Knepley   patch->viewPatches                       = PETSC_FALSE;
31625f824522SMatthew G. Knepley   patch->viewCells                         = PETSC_FALSE;
31635f824522SMatthew G. Knepley   patch->viewPoints                        = PETSC_FALSE;
31645f824522SMatthew G. Knepley   patch->viewSection                       = PETSC_FALSE;
31655f824522SMatthew G. Knepley   patch->viewMatrix                        = PETSC_FALSE;
31669d4fc724SLawrence Mitchell   patch->densesolve                        = NULL;
3167dadc69c5SMatthew G. Knepley   patch->setupsolver                       = PCSetUp_PATCH_Linear;
3168dadc69c5SMatthew G. Knepley   patch->applysolver                       = PCApply_PATCH_Linear;
3169dadc69c5SMatthew G. Knepley   patch->resetsolver                       = PCReset_PATCH_Linear;
3170dadc69c5SMatthew G. Knepley   patch->destroysolver                     = PCDestroy_PATCH_Linear;
31716c9c532dSPatrick Farrell   patch->updatemultiplicative              = PCUpdateMultiplicative_PATCH_Linear;
317247aca4a6SPatrick Farrell   patch->dofMappingWithoutToWithArtificial = NULL;
317347aca4a6SPatrick Farrell   patch->dofMappingWithoutToWithAll        = NULL;
31744bbf5ea8SMatthew G. Knepley 
31754bbf5ea8SMatthew G. Knepley   pc->data                 = (void *)patch;
31764bbf5ea8SMatthew G. Knepley   pc->ops->apply           = PCApply_PATCH;
31770a545947SLisandro Dalcin   pc->ops->applytranspose  = NULL; /* PCApplyTranspose_PATCH; */
31784bbf5ea8SMatthew G. Knepley   pc->ops->setup           = PCSetUp_PATCH;
31794bbf5ea8SMatthew G. Knepley   pc->ops->reset           = PCReset_PATCH;
31804bbf5ea8SMatthew G. Knepley   pc->ops->destroy         = PCDestroy_PATCH;
31814bbf5ea8SMatthew G. Knepley   pc->ops->setfromoptions  = PCSetFromOptions_PATCH;
31824bbf5ea8SMatthew G. Knepley   pc->ops->setuponblocks   = PCSetUpOnBlocks_PATCH;
31834bbf5ea8SMatthew G. Knepley   pc->ops->view            = PCView_PATCH;
31840a545947SLisandro Dalcin   pc->ops->applyrichardson = NULL;
31854bbf5ea8SMatthew G. Knepley 
31864bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
31874bbf5ea8SMatthew G. Knepley }
3188