xref: /petsc/src/ksp/pc/impls/patch/pcpatch.c (revision 0a3909433380636ca9103c33c9102eb54498e5e8)
14bbf5ea8SMatthew G. Knepley #include <petsc/private/pcpatchimpl.h>     /*I "petscpc.h" I*/
254ab768cSLawrence Mitchell #include <petsc/private/kspimpl.h>         /* For ksp->setfromoptionscalled */
35f824522SMatthew G. Knepley #include <petsc/private/dmpleximpl.h> /* For DMPlexComputeJacobian_Patch_Internal() */
44bbf5ea8SMatthew G. Knepley #include <petscsf.h>
54bbf5ea8SMatthew G. Knepley #include <petscbt.h>
65f824522SMatthew G. Knepley #include <petscds.h>
74bbf5ea8SMatthew G. Knepley 
84bbf5ea8SMatthew G. Knepley PetscLogEvent PC_Patch_CreatePatches, PC_Patch_ComputeOp, PC_Patch_Solve, PC_Patch_Scatter, PC_Patch_Apply, PC_Patch_Prealloc;
94bbf5ea8SMatthew G. Knepley 
105f824522SMatthew G. Knepley PETSC_STATIC_INLINE PetscErrorCode ObjectView(PetscObject obj, PetscViewer viewer, PetscViewerFormat format)
115f824522SMatthew G. Knepley {
125f824522SMatthew G. Knepley   PetscErrorCode ierr;
135f824522SMatthew G. Knepley 
145f824522SMatthew G. Knepley   ierr = PetscViewerPushFormat(viewer, format);CHKERRQ(ierr);
155f824522SMatthew G. Knepley   ierr = PetscObjectView(obj, viewer);CHKERRQ(ierr);
165f824522SMatthew G. Knepley   ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
177974b488SMatthew G. Knepley   return(0);
185f824522SMatthew G. Knepley }
195f824522SMatthew G. Knepley 
201b68eb51SMatthew G. Knepley static PetscErrorCode PCPatchConstruct_Star(void *vpatch, DM dm, PetscInt point, PetscHSetI ht)
214bbf5ea8SMatthew G. Knepley {
224bbf5ea8SMatthew G. Knepley   PetscInt       starSize;
234bbf5ea8SMatthew G. Knepley   PetscInt      *star = NULL, si;
244bbf5ea8SMatthew G. Knepley   PetscErrorCode ierr;
254bbf5ea8SMatthew G. Knepley 
264bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
271b68eb51SMatthew G. Knepley   PetscHSetIClear(ht);
284bbf5ea8SMatthew G. Knepley   /* To start with, add the point we care about */
291b68eb51SMatthew G. Knepley   ierr = PetscHSetIAdd(ht, point);CHKERRQ(ierr);
304bbf5ea8SMatthew G. Knepley   /* Loop over all the points that this point connects to */
314bbf5ea8SMatthew G. Knepley   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
321b68eb51SMatthew G. Knepley   for (si = 0; si < starSize*2; si += 2) {ierr = PetscHSetIAdd(ht, star[si]);CHKERRQ(ierr);}
334bbf5ea8SMatthew G. Knepley   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
344bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
354bbf5ea8SMatthew G. Knepley }
364bbf5ea8SMatthew G. Knepley 
371b68eb51SMatthew G. Knepley static PetscErrorCode PCPatchConstruct_Vanka(void *vpatch, DM dm, PetscInt point, PetscHSetI ht)
384bbf5ea8SMatthew G. Knepley {
394bbf5ea8SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) vpatch;
404bbf5ea8SMatthew G. Knepley   PetscInt       starSize;
414bbf5ea8SMatthew G. Knepley   PetscInt      *star = NULL;
424bbf5ea8SMatthew G. Knepley   PetscBool      shouldIgnore = PETSC_FALSE;
434bbf5ea8SMatthew G. Knepley   PetscInt       cStart, cEnd, iStart, iEnd, si;
444bbf5ea8SMatthew G. Knepley   PetscErrorCode ierr;
454bbf5ea8SMatthew G. Knepley 
464bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
471b68eb51SMatthew G. Knepley   ierr = PetscHSetIClear(ht);CHKERRQ(ierr);
484bbf5ea8SMatthew G. Knepley   /* To start with, add the point we care about */
491b68eb51SMatthew G. Knepley   ierr = PetscHSetIAdd(ht, point);CHKERRQ(ierr);
504bbf5ea8SMatthew G. Knepley   /* Should we ignore any points of a certain dimension? */
514bbf5ea8SMatthew G. Knepley   if (patch->vankadim >= 0) {
524bbf5ea8SMatthew G. Knepley     shouldIgnore = PETSC_TRUE;
534bbf5ea8SMatthew G. Knepley     ierr = DMPlexGetDepthStratum(dm, patch->vankadim, &iStart, &iEnd);CHKERRQ(ierr);
544bbf5ea8SMatthew G. Knepley   }
554bbf5ea8SMatthew G. Knepley   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
564bbf5ea8SMatthew G. Knepley   /* Loop over all the cells that this point connects to */
574bbf5ea8SMatthew G. Knepley   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
585f824522SMatthew G. Knepley   for (si = 0; si < starSize*2; si += 2) {
594bbf5ea8SMatthew G. Knepley     const PetscInt cell = star[si];
604bbf5ea8SMatthew G. Knepley     PetscInt       closureSize;
614bbf5ea8SMatthew G. Knepley     PetscInt      *closure = NULL, ci;
624bbf5ea8SMatthew G. Knepley 
634bbf5ea8SMatthew G. Knepley     if (cell < cStart || cell >= cEnd) continue;
644bbf5ea8SMatthew G. Knepley     /* now loop over all entities in the closure of that cell */
654bbf5ea8SMatthew G. Knepley     ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
665f824522SMatthew G. Knepley     for (ci = 0; ci < closureSize*2; ci += 2) {
674bbf5ea8SMatthew G. Knepley       const PetscInt newpoint = closure[ci];
684bbf5ea8SMatthew G. Knepley 
694bbf5ea8SMatthew G. Knepley       /* We've been told to ignore entities of this type.*/
704bbf5ea8SMatthew G. Knepley       if (shouldIgnore && newpoint >= iStart && newpoint < iEnd) continue;
711b68eb51SMatthew G. Knepley       ierr = PetscHSetIAdd(ht, newpoint);CHKERRQ(ierr);
724bbf5ea8SMatthew G. Knepley     }
734bbf5ea8SMatthew G. Knepley     ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
744bbf5ea8SMatthew G. Knepley   }
754bbf5ea8SMatthew G. Knepley   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
764bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
774bbf5ea8SMatthew G. Knepley }
784bbf5ea8SMatthew G. Knepley 
79*0a390943SPatrick Farrell static PetscErrorCode PCPatchConstruct_Owned(void *vpatch, DM dm, PetscInt point, PetscHSetI ht)
80*0a390943SPatrick Farrell {
81*0a390943SPatrick Farrell   DMLabel         ghost = NULL;
82*0a390943SPatrick Farrell   const PetscInt *leaves;
83*0a390943SPatrick Farrell   PetscInt        nleaves, pStart, pEnd, loc;
84*0a390943SPatrick Farrell   PetscBool       isFiredrake;
85*0a390943SPatrick Farrell   DM              plex;
86*0a390943SPatrick Farrell   PetscBool       flg;
87*0a390943SPatrick Farrell   PetscErrorCode ierr;
88*0a390943SPatrick Farrell 
89*0a390943SPatrick Farrell   PetscFunctionBegin;
90*0a390943SPatrick Farrell   PetscHSetIClear(ht);
91*0a390943SPatrick Farrell 
92*0a390943SPatrick Farrell   ierr = DMConvert(dm, DMPLEX, &plex);CHKERRQ(ierr);
93*0a390943SPatrick Farrell   ierr = DMPlexGetChart(plex, &pStart, &pEnd);CHKERRQ(ierr);
94*0a390943SPatrick Farrell 
95*0a390943SPatrick Farrell   ierr = DMHasLabel(dm, "pyop2_ghost", &isFiredrake);CHKERRQ(ierr);
96*0a390943SPatrick Farrell   if (isFiredrake) {
97*0a390943SPatrick Farrell     ierr = DMGetLabel(dm, "pyop2_ghost", &ghost);CHKERRQ(ierr);
98*0a390943SPatrick Farrell     ierr = DMLabelCreateIndex(ghost, pStart, pEnd);CHKERRQ(ierr);
99*0a390943SPatrick Farrell   } else {
100*0a390943SPatrick Farrell     PetscSF sf;
101*0a390943SPatrick Farrell     ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
102*0a390943SPatrick Farrell     ierr = PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL);CHKERRQ(ierr);
103*0a390943SPatrick Farrell     nleaves = PetscMax(nleaves, 0);
104*0a390943SPatrick Farrell   }
105*0a390943SPatrick Farrell 
106*0a390943SPatrick Farrell   for (PetscInt point = pStart; point < pEnd; ++point) {
107*0a390943SPatrick Farrell     if (ghost) {ierr = DMLabelHasPoint(ghost, point, &flg);CHKERRQ(ierr);}
108*0a390943SPatrick Farrell     else       {ierr = PetscFindInt(point, nleaves, leaves, &loc);CHKERRQ(ierr); flg = loc >=0 ? PETSC_TRUE : PETSC_FALSE;}
109*0a390943SPatrick Farrell     /* Not an owned entity, don't make a cell patch. */
110*0a390943SPatrick Farrell     if (flg) continue;
111*0a390943SPatrick Farrell     ierr = PetscHSetIAdd(ht, point);CHKERRQ(ierr);
112*0a390943SPatrick Farrell   }
113*0a390943SPatrick Farrell 
114*0a390943SPatrick Farrell   PetscFunctionReturn(0);
115*0a390943SPatrick Farrell }
116*0a390943SPatrick Farrell 
1174bbf5ea8SMatthew G. Knepley /* The user's already set the patches in patch->userIS. Build the hash tables */
1181b68eb51SMatthew G. Knepley static PetscErrorCode PCPatchConstruct_User(void *vpatch, DM dm, PetscInt point, PetscHSetI ht)
1194bbf5ea8SMatthew G. Knepley {
1204bbf5ea8SMatthew G. Knepley   PC_PATCH       *patch   = (PC_PATCH *) vpatch;
1214bbf5ea8SMatthew G. Knepley   IS              patchis = patch->userIS[point];
1224bbf5ea8SMatthew G. Knepley   PetscInt        n;
1234bbf5ea8SMatthew G. Knepley   const PetscInt *patchdata;
1244bbf5ea8SMatthew G. Knepley   PetscInt        pStart, pEnd, i;
1254bbf5ea8SMatthew G. Knepley   PetscErrorCode  ierr;
1264bbf5ea8SMatthew G. Knepley 
1274bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
1281b68eb51SMatthew G. Knepley   ierr = PetscHSetIClear(ht);CHKERRQ(ierr);
1291b68eb51SMatthew G. Knepley   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1304bbf5ea8SMatthew G. Knepley   ierr = ISGetLocalSize(patchis, &n);CHKERRQ(ierr);
1314bbf5ea8SMatthew G. Knepley   ierr = ISGetIndices(patchis, &patchdata);CHKERRQ(ierr);
1324bbf5ea8SMatthew G. Knepley   for (i = 0; i < n; ++i) {
1334bbf5ea8SMatthew G. Knepley     const PetscInt ownedpoint = patchdata[i];
1344bbf5ea8SMatthew G. Knepley 
1354bbf5ea8SMatthew G. Knepley     if (ownedpoint < pStart || ownedpoint >= pEnd) {
1364bbf5ea8SMatthew G. Knepley       SETERRQ3(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D was not in [%D, %D)", ownedpoint, pStart, pEnd);
1374bbf5ea8SMatthew G. Knepley     }
1381b68eb51SMatthew G. Knepley     ierr = PetscHSetIAdd(ht, ownedpoint);CHKERRQ(ierr);
1394bbf5ea8SMatthew G. Knepley   }
1404bbf5ea8SMatthew G. Knepley   ierr = ISRestoreIndices(patchis, &patchdata);CHKERRQ(ierr);
1414bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
1424bbf5ea8SMatthew G. Knepley }
1434bbf5ea8SMatthew G. Knepley 
1444bbf5ea8SMatthew G. Knepley static PetscErrorCode PCPatchCreateDefaultSF_Private(PC pc, PetscInt n, const PetscSF *sf, const PetscInt *bs)
1454bbf5ea8SMatthew G. Knepley {
1464bbf5ea8SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
1474bbf5ea8SMatthew G. Knepley   PetscInt       i;
1484bbf5ea8SMatthew G. Knepley   PetscErrorCode ierr;
1494bbf5ea8SMatthew G. Knepley 
1504bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
1514bbf5ea8SMatthew G. Knepley   if (n == 1 && bs[0] == 1) {
1524bbf5ea8SMatthew G. Knepley     patch->defaultSF = sf[0];
1534bbf5ea8SMatthew G. Knepley     ierr = PetscObjectReference((PetscObject) patch->defaultSF);CHKERRQ(ierr);
1544bbf5ea8SMatthew G. Knepley   } else {
1554bbf5ea8SMatthew G. Knepley     PetscInt     allRoots = 0, allLeaves = 0;
1564bbf5ea8SMatthew G. Knepley     PetscInt     leafOffset = 0;
1574bbf5ea8SMatthew G. Knepley     PetscInt    *ilocal = NULL;
1584bbf5ea8SMatthew G. Knepley     PetscSFNode *iremote = NULL;
1594bbf5ea8SMatthew G. Knepley     PetscInt    *remoteOffsets = NULL;
1604bbf5ea8SMatthew G. Knepley     PetscInt     index = 0;
1611b68eb51SMatthew G. Knepley     PetscHMapI   rankToIndex;
1624bbf5ea8SMatthew G. Knepley     PetscInt     numRanks = 0;
1634bbf5ea8SMatthew G. Knepley     PetscSFNode *remote = NULL;
1644bbf5ea8SMatthew G. Knepley     PetscSF      rankSF;
1654bbf5ea8SMatthew G. Knepley     PetscInt    *ranks = NULL;
1664bbf5ea8SMatthew G. Knepley     PetscInt    *offsets = NULL;
1674bbf5ea8SMatthew G. Knepley     MPI_Datatype contig;
1681b68eb51SMatthew G. Knepley     PetscHSetI   ranksUniq;
1694bbf5ea8SMatthew G. Knepley 
1704bbf5ea8SMatthew G. Knepley     /* First figure out how many dofs there are in the concatenated numbering.
1714bbf5ea8SMatthew G. Knepley      * allRoots: number of owned global dofs;
1724bbf5ea8SMatthew G. Knepley      * allLeaves: number of visible dofs (global + ghosted).
1734bbf5ea8SMatthew G. Knepley      */
1744bbf5ea8SMatthew G. Knepley     for (i = 0; i < n; ++i) {
1754bbf5ea8SMatthew G. Knepley       PetscInt nroots, nleaves;
1764bbf5ea8SMatthew G. Knepley 
1774bbf5ea8SMatthew G. Knepley       ierr = PetscSFGetGraph(sf[i], &nroots, &nleaves, NULL, NULL);CHKERRQ(ierr);
1784bbf5ea8SMatthew G. Knepley       allRoots  += nroots * bs[i];
1794bbf5ea8SMatthew G. Knepley       allLeaves += nleaves * bs[i];
1804bbf5ea8SMatthew G. Knepley     }
1814bbf5ea8SMatthew G. Knepley     ierr = PetscMalloc1(allLeaves, &ilocal);CHKERRQ(ierr);
1824bbf5ea8SMatthew G. Knepley     ierr = PetscMalloc1(allLeaves, &iremote);CHKERRQ(ierr);
1834bbf5ea8SMatthew G. Knepley     /* Now build an SF that just contains process connectivity. */
1841b68eb51SMatthew G. Knepley     ierr = PetscHSetICreate(&ranksUniq);CHKERRQ(ierr);
1854bbf5ea8SMatthew G. Knepley     for (i = 0; i < n; ++i) {
1864bbf5ea8SMatthew G. Knepley       const PetscMPIInt *ranks = NULL;
1874bbf5ea8SMatthew G. Knepley       PetscInt           nranks, j;
1884bbf5ea8SMatthew G. Knepley 
1894bbf5ea8SMatthew G. Knepley       ierr = PetscSFSetUp(sf[i]);CHKERRQ(ierr);
1904bbf5ea8SMatthew G. Knepley       ierr = PetscSFGetRanks(sf[i], &nranks, &ranks, NULL, NULL, NULL);CHKERRQ(ierr);
1914bbf5ea8SMatthew G. Knepley       /* These are all the ranks who communicate with me. */
1924bbf5ea8SMatthew G. Knepley       for (j = 0; j < nranks; ++j) {
1931b68eb51SMatthew G. Knepley         ierr = PetscHSetIAdd(ranksUniq, (PetscInt) ranks[j]);CHKERRQ(ierr);
1944bbf5ea8SMatthew G. Knepley       }
1954bbf5ea8SMatthew G. Knepley     }
1961b68eb51SMatthew G. Knepley     ierr = PetscHSetIGetSize(ranksUniq, &numRanks);CHKERRQ(ierr);
1974bbf5ea8SMatthew G. Knepley     ierr = PetscMalloc1(numRanks, &remote);CHKERRQ(ierr);
1984bbf5ea8SMatthew G. Knepley     ierr = PetscMalloc1(numRanks, &ranks);CHKERRQ(ierr);
1991b68eb51SMatthew G. Knepley     ierr = PetscHSetIGetElems(ranksUniq, &index, ranks);CHKERRQ(ierr);
2004bbf5ea8SMatthew G. Knepley 
2011b68eb51SMatthew G. Knepley     ierr = PetscHMapICreate(&rankToIndex);CHKERRQ(ierr);
2024bbf5ea8SMatthew G. Knepley     for (i = 0; i < numRanks; ++i) {
2034bbf5ea8SMatthew G. Knepley       remote[i].rank  = ranks[i];
2044bbf5ea8SMatthew G. Knepley       remote[i].index = 0;
2051b68eb51SMatthew G. Knepley       ierr = PetscHMapISet(rankToIndex, ranks[i], i);CHKERRQ(ierr);
2064bbf5ea8SMatthew G. Knepley     }
2074bbf5ea8SMatthew G. Knepley     ierr = PetscFree(ranks);CHKERRQ(ierr);
2081b68eb51SMatthew G. Knepley     ierr = PetscHSetIDestroy(&ranksUniq);CHKERRQ(ierr);
2094bbf5ea8SMatthew G. Knepley     ierr = PetscSFCreate(PetscObjectComm((PetscObject) pc), &rankSF);CHKERRQ(ierr);
2104bbf5ea8SMatthew G. Knepley     ierr = PetscSFSetGraph(rankSF, 1, numRanks, NULL, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);CHKERRQ(ierr);
2114bbf5ea8SMatthew G. Knepley     ierr = PetscSFSetUp(rankSF);CHKERRQ(ierr);
2124bbf5ea8SMatthew G. Knepley     /* OK, use it to communicate the root offset on the remote
2134bbf5ea8SMatthew G. Knepley      * processes for each subspace. */
2144bbf5ea8SMatthew G. Knepley     ierr = PetscMalloc1(n, &offsets);CHKERRQ(ierr);
2154bbf5ea8SMatthew G. Knepley     ierr = PetscMalloc1(n*numRanks, &remoteOffsets);CHKERRQ(ierr);
2164bbf5ea8SMatthew G. Knepley 
2174bbf5ea8SMatthew G. Knepley     offsets[0] = 0;
2184bbf5ea8SMatthew G. Knepley     for (i = 1; i < n; ++i) {
2194bbf5ea8SMatthew G. Knepley       PetscInt nroots;
2204bbf5ea8SMatthew G. Knepley 
2214bbf5ea8SMatthew G. Knepley       ierr = PetscSFGetGraph(sf[i-1], &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
2224bbf5ea8SMatthew G. Knepley       offsets[i] = offsets[i-1] + nroots*bs[i-1];
2234bbf5ea8SMatthew G. Knepley     }
2244bbf5ea8SMatthew G. Knepley     /* Offsets are the offsets on the current process of the
2254bbf5ea8SMatthew G. Knepley      * global dof numbering for the subspaces. */
2264bbf5ea8SMatthew G. Knepley     ierr = MPI_Type_contiguous(n, MPIU_INT, &contig);CHKERRQ(ierr);
2274bbf5ea8SMatthew G. Knepley     ierr = MPI_Type_commit(&contig);CHKERRQ(ierr);
2284bbf5ea8SMatthew G. Knepley 
2294bbf5ea8SMatthew G. Knepley     ierr = PetscSFBcastBegin(rankSF, contig, offsets, remoteOffsets);CHKERRQ(ierr);
2304bbf5ea8SMatthew G. Knepley     ierr = PetscSFBcastEnd(rankSF, contig, offsets, remoteOffsets);CHKERRQ(ierr);
2314bbf5ea8SMatthew G. Knepley     ierr = MPI_Type_free(&contig);CHKERRQ(ierr);
2324bbf5ea8SMatthew G. Knepley     ierr = PetscFree(offsets);CHKERRQ(ierr);
2334bbf5ea8SMatthew G. Knepley     ierr = PetscSFDestroy(&rankSF);CHKERRQ(ierr);
2344bbf5ea8SMatthew G. Knepley     /* Now remoteOffsets contains the offsets on the remote
2354bbf5ea8SMatthew G. Knepley      * processes who communicate with me.  So now we can
2364bbf5ea8SMatthew G. Knepley      * concatenate the list of SFs into a single one. */
2374bbf5ea8SMatthew G. Knepley     index = 0;
2384bbf5ea8SMatthew G. Knepley     for (i = 0; i < n; ++i) {
2394bbf5ea8SMatthew G. Knepley       const PetscSFNode *remote = NULL;
2404bbf5ea8SMatthew G. Knepley       const PetscInt    *local  = NULL;
2414bbf5ea8SMatthew G. Knepley       PetscInt           nroots, nleaves, j;
2424bbf5ea8SMatthew G. Knepley 
2434bbf5ea8SMatthew G. Knepley       ierr = PetscSFGetGraph(sf[i], &nroots, &nleaves, &local, &remote);CHKERRQ(ierr);
2444bbf5ea8SMatthew G. Knepley       for (j = 0; j < nleaves; ++j) {
2454bbf5ea8SMatthew G. Knepley         PetscInt rank = remote[j].rank;
2464bbf5ea8SMatthew G. Knepley         PetscInt idx, rootOffset, k;
2474bbf5ea8SMatthew G. Knepley 
2481b68eb51SMatthew G. Knepley         ierr = PetscHMapIGet(rankToIndex, rank, &idx);CHKERRQ(ierr);
2494bbf5ea8SMatthew G. Knepley         if (idx == -1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Didn't find rank, huh?");
2504bbf5ea8SMatthew G. Knepley         /* Offset on given rank for ith subspace */
2514bbf5ea8SMatthew G. Knepley         rootOffset = remoteOffsets[n*idx + i];
2524bbf5ea8SMatthew G. Knepley         for (k = 0; k < bs[i]; ++k) {
25373ec7555SLawrence Mitchell           ilocal[index]        = (local ? local[j] : j)*bs[i] + k + leafOffset;
2544bbf5ea8SMatthew G. Knepley           iremote[index].rank  = remote[j].rank;
2554bbf5ea8SMatthew G. Knepley           iremote[index].index = remote[j].index*bs[i] + k + rootOffset;
2564bbf5ea8SMatthew G. Knepley           ++index;
2574bbf5ea8SMatthew G. Knepley         }
2584bbf5ea8SMatthew G. Knepley       }
2594bbf5ea8SMatthew G. Knepley       leafOffset += nleaves * bs[i];
2604bbf5ea8SMatthew G. Knepley     }
2611b68eb51SMatthew G. Knepley     ierr = PetscHMapIDestroy(&rankToIndex);CHKERRQ(ierr);
2624bbf5ea8SMatthew G. Knepley     ierr = PetscFree(remoteOffsets);CHKERRQ(ierr);
2634bbf5ea8SMatthew G. Knepley     ierr = PetscSFCreate(PetscObjectComm((PetscObject)pc), &patch->defaultSF);CHKERRQ(ierr);
2644bbf5ea8SMatthew G. Knepley     ierr = PetscSFSetGraph(patch->defaultSF, allRoots, allLeaves, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER);CHKERRQ(ierr);
2654bbf5ea8SMatthew G. Knepley   }
2664bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
2674bbf5ea8SMatthew G. Knepley }
2684bbf5ea8SMatthew G. Knepley 
2694bbf5ea8SMatthew G. Knepley /* TODO: Docs */
2705f824522SMatthew G. Knepley PetscErrorCode PCPatchSetIgnoreDim(PC pc, PetscInt dim)
2715f824522SMatthew G. Knepley {
2725f824522SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *) pc->data;
2735f824522SMatthew G. Knepley   PetscFunctionBegin;
2745f824522SMatthew G. Knepley   patch->ignoredim = dim;
2755f824522SMatthew G. Knepley   PetscFunctionReturn(0);
2765f824522SMatthew G. Knepley }
2775f824522SMatthew G. Knepley 
2785f824522SMatthew G. Knepley /* TODO: Docs */
2795f824522SMatthew G. Knepley PetscErrorCode PCPatchGetIgnoreDim(PC pc, PetscInt *dim)
2805f824522SMatthew G. Knepley {
2815f824522SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *) pc->data;
2825f824522SMatthew G. Knepley   PetscFunctionBegin;
2835f824522SMatthew G. Knepley   *dim = patch->ignoredim;
2845f824522SMatthew G. Knepley   PetscFunctionReturn(0);
2855f824522SMatthew G. Knepley }
2865f824522SMatthew G. Knepley 
2875f824522SMatthew G. Knepley /* TODO: Docs */
2884bbf5ea8SMatthew G. Knepley PetscErrorCode PCPatchSetSaveOperators(PC pc, PetscBool flg)
2894bbf5ea8SMatthew G. Knepley {
2904bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *) pc->data;
2914bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
2924bbf5ea8SMatthew G. Knepley   patch->save_operators = flg;
2934bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
2944bbf5ea8SMatthew G. Knepley }
2954bbf5ea8SMatthew G. Knepley 
2964bbf5ea8SMatthew G. Knepley /* TODO: Docs */
2974bbf5ea8SMatthew G. Knepley PetscErrorCode PCPatchGetSaveOperators(PC pc, PetscBool *flg)
2984bbf5ea8SMatthew G. Knepley {
2994bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *) pc->data;
3004bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
3014bbf5ea8SMatthew G. Knepley   *flg = patch->save_operators;
3024bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
3034bbf5ea8SMatthew G. Knepley }
3044bbf5ea8SMatthew G. Knepley 
3054bbf5ea8SMatthew G. Knepley /* TODO: Docs */
3064bbf5ea8SMatthew G. Knepley PetscErrorCode PCPatchSetPartitionOfUnity(PC pc, PetscBool flg)
3074bbf5ea8SMatthew G. Knepley {
3084bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *) pc->data;
3094bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
3104bbf5ea8SMatthew G. Knepley   patch->partition_of_unity = flg;
3114bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
3124bbf5ea8SMatthew G. Knepley }
3134bbf5ea8SMatthew G. Knepley 
3144bbf5ea8SMatthew G. Knepley /* TODO: Docs */
3154bbf5ea8SMatthew G. Knepley PetscErrorCode PCPatchGetPartitionOfUnity(PC pc, PetscBool *flg)
3164bbf5ea8SMatthew G. Knepley {
3174bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *) pc->data;
3184bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
3194bbf5ea8SMatthew G. Knepley   *flg = patch->partition_of_unity;
3204bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
3214bbf5ea8SMatthew G. Knepley }
3224bbf5ea8SMatthew G. Knepley 
3234bbf5ea8SMatthew G. Knepley /* TODO: Docs */
32461c4b389SFlorian Wechsung PetscErrorCode PCPatchSetLocalComposition(PC pc, PCCompositeType type)
325c2e6f3c0SFlorian Wechsung {
326c2e6f3c0SFlorian Wechsung   PC_PATCH *patch = (PC_PATCH *) pc->data;
327c2e6f3c0SFlorian Wechsung   PetscFunctionBegin;
32861c4b389SFlorian Wechsung   if (type != PC_COMPOSITE_ADDITIVE && type != PC_COMPOSITE_MULTIPLICATIVE) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Only supports additive or multiplicative as the local type");
32961c4b389SFlorian Wechsung   patch->local_composition_type = type;
330c2e6f3c0SFlorian Wechsung   PetscFunctionReturn(0);
331c2e6f3c0SFlorian Wechsung }
332c2e6f3c0SFlorian Wechsung 
333c2e6f3c0SFlorian Wechsung /* TODO: Docs */
33461c4b389SFlorian Wechsung PetscErrorCode PCPatchGetLocalComposition(PC pc, PCCompositeType *type)
335c2e6f3c0SFlorian Wechsung {
336c2e6f3c0SFlorian Wechsung   PC_PATCH *patch = (PC_PATCH *) pc->data;
337c2e6f3c0SFlorian Wechsung   PetscFunctionBegin;
33861c4b389SFlorian Wechsung   *type = patch->local_composition_type;
339c2e6f3c0SFlorian Wechsung   PetscFunctionReturn(0);
340c2e6f3c0SFlorian Wechsung }
341c2e6f3c0SFlorian Wechsung 
342c2e6f3c0SFlorian Wechsung /* TODO: Docs */
3434bbf5ea8SMatthew G. Knepley PetscErrorCode PCPatchSetSubMatType(PC pc, MatType sub_mat_type)
3444bbf5ea8SMatthew G. Knepley {
3454bbf5ea8SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
3464bbf5ea8SMatthew G. Knepley   PetscErrorCode ierr;
3474bbf5ea8SMatthew G. Knepley 
3484bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
3494bbf5ea8SMatthew G. Knepley   if (patch->sub_mat_type) {ierr = PetscFree(patch->sub_mat_type);CHKERRQ(ierr);}
3504bbf5ea8SMatthew G. Knepley   ierr = PetscStrallocpy(sub_mat_type, (char **) &patch->sub_mat_type);CHKERRQ(ierr);
3514bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
3524bbf5ea8SMatthew G. Knepley }
3534bbf5ea8SMatthew G. Knepley 
3544bbf5ea8SMatthew G. Knepley /* TODO: Docs */
3554bbf5ea8SMatthew G. Knepley PetscErrorCode PCPatchGetSubMatType(PC pc, MatType *sub_mat_type)
3564bbf5ea8SMatthew G. Knepley {
3574bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *) pc->data;
3584bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
3594bbf5ea8SMatthew G. Knepley   *sub_mat_type = patch->sub_mat_type;
3604bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
3614bbf5ea8SMatthew G. Knepley }
3624bbf5ea8SMatthew G. Knepley 
3634bbf5ea8SMatthew G. Knepley /* TODO: Docs */
3644bbf5ea8SMatthew G. Knepley PetscErrorCode PCPatchSetCellNumbering(PC pc, PetscSection cellNumbering)
3654bbf5ea8SMatthew G. Knepley {
3664bbf5ea8SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
3674bbf5ea8SMatthew G. Knepley   PetscErrorCode ierr;
3684bbf5ea8SMatthew G. Knepley 
3694bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
3704bbf5ea8SMatthew G. Knepley   patch->cellNumbering = cellNumbering;
3714bbf5ea8SMatthew G. Knepley   ierr = PetscObjectReference((PetscObject) cellNumbering);CHKERRQ(ierr);
3724bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
3734bbf5ea8SMatthew G. Knepley }
3744bbf5ea8SMatthew G. Knepley 
3754bbf5ea8SMatthew G. Knepley /* TODO: Docs */
3764bbf5ea8SMatthew G. Knepley PetscErrorCode PCPatchGetCellNumbering(PC pc, PetscSection *cellNumbering)
3774bbf5ea8SMatthew G. Knepley {
3784bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *) pc->data;
3794bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
3804bbf5ea8SMatthew G. Knepley   *cellNumbering = patch->cellNumbering;
3814bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
3824bbf5ea8SMatthew G. Knepley }
3834bbf5ea8SMatthew G. Knepley 
3844bbf5ea8SMatthew G. Knepley /* TODO: Docs */
3854bbf5ea8SMatthew G. Knepley PetscErrorCode PCPatchSetConstructType(PC pc, PCPatchConstructType ctype, PetscErrorCode (*func)(PC, PetscInt *, IS **, IS *, void *), void *ctx)
3864bbf5ea8SMatthew G. Knepley {
3874bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *) pc->data;
3884bbf5ea8SMatthew G. Knepley 
3894bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
3904bbf5ea8SMatthew G. Knepley   patch->ctype = ctype;
3914bbf5ea8SMatthew G. Knepley   switch (ctype) {
3924bbf5ea8SMatthew G. Knepley   case PC_PATCH_STAR:
39340c17a03SPatrick Farrell     patch->user_patches     = PETSC_FALSE;
3944bbf5ea8SMatthew G. Knepley     patch->patchconstructop = PCPatchConstruct_Star;
3954bbf5ea8SMatthew G. Knepley     break;
3964bbf5ea8SMatthew G. Knepley   case PC_PATCH_VANKA:
39740c17a03SPatrick Farrell     patch->user_patches     = PETSC_FALSE;
3984bbf5ea8SMatthew G. Knepley     patch->patchconstructop = PCPatchConstruct_Vanka;
3994bbf5ea8SMatthew G. Knepley     break;
400*0a390943SPatrick Farrell   case PC_PATCH_OWNED:
401*0a390943SPatrick Farrell     patch->user_patches     = PETSC_FALSE;
402*0a390943SPatrick Farrell     patch->patchconstructop = PCPatchConstruct_Owned;
403*0a390943SPatrick Farrell     break;
4044bbf5ea8SMatthew G. Knepley   case PC_PATCH_USER:
4054bbf5ea8SMatthew G. Knepley   case PC_PATCH_PYTHON:
4064bbf5ea8SMatthew G. Knepley     patch->user_patches     = PETSC_TRUE;
4074bbf5ea8SMatthew G. Knepley     patch->patchconstructop = PCPatchConstruct_User;
408bdd9e0cdSPatrick Farrell     if (func) {
4094bbf5ea8SMatthew G. Knepley       patch->userpatchconstructionop = func;
4104bbf5ea8SMatthew G. Knepley       patch->userpatchconstructctx   = ctx;
411bdd9e0cdSPatrick Farrell     }
4124bbf5ea8SMatthew G. Knepley     break;
4134bbf5ea8SMatthew G. Knepley   default:
4144bbf5ea8SMatthew G. Knepley     SETERRQ1(PetscObjectComm((PetscObject) pc), PETSC_ERR_USER, "Unknown patch construction type %D", (PetscInt) patch->ctype);
4154bbf5ea8SMatthew G. Knepley   }
4164bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
4174bbf5ea8SMatthew G. Knepley }
4184bbf5ea8SMatthew G. Knepley 
4194bbf5ea8SMatthew G. Knepley /* TODO: Docs */
4204bbf5ea8SMatthew G. Knepley PetscErrorCode PCPatchGetConstructType(PC pc, PCPatchConstructType *ctype, PetscErrorCode (**func)(PC, PetscInt *, IS **, IS *, void *), void **ctx)
4214bbf5ea8SMatthew G. Knepley {
4224bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *) pc->data;
4234bbf5ea8SMatthew G. Knepley 
4244bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
4254bbf5ea8SMatthew G. Knepley   *ctype = patch->ctype;
4264bbf5ea8SMatthew G. Knepley   switch (patch->ctype) {
4274bbf5ea8SMatthew G. Knepley   case PC_PATCH_STAR:
4284bbf5ea8SMatthew G. Knepley   case PC_PATCH_VANKA:
429*0a390943SPatrick Farrell   case PC_PATCH_OWNED:
4304bbf5ea8SMatthew G. Knepley     break;
4314bbf5ea8SMatthew G. Knepley   case PC_PATCH_USER:
4324bbf5ea8SMatthew G. Knepley   case PC_PATCH_PYTHON:
4334bbf5ea8SMatthew G. Knepley     *func = patch->userpatchconstructionop;
4344bbf5ea8SMatthew G. Knepley     *ctx  = patch->userpatchconstructctx;
4354bbf5ea8SMatthew G. Knepley     break;
4364bbf5ea8SMatthew G. Knepley   default:
4374bbf5ea8SMatthew G. Knepley     SETERRQ1(PetscObjectComm((PetscObject) pc), PETSC_ERR_USER, "Unknown patch construction type %D", (PetscInt) patch->ctype);
4384bbf5ea8SMatthew G. Knepley   }
4394bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
4404bbf5ea8SMatthew G. Knepley }
4414bbf5ea8SMatthew G. Knepley 
4424bbf5ea8SMatthew G. Knepley /* TODO: Docs */
4434bbf5ea8SMatthew G. Knepley PetscErrorCode PCPatchSetDiscretisationInfo(PC pc, PetscInt nsubspaces, DM *dms, PetscInt *bs, PetscInt *nodesPerCell, const PetscInt **cellNodeMap,
4444bbf5ea8SMatthew G. Knepley                                             const PetscInt *subspaceOffsets, PetscInt numGhostBcs, const PetscInt *ghostBcNodes, PetscInt numGlobalBcs, const PetscInt *globalBcNodes)
4454bbf5ea8SMatthew G. Knepley {
4464bbf5ea8SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
4475f824522SMatthew G. Knepley   DM             dm;
4484bbf5ea8SMatthew G. Knepley   PetscSF       *sfs;
4495f824522SMatthew G. Knepley   PetscInt       cStart, cEnd, i, j;
4504bbf5ea8SMatthew G. Knepley   PetscErrorCode ierr;
4514bbf5ea8SMatthew G. Knepley 
4524bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
4535f824522SMatthew G. Knepley   ierr = PCGetDM(pc, &dm);CHKERRQ(ierr);
4545f824522SMatthew G. Knepley   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4554bbf5ea8SMatthew G. Knepley   ierr = PetscMalloc1(nsubspaces, &sfs);CHKERRQ(ierr);
4564bbf5ea8SMatthew G. Knepley   ierr = PetscMalloc1(nsubspaces, &patch->dofSection);CHKERRQ(ierr);
4574bbf5ea8SMatthew G. Knepley   ierr = PetscMalloc1(nsubspaces, &patch->bs);CHKERRQ(ierr);
4584bbf5ea8SMatthew G. Knepley   ierr = PetscMalloc1(nsubspaces, &patch->nodesPerCell);CHKERRQ(ierr);
4594bbf5ea8SMatthew G. Knepley   ierr = PetscMalloc1(nsubspaces, &patch->cellNodeMap);CHKERRQ(ierr);
4604bbf5ea8SMatthew G. Knepley   ierr = PetscMalloc1(nsubspaces+1, &patch->subspaceOffsets);CHKERRQ(ierr);
4614bbf5ea8SMatthew G. Knepley 
4624bbf5ea8SMatthew G. Knepley   patch->nsubspaces       = nsubspaces;
4634bbf5ea8SMatthew G. Knepley   patch->totalDofsPerCell = 0;
4644bbf5ea8SMatthew G. Knepley   for (i = 0; i < nsubspaces; ++i) {
4654bbf5ea8SMatthew G. Knepley     ierr = DMGetDefaultSection(dms[i], &patch->dofSection[i]);CHKERRQ(ierr);
4664bbf5ea8SMatthew G. Knepley     ierr = PetscObjectReference((PetscObject) patch->dofSection[i]);CHKERRQ(ierr);
4674bbf5ea8SMatthew G. Knepley     ierr = DMGetDefaultSF(dms[i], &sfs[i]);CHKERRQ(ierr);
4684bbf5ea8SMatthew G. Knepley     patch->bs[i]              = bs[i];
4694bbf5ea8SMatthew G. Knepley     patch->nodesPerCell[i]    = nodesPerCell[i];
4704bbf5ea8SMatthew G. Knepley     patch->totalDofsPerCell  += nodesPerCell[i]*bs[i];
47180e8a965SFlorian Wechsung     ierr = PetscMalloc1((cEnd-cStart)*nodesPerCell[i], &patch->cellNodeMap[i]);CHKERRQ(ierr);
47280e8a965SFlorian Wechsung     for (j = 0; j < (cEnd-cStart)*nodesPerCell[i]; ++j) patch->cellNodeMap[i][j] = cellNodeMap[i][j];
4734bbf5ea8SMatthew G. Knepley     patch->subspaceOffsets[i] = subspaceOffsets[i];
4744bbf5ea8SMatthew G. Knepley   }
4754bbf5ea8SMatthew G. Knepley   ierr = PCPatchCreateDefaultSF_Private(pc, nsubspaces, sfs, patch->bs);CHKERRQ(ierr);
4764bbf5ea8SMatthew G. Knepley   ierr = PetscFree(sfs);CHKERRQ(ierr);
4774bbf5ea8SMatthew G. Knepley 
4784bbf5ea8SMatthew G. Knepley   patch->subspaceOffsets[nsubspaces] = subspaceOffsets[nsubspaces];
4794bbf5ea8SMatthew G. Knepley   ierr = ISCreateGeneral(PETSC_COMM_SELF, numGhostBcs, ghostBcNodes, PETSC_COPY_VALUES, &patch->ghostBcNodes);CHKERRQ(ierr);
4804bbf5ea8SMatthew G. Knepley   ierr = ISCreateGeneral(PETSC_COMM_SELF, numGlobalBcs, globalBcNodes, PETSC_COPY_VALUES, &patch->globalBcNodes);CHKERRQ(ierr);
4814bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
4824bbf5ea8SMatthew G. Knepley }
4834bbf5ea8SMatthew G. Knepley 
4844bbf5ea8SMatthew G. Knepley /* TODO: Docs */
4855f824522SMatthew G. Knepley PetscErrorCode PCPatchSetDiscretisationInfoCombined(PC pc, DM dm, PetscInt *nodesPerCell, const PetscInt **cellNodeMap, PetscInt numGhostBcs, const PetscInt *ghostBcNodes, PetscInt numGlobalBcs, const PetscInt *globalBcNodes)
4865f824522SMatthew G. Knepley {
4875f824522SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
4885f824522SMatthew G. Knepley   PetscInt       cStart, cEnd, i, j;
4895f824522SMatthew G. Knepley   PetscErrorCode ierr;
4905f824522SMatthew G. Knepley 
4915f824522SMatthew G. Knepley   PetscFunctionBegin;
4925f824522SMatthew G. Knepley   patch->combined = PETSC_TRUE;
4935f824522SMatthew G. Knepley   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4945f824522SMatthew G. Knepley   ierr = DMGetNumFields(dm, &patch->nsubspaces);CHKERRQ(ierr);
4955f824522SMatthew G. Knepley   ierr = PetscCalloc1(patch->nsubspaces, &patch->dofSection);CHKERRQ(ierr);
4965f824522SMatthew G. Knepley   ierr = PetscMalloc1(patch->nsubspaces, &patch->bs);CHKERRQ(ierr);
4975f824522SMatthew G. Knepley   ierr = PetscMalloc1(patch->nsubspaces, &patch->nodesPerCell);CHKERRQ(ierr);
4985f824522SMatthew G. Knepley   ierr = PetscMalloc1(patch->nsubspaces, &patch->cellNodeMap);CHKERRQ(ierr);
4995f824522SMatthew G. Knepley   ierr = PetscCalloc1(patch->nsubspaces+1, &patch->subspaceOffsets);CHKERRQ(ierr);
5005f824522SMatthew G. Knepley   ierr = DMGetDefaultSection(dm, &patch->dofSection[0]);CHKERRQ(ierr);
5015f824522SMatthew G. Knepley   ierr = PetscObjectReference((PetscObject) patch->dofSection[0]);CHKERRQ(ierr);
5025f824522SMatthew G. Knepley   ierr = PetscSectionGetStorageSize(patch->dofSection[0], &patch->subspaceOffsets[patch->nsubspaces]);CHKERRQ(ierr);
5035f824522SMatthew G. Knepley   patch->totalDofsPerCell = 0;
5045f824522SMatthew G. Knepley   for (i = 0; i < patch->nsubspaces; ++i) {
5055f824522SMatthew G. Knepley     patch->bs[i]             = 1;
5065f824522SMatthew G. Knepley     patch->nodesPerCell[i]   = nodesPerCell[i];
5075f824522SMatthew G. Knepley     patch->totalDofsPerCell += nodesPerCell[i];
5085f824522SMatthew G. Knepley     ierr = PetscMalloc1((cEnd-cStart)*nodesPerCell[i], &patch->cellNodeMap[i]);CHKERRQ(ierr);
5095f824522SMatthew G. Knepley     for (j = 0; j < (cEnd-cStart)*nodesPerCell[i]; ++j) patch->cellNodeMap[i][j] = cellNodeMap[i][j];
5105f824522SMatthew G. Knepley   }
5115f824522SMatthew G. Knepley   ierr = DMGetDefaultSF(dm, &patch->defaultSF);CHKERRQ(ierr);
5125f824522SMatthew G. Knepley   ierr = PetscObjectReference((PetscObject) patch->defaultSF);CHKERRQ(ierr);
5135f824522SMatthew G. Knepley   ierr = ISCreateGeneral(PETSC_COMM_SELF, numGhostBcs, ghostBcNodes, PETSC_COPY_VALUES, &patch->ghostBcNodes);CHKERRQ(ierr);
5145f824522SMatthew G. Knepley   ierr = ISCreateGeneral(PETSC_COMM_SELF, numGlobalBcs, globalBcNodes, PETSC_COPY_VALUES, &patch->globalBcNodes);CHKERRQ(ierr);
5155f824522SMatthew G. Knepley   PetscFunctionReturn(0);
5165f824522SMatthew G. Knepley }
5175f824522SMatthew G. Knepley 
5185f824522SMatthew G. Knepley /*@C
5195f824522SMatthew G. Knepley 
52092d50984SMatthew G. Knepley   PCPatchSetComputeFunction - Set the callback used to compute patch residuals
52192d50984SMatthew G. Knepley 
52292d50984SMatthew G. Knepley   Input Parameters:
52392d50984SMatthew G. Knepley + pc   - The PC
52492d50984SMatthew G. Knepley . func - The callback
52592d50984SMatthew G. Knepley - ctx  - The user context
52692d50984SMatthew G. Knepley 
52792d50984SMatthew G. Knepley   Level: advanced
52892d50984SMatthew G. Knepley 
52992d50984SMatthew G. Knepley   Note:
53092d50984SMatthew G. Knepley   The callback has signature:
53192d50984SMatthew G. Knepley +  usercomputef(pc, point, x, f, cellIS, n, u, ctx)
53292d50984SMatthew G. Knepley +  pc     - The PC
53392d50984SMatthew G. Knepley +  point  - The point
53492d50984SMatthew G. Knepley +  x      - The input solution (not used in linear problems)
53592d50984SMatthew G. Knepley +  f      - The patch residual vector
53692d50984SMatthew G. Knepley +  cellIS - An array of the cell numbers
53792d50984SMatthew G. Knepley +  n      - The size of g2l
53892d50984SMatthew G. Knepley +  g2l    - The global to local dof translation table
53992d50984SMatthew G. Knepley +  ctx    - The user context
54092d50984SMatthew G. Knepley   and can assume that the matrix entries have been set to zero before the call.
54192d50984SMatthew G. Knepley 
54292d50984SMatthew G. Knepley .seealso: PCPatchSetComputeOperator(), PCPatchGetComputeOperator(), PCPatchSetDiscretisationInfo()
54392d50984SMatthew G. Knepley @*/
54439fd2e8aSPatrick Farrell PetscErrorCode PCPatchSetComputeFunction(PC pc, PetscErrorCode (*func)(PC, PetscInt, Vec, Vec, IS, PetscInt, const PetscInt *, const PetscInt *, void *), void *ctx)
54592d50984SMatthew G. Knepley {
54692d50984SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *) pc->data;
54792d50984SMatthew G. Knepley 
54892d50984SMatthew G. Knepley   PetscFunctionBegin;
54992d50984SMatthew G. Knepley   patch->usercomputef    = func;
55092d50984SMatthew G. Knepley   patch->usercomputefctx = ctx;
55192d50984SMatthew G. Knepley   PetscFunctionReturn(0);
55292d50984SMatthew G. Knepley }
55392d50984SMatthew G. Knepley 
55492d50984SMatthew G. Knepley /*@C
55592d50984SMatthew G. Knepley 
5565f824522SMatthew G. Knepley   PCPatchSetComputeOperator - Set the callback used to compute patch matrices
5575f824522SMatthew G. Knepley 
5585f824522SMatthew G. Knepley   Input Parameters:
5595f824522SMatthew G. Knepley + pc   - The PC
5605f824522SMatthew G. Knepley . func - The callback
5615f824522SMatthew G. Knepley - ctx  - The user context
5625f824522SMatthew G. Knepley 
5635f824522SMatthew G. Knepley   Level: advanced
5645f824522SMatthew G. Knepley 
5655f824522SMatthew G. Knepley   Note:
5665f824522SMatthew G. Knepley   The callback has signature:
567723f9013SMatthew G. Knepley +  usercomputeop(pc, point, x, mat, cellIS, n, u, ctx)
5685f824522SMatthew G. Knepley +  pc     - The PC
569bdd9e0cdSPatrick Farrell +  point  - The point
570723f9013SMatthew G. Knepley +  x      - The input solution (not used in linear problems)
5715f824522SMatthew G. Knepley +  mat    - The patch matrix
5726f158342SMatthew G. Knepley +  cellIS - An array of the cell numbers
5735f824522SMatthew G. Knepley +  n      - The size of g2l
5745f824522SMatthew G. Knepley +  g2l    - The global to local dof translation table
5755f824522SMatthew G. Knepley +  ctx    - The user context
5765f824522SMatthew G. Knepley   and can assume that the matrix entries have been set to zero before the call.
5775f824522SMatthew G. Knepley 
578723f9013SMatthew G. Knepley .seealso: PCPatchGetComputeOperator(), PCPatchSetComputeFunction(), PCPatchSetDiscretisationInfo()
5795f824522SMatthew G. Knepley @*/
5804d04e9f1SPatrick Farrell PetscErrorCode PCPatchSetComputeOperator(PC pc, PetscErrorCode (*func)(PC, PetscInt, Vec, Mat, IS, PetscInt, const PetscInt *, const PetscInt *, void *), void *ctx)
5814bbf5ea8SMatthew G. Knepley {
5824bbf5ea8SMatthew G. Knepley   PC_PATCH *patch = (PC_PATCH *) pc->data;
5834bbf5ea8SMatthew G. Knepley 
5844bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
5854bbf5ea8SMatthew G. Knepley   patch->usercomputeop    = func;
586723f9013SMatthew G. Knepley   patch->usercomputeopctx = ctx;
5874bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
5884bbf5ea8SMatthew G. Knepley }
5894bbf5ea8SMatthew G. Knepley 
5904bbf5ea8SMatthew G. Knepley /* On entry, ht contains the topological entities whose dofs we are responsible for solving for;
5914bbf5ea8SMatthew G. Knepley    on exit, cht contains all the topological entities we need to compute their residuals.
5924bbf5ea8SMatthew G. Knepley    In full generality this should incorporate knowledge of the sparsity pattern of the matrix;
5934bbf5ea8SMatthew G. Knepley    here we assume a standard FE sparsity pattern.*/
5944bbf5ea8SMatthew G. Knepley /* TODO: Use DMPlexGetAdjacency() */
5951b68eb51SMatthew G. Knepley static PetscErrorCode PCPatchCompleteCellPatch(PC pc, PetscHSetI ht, PetscHSetI cht)
5964bbf5ea8SMatthew G. Knepley {
5975f824522SMatthew G. Knepley   DM             dm;
5981b68eb51SMatthew G. Knepley   PetscHashIter  hi;
5994bbf5ea8SMatthew G. Knepley   PetscInt       point;
6004bbf5ea8SMatthew G. Knepley   PetscInt      *star = NULL, *closure = NULL;
6014c954380SMatthew G. Knepley   PetscInt       ignoredim, iStart = 0, iEnd = -1, starSize, closureSize, si, ci;
6024bbf5ea8SMatthew G. Knepley   PetscErrorCode ierr;
6034bbf5ea8SMatthew G. Knepley 
6044bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
6055f824522SMatthew G. Knepley   ierr = PCGetDM(pc, &dm);CHKERRQ(ierr);
6065f824522SMatthew G. Knepley   ierr = PCPatchGetIgnoreDim(pc, &ignoredim);CHKERRQ(ierr);
6075f824522SMatthew G. Knepley   if (ignoredim >= 0) {ierr = DMPlexGetDepthStratum(dm, ignoredim, &iStart, &iEnd);CHKERRQ(ierr);}
6081b68eb51SMatthew G. Knepley   ierr = PetscHSetIClear(cht);CHKERRQ(ierr);
6091b68eb51SMatthew G. Knepley   PetscHashIterBegin(ht, hi);
6101b68eb51SMatthew G. Knepley   while (!PetscHashIterAtEnd(ht, hi)) {
6114c954380SMatthew G. Knepley 
6121b68eb51SMatthew G. Knepley     PetscHashIterGetKey(ht, hi, point);
6131b68eb51SMatthew G. Knepley     PetscHashIterNext(ht, hi);
6144bbf5ea8SMatthew G. Knepley 
6154bbf5ea8SMatthew G. Knepley     /* Loop over all the cells that this point connects to */
6164bbf5ea8SMatthew G. Knepley     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
6175f824522SMatthew G. Knepley     for (si = 0; si < starSize*2; si += 2) {
6184c954380SMatthew G. Knepley       const PetscInt ownedpoint = star[si];
6195f824522SMatthew G. Knepley       /* TODO Check for point in cht before running through closure again */
6204bbf5ea8SMatthew G. Knepley       /* now loop over all entities in the closure of that cell */
6214bbf5ea8SMatthew G. Knepley       ierr = DMPlexGetTransitiveClosure(dm, ownedpoint, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6225f824522SMatthew G. Knepley       for (ci = 0; ci < closureSize*2; ci += 2) {
6234c954380SMatthew G. Knepley         const PetscInt seenpoint = closure[ci];
6245f824522SMatthew G. Knepley         if (ignoredim >= 0 && seenpoint >= iStart && seenpoint < iEnd) continue;
6251b68eb51SMatthew G. Knepley         ierr = PetscHSetIAdd(cht, seenpoint);CHKERRQ(ierr);
6264bbf5ea8SMatthew G. Knepley       }
6274bbf5ea8SMatthew G. Knepley     }
6284bbf5ea8SMatthew G. Knepley   }
6294c954380SMatthew G. Knepley   ierr = DMPlexRestoreTransitiveClosure(dm, 0, PETSC_TRUE, NULL, &closure);CHKERRQ(ierr);
6305f824522SMatthew G. Knepley   ierr = DMPlexRestoreTransitiveClosure(dm, 0, PETSC_FALSE, NULL, &star);CHKERRQ(ierr);
6315f824522SMatthew G. Knepley   PetscFunctionReturn(0);
6325f824522SMatthew G. Knepley }
6335f824522SMatthew G. Knepley 
6345f824522SMatthew G. Knepley static PetscErrorCode PCPatchGetGlobalDofs(PC pc, PetscSection dofSection[], PetscInt f, PetscBool combined, PetscInt p, PetscInt *dof, PetscInt *off)
6355f824522SMatthew G. Knepley {
6365f824522SMatthew G. Knepley   PetscErrorCode ierr;
6375f824522SMatthew G. Knepley 
6385f824522SMatthew G. Knepley   PetscFunctionBegin;
6395f824522SMatthew G. Knepley   if (combined) {
6405f824522SMatthew G. Knepley     if (f < 0) {
6415f824522SMatthew G. Knepley       if (dof) {ierr = PetscSectionGetDof(dofSection[0], p, dof);CHKERRQ(ierr);}
6425f824522SMatthew G. Knepley       if (off) {ierr = PetscSectionGetOffset(dofSection[0], p, off);CHKERRQ(ierr);}
6435f824522SMatthew G. Knepley     } else {
6445f824522SMatthew G. Knepley       if (dof) {ierr = PetscSectionGetFieldDof(dofSection[0], p, f, dof);CHKERRQ(ierr);}
6455f824522SMatthew G. Knepley       if (off) {ierr = PetscSectionGetFieldOffset(dofSection[0], p, f, off);CHKERRQ(ierr);}
6465f824522SMatthew G. Knepley     }
6475f824522SMatthew G. Knepley   } else {
6485f824522SMatthew G. Knepley     if (f < 0) {
6495f824522SMatthew G. Knepley       PC_PATCH *patch = (PC_PATCH *) pc->data;
6505f824522SMatthew G. Knepley       PetscInt  fdof, g;
6515f824522SMatthew G. Knepley 
6525f824522SMatthew G. Knepley       if (dof) {
6535f824522SMatthew G. Knepley         *dof = 0;
6545f824522SMatthew G. Knepley         for (g = 0; g < patch->nsubspaces; ++g) {
6555f824522SMatthew G. Knepley           ierr = PetscSectionGetDof(dofSection[g], p, &fdof);CHKERRQ(ierr);
6565f824522SMatthew G. Knepley           *dof += fdof;
6575f824522SMatthew G. Knepley         }
6585f824522SMatthew G. Knepley       }
659624e31c3SLawrence Mitchell       if (off) {
660624e31c3SLawrence Mitchell         *off = 0;
661624e31c3SLawrence Mitchell         for (g = 0; g < patch->nsubspaces; ++g) {
662624e31c3SLawrence Mitchell           ierr = PetscSectionGetOffset(dofSection[g], p, &fdof);CHKERRQ(ierr);
663624e31c3SLawrence Mitchell           *off += fdof;
664624e31c3SLawrence Mitchell         }
665624e31c3SLawrence Mitchell       }
6665f824522SMatthew G. Knepley     } else {
6675f824522SMatthew G. Knepley       if (dof) {ierr = PetscSectionGetDof(dofSection[f], p, dof);CHKERRQ(ierr);}
6685f824522SMatthew G. Knepley       if (off) {ierr = PetscSectionGetOffset(dofSection[f], p, off);CHKERRQ(ierr);}
6695f824522SMatthew G. Knepley     }
6705f824522SMatthew G. Knepley   }
6714bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
6724bbf5ea8SMatthew G. Knepley }
6734bbf5ea8SMatthew G. Knepley 
6744bbf5ea8SMatthew G. Knepley /* Given a hash table with a set of topological entities (pts), compute the degrees of
6754bbf5ea8SMatthew G. Knepley    freedom in global concatenated numbering on those entities.
6764bbf5ea8SMatthew G. Knepley    For Vanka smoothing, this needs to do something special: ignore dofs of the
6774bbf5ea8SMatthew G. Knepley    constraint subspace on entities that aren't the base entity we're building the patch
6784bbf5ea8SMatthew G. Knepley    around. */
679e4c66b91SPatrick Farrell static PetscErrorCode PCPatchGetPointDofs(PC pc, PetscHSetI pts, PetscHSetI dofs, PetscInt base, PetscHSetI* subspaces_to_exclude)
6804bbf5ea8SMatthew G. Knepley {
6815f824522SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
6821b68eb51SMatthew G. Knepley   PetscHashIter  hi;
6834bbf5ea8SMatthew G. Knepley   PetscInt       ldof, loff;
6844bbf5ea8SMatthew G. Knepley   PetscInt       k, p;
6854bbf5ea8SMatthew G. Knepley   PetscErrorCode ierr;
6864bbf5ea8SMatthew G. Knepley 
6874bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
6881b68eb51SMatthew G. Knepley   ierr = PetscHSetIClear(dofs);CHKERRQ(ierr);
6894bbf5ea8SMatthew G. Knepley   for (k = 0; k < patch->nsubspaces; ++k) {
6904bbf5ea8SMatthew G. Knepley     PetscInt subspaceOffset = patch->subspaceOffsets[k];
6914bbf5ea8SMatthew G. Knepley     PetscInt bs             = patch->bs[k];
6924bbf5ea8SMatthew G. Knepley     PetscInt j, l;
6934bbf5ea8SMatthew G. Knepley 
694e4c66b91SPatrick Farrell     if (subspaces_to_exclude != NULL) {
695e4c66b91SPatrick Farrell       PetscBool should_exclude_k = PETSC_FALSE;
696e4c66b91SPatrick Farrell       PetscHSetIHas(*subspaces_to_exclude, k, &should_exclude_k);
697e4c66b91SPatrick Farrell       if (should_exclude_k) {
6984bbf5ea8SMatthew G. Knepley         /* only get this subspace dofs at the base entity, not any others */
6995f824522SMatthew G. Knepley         ierr = PCPatchGetGlobalDofs(pc, patch->dofSection, k, patch->combined, base, &ldof, &loff);CHKERRQ(ierr);
7004bbf5ea8SMatthew G. Knepley         if (0 == ldof) continue;
7014bbf5ea8SMatthew G. Knepley         for (j = loff; j < ldof + loff; ++j) {
7024bbf5ea8SMatthew G. Knepley           for (l = 0; l < bs; ++l) {
7034bbf5ea8SMatthew G. Knepley             PetscInt dof = bs*j + l + subspaceOffset;
7041b68eb51SMatthew G. Knepley             ierr = PetscHSetIAdd(dofs, dof);CHKERRQ(ierr);
7054bbf5ea8SMatthew G. Knepley           }
7064bbf5ea8SMatthew G. Knepley         }
7074bbf5ea8SMatthew G. Knepley         continue; /* skip the other dofs of this subspace */
7084bbf5ea8SMatthew G. Knepley       }
709e4c66b91SPatrick Farrell     }
7104bbf5ea8SMatthew G. Knepley 
7111b68eb51SMatthew G. Knepley     PetscHashIterBegin(pts, hi);
7121b68eb51SMatthew G. Knepley     while (!PetscHashIterAtEnd(pts, hi)) {
7131b68eb51SMatthew G. Knepley       PetscHashIterGetKey(pts, hi, p);
7141b68eb51SMatthew G. Knepley       PetscHashIterNext(pts, hi);
7155f824522SMatthew G. Knepley       ierr = PCPatchGetGlobalDofs(pc, patch->dofSection, k, patch->combined, p, &ldof, &loff);CHKERRQ(ierr);
7164bbf5ea8SMatthew G. Knepley       if (0 == ldof) continue;
7174bbf5ea8SMatthew G. Knepley       for (j = loff; j < ldof + loff; ++j) {
7184bbf5ea8SMatthew G. Knepley         for (l = 0; l < bs; ++l) {
7194bbf5ea8SMatthew G. Knepley           PetscInt dof = bs*j + l + subspaceOffset;
7201b68eb51SMatthew G. Knepley           ierr = PetscHSetIAdd(dofs, dof);CHKERRQ(ierr);
7214bbf5ea8SMatthew G. Knepley         }
7224bbf5ea8SMatthew G. Knepley       }
7234bbf5ea8SMatthew G. Knepley     }
7244bbf5ea8SMatthew G. Knepley   }
7254bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
7264bbf5ea8SMatthew G. Knepley }
7274bbf5ea8SMatthew G. Knepley 
7284bbf5ea8SMatthew G. Knepley /* Given two hash tables A and B, compute the keys in B that are not in A, and put them in C */
7291b68eb51SMatthew G. Knepley static PetscErrorCode PCPatchComputeSetDifference_Private(PetscHSetI A, PetscHSetI B, PetscHSetI C)
7304bbf5ea8SMatthew G. Knepley {
7311b68eb51SMatthew G. Knepley   PetscHashIter  hi;
7321b68eb51SMatthew G. Knepley   PetscInt       key;
7334bbf5ea8SMatthew G. Knepley   PetscBool      flg;
7341b68eb51SMatthew G. Knepley   PetscErrorCode ierr;
7354bbf5ea8SMatthew G. Knepley 
7364bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
7371b68eb51SMatthew G. Knepley   ierr = PetscHSetIClear(C);CHKERRQ(ierr);
7381b68eb51SMatthew G. Knepley   PetscHashIterBegin(B, hi);
7391b68eb51SMatthew G. Knepley   while (!PetscHashIterAtEnd(B, hi)) {
7401b68eb51SMatthew G. Knepley     PetscHashIterGetKey(B, hi, key);
7411b68eb51SMatthew G. Knepley     PetscHashIterNext(B, hi);
7421b68eb51SMatthew G. Knepley     ierr = PetscHSetIHas(A, key, &flg);CHKERRQ(ierr);
7431b68eb51SMatthew G. Knepley     if (!flg) {ierr = PetscHSetIAdd(C, key);CHKERRQ(ierr);}
7444bbf5ea8SMatthew G. Knepley   }
7454bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
7464bbf5ea8SMatthew G. Knepley }
7474bbf5ea8SMatthew G. Knepley 
7484bbf5ea8SMatthew G. Knepley /*
7494bbf5ea8SMatthew G. Knepley  * PCPatchCreateCellPatches - create patches.
7504bbf5ea8SMatthew G. Knepley  *
7514bbf5ea8SMatthew G. Knepley  * Input Parameters:
7524bbf5ea8SMatthew G. Knepley  * + dm - The DMPlex object defining the mesh
7534bbf5ea8SMatthew G. Knepley  *
7544bbf5ea8SMatthew G. Knepley  * Output Parameters:
7554bbf5ea8SMatthew G. Knepley  * + cellCounts  - Section with counts of cells around each vertex
7565f824522SMatthew G. Knepley  * . cells       - IS of the cell point indices of cells in each patch
7575f824522SMatthew G. Knepley  * . pointCounts - Section with counts of cells around each vertex
7585f824522SMatthew G. Knepley  * - point       - IS of the cell point indices of cells in each patch
7594bbf5ea8SMatthew G. Knepley  */
7604bbf5ea8SMatthew G. Knepley static PetscErrorCode PCPatchCreateCellPatches(PC pc)
7614bbf5ea8SMatthew G. Knepley {
7624bbf5ea8SMatthew G. Knepley   PC_PATCH       *patch = (PC_PATCH *) pc->data;
7635f824522SMatthew G. Knepley   DMLabel         ghost = NULL;
7644bbf5ea8SMatthew G. Knepley   DM              dm, plex;
7651b68eb51SMatthew G. Knepley   PetscHSetI      ht, cht;
7665f824522SMatthew G. Knepley   PetscSection    cellCounts,  pointCounts;
7675f824522SMatthew G. Knepley   PetscInt       *cellsArray, *pointsArray;
7685f824522SMatthew G. Knepley   PetscInt        numCells,    numPoints;
7695f824522SMatthew G. Knepley   const PetscInt *leaves;
7705f824522SMatthew G. Knepley   PetscInt        nleaves, pStart, pEnd, cStart, cEnd, vStart, vEnd, v;
7715f824522SMatthew G. Knepley   PetscBool       isFiredrake;
7724bbf5ea8SMatthew G. Knepley   PetscErrorCode  ierr;
7734bbf5ea8SMatthew G. Knepley 
7744bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
7754bbf5ea8SMatthew G. Knepley   /* Used to keep track of the cells in the patch. */
7761b68eb51SMatthew G. Knepley   ierr = PetscHSetICreate(&ht);CHKERRQ(ierr);
7771b68eb51SMatthew G. Knepley   ierr = PetscHSetICreate(&cht);CHKERRQ(ierr);
7784bbf5ea8SMatthew G. Knepley 
7794bbf5ea8SMatthew G. Knepley   ierr = PCGetDM(pc, &dm);CHKERRQ(ierr);
7804bbf5ea8SMatthew G. Knepley   if (!dm) SETERRQ(PetscObjectComm((PetscObject) pc), PETSC_ERR_ARG_WRONGSTATE, "DM not yet set on patch PC\n");
7814bbf5ea8SMatthew G. Knepley   ierr = DMConvert(dm, DMPLEX, &plex);CHKERRQ(ierr);
7824bbf5ea8SMatthew G. Knepley   ierr = DMPlexGetChart(plex, &pStart, &pEnd);CHKERRQ(ierr);
7834bbf5ea8SMatthew G. Knepley   ierr = DMPlexGetHeightStratum(plex, 0, &cStart, &cEnd);CHKERRQ(ierr);
7844bbf5ea8SMatthew G. Knepley 
7854bbf5ea8SMatthew G. Knepley   if (patch->user_patches) {
7865f824522SMatthew G. Knepley     ierr = patch->userpatchconstructionop(pc, &patch->npatch, &patch->userIS, &patch->iterationSet, patch->userpatchconstructctx);CHKERRQ(ierr);
7875f824522SMatthew G. Knepley     vStart = 0; vEnd = patch->npatch;
788*0a390943SPatrick Farrell   } else if (patch->ctype == PC_PATCH_OWNED) {
789*0a390943SPatrick Farrell     vStart = 0; vEnd = 1;
7905f824522SMatthew G. Knepley   } else if (patch->codim < 0) {
7915f824522SMatthew G. Knepley     if (patch->dim < 0) {ierr = DMPlexGetDepthStratum(plex,  0,            &vStart, &vEnd);CHKERRQ(ierr);}
7925f824522SMatthew G. Knepley     else                {ierr = DMPlexGetDepthStratum(plex,  patch->dim,   &vStart, &vEnd);CHKERRQ(ierr);}
7935f824522SMatthew G. Knepley   } else                {ierr = DMPlexGetHeightStratum(plex, patch->codim, &vStart, &vEnd);CHKERRQ(ierr);}
7945f824522SMatthew G. Knepley   patch->npatch = vEnd - vStart;
7954bbf5ea8SMatthew G. Knepley 
7964bbf5ea8SMatthew G. Knepley   /* These labels mark the owned points.  We only create patches around points that this process owns. */
7975f824522SMatthew G. Knepley   ierr = DMHasLabel(dm, "pyop2_ghost", &isFiredrake);CHKERRQ(ierr);
7985f824522SMatthew G. Knepley   if (isFiredrake) {
7994bbf5ea8SMatthew G. Knepley     ierr = DMGetLabel(dm, "pyop2_ghost", &ghost);CHKERRQ(ierr);
8004bbf5ea8SMatthew G. Knepley     ierr = DMLabelCreateIndex(ghost, pStart, pEnd);CHKERRQ(ierr);
8015f824522SMatthew G. Knepley   } else {
8025f824522SMatthew G. Knepley     PetscSF sf;
8035f824522SMatthew G. Knepley 
8045f824522SMatthew G. Knepley     ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
8055f824522SMatthew G. Knepley     ierr = PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL);CHKERRQ(ierr);
8065f824522SMatthew G. Knepley     nleaves = PetscMax(nleaves, 0);
8075f824522SMatthew G. Knepley   }
8084bbf5ea8SMatthew G. Knepley 
8094bbf5ea8SMatthew G. Knepley   ierr = PetscSectionCreate(PETSC_COMM_SELF, &patch->cellCounts);CHKERRQ(ierr);
8105f824522SMatthew G. Knepley   ierr = PetscObjectSetName((PetscObject) patch->cellCounts, "Patch Cell Layout");CHKERRQ(ierr);
8114bbf5ea8SMatthew G. Knepley   cellCounts = patch->cellCounts;
8124bbf5ea8SMatthew G. Knepley   ierr = PetscSectionSetChart(cellCounts, vStart, vEnd);CHKERRQ(ierr);
8135f824522SMatthew G. Knepley   ierr = PetscSectionCreate(PETSC_COMM_SELF, &patch->pointCounts);CHKERRQ(ierr);
8145f824522SMatthew G. Knepley   ierr = PetscObjectSetName((PetscObject) patch->pointCounts, "Patch Point Layout");CHKERRQ(ierr);
8155f824522SMatthew G. Knepley   pointCounts = patch->pointCounts;
8165f824522SMatthew G. Knepley   ierr = PetscSectionSetChart(pointCounts, vStart, vEnd);CHKERRQ(ierr);
8175f824522SMatthew G. Knepley   /* Count cells and points in the patch surrounding each entity */
8184bbf5ea8SMatthew G. Knepley   for (v = vStart; v < vEnd; ++v) {
8191b68eb51SMatthew G. Knepley     PetscHashIter hi;
8205f824522SMatthew G. Knepley     PetscInt       chtSize, loc = -1;
8215f824522SMatthew G. Knepley     PetscBool      flg;
8224bbf5ea8SMatthew G. Knepley 
8234bbf5ea8SMatthew G. Knepley     if (!patch->user_patches) {
8245f824522SMatthew G. Knepley       if (ghost) {ierr = DMLabelHasPoint(ghost, v, &flg);CHKERRQ(ierr);}
825928bb9adSStefano Zampini       else       {ierr = PetscFindInt(v, nleaves, leaves, &loc);CHKERRQ(ierr); flg = loc >=0 ? PETSC_TRUE : PETSC_FALSE;}
8264bbf5ea8SMatthew G. Knepley       /* Not an owned entity, don't make a cell patch. */
8274bbf5ea8SMatthew G. Knepley       if (flg) continue;
8284bbf5ea8SMatthew G. Knepley     }
8294bbf5ea8SMatthew G. Knepley 
8304bbf5ea8SMatthew G. Knepley     ierr = patch->patchconstructop((void *) patch, dm, v, ht);CHKERRQ(ierr);
8315f824522SMatthew G. Knepley     ierr = PCPatchCompleteCellPatch(pc, ht, cht);CHKERRQ(ierr);
8321b68eb51SMatthew G. Knepley     ierr = PetscHSetIGetSize(cht, &chtSize);CHKERRQ(ierr);
8334bbf5ea8SMatthew G. Knepley     /* empty patch, continue */
8344bbf5ea8SMatthew G. Knepley     if (chtSize == 0) continue;
8354bbf5ea8SMatthew G. Knepley 
8364bbf5ea8SMatthew G. Knepley     /* safe because size(cht) > 0 from above */
8371b68eb51SMatthew G. Knepley     PetscHashIterBegin(cht, hi);
8381b68eb51SMatthew G. Knepley     while (!PetscHashIterAtEnd(cht, hi)) {
8395f824522SMatthew G. Knepley       PetscInt point, pdof;
8404bbf5ea8SMatthew G. Knepley 
8411b68eb51SMatthew G. Knepley       PetscHashIterGetKey(cht, hi, point);
8425f824522SMatthew G. Knepley       ierr = PCPatchGetGlobalDofs(pc, patch->dofSection, -1, patch->combined, point, &pdof, NULL);CHKERRQ(ierr);
8435f824522SMatthew G. Knepley       if (pdof)                            {ierr = PetscSectionAddDof(pointCounts, v, 1);CHKERRQ(ierr);}
8445f824522SMatthew G. Knepley       if (point >= cStart && point < cEnd) {ierr = PetscSectionAddDof(cellCounts, v, 1);CHKERRQ(ierr);}
8451b68eb51SMatthew G. Knepley       PetscHashIterNext(cht, hi);
8464bbf5ea8SMatthew G. Knepley     }
8474bbf5ea8SMatthew G. Knepley   }
8485f824522SMatthew G. Knepley   if (isFiredrake) {ierr = DMLabelDestroyIndex(ghost);CHKERRQ(ierr);}
8494bbf5ea8SMatthew G. Knepley 
8504bbf5ea8SMatthew G. Knepley   ierr = PetscSectionSetUp(cellCounts);CHKERRQ(ierr);
8514bbf5ea8SMatthew G. Knepley   ierr = PetscSectionGetStorageSize(cellCounts, &numCells);CHKERRQ(ierr);
8524bbf5ea8SMatthew G. Knepley   ierr = PetscMalloc1(numCells, &cellsArray);CHKERRQ(ierr);
8535f824522SMatthew G. Knepley   ierr = PetscSectionSetUp(pointCounts);CHKERRQ(ierr);
8545f824522SMatthew G. Knepley   ierr = PetscSectionGetStorageSize(pointCounts, &numPoints);CHKERRQ(ierr);
8555f824522SMatthew G. Knepley   ierr = PetscMalloc1(numPoints, &pointsArray);CHKERRQ(ierr);
8564bbf5ea8SMatthew G. Knepley 
8574bbf5ea8SMatthew G. Knepley   /* Now that we know how much space we need, run through again and actually remember the cells. */
8584bbf5ea8SMatthew G. Knepley   for (v = vStart; v < vEnd; v++ ) {
8591b68eb51SMatthew G. Knepley     PetscHashIter hi;
8605f824522SMatthew G. Knepley     PetscInt       dof, off, cdof, coff, pdof, n = 0, cn = 0;
8614bbf5ea8SMatthew G. Knepley 
8625f824522SMatthew G. Knepley     ierr = PetscSectionGetDof(pointCounts, v, &dof);CHKERRQ(ierr);
8635f824522SMatthew G. Knepley     ierr = PetscSectionGetOffset(pointCounts, v, &off);CHKERRQ(ierr);
8645f824522SMatthew G. Knepley     ierr = PetscSectionGetDof(cellCounts, v, &cdof);CHKERRQ(ierr);
8655f824522SMatthew G. Knepley     ierr = PetscSectionGetOffset(cellCounts, v, &coff);CHKERRQ(ierr);
8665f824522SMatthew G. Knepley     if (dof <= 0) continue;
8674bbf5ea8SMatthew G. Knepley     ierr = patch->patchconstructop((void *) patch, dm, v, ht);CHKERRQ(ierr);
8685f824522SMatthew G. Knepley     ierr = PCPatchCompleteCellPatch(pc, ht, cht);CHKERRQ(ierr);
8691b68eb51SMatthew G. Knepley     PetscHashIterBegin(cht, hi);
8701b68eb51SMatthew G. Knepley     while (!PetscHashIterAtEnd(cht, hi)) {
8714bbf5ea8SMatthew G. Knepley       PetscInt point;
8724bbf5ea8SMatthew G. Knepley 
8731b68eb51SMatthew G. Knepley       PetscHashIterGetKey(cht, hi, point);
8745f824522SMatthew G. Knepley       ierr = PCPatchGetGlobalDofs(pc, patch->dofSection, -1, patch->combined, point, &pdof, NULL);CHKERRQ(ierr);
8755f824522SMatthew G. Knepley       if (pdof)                            {pointsArray[off + n++] = point;}
8765f824522SMatthew G. Knepley       if (point >= cStart && point < cEnd) {cellsArray[coff + cn++] = point;}
8771b68eb51SMatthew G. Knepley       PetscHashIterNext(cht, hi);
8784bbf5ea8SMatthew G. Knepley     }
8795f824522SMatthew G. Knepley     if (cn != cdof) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of cells in patch %D is %D, but should be %D", v, cn, cdof);
8805f824522SMatthew G. Knepley     if (n  != dof)  SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of points in patch %D is %D, but should be %D", v, n, dof);
8814bbf5ea8SMatthew G. Knepley   }
8821b68eb51SMatthew G. Knepley   ierr = PetscHSetIDestroy(&ht);CHKERRQ(ierr);
8831b68eb51SMatthew G. Knepley   ierr = PetscHSetIDestroy(&cht);CHKERRQ(ierr);
8844bbf5ea8SMatthew G. Knepley   ierr = DMDestroy(&plex);CHKERRQ(ierr);
8855f824522SMatthew G. Knepley 
8865f824522SMatthew G. Knepley   ierr = ISCreateGeneral(PETSC_COMM_SELF, numCells,  cellsArray,  PETSC_OWN_POINTER, &patch->cells);CHKERRQ(ierr);
8875f824522SMatthew G. Knepley   ierr = PetscObjectSetName((PetscObject) patch->cells,  "Patch Cells");CHKERRQ(ierr);
8885f824522SMatthew G. Knepley   if (patch->viewCells) {
8895f824522SMatthew G. Knepley     ierr = ObjectView((PetscObject) patch->cellCounts, patch->viewerCells, patch->formatCells);CHKERRQ(ierr);
8905f824522SMatthew G. Knepley     ierr = ObjectView((PetscObject) patch->cells,      patch->viewerCells, patch->formatCells);CHKERRQ(ierr);
8915f824522SMatthew G. Knepley   }
8925f824522SMatthew G. Knepley   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, pointsArray, PETSC_OWN_POINTER, &patch->points);CHKERRQ(ierr);
8935f824522SMatthew G. Knepley   ierr = PetscObjectSetName((PetscObject) patch->points, "Patch Points");CHKERRQ(ierr);
8945f824522SMatthew G. Knepley   if (patch->viewPoints) {
8955f824522SMatthew G. Knepley     ierr = ObjectView((PetscObject) patch->pointCounts, patch->viewerPoints, patch->formatPoints);CHKERRQ(ierr);
8965f824522SMatthew G. Knepley     ierr = ObjectView((PetscObject) patch->points,      patch->viewerPoints, patch->formatPoints);CHKERRQ(ierr);
8975f824522SMatthew G. Knepley   }
8984bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
8994bbf5ea8SMatthew G. Knepley }
9004bbf5ea8SMatthew G. Knepley 
9014bbf5ea8SMatthew G. Knepley /*
9024bbf5ea8SMatthew G. Knepley  * PCPatchCreateCellPatchDiscretisationInfo - Build the dof maps for cell patches
9034bbf5ea8SMatthew G. Knepley  *
9044bbf5ea8SMatthew G. Knepley  * Input Parameters:
9054bbf5ea8SMatthew G. Knepley  * + dm - The DMPlex object defining the mesh
9064bbf5ea8SMatthew G. Knepley  * . cellCounts - Section with counts of cells around each vertex
9074bbf5ea8SMatthew G. Knepley  * . cells - IS of the cell point indices of cells in each patch
9084bbf5ea8SMatthew G. Knepley  * . cellNumbering - Section mapping plex cell points to Firedrake cell indices.
9094bbf5ea8SMatthew G. Knepley  * . nodesPerCell - number of nodes per cell.
9104bbf5ea8SMatthew G. Knepley  * - cellNodeMap - map from cells to node indices (nodesPerCell * numCells)
9114bbf5ea8SMatthew G. Knepley  *
9124bbf5ea8SMatthew G. Knepley  * Output Parameters:
9135f824522SMatthew G. Knepley  * + dofs - IS of local dof numbers of each cell in the patch, where local is a patch local numbering
9144bbf5ea8SMatthew G. Knepley  * . gtolCounts - Section with counts of dofs per cell patch
9154bbf5ea8SMatthew G. Knepley  * - gtol - IS mapping from global dofs to local dofs for each patch.
9164bbf5ea8SMatthew G. Knepley  */
9174bbf5ea8SMatthew G. Knepley static PetscErrorCode PCPatchCreateCellPatchDiscretisationInfo(PC pc)
9184bbf5ea8SMatthew G. Knepley {
9194bbf5ea8SMatthew G. Knepley   PC_PATCH       *patch           = (PC_PATCH *) pc->data;
9204bbf5ea8SMatthew G. Knepley   PetscSection    cellCounts      = patch->cellCounts;
9215f824522SMatthew G. Knepley   PetscSection    pointCounts     = patch->pointCounts;
9220904074fSPatrick Farrell   PetscSection    gtolCounts, gtolCountsWithArtificial = NULL, gtolCountsWithAll = NULL;
9234bbf5ea8SMatthew G. Knepley   IS              cells           = patch->cells;
9245f824522SMatthew G. Knepley   IS              points          = patch->points;
9254bbf5ea8SMatthew G. Knepley   PetscSection    cellNumbering   = patch->cellNumbering;
9265f824522SMatthew G. Knepley   PetscInt        Nf              = patch->nsubspaces;
9275f824522SMatthew G. Knepley   PetscInt        numCells, numPoints;
9284bbf5ea8SMatthew G. Knepley   PetscInt        numDofs;
9290904074fSPatrick Farrell   PetscInt        numGlobalDofs, numGlobalDofsWithArtificial, numGlobalDofsWithAll;
9304bbf5ea8SMatthew G. Knepley   PetscInt        totalDofsPerCell = patch->totalDofsPerCell;
9314bbf5ea8SMatthew G. Knepley   PetscInt        vStart, vEnd, v;
9325f824522SMatthew G. Knepley   const PetscInt *cellsArray, *pointsArray;
9334bbf5ea8SMatthew G. Knepley   PetscInt       *newCellsArray   = NULL;
9344bbf5ea8SMatthew G. Knepley   PetscInt       *dofsArray       = NULL;
935c2e6f3c0SFlorian Wechsung   PetscInt       *dofsArrayWithArtificial = NULL;
9360904074fSPatrick Farrell   PetscInt       *dofsArrayWithAll = NULL;
9375f824522SMatthew G. Knepley   PetscInt       *offsArray       = NULL;
938c2e6f3c0SFlorian Wechsung   PetscInt       *offsArrayWithArtificial = NULL;
9390904074fSPatrick Farrell   PetscInt       *offsArrayWithAll = NULL;
9404bbf5ea8SMatthew G. Knepley   PetscInt       *asmArray        = NULL;
941c2e6f3c0SFlorian Wechsung   PetscInt       *asmArrayWithArtificial = NULL;
9420904074fSPatrick Farrell   PetscInt       *asmArrayWithAll = NULL;
9434bbf5ea8SMatthew G. Knepley   PetscInt       *globalDofsArray = NULL;
944c2e6f3c0SFlorian Wechsung   PetscInt       *globalDofsArrayWithArtificial = NULL;
9450904074fSPatrick Farrell   PetscInt       *globalDofsArrayWithAll = NULL;
9464bbf5ea8SMatthew G. Knepley   PetscInt        globalIndex     = 0;
9474bbf5ea8SMatthew G. Knepley   PetscInt        key             = 0;
9484bbf5ea8SMatthew G. Knepley   PetscInt        asmKey          = 0;
949557beb66SLawrence Mitchell   DM              dm              = NULL;
950557beb66SLawrence Mitchell   const PetscInt *bcNodes         = NULL;
9511b68eb51SMatthew G. Knepley   PetscHMapI      ht;
952c2e6f3c0SFlorian Wechsung   PetscHMapI      htWithArtificial;
9530904074fSPatrick Farrell   PetscHMapI      htWithAll;
9541b68eb51SMatthew G. Knepley   PetscHSetI      globalBcs;
955557beb66SLawrence Mitchell   PetscInt        numBcs;
9561b68eb51SMatthew G. Knepley   PetscHSetI      ownedpts, seenpts, owneddofs, seendofs, artificialbcs;
957cda239d9SMatthew G. Knepley   PetscInt        pStart, pEnd, p, i;
95810534d48SPatrick Farrell   char            option[PETSC_MAX_PATH_LEN];
95939fd2e8aSPatrick Farrell   PetscBool       isNonlinear;
9604bbf5ea8SMatthew G. Knepley   PetscErrorCode  ierr;
9614bbf5ea8SMatthew G. Knepley 
9624bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
963557beb66SLawrence Mitchell 
964557beb66SLawrence Mitchell   ierr = PCGetDM(pc, &dm); CHKERRQ(ierr);
9654bbf5ea8SMatthew G. Knepley   /* dofcounts section is cellcounts section * dofPerCell */
9664bbf5ea8SMatthew G. Knepley   ierr = PetscSectionGetStorageSize(cellCounts, &numCells);CHKERRQ(ierr);
9675f824522SMatthew G. Knepley   ierr = PetscSectionGetStorageSize(patch->pointCounts, &numPoints);CHKERRQ(ierr);
9684bbf5ea8SMatthew G. Knepley   numDofs = numCells * totalDofsPerCell;
9694bbf5ea8SMatthew G. Knepley   ierr = PetscMalloc1(numDofs, &dofsArray);CHKERRQ(ierr);
9705f824522SMatthew G. Knepley   ierr = PetscMalloc1(numPoints*Nf, &offsArray);CHKERRQ(ierr);
9714bbf5ea8SMatthew G. Knepley   ierr = PetscMalloc1(numDofs, &asmArray);CHKERRQ(ierr);
9724bbf5ea8SMatthew G. Knepley   ierr = PetscMalloc1(numCells, &newCellsArray);CHKERRQ(ierr);
9734bbf5ea8SMatthew G. Knepley   ierr = PetscSectionGetChart(cellCounts, &vStart, &vEnd);CHKERRQ(ierr);
9744bbf5ea8SMatthew G. Knepley   ierr = PetscSectionCreate(PETSC_COMM_SELF, &patch->gtolCounts);CHKERRQ(ierr);
9754bbf5ea8SMatthew G. Knepley   gtolCounts = patch->gtolCounts;
9764bbf5ea8SMatthew G. Knepley   ierr = PetscSectionSetChart(gtolCounts, vStart, vEnd);CHKERRQ(ierr);
9775f824522SMatthew G. Knepley   ierr = PetscObjectSetName((PetscObject) patch->gtolCounts, "Patch Global Index Section");CHKERRQ(ierr);
9784bbf5ea8SMatthew G. Knepley 
9790904074fSPatrick Farrell   if(patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE)
980c2e6f3c0SFlorian Wechsung   {
981f0dcb611SKarl Rupp     ierr = PetscMalloc1(numPoints*Nf, &offsArrayWithArtificial);CHKERRQ(ierr);
982c2e6f3c0SFlorian Wechsung     ierr = PetscMalloc1(numDofs, &asmArrayWithArtificial);CHKERRQ(ierr);
983c2e6f3c0SFlorian Wechsung     ierr = PetscMalloc1(numDofs, &dofsArrayWithArtificial);CHKERRQ(ierr);
984c2e6f3c0SFlorian Wechsung     ierr = PetscSectionCreate(PETSC_COMM_SELF, &patch->gtolCountsWithArtificial);CHKERRQ(ierr);
985c2e6f3c0SFlorian Wechsung     gtolCountsWithArtificial = patch->gtolCountsWithArtificial;
986c2e6f3c0SFlorian Wechsung     ierr = PetscSectionSetChart(gtolCountsWithArtificial, vStart, vEnd);CHKERRQ(ierr);
987c2e6f3c0SFlorian Wechsung     ierr = PetscObjectSetName((PetscObject) patch->gtolCountsWithArtificial, "Patch Global Index Section Including Artificial BCs");CHKERRQ(ierr);
988c2e6f3c0SFlorian Wechsung   }
989c2e6f3c0SFlorian Wechsung 
9900904074fSPatrick Farrell   isNonlinear = patch->isNonlinear;
9910904074fSPatrick Farrell   if(isNonlinear)
9920904074fSPatrick Farrell   {
9930904074fSPatrick Farrell     ierr = PetscMalloc1(numPoints*Nf, &offsArrayWithAll);CHKERRQ(ierr);
9940904074fSPatrick Farrell     ierr = PetscMalloc1(numDofs, &asmArrayWithAll);CHKERRQ(ierr);
9950904074fSPatrick Farrell     ierr = PetscMalloc1(numDofs, &dofsArrayWithAll);CHKERRQ(ierr);
9960904074fSPatrick Farrell     ierr = PetscSectionCreate(PETSC_COMM_SELF, &patch->gtolCountsWithAll);CHKERRQ(ierr);
9970904074fSPatrick Farrell     gtolCountsWithAll = patch->gtolCountsWithAll;
9980904074fSPatrick Farrell     ierr = PetscSectionSetChart(gtolCountsWithAll, vStart, vEnd);CHKERRQ(ierr);
9990904074fSPatrick Farrell     ierr = PetscObjectSetName((PetscObject) patch->gtolCountsWithAll, "Patch Global Index Section Including All BCs");CHKERRQ(ierr);
10000904074fSPatrick Farrell   }
10010904074fSPatrick Farrell 
1002557beb66SLawrence Mitchell   /* Outside the patch loop, get the dofs that are globally-enforced Dirichlet
1003557beb66SLawrence Mitchell    conditions */
10041b68eb51SMatthew G. Knepley   ierr = PetscHSetICreate(&globalBcs);CHKERRQ(ierr);
1005557beb66SLawrence Mitchell   ierr = ISGetIndices(patch->ghostBcNodes, &bcNodes); CHKERRQ(ierr);
1006557beb66SLawrence Mitchell   ierr = ISGetSize(patch->ghostBcNodes, &numBcs); CHKERRQ(ierr);
1007cda239d9SMatthew G. Knepley   for (i = 0; i < numBcs; ++i) {
10081b68eb51SMatthew G. Knepley     ierr = PetscHSetIAdd(globalBcs, bcNodes[i]);CHKERRQ(ierr); /* these are already in concatenated numbering */
1009557beb66SLawrence Mitchell   }
1010557beb66SLawrence Mitchell   ierr = ISRestoreIndices(patch->ghostBcNodes, &bcNodes); CHKERRQ(ierr);
1011557beb66SLawrence Mitchell   ierr = ISDestroy(&patch->ghostBcNodes); CHKERRQ(ierr); /* memory optimisation */
1012557beb66SLawrence Mitchell 
1013557beb66SLawrence Mitchell   /* Hash tables for artificial BC construction */
10141b68eb51SMatthew G. Knepley   ierr = PetscHSetICreate(&ownedpts);CHKERRQ(ierr);
10151b68eb51SMatthew G. Knepley   ierr = PetscHSetICreate(&seenpts);CHKERRQ(ierr);
10161b68eb51SMatthew G. Knepley   ierr = PetscHSetICreate(&owneddofs);CHKERRQ(ierr);
10171b68eb51SMatthew G. Knepley   ierr = PetscHSetICreate(&seendofs);CHKERRQ(ierr);
10181b68eb51SMatthew G. Knepley   ierr = PetscHSetICreate(&artificialbcs);CHKERRQ(ierr);
1019557beb66SLawrence Mitchell 
10204bbf5ea8SMatthew G. Knepley   ierr = ISGetIndices(cells, &cellsArray);CHKERRQ(ierr);
10215f824522SMatthew G. Knepley   ierr = ISGetIndices(points, &pointsArray);CHKERRQ(ierr);
10221b68eb51SMatthew G. Knepley   ierr = PetscHMapICreate(&ht);CHKERRQ(ierr);
1023c2e6f3c0SFlorian Wechsung   ierr = PetscHMapICreate(&htWithArtificial);CHKERRQ(ierr);
10240904074fSPatrick Farrell   ierr = PetscHMapICreate(&htWithAll);CHKERRQ(ierr);
10254bbf5ea8SMatthew G. Knepley   for (v = vStart; v < vEnd; ++v) {
10264bbf5ea8SMatthew G. Knepley     PetscInt localIndex = 0;
1027c2e6f3c0SFlorian Wechsung     PetscInt localIndexWithArtificial = 0;
10280904074fSPatrick Farrell     PetscInt localIndexWithAll = 0;
10294bbf5ea8SMatthew G. Knepley     PetscInt dof, off, i, j, k, l;
10304bbf5ea8SMatthew G. Knepley 
10311b68eb51SMatthew G. Knepley     ierr = PetscHMapIClear(ht);CHKERRQ(ierr);
1032c2e6f3c0SFlorian Wechsung     ierr = PetscHMapIClear(htWithArtificial);CHKERRQ(ierr);
10330904074fSPatrick Farrell     ierr = PetscHMapIClear(htWithAll);CHKERRQ(ierr);
10344bbf5ea8SMatthew G. Knepley     ierr = PetscSectionGetDof(cellCounts, v, &dof);CHKERRQ(ierr);
10354bbf5ea8SMatthew G. Knepley     ierr = PetscSectionGetOffset(cellCounts, v, &off);CHKERRQ(ierr);
10364bbf5ea8SMatthew G. Knepley     if (dof <= 0) continue;
10374bbf5ea8SMatthew G. Knepley 
1038557beb66SLawrence Mitchell     /* Calculate the global numbers of the artificial BC dofs here first */
1039557beb66SLawrence Mitchell     ierr = patch->patchconstructop((void*)patch, dm, v, ownedpts); CHKERRQ(ierr);
1040557beb66SLawrence Mitchell     ierr = PCPatchCompleteCellPatch(pc, ownedpts, seenpts); CHKERRQ(ierr);
1041e4c66b91SPatrick Farrell     ierr = PCPatchGetPointDofs(pc, ownedpts, owneddofs, v, &patch->subspaces_to_exclude); CHKERRQ(ierr);
1042e4c66b91SPatrick Farrell     ierr = PCPatchGetPointDofs(pc, seenpts, seendofs, v, NULL); CHKERRQ(ierr);
1043557beb66SLawrence Mitchell     ierr = PCPatchComputeSetDifference_Private(owneddofs, seendofs, artificialbcs); CHKERRQ(ierr);
10448135ed82SLawrence Mitchell     if (patch->viewPatches) {
10451b68eb51SMatthew G. Knepley       PetscHSetI globalbcdofs;
10461b68eb51SMatthew G. Knepley       PetscHashIter hi;
10478135ed82SLawrence Mitchell       MPI_Comm comm = PetscObjectComm((PetscObject)pc);
10481b68eb51SMatthew G. Knepley 
10491b68eb51SMatthew G. Knepley       ierr = PetscHSetICreate(&globalbcdofs);CHKERRQ(ierr);
10508135ed82SLawrence Mitchell       ierr = PetscSynchronizedPrintf(comm, "Patch %d: owned dofs:\n", v); CHKERRQ(ierr);
10511b68eb51SMatthew G. Knepley       PetscHashIterBegin(owneddofs, hi);
10521b68eb51SMatthew G. Knepley       while (!PetscHashIterAtEnd(owneddofs, hi)) {
10538135ed82SLawrence Mitchell         PetscInt globalDof;
10548135ed82SLawrence Mitchell 
10551b68eb51SMatthew G. Knepley         PetscHashIterGetKey(owneddofs, hi, globalDof);
10561b68eb51SMatthew G. Knepley         PetscHashIterNext(owneddofs, hi);
10578135ed82SLawrence Mitchell         ierr = PetscSynchronizedPrintf(comm, "%d ", globalDof); CHKERRQ(ierr);
10588135ed82SLawrence Mitchell       }
10598135ed82SLawrence Mitchell       ierr = PetscSynchronizedPrintf(comm, "\n"); CHKERRQ(ierr);
10608135ed82SLawrence Mitchell       ierr = PetscSynchronizedPrintf(comm, "Patch %d: seen dofs:\n", v); CHKERRQ(ierr);
10611b68eb51SMatthew G. Knepley       PetscHashIterBegin(seendofs, hi);
10621b68eb51SMatthew G. Knepley       while (!PetscHashIterAtEnd(seendofs, hi)) {
10638135ed82SLawrence Mitchell         PetscInt globalDof;
10648135ed82SLawrence Mitchell         PetscBool flg;
10658135ed82SLawrence Mitchell 
10661b68eb51SMatthew G. Knepley         PetscHashIterGetKey(seendofs, hi, globalDof);
10671b68eb51SMatthew G. Knepley         PetscHashIterNext(seendofs, hi);
10688135ed82SLawrence Mitchell         ierr = PetscSynchronizedPrintf(comm, "%d ", globalDof); CHKERRQ(ierr);
10698135ed82SLawrence Mitchell 
10701b68eb51SMatthew G. Knepley         ierr = PetscHSetIHas(globalBcs, globalDof, &flg);CHKERRQ(ierr);
10711b68eb51SMatthew G. Knepley         if (flg) {ierr = PetscHSetIAdd(globalbcdofs, globalDof);CHKERRQ(ierr);}
10728135ed82SLawrence Mitchell       }
10738135ed82SLawrence Mitchell       ierr = PetscSynchronizedPrintf(comm, "\n"); CHKERRQ(ierr);
10748135ed82SLawrence Mitchell       ierr = PetscSynchronizedPrintf(comm, "Patch %d: global BCs:\n", v); CHKERRQ(ierr);
10751b68eb51SMatthew G. Knepley       ierr = PetscHSetIGetSize(globalbcdofs, &numBcs);CHKERRQ(ierr);
10768135ed82SLawrence Mitchell       if (numBcs > 0) {
10771b68eb51SMatthew G. Knepley         PetscHashIterBegin(globalbcdofs, hi);
10781b68eb51SMatthew G. Knepley         while (!PetscHashIterAtEnd(globalbcdofs, hi)) {
10798135ed82SLawrence Mitchell           PetscInt globalDof;
10801b68eb51SMatthew G. Knepley           PetscHashIterGetKey(globalbcdofs, hi, globalDof);
10811b68eb51SMatthew G. Knepley           PetscHashIterNext(globalbcdofs, hi);
10828135ed82SLawrence Mitchell           ierr = PetscSynchronizedPrintf(comm, "%d ", globalDof);CHKERRQ(ierr);
10838135ed82SLawrence Mitchell         }
10848135ed82SLawrence Mitchell       }
10858135ed82SLawrence Mitchell       ierr = PetscSynchronizedPrintf(comm, "\n");CHKERRQ(ierr);
10868135ed82SLawrence Mitchell       ierr = PetscSynchronizedPrintf(comm, "Patch %d: artificial BCs:\n", v);CHKERRQ(ierr);
10871b68eb51SMatthew G. Knepley       ierr = PetscHSetIGetSize(artificialbcs, &numBcs);CHKERRQ(ierr);
10888135ed82SLawrence Mitchell       if (numBcs > 0) {
10891b68eb51SMatthew G. Knepley         PetscHashIterBegin(artificialbcs, hi);
10901b68eb51SMatthew G. Knepley         while (!PetscHashIterAtEnd(artificialbcs, hi)) {
10918135ed82SLawrence Mitchell           PetscInt globalDof;
10921b68eb51SMatthew G. Knepley           PetscHashIterGetKey(artificialbcs, hi, globalDof);
10931b68eb51SMatthew G. Knepley           PetscHashIterNext(artificialbcs, hi);
10948135ed82SLawrence Mitchell           ierr = PetscSynchronizedPrintf(comm, "%d ", globalDof); CHKERRQ(ierr);
10958135ed82SLawrence Mitchell         }
10968135ed82SLawrence Mitchell       }
10978135ed82SLawrence Mitchell       ierr = PetscSynchronizedPrintf(comm, "\n\n"); CHKERRQ(ierr);
10981b68eb51SMatthew G. Knepley       ierr = PetscHSetIDestroy(&globalbcdofs);CHKERRQ(ierr);
10998135ed82SLawrence Mitchell     }
11004bbf5ea8SMatthew G. Knepley    for (k = 0; k < patch->nsubspaces; ++k) {
11014bbf5ea8SMatthew G. Knepley       const PetscInt *cellNodeMap    = patch->cellNodeMap[k];
11024bbf5ea8SMatthew G. Knepley       PetscInt        nodesPerCell   = patch->nodesPerCell[k];
11034bbf5ea8SMatthew G. Knepley       PetscInt        subspaceOffset = patch->subspaceOffsets[k];
11044bbf5ea8SMatthew G. Knepley       PetscInt        bs             = patch->bs[k];
11054bbf5ea8SMatthew G. Knepley 
11064bbf5ea8SMatthew G. Knepley       for (i = off; i < off + dof; ++i) {
11074bbf5ea8SMatthew G. Knepley         /* Walk over the cells in this patch. */
11084bbf5ea8SMatthew G. Knepley         const PetscInt c    = cellsArray[i];
11095f824522SMatthew G. Knepley         PetscInt       cell = c;
11104bbf5ea8SMatthew G. Knepley 
11115f824522SMatthew G. Knepley         /* TODO Change this to an IS */
11125f824522SMatthew G. Knepley         if (cellNumbering) {
11134bbf5ea8SMatthew G. Knepley           ierr = PetscSectionGetDof(cellNumbering, c, &cell);CHKERRQ(ierr);
11144bbf5ea8SMatthew G. Knepley           if (cell <= 0) SETERRQ1(PetscObjectComm((PetscObject) pc), PETSC_ERR_ARG_OUTOFRANGE, "Cell %D doesn't appear in cell numbering map", c);
11154bbf5ea8SMatthew G. Knepley           ierr = PetscSectionGetOffset(cellNumbering, c, &cell);CHKERRQ(ierr);
11165f824522SMatthew G. Knepley         }
11174bbf5ea8SMatthew G. Knepley         newCellsArray[i] = cell;
11184bbf5ea8SMatthew G. Knepley         for (j = 0; j < nodesPerCell; ++j) {
11194bbf5ea8SMatthew G. Knepley           /* For each global dof, map it into contiguous local storage. */
11204bbf5ea8SMatthew G. Knepley           const PetscInt globalDof = cellNodeMap[cell*nodesPerCell + j]*bs + subspaceOffset;
11214bbf5ea8SMatthew G. Knepley           /* finally, loop over block size */
11224bbf5ea8SMatthew G. Knepley           for (l = 0; l < bs; ++l) {
11231b68eb51SMatthew G. Knepley             PetscInt  localDof;
11241b68eb51SMatthew G. Knepley             PetscBool isGlobalBcDof, isArtificialBcDof;
11254bbf5ea8SMatthew G. Knepley 
1126557beb66SLawrence Mitchell             /* first, check if this is either a globally enforced or locally enforced BC dof */
11271b68eb51SMatthew G. Knepley             ierr = PetscHSetIHas(globalBcs, globalDof + l, &isGlobalBcDof);CHKERRQ(ierr);
11281b68eb51SMatthew G. Knepley             ierr = PetscHSetIHas(artificialbcs, globalDof + l, &isArtificialBcDof);CHKERRQ(ierr);
1129557beb66SLawrence Mitchell 
1130557beb66SLawrence Mitchell             /* if it's either, don't ever give it a local dof number */
11311b68eb51SMatthew G. Knepley             if (isGlobalBcDof || isArtificialBcDof) {
1132c2e6f3c0SFlorian Wechsung               dofsArray[globalIndex] = -1; /* don't use this in assembly in this patch */
1133557beb66SLawrence Mitchell             } else {
11341b68eb51SMatthew G. Knepley               ierr = PetscHMapIGet(ht, globalDof + l, &localDof);CHKERRQ(ierr);
11354bbf5ea8SMatthew G. Knepley               if (localDof == -1) {
11364bbf5ea8SMatthew G. Knepley                 localDof = localIndex++;
11371b68eb51SMatthew G. Knepley                 ierr = PetscHMapISet(ht, globalDof + l, localDof);CHKERRQ(ierr);
11384bbf5ea8SMatthew G. Knepley               }
11394bbf5ea8SMatthew G. Knepley               if ( globalIndex >= numDofs ) SETERRQ2(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Found more dofs %D than expected %D", globalIndex+1, numDofs);
11404bbf5ea8SMatthew G. Knepley               /* And store. */
1141c2e6f3c0SFlorian Wechsung               dofsArray[globalIndex] = localDof;
11424bbf5ea8SMatthew G. Knepley             }
1143c2e6f3c0SFlorian Wechsung 
11440904074fSPatrick Farrell             if(patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
1145c2e6f3c0SFlorian Wechsung               if (isGlobalBcDof) {
1146e047a90bSFlorian Wechsung                 dofsArrayWithArtificial[globalIndex] = -1; /* don't use this in assembly in this patch */
1147c2e6f3c0SFlorian Wechsung               } else {
1148c2e6f3c0SFlorian Wechsung                 ierr = PetscHMapIGet(htWithArtificial, globalDof + l, &localDof);CHKERRQ(ierr);
1149c2e6f3c0SFlorian Wechsung                 if (localDof == -1) {
1150c2e6f3c0SFlorian Wechsung                   localDof = localIndexWithArtificial++;
1151c2e6f3c0SFlorian Wechsung                   ierr = PetscHMapISet(htWithArtificial, globalDof + l, localDof);CHKERRQ(ierr);
1152c2e6f3c0SFlorian Wechsung                 }
1153c2e6f3c0SFlorian Wechsung                 if ( globalIndex >= numDofs ) SETERRQ2(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Found more dofs %D than expected %D", globalIndex+1, numDofs);
1154c2e6f3c0SFlorian Wechsung                 /* And store.*/
1155c2e6f3c0SFlorian Wechsung                 dofsArrayWithArtificial[globalIndex] = localDof;
1156c2e6f3c0SFlorian Wechsung               }
1157c2e6f3c0SFlorian Wechsung             }
11580904074fSPatrick Farrell 
11590904074fSPatrick Farrell             if(isNonlinear) {
11600904074fSPatrick Farrell               /* Build the dofmap for the function space with _all_ dofs,
11610904074fSPatrick Farrell                  including those in any kind of boundary condition */
11620904074fSPatrick Farrell               ierr = PetscHMapIGet(htWithAll, globalDof + l, &localDof);CHKERRQ(ierr);
11630904074fSPatrick Farrell               if (localDof == -1) {
11640904074fSPatrick Farrell                 localDof = localIndexWithAll++;
11650904074fSPatrick Farrell                 ierr = PetscHMapISet(htWithAll, globalDof + l, localDof);CHKERRQ(ierr);
11660904074fSPatrick Farrell               }
11670904074fSPatrick Farrell               if ( globalIndex >= numDofs ) SETERRQ2(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Found more dofs %D than expected %D", globalIndex+1, numDofs);
11680904074fSPatrick Farrell               /* And store.*/
11690904074fSPatrick Farrell               dofsArrayWithAll[globalIndex] = localDof;
11700904074fSPatrick Farrell             }
1171c2e6f3c0SFlorian Wechsung             globalIndex++;
11724bbf5ea8SMatthew G. Knepley           }
11734bbf5ea8SMatthew G. Knepley         }
11744bbf5ea8SMatthew G. Knepley       }
1175557beb66SLawrence Mitchell     }
11764bbf5ea8SMatthew G. Knepley      /*How many local dofs in this patch? */
11770904074fSPatrick Farrell    if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
1178c2e6f3c0SFlorian Wechsung      ierr = PetscHMapIGetSize(htWithArtificial, &dof);CHKERRQ(ierr);
1179c2e6f3c0SFlorian Wechsung      ierr = PetscSectionSetDof(gtolCountsWithArtificial, v, dof);CHKERRQ(ierr);
1180c2e6f3c0SFlorian Wechsung    }
11810904074fSPatrick Farrell    if (isNonlinear) {
11820904074fSPatrick Farrell      ierr = PetscHMapIGetSize(htWithAll, &dof);CHKERRQ(ierr);
11830904074fSPatrick Farrell      ierr = PetscSectionSetDof(gtolCountsWithAll, v, dof);CHKERRQ(ierr);
11840904074fSPatrick Farrell    }
11851b68eb51SMatthew G. Knepley     ierr = PetscHMapIGetSize(ht, &dof);CHKERRQ(ierr);
11864bbf5ea8SMatthew G. Knepley     ierr = PetscSectionSetDof(gtolCounts, v, dof);CHKERRQ(ierr);
11874bbf5ea8SMatthew G. Knepley   }
11884bbf5ea8SMatthew G. Knepley   if (globalIndex != numDofs) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Expected number of dofs (%d) doesn't match found number (%d)", numDofs, globalIndex);
11894bbf5ea8SMatthew G. Knepley   ierr = PetscSectionSetUp(gtolCounts);CHKERRQ(ierr);
11904bbf5ea8SMatthew G. Knepley   ierr = PetscSectionGetStorageSize(gtolCounts, &numGlobalDofs);CHKERRQ(ierr);
11914bbf5ea8SMatthew G. Knepley   ierr = PetscMalloc1(numGlobalDofs, &globalDofsArray);CHKERRQ(ierr);
11924bbf5ea8SMatthew G. Knepley 
11930904074fSPatrick Farrell   if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
1194c2e6f3c0SFlorian Wechsung     ierr = PetscSectionSetUp(gtolCountsWithArtificial);CHKERRQ(ierr);
1195c2e6f3c0SFlorian Wechsung     ierr = PetscSectionGetStorageSize(gtolCountsWithArtificial, &numGlobalDofsWithArtificial);CHKERRQ(ierr);
1196c2e6f3c0SFlorian Wechsung     ierr = PetscMalloc1(numGlobalDofsWithArtificial, &globalDofsArrayWithArtificial);CHKERRQ(ierr);
1197c2e6f3c0SFlorian Wechsung   }
11980904074fSPatrick Farrell   if (isNonlinear) {
11990904074fSPatrick Farrell     ierr = PetscSectionSetUp(gtolCountsWithAll);CHKERRQ(ierr);
12000904074fSPatrick Farrell     ierr = PetscSectionGetStorageSize(gtolCountsWithAll, &numGlobalDofsWithAll);CHKERRQ(ierr);
12010904074fSPatrick Farrell     ierr = PetscMalloc1(numGlobalDofsWithAll, &globalDofsArrayWithAll);CHKERRQ(ierr);
12020904074fSPatrick Farrell   }
12034bbf5ea8SMatthew 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. */
12044bbf5ea8SMatthew G. Knepley   for (v = vStart; v < vEnd; ++v) {
12051b68eb51SMatthew G. Knepley     PetscHashIter hi;
12065f824522SMatthew G. Knepley     PetscInt      dof, off, Np, ooff, i, j, k, l;
12074bbf5ea8SMatthew G. Knepley 
12081b68eb51SMatthew G. Knepley     ierr = PetscHMapIClear(ht);CHKERRQ(ierr);
1209c2e6f3c0SFlorian Wechsung     ierr = PetscHMapIClear(htWithArtificial);CHKERRQ(ierr);
12100904074fSPatrick Farrell     ierr = PetscHMapIClear(htWithAll);CHKERRQ(ierr);
12114bbf5ea8SMatthew G. Knepley     ierr = PetscSectionGetDof(cellCounts, v, &dof);CHKERRQ(ierr);
12124bbf5ea8SMatthew G. Knepley     ierr = PetscSectionGetOffset(cellCounts, v, &off);CHKERRQ(ierr);
12135f824522SMatthew G. Knepley     ierr = PetscSectionGetDof(pointCounts, v, &Np);CHKERRQ(ierr);
12145f824522SMatthew G. Knepley     ierr = PetscSectionGetOffset(pointCounts, v, &ooff);CHKERRQ(ierr);
12154bbf5ea8SMatthew G. Knepley     if (dof <= 0) continue;
12164bbf5ea8SMatthew G. Knepley 
12174bbf5ea8SMatthew G. Knepley     for (k = 0; k < patch->nsubspaces; ++k) {
12184bbf5ea8SMatthew G. Knepley       const PetscInt *cellNodeMap    = patch->cellNodeMap[k];
12194bbf5ea8SMatthew G. Knepley       PetscInt        nodesPerCell   = patch->nodesPerCell[k];
12204bbf5ea8SMatthew G. Knepley       PetscInt        subspaceOffset = patch->subspaceOffsets[k];
12214bbf5ea8SMatthew G. Knepley       PetscInt        bs             = patch->bs[k];
1222d490bb3dSLawrence Mitchell       PetscInt        goff;
12234bbf5ea8SMatthew G. Knepley 
12244bbf5ea8SMatthew G. Knepley       for (i = off; i < off + dof; ++i) {
12254bbf5ea8SMatthew G. Knepley         /* Reconstruct mapping of global-to-local on this patch. */
12264bbf5ea8SMatthew G. Knepley         const PetscInt c    = cellsArray[i];
12275f824522SMatthew G. Knepley         PetscInt       cell = c;
12284bbf5ea8SMatthew G. Knepley 
12295f824522SMatthew G. Knepley         if (cellNumbering) {ierr = PetscSectionGetOffset(cellNumbering, c, &cell);CHKERRQ(ierr);}
12304bbf5ea8SMatthew G. Knepley         for (j = 0; j < nodesPerCell; ++j) {
12314bbf5ea8SMatthew G. Knepley           for (l = 0; l < bs; ++l) {
12325f824522SMatthew G. Knepley             const PetscInt globalDof = cellNodeMap[cell*nodesPerCell + j]*bs + l + subspaceOffset;
1233c2e6f3c0SFlorian Wechsung             const PetscInt localDof  = dofsArray[key];
12341b68eb51SMatthew G. Knepley             if (localDof >= 0) {ierr = PetscHMapISet(ht, globalDof, localDof);CHKERRQ(ierr);}
12350904074fSPatrick Farrell             if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
1236c2e6f3c0SFlorian Wechsung               const PetscInt localDofWithArtificial = dofsArrayWithArtificial[key];
1237c2e6f3c0SFlorian Wechsung               if (localDofWithArtificial >= 0) {
1238c2e6f3c0SFlorian Wechsung                 ierr = PetscHMapISet(htWithArtificial, globalDof, localDofWithArtificial);CHKERRQ(ierr);
1239c2e6f3c0SFlorian Wechsung               }
1240c2e6f3c0SFlorian Wechsung             }
12410904074fSPatrick Farrell             if (isNonlinear) {
12420904074fSPatrick Farrell               const PetscInt localDofWithAll = dofsArrayWithAll[key];
12430904074fSPatrick Farrell               if (localDofWithAll >= 0) {
12440904074fSPatrick Farrell                 ierr = PetscHMapISet(htWithAll, globalDof, localDofWithAll);CHKERRQ(ierr);
12450904074fSPatrick Farrell               }
12460904074fSPatrick Farrell             }
1247c2e6f3c0SFlorian Wechsung             key++;
12484bbf5ea8SMatthew G. Knepley           }
12494bbf5ea8SMatthew G. Knepley         }
12504bbf5ea8SMatthew G. Knepley       }
1251557beb66SLawrence Mitchell 
12524bbf5ea8SMatthew G. Knepley       /* Shove it in the output data structure. */
12534bbf5ea8SMatthew G. Knepley       ierr = PetscSectionGetOffset(gtolCounts, v, &goff);CHKERRQ(ierr);
12541b68eb51SMatthew G. Knepley       PetscHashIterBegin(ht, hi);
12551b68eb51SMatthew G. Knepley       while (!PetscHashIterAtEnd(ht, hi)) {
12564bbf5ea8SMatthew G. Knepley         PetscInt globalDof, localDof;
12574bbf5ea8SMatthew G. Knepley 
12581b68eb51SMatthew G. Knepley         PetscHashIterGetKey(ht, hi, globalDof);
12591b68eb51SMatthew G. Knepley         PetscHashIterGetVal(ht, hi, localDof);
12604bbf5ea8SMatthew G. Knepley         if (globalDof >= 0) globalDofsArray[goff + localDof] = globalDof;
12611b68eb51SMatthew G. Knepley         PetscHashIterNext(ht, hi);
12624bbf5ea8SMatthew G. Knepley       }
12635f824522SMatthew G. Knepley 
12640904074fSPatrick Farrell       if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
1265c2e6f3c0SFlorian Wechsung         ierr = PetscSectionGetOffset(gtolCountsWithArtificial, v, &goff);CHKERRQ(ierr);
1266c2e6f3c0SFlorian Wechsung         PetscHashIterBegin(htWithArtificial, hi);
1267c2e6f3c0SFlorian Wechsung         while (!PetscHashIterAtEnd(htWithArtificial, hi)) {
1268c2e6f3c0SFlorian Wechsung           PetscInt globalDof, localDof;
1269c2e6f3c0SFlorian Wechsung           PetscHashIterGetKey(htWithArtificial, hi, globalDof);
1270c2e6f3c0SFlorian Wechsung           PetscHashIterGetVal(htWithArtificial, hi, localDof);
1271c2e6f3c0SFlorian Wechsung           if (globalDof >= 0) globalDofsArrayWithArtificial[goff + localDof] = globalDof;
1272c2e6f3c0SFlorian Wechsung           PetscHashIterNext(htWithArtificial, hi);
1273c2e6f3c0SFlorian Wechsung         }
1274c2e6f3c0SFlorian Wechsung       }
12750904074fSPatrick Farrell       if (isNonlinear) {
12760904074fSPatrick Farrell         ierr = PetscSectionGetOffset(gtolCountsWithAll, v, &goff);CHKERRQ(ierr);
12770904074fSPatrick Farrell         PetscHashIterBegin(htWithAll, hi);
12780904074fSPatrick Farrell         while (!PetscHashIterAtEnd(htWithAll, hi)) {
12790904074fSPatrick Farrell           PetscInt globalDof, localDof;
12800904074fSPatrick Farrell           PetscHashIterGetKey(htWithAll, hi, globalDof);
12810904074fSPatrick Farrell           PetscHashIterGetVal(htWithAll, hi, localDof);
12820904074fSPatrick Farrell           if (globalDof >= 0) globalDofsArrayWithAll[goff + localDof] = globalDof;
12830904074fSPatrick Farrell           PetscHashIterNext(htWithAll, hi);
12840904074fSPatrick Farrell         }
12850904074fSPatrick Farrell       }
1286c2e6f3c0SFlorian Wechsung 
12875f824522SMatthew G. Knepley       for (p = 0; p < Np; ++p) {
12885f824522SMatthew G. Knepley         const PetscInt point = pointsArray[ooff + p];
12895f824522SMatthew G. Knepley         PetscInt       globalDof, localDof;
12905f824522SMatthew G. Knepley 
12915f824522SMatthew G. Knepley         ierr = PCPatchGetGlobalDofs(pc, patch->dofSection, k, patch->combined, point, NULL, &globalDof);CHKERRQ(ierr);
12921b68eb51SMatthew G. Knepley         ierr = PetscHMapIGet(ht, globalDof, &localDof);CHKERRQ(ierr);
12935f824522SMatthew G. Knepley         offsArray[(ooff + p)*Nf + k] = localDof;
12940904074fSPatrick Farrell         if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
1295c2e6f3c0SFlorian Wechsung           ierr = PetscHMapIGet(htWithArtificial, globalDof, &localDof);CHKERRQ(ierr);
1296c2e6f3c0SFlorian Wechsung           offsArrayWithArtificial[(ooff + p)*Nf + k] = localDof;
1297c2e6f3c0SFlorian Wechsung         }
12980904074fSPatrick Farrell         if (isNonlinear) {
12990904074fSPatrick Farrell           ierr = PetscHMapIGet(htWithAll, globalDof, &localDof);CHKERRQ(ierr);
13000904074fSPatrick Farrell           offsArrayWithAll[(ooff + p)*Nf + k] = localDof;
13010904074fSPatrick Farrell         }
13025f824522SMatthew G. Knepley       }
13034bbf5ea8SMatthew G. Knepley     }
13044bbf5ea8SMatthew G. Knepley 
13050cd083f8SSatish Balay     ierr = PetscHSetIDestroy(&globalBcs);CHKERRQ(ierr);
13061b68eb51SMatthew G. Knepley     ierr = PetscHSetIDestroy(&ownedpts);CHKERRQ(ierr);
13071b68eb51SMatthew G. Knepley     ierr = PetscHSetIDestroy(&seenpts);CHKERRQ(ierr);
13081b68eb51SMatthew G. Knepley     ierr = PetscHSetIDestroy(&owneddofs);CHKERRQ(ierr);
13091b68eb51SMatthew G. Knepley     ierr = PetscHSetIDestroy(&seendofs);CHKERRQ(ierr);
13101b68eb51SMatthew G. Knepley     ierr = PetscHSetIDestroy(&artificialbcs);CHKERRQ(ierr);
1311557beb66SLawrence Mitchell 
13124bbf5ea8SMatthew G. Knepley       /* At this point, we have a hash table ht built that maps globalDof -> localDof.
13134bbf5ea8SMatthew G. Knepley      We need to create the dof table laid out cellwise first, then by subspace,
13144bbf5ea8SMatthew G. Knepley      as the assembler assembles cell-wise and we need to stuff the different
13154bbf5ea8SMatthew G. Knepley      contributions of the different function spaces to the right places. So we loop
13164bbf5ea8SMatthew G. Knepley      over cells, then over subspaces. */
13174bbf5ea8SMatthew G. Knepley     if (patch->nsubspaces > 1) { /* for nsubspaces = 1, data we need is already in dofsArray */
13184bbf5ea8SMatthew G. Knepley       for (i = off; i < off + dof; ++i) {
13194bbf5ea8SMatthew G. Knepley         const PetscInt c    = cellsArray[i];
13205f824522SMatthew G. Knepley         PetscInt       cell = c;
13214bbf5ea8SMatthew G. Knepley 
13225f824522SMatthew G. Knepley         if (cellNumbering) {ierr = PetscSectionGetOffset(cellNumbering, c, &cell);CHKERRQ(ierr);}
13234bbf5ea8SMatthew G. Knepley         for (k = 0; k < patch->nsubspaces; ++k) {
13244bbf5ea8SMatthew G. Knepley           const PetscInt *cellNodeMap    = patch->cellNodeMap[k];
13254bbf5ea8SMatthew G. Knepley           PetscInt        nodesPerCell   = patch->nodesPerCell[k];
13264bbf5ea8SMatthew G. Knepley           PetscInt        subspaceOffset = patch->subspaceOffsets[k];
13274bbf5ea8SMatthew G. Knepley           PetscInt        bs             = patch->bs[k];
13284bbf5ea8SMatthew G. Knepley 
13294bbf5ea8SMatthew G. Knepley           for (j = 0; j < nodesPerCell; ++j) {
13304bbf5ea8SMatthew G. Knepley             for (l = 0; l < bs; ++l) {
13315f824522SMatthew G. Knepley               const PetscInt globalDof = cellNodeMap[cell*nodesPerCell + j]*bs + l + subspaceOffset;
13324bbf5ea8SMatthew G. Knepley               PetscInt       localDof;
13334bbf5ea8SMatthew G. Knepley 
13341b68eb51SMatthew G. Knepley               ierr = PetscHMapIGet(ht, globalDof, &localDof);CHKERRQ(ierr);
1335557beb66SLawrence Mitchell               /* If it's not in the hash table, i.e. is a BC dof,
13361b68eb51SMatthew G. Knepley                then the PetscHSetIMap above gives -1, which matches
1337557beb66SLawrence Mitchell                exactly the convention for PETSc's matrix assembly to
1338557beb66SLawrence Mitchell                ignore the dof. So we don't need to do anything here */
1339c2e6f3c0SFlorian Wechsung               asmArray[asmKey] = localDof;
13400904074fSPatrick Farrell               if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
1341c2e6f3c0SFlorian Wechsung                 ierr = PetscHMapIGet(htWithArtificial, globalDof, &localDof);CHKERRQ(ierr);
1342c2e6f3c0SFlorian Wechsung                 asmArrayWithArtificial[asmKey] = localDof;
1343c2e6f3c0SFlorian Wechsung               }
13440904074fSPatrick Farrell               if (isNonlinear) {
13450904074fSPatrick Farrell                 ierr = PetscHMapIGet(htWithAll, globalDof, &localDof);CHKERRQ(ierr);
13460904074fSPatrick Farrell                 asmArrayWithAll[asmKey] = localDof;
13470904074fSPatrick Farrell               }
1348c2e6f3c0SFlorian Wechsung               asmKey++;
13494bbf5ea8SMatthew G. Knepley             }
13504bbf5ea8SMatthew G. Knepley           }
13514bbf5ea8SMatthew G. Knepley         }
13524bbf5ea8SMatthew G. Knepley       }
13534bbf5ea8SMatthew G. Knepley     }
13544bbf5ea8SMatthew G. Knepley   }
1355c2e6f3c0SFlorian Wechsung   if (1 == patch->nsubspaces) {
1356c2e6f3c0SFlorian Wechsung     ierr = PetscMemcpy(asmArray, dofsArray, numDofs * sizeof(PetscInt));CHKERRQ(ierr);
13570904074fSPatrick Farrell     if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
1358c2e6f3c0SFlorian Wechsung       ierr = PetscMemcpy(asmArrayWithArtificial, dofsArrayWithArtificial, numDofs * sizeof(PetscInt));CHKERRQ(ierr);
1359c2e6f3c0SFlorian Wechsung     }
13600904074fSPatrick Farrell     if (isNonlinear) {
13610904074fSPatrick Farrell       ierr = PetscMemcpy(asmArrayWithAll, dofsArrayWithAll, numDofs * sizeof(PetscInt));CHKERRQ(ierr);
13620904074fSPatrick Farrell     }
1363c2e6f3c0SFlorian Wechsung   }
13644bbf5ea8SMatthew G. Knepley 
13651b68eb51SMatthew G. Knepley   ierr = PetscHMapIDestroy(&ht);CHKERRQ(ierr);
1366c2e6f3c0SFlorian Wechsung   ierr = PetscHMapIDestroy(&htWithArtificial);CHKERRQ(ierr);
13670904074fSPatrick Farrell   ierr = PetscHMapIDestroy(&htWithAll);CHKERRQ(ierr);
13684bbf5ea8SMatthew G. Knepley   ierr = ISRestoreIndices(cells, &cellsArray);CHKERRQ(ierr);
13695f824522SMatthew G. Knepley   ierr = ISRestoreIndices(points, &pointsArray);CHKERRQ(ierr);
13704bbf5ea8SMatthew G. Knepley   ierr = PetscFree(dofsArray);CHKERRQ(ierr);
13710904074fSPatrick Farrell   if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
1372c2e6f3c0SFlorian Wechsung     ierr = PetscFree(dofsArrayWithArtificial);CHKERRQ(ierr);
1373c2e6f3c0SFlorian Wechsung   }
13740904074fSPatrick Farrell   if (isNonlinear) {
13750904074fSPatrick Farrell     ierr = PetscFree(dofsArrayWithAll);CHKERRQ(ierr);
13760904074fSPatrick Farrell   }
13775f824522SMatthew G. Knepley   /* Create placeholder section for map from points to patch dofs */
13785f824522SMatthew G. Knepley   ierr = PetscSectionCreate(PETSC_COMM_SELF, &patch->patchSection);CHKERRQ(ierr);
13795f824522SMatthew G. Knepley   ierr = PetscSectionSetNumFields(patch->patchSection, patch->nsubspaces);CHKERRQ(ierr);
13801e5fa6bbSLawrence Mitchell   if (patch->combined) {
13811e5fa6bbSLawrence Mitchell     PetscInt numFields;
13821e5fa6bbSLawrence Mitchell     ierr = PetscSectionGetNumFields(patch->dofSection[0], &numFields);CHKERRQ(ierr);
13831e5fa6bbSLawrence Mitchell     if (numFields != patch->nsubspaces) SETERRQ2(PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "Mismatch between number of section fields %D and number of subspaces %D", numFields, patch->nsubspaces);
13845f824522SMatthew G. Knepley     ierr = PetscSectionGetChart(patch->dofSection[0], &pStart, &pEnd);CHKERRQ(ierr);
13855f824522SMatthew G. Knepley     ierr = PetscSectionSetChart(patch->patchSection, pStart, pEnd);CHKERRQ(ierr);
13865f824522SMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
13875f824522SMatthew G. Knepley       PetscInt dof, fdof, f;
13885f824522SMatthew G. Knepley 
13895f824522SMatthew G. Knepley       ierr = PetscSectionGetDof(patch->dofSection[0], p, &dof);CHKERRQ(ierr);
13905f824522SMatthew G. Knepley       ierr = PetscSectionSetDof(patch->patchSection, p, dof);CHKERRQ(ierr);
13915f824522SMatthew G. Knepley       for (f = 0; f < patch->nsubspaces; ++f) {
13921e5fa6bbSLawrence Mitchell         ierr = PetscSectionGetFieldDof(patch->dofSection[0], p, f, &fdof);CHKERRQ(ierr);
13935f824522SMatthew G. Knepley         ierr = PetscSectionSetFieldDof(patch->patchSection, p, f, fdof);CHKERRQ(ierr);
13945f824522SMatthew G. Knepley       }
13951e5fa6bbSLawrence Mitchell     }
13961e5fa6bbSLawrence Mitchell   } else {
13971e5fa6bbSLawrence Mitchell     PetscInt pStartf, pEndf, f;
13981e5fa6bbSLawrence Mitchell     pStart = PETSC_MAX_INT;
13991e5fa6bbSLawrence Mitchell     pEnd = PETSC_MIN_INT;
14001e5fa6bbSLawrence Mitchell     for (f = 0; f < patch->nsubspaces; ++f) {
14011e5fa6bbSLawrence Mitchell       ierr = PetscSectionGetChart(patch->dofSection[f], &pStartf, &pEndf);CHKERRQ(ierr);
14021e5fa6bbSLawrence Mitchell       pStart = PetscMin(pStart, pStartf);
14031e5fa6bbSLawrence Mitchell       pEnd = PetscMax(pEnd, pEndf);
14041e5fa6bbSLawrence Mitchell     }
14051e5fa6bbSLawrence Mitchell     ierr = PetscSectionSetChart(patch->patchSection, pStart, pEnd);CHKERRQ(ierr);
14061e5fa6bbSLawrence Mitchell     for (f = 0; f < patch->nsubspaces; ++f) {
14071e5fa6bbSLawrence Mitchell       ierr = PetscSectionGetChart(patch->dofSection[f], &pStartf, &pEndf);CHKERRQ(ierr);
14081e5fa6bbSLawrence Mitchell       for (p = pStartf; p < pEndf; ++p) {
14091e5fa6bbSLawrence Mitchell         PetscInt fdof;
14101e5fa6bbSLawrence Mitchell         ierr = PetscSectionGetDof(patch->dofSection[f], p, &fdof);CHKERRQ(ierr);
14111e5fa6bbSLawrence Mitchell         ierr = PetscSectionAddDof(patch->patchSection, p, fdof);CHKERRQ(ierr);
14121e5fa6bbSLawrence Mitchell         ierr = PetscSectionSetFieldDof(patch->patchSection, p, f, fdof);CHKERRQ(ierr);
1413bdd9e0cdSPatrick Farrell       }
1414bdd9e0cdSPatrick Farrell     }
14155f824522SMatthew G. Knepley   }
14165f824522SMatthew G. Knepley   ierr = PetscSectionSetUp(patch->patchSection);CHKERRQ(ierr);
14175f824522SMatthew G. Knepley   ierr = PetscSectionSetUseFieldOffsets(patch->patchSection, PETSC_TRUE);CHKERRQ(ierr);
14184bbf5ea8SMatthew G. Knepley   /* Replace cell indices with firedrake-numbered ones. */
14194bbf5ea8SMatthew G. Knepley   ierr = ISGeneralSetIndices(cells, numCells, (const PetscInt *) newCellsArray, PETSC_OWN_POINTER);CHKERRQ(ierr);
14204bbf5ea8SMatthew G. Knepley   ierr = ISCreateGeneral(PETSC_COMM_SELF, numGlobalDofs, globalDofsArray, PETSC_OWN_POINTER, &patch->gtol);CHKERRQ(ierr);
14215f824522SMatthew G. Knepley   ierr = PetscObjectSetName((PetscObject) patch->gtol, "Global Indices");CHKERRQ(ierr);
142210534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_g2l_view", patch->classname);CHKERRQ(ierr);
142310534d48SPatrick Farrell   ierr = PetscSectionViewFromOptions(patch->gtolCounts, (PetscObject) pc, option);CHKERRQ(ierr);
142410534d48SPatrick Farrell   ierr = ISViewFromOptions(patch->gtol, (PetscObject) pc, option);CHKERRQ(ierr);
14254bbf5ea8SMatthew G. Knepley   ierr = ISCreateGeneral(PETSC_COMM_SELF, numDofs, asmArray, PETSC_OWN_POINTER, &patch->dofs);CHKERRQ(ierr);
14265f824522SMatthew G. Knepley   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints*Nf, offsArray, PETSC_OWN_POINTER, &patch->offs);CHKERRQ(ierr);
14270904074fSPatrick Farrell   if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
1428c2e6f3c0SFlorian Wechsung     ierr = ISCreateGeneral(PETSC_COMM_SELF, numGlobalDofsWithArtificial, globalDofsArrayWithArtificial, PETSC_OWN_POINTER, &patch->gtolWithArtificial);CHKERRQ(ierr);
1429c2e6f3c0SFlorian Wechsung     ierr = ISCreateGeneral(PETSC_COMM_SELF, numDofs, asmArrayWithArtificial, PETSC_OWN_POINTER, &patch->dofsWithArtificial);CHKERRQ(ierr);
1430c2e6f3c0SFlorian Wechsung     ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints*Nf, offsArrayWithArtificial, PETSC_OWN_POINTER, &patch->offsWithArtificial);CHKERRQ(ierr);
1431c2e6f3c0SFlorian Wechsung   }
14320904074fSPatrick Farrell   if (isNonlinear) {
14330904074fSPatrick Farrell     ierr = ISCreateGeneral(PETSC_COMM_SELF, numGlobalDofsWithAll, globalDofsArrayWithAll, PETSC_OWN_POINTER, &patch->gtolWithAll);CHKERRQ(ierr);
14340904074fSPatrick Farrell     ierr = ISCreateGeneral(PETSC_COMM_SELF, numDofs, asmArrayWithAll, PETSC_OWN_POINTER, &patch->dofsWithAll);CHKERRQ(ierr);
14350904074fSPatrick Farrell     ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints*Nf, offsArrayWithAll, PETSC_OWN_POINTER, &patch->offsWithAll);CHKERRQ(ierr);
14360904074fSPatrick Farrell   }
14374bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
14384bbf5ea8SMatthew G. Knepley }
14394bbf5ea8SMatthew G. Knepley 
14404bbf5ea8SMatthew G. Knepley static PetscErrorCode PCPatchZeroFillMatrix_Private(Mat mat, const PetscInt ncell, const PetscInt ndof, const PetscInt *dof)
14414bbf5ea8SMatthew G. Knepley {
144223b8bdd9SMatthew G. Knepley   PetscScalar    *values = NULL;
14434bbf5ea8SMatthew G. Knepley   PetscInt        rows, c, i;
14444bbf5ea8SMatthew G. Knepley   PetscErrorCode  ierr;
14454bbf5ea8SMatthew G. Knepley 
14464bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
14474bbf5ea8SMatthew G. Knepley   ierr = PetscCalloc1(ndof*ndof, &values);CHKERRQ(ierr);
14484bbf5ea8SMatthew G. Knepley   for (c = 0; c < ncell; ++c) {
14494bbf5ea8SMatthew G. Knepley     const PetscInt *idx = &dof[ndof*c];
14504bbf5ea8SMatthew G. Knepley     ierr = MatSetValues(mat, ndof, idx, ndof, idx, values, INSERT_VALUES);CHKERRQ(ierr);
14514bbf5ea8SMatthew G. Knepley   }
14524bbf5ea8SMatthew G. Knepley   ierr = MatGetLocalSize(mat, &rows, NULL);CHKERRQ(ierr);
14534bbf5ea8SMatthew G. Knepley   for (i = 0; i < rows; ++i) {
14544bbf5ea8SMatthew G. Knepley     ierr = MatSetValues(mat, 1, &i, 1, &i, values, INSERT_VALUES);CHKERRQ(ierr);
14554bbf5ea8SMatthew G. Knepley   }
14564bbf5ea8SMatthew G. Knepley   ierr = MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
14574bbf5ea8SMatthew G. Knepley   ierr = MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
14584bbf5ea8SMatthew G. Knepley   ierr = PetscFree(values);CHKERRQ(ierr);
14594bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
14604bbf5ea8SMatthew G. Knepley }
14614bbf5ea8SMatthew G. Knepley 
1462c2e6f3c0SFlorian Wechsung static PetscErrorCode PCPatchCreateMatrix_Private(PC pc, PetscInt point, Mat *mat, PetscBool withArtificial)
14634bbf5ea8SMatthew G. Knepley {
14644bbf5ea8SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
14654bbf5ea8SMatthew G. Knepley   Vec            x, y;
14664bbf5ea8SMatthew G. Knepley   PetscBool      flg;
14674bbf5ea8SMatthew G. Knepley   PetscInt       csize, rsize;
14684bbf5ea8SMatthew G. Knepley   const char    *prefix = NULL;
14694bbf5ea8SMatthew G. Knepley   PetscErrorCode ierr;
14704bbf5ea8SMatthew G. Knepley 
14714bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
1472c2e6f3c0SFlorian Wechsung   if(withArtificial) {
1473e047a90bSFlorian Wechsung     /* would be nice if we could create a rectangular matrix of size numDofsWithArtificial x numDofs here */
14741202d238SPatrick Farrell     x = patch->patchRHSWithArtificial[point];
14751202d238SPatrick Farrell     y = patch->patchRHSWithArtificial[point];
1476ff201f6aSFlorian Wechsung   } else {
14771202d238SPatrick Farrell     x = patch->patchRHS[point];
14781202d238SPatrick Farrell     y = patch->patchUpdate[point];
1479c2e6f3c0SFlorian Wechsung   }
1480c2e6f3c0SFlorian Wechsung 
14814bbf5ea8SMatthew G. Knepley   ierr = VecGetSize(x, &csize);CHKERRQ(ierr);
14824bbf5ea8SMatthew G. Knepley   ierr = VecGetSize(y, &rsize);CHKERRQ(ierr);
14834bbf5ea8SMatthew G. Knepley   ierr = MatCreate(PETSC_COMM_SELF, mat);CHKERRQ(ierr);
14844bbf5ea8SMatthew G. Knepley   ierr = PCGetOptionsPrefix(pc, &prefix);CHKERRQ(ierr);
14854bbf5ea8SMatthew G. Knepley   ierr = MatSetOptionsPrefix(*mat, prefix);CHKERRQ(ierr);
14865f824522SMatthew G. Knepley   ierr = MatAppendOptionsPrefix(*mat, "pc_patch_sub_");CHKERRQ(ierr);
14874bbf5ea8SMatthew G. Knepley   if (patch->sub_mat_type)       {ierr = MatSetType(*mat, patch->sub_mat_type);CHKERRQ(ierr);}
14887974b488SMatthew G. Knepley   else if (!patch->sub_mat_type) {ierr = MatSetType(*mat, MATDENSE);CHKERRQ(ierr);}
14894bbf5ea8SMatthew G. Knepley   ierr = MatSetSizes(*mat, rsize, csize, rsize, csize);CHKERRQ(ierr);
14904bbf5ea8SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) *mat, MATDENSE, &flg);CHKERRQ(ierr);
14914bbf5ea8SMatthew G. Knepley   if (!flg) {ierr = PetscObjectTypeCompare((PetscObject)*mat, MATSEQDENSE, &flg);CHKERRQ(ierr);}
14924bbf5ea8SMatthew G. Knepley   /* Sparse patch matrices */
14934bbf5ea8SMatthew G. Knepley   if (!flg) {
14944bbf5ea8SMatthew G. Knepley     PetscBT         bt;
14954bbf5ea8SMatthew G. Knepley     PetscInt       *dnnz      = NULL;
14964bbf5ea8SMatthew G. Knepley     const PetscInt *dofsArray = NULL;
14974bbf5ea8SMatthew G. Knepley     PetscInt        pStart, pEnd, ncell, offset, c, i, j;
14984bbf5ea8SMatthew G. Knepley 
1499c2e6f3c0SFlorian Wechsung     if(withArtificial) {
1500c2e6f3c0SFlorian Wechsung       ierr = ISGetIndices(patch->dofsWithArtificial, &dofsArray);CHKERRQ(ierr);
1501ff201f6aSFlorian Wechsung     } else {
15024bbf5ea8SMatthew G. Knepley       ierr = ISGetIndices(patch->dofs, &dofsArray);CHKERRQ(ierr);
1503c2e6f3c0SFlorian Wechsung     }
15044bbf5ea8SMatthew G. Knepley     ierr = PetscSectionGetChart(patch->cellCounts, &pStart, &pEnd);CHKERRQ(ierr);
15054bbf5ea8SMatthew G. Knepley     point += pStart;
15064bbf5ea8SMatthew G. Knepley     if (point >= pEnd) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Operator point %D not in [%D, %D)\n", point, pStart, pEnd);CHKERRQ(ierr);
15074bbf5ea8SMatthew G. Knepley     ierr = PetscSectionGetDof(patch->cellCounts, point, &ncell);CHKERRQ(ierr);
15084bbf5ea8SMatthew G. Knepley     ierr = PetscSectionGetOffset(patch->cellCounts, point, &offset);CHKERRQ(ierr);
15094bbf5ea8SMatthew G. Knepley     ierr = PetscCalloc1(rsize, &dnnz);CHKERRQ(ierr);
15104bbf5ea8SMatthew G. Knepley     ierr = PetscLogEventBegin(PC_Patch_Prealloc, pc, 0, 0, 0);CHKERRQ(ierr);
15114bbf5ea8SMatthew G. Knepley     /* XXX: This uses N^2 bits to store the sparsity pattern on a
15124bbf5ea8SMatthew G. Knepley      * patch.  This is probably OK if the patches are not too big,
15134bbf5ea8SMatthew G. Knepley      * but could use quite a bit of memory for planes in 3D.
15144bbf5ea8SMatthew G. Knepley      * Should we switch based on the value of rsize to a
15154bbf5ea8SMatthew G. Knepley      * hash-table (slower, but more memory efficient) approach? */
15164bbf5ea8SMatthew G. Knepley     ierr = PetscBTCreate(rsize*rsize, &bt);CHKERRQ(ierr);
15174bbf5ea8SMatthew G. Knepley     for (c = 0; c < ncell; ++c) {
15184bbf5ea8SMatthew G. Knepley       const PetscInt *idx = dofsArray + (offset + c)*patch->totalDofsPerCell;
15194bbf5ea8SMatthew G. Knepley       for (i = 0; i < patch->totalDofsPerCell; ++i) {
15204bbf5ea8SMatthew G. Knepley         const PetscInt row = idx[i];
1521557beb66SLawrence Mitchell         if (row < 0) continue;
15224bbf5ea8SMatthew G. Knepley         for (j = 0; j < patch->totalDofsPerCell; ++j) {
15234bbf5ea8SMatthew G. Knepley           const PetscInt col = idx[j];
15244bbf5ea8SMatthew G. Knepley           const PetscInt key = row*rsize + col;
1525557beb66SLawrence Mitchell           if (col < 0) continue;
15264bbf5ea8SMatthew G. Knepley           if (!PetscBTLookupSet(bt, key)) ++dnnz[row];
15274bbf5ea8SMatthew G. Knepley         }
15284bbf5ea8SMatthew G. Knepley       }
15294bbf5ea8SMatthew G. Knepley     }
15304bbf5ea8SMatthew G. Knepley     ierr = PetscBTDestroy(&bt);CHKERRQ(ierr);
15314bbf5ea8SMatthew G. Knepley     ierr = MatXAIJSetPreallocation(*mat, 1, dnnz, NULL, NULL, NULL);CHKERRQ(ierr);
15324bbf5ea8SMatthew G. Knepley     ierr = PetscFree(dnnz);CHKERRQ(ierr);
15334bbf5ea8SMatthew G. Knepley     ierr = PCPatchZeroFillMatrix_Private(*mat, ncell, patch->totalDofsPerCell, &dofsArray[offset*patch->totalDofsPerCell]);CHKERRQ(ierr);
15344bbf5ea8SMatthew G. Knepley     ierr = PetscLogEventEnd(PC_Patch_Prealloc, pc, 0, 0, 0);CHKERRQ(ierr);
1535fe117d09SFlorian Wechsung     if(withArtificial) {
1536fe117d09SFlorian Wechsung       ierr = ISRestoreIndices(patch->dofsWithArtificial, &dofsArray);CHKERRQ(ierr);
1537fe117d09SFlorian Wechsung     } else {
15384bbf5ea8SMatthew G. Knepley       ierr = ISRestoreIndices(patch->dofs, &dofsArray);CHKERRQ(ierr);
15394bbf5ea8SMatthew G. Knepley     }
1540fe117d09SFlorian Wechsung   }
15414bbf5ea8SMatthew G. Knepley   ierr = MatSetUp(*mat);CHKERRQ(ierr);
15424bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
15434bbf5ea8SMatthew G. Knepley }
15444bbf5ea8SMatthew G. Knepley 
15450904074fSPatrick Farrell 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)
154692d50984SMatthew G. Knepley {
154792d50984SMatthew G. Knepley   PC_PATCH       *patch = (PC_PATCH *) pc->data;
154892d50984SMatthew G. Knepley   DM              dm;
154992d50984SMatthew G. Knepley   PetscSection    s;
155092d50984SMatthew G. Knepley   const PetscInt *parray, *oarray;
155192d50984SMatthew G. Knepley   PetscInt        Nf = patch->nsubspaces, Np, poff, p, f;
155292d50984SMatthew G. Knepley   PetscErrorCode  ierr;
155392d50984SMatthew G. Knepley 
155492d50984SMatthew G. Knepley   PetscFunctionBegin;
155592d50984SMatthew G. Knepley   ierr = PCGetDM(pc, &dm);CHKERRQ(ierr);
155692d50984SMatthew G. Knepley   ierr = DMGetDefaultSection(dm, &s);CHKERRQ(ierr);
155792d50984SMatthew G. Knepley   /* Set offset into patch */
155892d50984SMatthew G. Knepley   ierr = PetscSectionGetDof(patch->pointCounts, patchNum, &Np);CHKERRQ(ierr);
155992d50984SMatthew G. Knepley   ierr = PetscSectionGetOffset(patch->pointCounts, patchNum, &poff);CHKERRQ(ierr);
156092d50984SMatthew G. Knepley   ierr = ISGetIndices(patch->points, &parray);CHKERRQ(ierr);
156192d50984SMatthew G. Knepley   ierr = ISGetIndices(patch->offs,   &oarray);CHKERRQ(ierr);
156292d50984SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
156392d50984SMatthew G. Knepley     for (p = 0; p < Np; ++p) {
156492d50984SMatthew G. Knepley       const PetscInt point = parray[poff+p];
156592d50984SMatthew G. Knepley       PetscInt       dof;
156692d50984SMatthew G. Knepley 
156792d50984SMatthew G. Knepley       ierr = PetscSectionGetFieldDof(patch->patchSection, point, f, &dof);CHKERRQ(ierr);
156892d50984SMatthew G. Knepley       ierr = PetscSectionSetFieldOffset(patch->patchSection, point, f, oarray[(poff+p)*Nf+f]);CHKERRQ(ierr);
156992d50984SMatthew G. Knepley       if (patch->nsubspaces == 1) {ierr = PetscSectionSetOffset(patch->patchSection, point, oarray[(poff+p)*Nf+f]);CHKERRQ(ierr);}
157092d50984SMatthew G. Knepley       else                        {ierr = PetscSectionSetOffset(patch->patchSection, point, -1);CHKERRQ(ierr);}
157192d50984SMatthew G. Knepley     }
157292d50984SMatthew G. Knepley   }
157392d50984SMatthew G. Knepley   ierr = ISRestoreIndices(patch->points, &parray);CHKERRQ(ierr);
157492d50984SMatthew G. Knepley   ierr = ISRestoreIndices(patch->offs,   &oarray);CHKERRQ(ierr);
157592d50984SMatthew G. Knepley   if (patch->viewSection) {ierr = ObjectView((PetscObject) patch->patchSection, patch->viewerSection, patch->formatSection);CHKERRQ(ierr);}
157692d50984SMatthew G. Knepley   ierr = DMPlexComputeResidual_Patch_Internal(pc->dm, patch->patchSection, cellIS, 0.0, x, NULL, F, ctx);CHKERRQ(ierr);
157792d50984SMatthew G. Knepley   PetscFunctionReturn(0);
157892d50984SMatthew G. Knepley }
157992d50984SMatthew G. Knepley 
158092d50984SMatthew G. Knepley PetscErrorCode PCPatchComputeFunction_Internal(PC pc, Vec x, Vec F, PetscInt point)
158192d50984SMatthew G. Knepley {
158292d50984SMatthew G. Knepley   PC_PATCH       *patch = (PC_PATCH *) pc->data;
158392d50984SMatthew G. Knepley   const PetscInt *dofsArray;
15840904074fSPatrick Farrell   const PetscInt *dofsArrayWithAll;
158592d50984SMatthew G. Knepley   const PetscInt *cellsArray;
158692d50984SMatthew G. Knepley   PetscInt        ncell, offset, pStart, pEnd;
158792d50984SMatthew G. Knepley   PetscErrorCode  ierr;
158892d50984SMatthew G. Knepley 
158992d50984SMatthew G. Knepley   PetscFunctionBegin;
159092d50984SMatthew G. Knepley   ierr = PetscLogEventBegin(PC_Patch_ComputeOp, pc, 0, 0, 0);CHKERRQ(ierr);
159192d50984SMatthew G. Knepley   if (!patch->usercomputeop) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call PCPatchSetComputeOperator() to set user callback\n");
159292d50984SMatthew G. Knepley   ierr = ISGetIndices(patch->dofs, &dofsArray);CHKERRQ(ierr);
15930904074fSPatrick Farrell   ierr = ISGetIndices(patch->dofsWithAll, &dofsArrayWithAll);CHKERRQ(ierr);
159492d50984SMatthew G. Knepley   ierr = ISGetIndices(patch->cells, &cellsArray);CHKERRQ(ierr);
159592d50984SMatthew G. Knepley   ierr = PetscSectionGetChart(patch->cellCounts, &pStart, &pEnd);CHKERRQ(ierr);
159692d50984SMatthew G. Knepley 
159792d50984SMatthew G. Knepley   point += pStart;
159892d50984SMatthew G. Knepley   if (point >= pEnd) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Operator point %D not in [%D, %D)\n", point, pStart, pEnd);CHKERRQ(ierr);
159992d50984SMatthew G. Knepley 
160092d50984SMatthew G. Knepley   ierr = PetscSectionGetDof(patch->cellCounts, point, &ncell);CHKERRQ(ierr);
160192d50984SMatthew G. Knepley   ierr = PetscSectionGetOffset(patch->cellCounts, point, &offset);CHKERRQ(ierr);
160292d50984SMatthew G. Knepley   if (ncell <= 0) {
160392d50984SMatthew G. Knepley     ierr = PetscLogEventEnd(PC_Patch_ComputeOp, pc, 0, 0, 0);CHKERRQ(ierr);
160492d50984SMatthew G. Knepley     PetscFunctionReturn(0);
160592d50984SMatthew G. Knepley   }
160692d50984SMatthew G. Knepley   PetscStackPush("PCPatch user callback");
160792d50984SMatthew G. Knepley   /* Cannot reuse the same IS because the geometry info is being cached in it */
160892d50984SMatthew G. Knepley   ierr = ISCreateGeneral(PETSC_COMM_SELF, ncell, cellsArray + offset, PETSC_USE_POINTER, &patch->cellIS);CHKERRQ(ierr);
160939fd2e8aSPatrick Farrell   ierr = patch->usercomputef(pc, point, x, F, patch->cellIS, ncell*patch->totalDofsPerCell, dofsArray + offset*patch->totalDofsPerCell,
16100904074fSPatrick Farrell                                                                                             dofsArrayWithAll + offset*patch->totalDofsPerCell,
161139fd2e8aSPatrick Farrell                                                                                             patch->usercomputefctx);CHKERRQ(ierr);
161292d50984SMatthew G. Knepley   PetscStackPop;
161392d50984SMatthew G. Knepley   ierr = ISDestroy(&patch->cellIS);CHKERRQ(ierr);
161492d50984SMatthew G. Knepley   ierr = ISRestoreIndices(patch->dofs, &dofsArray);CHKERRQ(ierr);
16150904074fSPatrick Farrell   ierr = ISRestoreIndices(patch->dofsWithAll, &dofsArrayWithAll);CHKERRQ(ierr);
161692d50984SMatthew G. Knepley   ierr = ISRestoreIndices(patch->cells, &cellsArray);CHKERRQ(ierr);
161792d50984SMatthew G. Knepley   if (patch->viewMatrix) {
161892d50984SMatthew G. Knepley     char name[PETSC_MAX_PATH_LEN];
161992d50984SMatthew G. Knepley 
162092d50984SMatthew G. Knepley     ierr = PetscSNPrintf(name, PETSC_MAX_PATH_LEN-1, "Patch vector for Point %D", point);CHKERRQ(ierr);
162192d50984SMatthew G. Knepley     ierr = PetscObjectSetName((PetscObject) F, name);CHKERRQ(ierr);
162292d50984SMatthew G. Knepley     ierr = ObjectView((PetscObject) F, patch->viewerMatrix, patch->formatMatrix);CHKERRQ(ierr);
162392d50984SMatthew G. Knepley   }
162492d50984SMatthew G. Knepley   ierr = PetscLogEventEnd(PC_Patch_ComputeOp, pc, 0, 0, 0);CHKERRQ(ierr);
162592d50984SMatthew G. Knepley   PetscFunctionReturn(0);
162692d50984SMatthew G. Knepley }
162792d50984SMatthew G. Knepley 
16280904074fSPatrick Farrell 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)
16295f824522SMatthew G. Knepley {
16305f824522SMatthew G. Knepley   PC_PATCH       *patch = (PC_PATCH *) pc->data;
16315f824522SMatthew G. Knepley   DM              dm;
16325f824522SMatthew G. Knepley   PetscSection    s;
16335f824522SMatthew G. Knepley   const PetscInt *parray, *oarray;
16345f824522SMatthew G. Knepley   PetscInt        Nf = patch->nsubspaces, Np, poff, p, f;
16355f824522SMatthew G. Knepley   PetscErrorCode  ierr;
16365f824522SMatthew G. Knepley 
16375f824522SMatthew G. Knepley   PetscFunctionBegin;
16385f824522SMatthew G. Knepley   ierr = PCGetDM(pc, &dm);CHKERRQ(ierr);
16395f824522SMatthew G. Knepley   ierr = DMGetDefaultSection(dm, &s);CHKERRQ(ierr);
16405f824522SMatthew G. Knepley   /* Set offset into patch */
16415f824522SMatthew G. Knepley   ierr = PetscSectionGetDof(patch->pointCounts, patchNum, &Np);CHKERRQ(ierr);
16425f824522SMatthew G. Knepley   ierr = PetscSectionGetOffset(patch->pointCounts, patchNum, &poff);CHKERRQ(ierr);
16435f824522SMatthew G. Knepley   ierr = ISGetIndices(patch->points, &parray);CHKERRQ(ierr);
16445f824522SMatthew G. Knepley   ierr = ISGetIndices(patch->offs,   &oarray);CHKERRQ(ierr);
16455f824522SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
16465f824522SMatthew G. Knepley     for (p = 0; p < Np; ++p) {
16475f824522SMatthew G. Knepley       const PetscInt point = parray[poff+p];
16485f824522SMatthew G. Knepley       PetscInt       dof;
16495f824522SMatthew G. Knepley 
16505f824522SMatthew G. Knepley       ierr = PetscSectionGetFieldDof(patch->patchSection, point, f, &dof);CHKERRQ(ierr);
16515f824522SMatthew G. Knepley       ierr = PetscSectionSetFieldOffset(patch->patchSection, point, f, oarray[(poff+p)*Nf+f]);CHKERRQ(ierr);
16525f824522SMatthew G. Knepley       if (patch->nsubspaces == 1) {ierr = PetscSectionSetOffset(patch->patchSection, point, oarray[(poff+p)*Nf+f]);CHKERRQ(ierr);}
16535f824522SMatthew G. Knepley       else                        {ierr = PetscSectionSetOffset(patch->patchSection, point, -1);CHKERRQ(ierr);}
16545f824522SMatthew G. Knepley     }
16555f824522SMatthew G. Knepley   }
16565f824522SMatthew G. Knepley   ierr = ISRestoreIndices(patch->points, &parray);CHKERRQ(ierr);
16575f824522SMatthew G. Knepley   ierr = ISRestoreIndices(patch->offs,   &oarray);CHKERRQ(ierr);
16585f824522SMatthew G. Knepley   if (patch->viewSection) {ierr = ObjectView((PetscObject) patch->patchSection, patch->viewerSection, patch->formatSection);CHKERRQ(ierr);}
16595f824522SMatthew G. Knepley   /* TODO Shut off MatViewFromOptions() in MatAssemblyEnd() here */
1660723f9013SMatthew G. Knepley   ierr = DMPlexComputeJacobian_Patch_Internal(pc->dm, patch->patchSection, patch->patchSection, cellIS, 0.0, 0.0, x, NULL, J, J, ctx);CHKERRQ(ierr);
16615f824522SMatthew G. Knepley   PetscFunctionReturn(0);
16625f824522SMatthew G. Knepley }
16635f824522SMatthew G. Knepley 
166434d8b122SPatrick Farrell PetscErrorCode PCPatchComputeOperator_Internal(PC pc, Vec x, Mat mat, PetscInt point, PetscBool withArtificial)
16654bbf5ea8SMatthew G. Knepley {
16664bbf5ea8SMatthew G. Knepley   PC_PATCH       *patch = (PC_PATCH *) pc->data;
16674bbf5ea8SMatthew G. Knepley   const PetscInt *dofsArray;
16684d04e9f1SPatrick Farrell   const PetscInt *dofsArrayWithArtificial = NULL;
16690904074fSPatrick Farrell   const PetscInt *dofsArrayWithAll = NULL;
16704bbf5ea8SMatthew G. Knepley   const PetscInt *cellsArray;
16714bbf5ea8SMatthew G. Knepley   PetscInt        ncell, offset, pStart, pEnd;
16724d04e9f1SPatrick Farrell   PetscBool       isNonlinear;
16734bbf5ea8SMatthew G. Knepley   PetscErrorCode  ierr;
16744bbf5ea8SMatthew G. Knepley 
16754bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
16764bbf5ea8SMatthew G. Knepley   ierr = PetscLogEventBegin(PC_Patch_ComputeOp, pc, 0, 0, 0);CHKERRQ(ierr);
1677debbdec3SPatrick Farrell   isNonlinear = patch->isNonlinear;
16784bbf5ea8SMatthew G. Knepley   if (!patch->usercomputeop) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call PCPatchSetComputeOperator() to set user callback\n");
1679c2e6f3c0SFlorian Wechsung   if(withArtificial) {
1680c2e6f3c0SFlorian Wechsung     ierr = ISGetIndices(patch->dofsWithArtificial, &dofsArray);CHKERRQ(ierr);
1681c2e6f3c0SFlorian Wechsung   } else {
16824bbf5ea8SMatthew G. Knepley     ierr = ISGetIndices(patch->dofs, &dofsArray);CHKERRQ(ierr);
1683c2e6f3c0SFlorian Wechsung   }
16844d04e9f1SPatrick Farrell   if (isNonlinear) {
16850904074fSPatrick Farrell     ierr = ISGetIndices(patch->dofsWithAll, &dofsArrayWithAll);CHKERRQ(ierr);
16864d04e9f1SPatrick Farrell   }
16874bbf5ea8SMatthew G. Knepley   ierr = ISGetIndices(patch->cells, &cellsArray);CHKERRQ(ierr);
16884bbf5ea8SMatthew G. Knepley   ierr = PetscSectionGetChart(patch->cellCounts, &pStart, &pEnd);CHKERRQ(ierr);
16894bbf5ea8SMatthew G. Knepley 
16904bbf5ea8SMatthew G. Knepley   point += pStart;
16914bbf5ea8SMatthew G. Knepley   if (point >= pEnd) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Operator point %D not in [%D, %D)\n", point, pStart, pEnd);CHKERRQ(ierr);
16924bbf5ea8SMatthew G. Knepley 
16934bbf5ea8SMatthew G. Knepley   ierr = PetscSectionGetDof(patch->cellCounts, point, &ncell);CHKERRQ(ierr);
16944bbf5ea8SMatthew G. Knepley   ierr = PetscSectionGetOffset(patch->cellCounts, point, &offset);CHKERRQ(ierr);
16954bbf5ea8SMatthew G. Knepley   if (ncell <= 0) {
16964bbf5ea8SMatthew G. Knepley     ierr = PetscLogEventEnd(PC_Patch_ComputeOp, pc, 0, 0, 0);CHKERRQ(ierr);
16974bbf5ea8SMatthew G. Knepley     PetscFunctionReturn(0);
16984bbf5ea8SMatthew G. Knepley   }
16994bbf5ea8SMatthew G. Knepley   PetscStackPush("PCPatch user callback");
17002aa6f319SMatthew G. Knepley   /* Cannot reuse the same IS because the geometry info is being cached in it */
17012aa6f319SMatthew G. Knepley   ierr = ISCreateGeneral(PETSC_COMM_SELF, ncell, cellsArray + offset, PETSC_USE_POINTER, &patch->cellIS);CHKERRQ(ierr);
17020904074fSPatrick Farrell   ierr = patch->usercomputeop(pc, point, x, mat, patch->cellIS, ncell*patch->totalDofsPerCell, dofsArray + offset*patch->totalDofsPerCell, dofsArrayWithAll ? dofsArrayWithAll + offset*patch->totalDofsPerCell : NULL, patch->usercomputeopctx);CHKERRQ(ierr);
17034bbf5ea8SMatthew G. Knepley   PetscStackPop;
17042aa6f319SMatthew G. Knepley   ierr = ISDestroy(&patch->cellIS);CHKERRQ(ierr);
17054d04e9f1SPatrick Farrell   if(withArtificial) {
1706c2e6f3c0SFlorian Wechsung     ierr = ISRestoreIndices(patch->dofsWithArtificial, &dofsArray);CHKERRQ(ierr);
1707c2e6f3c0SFlorian Wechsung   } else {
17084bbf5ea8SMatthew G. Knepley     ierr = ISRestoreIndices(patch->dofs, &dofsArray);CHKERRQ(ierr);
1709c2e6f3c0SFlorian Wechsung   }
17104d04e9f1SPatrick Farrell   if (isNonlinear) {
17110904074fSPatrick Farrell     ierr = ISRestoreIndices(patch->dofsWithAll, &dofsArrayWithAll);CHKERRQ(ierr);
17124d04e9f1SPatrick Farrell   }
17134bbf5ea8SMatthew G. Knepley   ierr = ISRestoreIndices(patch->cells, &cellsArray);CHKERRQ(ierr);
17142aa6f319SMatthew G. Knepley   if (patch->viewMatrix) {
17152aa6f319SMatthew G. Knepley     char name[PETSC_MAX_PATH_LEN];
17162aa6f319SMatthew G. Knepley 
17172aa6f319SMatthew G. Knepley     ierr = PetscSNPrintf(name, PETSC_MAX_PATH_LEN-1, "Patch matrix for Point %D", point);CHKERRQ(ierr);
17182aa6f319SMatthew G. Knepley     ierr = PetscObjectSetName((PetscObject) mat, name);CHKERRQ(ierr);
17192aa6f319SMatthew G. Knepley     ierr = ObjectView((PetscObject) mat, patch->viewerMatrix, patch->formatMatrix);CHKERRQ(ierr);
17202aa6f319SMatthew G. Knepley   }
17214bbf5ea8SMatthew G. Knepley   ierr = PetscLogEventEnd(PC_Patch_ComputeOp, pc, 0, 0, 0);CHKERRQ(ierr);
17224bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
17234bbf5ea8SMatthew G. Knepley }
17244bbf5ea8SMatthew G. Knepley 
17250904074fSPatrick Farrell PetscErrorCode PCPatch_ScatterLocal_Private(PC pc, PetscInt p, Vec x, Vec y, InsertMode mode, ScatterMode scat, PatchScatterType scattertype)
17264bbf5ea8SMatthew G. Knepley {
17274bbf5ea8SMatthew G. Knepley   PC_PATCH          *patch     = (PC_PATCH *) pc->data;
17284bbf5ea8SMatthew G. Knepley   const PetscScalar *xArray    = NULL;
17294bbf5ea8SMatthew G. Knepley   PetscScalar       *yArray    = NULL;
17304bbf5ea8SMatthew G. Knepley   const PetscInt    *gtolArray = NULL;
17314bbf5ea8SMatthew G. Knepley   PetscInt           dof, offset, lidx;
17324bbf5ea8SMatthew G. Knepley   PetscErrorCode     ierr;
17334bbf5ea8SMatthew G. Knepley 
17344bbf5ea8SMatthew G. Knepley   PetscFunctionBeginHot;
17354bbf5ea8SMatthew G. Knepley   ierr = PetscLogEventBegin(PC_Patch_Scatter, pc, 0, 0, 0);CHKERRQ(ierr);
17364bbf5ea8SMatthew G. Knepley   ierr = VecGetArrayRead(x, &xArray);CHKERRQ(ierr);
17374bbf5ea8SMatthew G. Knepley   ierr = VecGetArray(y, &yArray);CHKERRQ(ierr);
17380904074fSPatrick Farrell   if (scattertype == SCATTER_WITHARTIFICIAL) {
1739c2e6f3c0SFlorian Wechsung     ierr = PetscSectionGetDof(patch->gtolCountsWithArtificial, p, &dof);CHKERRQ(ierr);
1740c2e6f3c0SFlorian Wechsung     ierr = PetscSectionGetOffset(patch->gtolCountsWithArtificial, p, &offset);CHKERRQ(ierr);
1741c2e6f3c0SFlorian Wechsung     ierr = ISGetIndices(patch->gtolWithArtificial, &gtolArray);CHKERRQ(ierr);
17420904074fSPatrick Farrell   } else if (scattertype == SCATTER_WITHALL) {
17430904074fSPatrick Farrell     ierr = PetscSectionGetDof(patch->gtolCountsWithAll, p, &dof);CHKERRQ(ierr);
17440904074fSPatrick Farrell     ierr = PetscSectionGetOffset(patch->gtolCountsWithAll, p, &offset);CHKERRQ(ierr);
17450904074fSPatrick Farrell     ierr = ISGetIndices(patch->gtolWithAll, &gtolArray);CHKERRQ(ierr);
1746c2e6f3c0SFlorian Wechsung   } else {
17474bbf5ea8SMatthew G. Knepley     ierr = PetscSectionGetDof(patch->gtolCounts, p, &dof);CHKERRQ(ierr);
17484bbf5ea8SMatthew G. Knepley     ierr = PetscSectionGetOffset(patch->gtolCounts, p, &offset);CHKERRQ(ierr);
17494bbf5ea8SMatthew G. Knepley     ierr = ISGetIndices(patch->gtol, &gtolArray);CHKERRQ(ierr);
1750c2e6f3c0SFlorian Wechsung   }
17514bbf5ea8SMatthew G. Knepley   if (mode == INSERT_VALUES && scat != SCATTER_FORWARD) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Can't insert if not scattering forward\n");
17524bbf5ea8SMatthew G. Knepley   if (mode == ADD_VALUES    && scat != SCATTER_REVERSE) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Can't add if not scattering reverse\n");
17534bbf5ea8SMatthew G. Knepley   for (lidx = 0; lidx < dof; ++lidx) {
17544bbf5ea8SMatthew G. Knepley     const PetscInt gidx = gtolArray[offset+lidx];
17554bbf5ea8SMatthew G. Knepley 
17564bbf5ea8SMatthew G. Knepley     if (mode == INSERT_VALUES) yArray[lidx]  = xArray[gidx]; /* Forward */
17574bbf5ea8SMatthew G. Knepley     else                       yArray[gidx] += xArray[lidx]; /* Reverse */
17584bbf5ea8SMatthew G. Knepley   }
17590904074fSPatrick Farrell   if (scattertype == SCATTER_WITHARTIFICIAL) {
1760c2e6f3c0SFlorian Wechsung     ierr = ISRestoreIndices(patch->gtolWithArtificial, &gtolArray);CHKERRQ(ierr);
17610904074fSPatrick Farrell   } else if (scattertype == SCATTER_WITHALL) {
17620904074fSPatrick Farrell     ierr = ISRestoreIndices(patch->gtolWithAll, &gtolArray);CHKERRQ(ierr);
1763c2e6f3c0SFlorian Wechsung   } else {
17644bbf5ea8SMatthew G. Knepley     ierr = ISRestoreIndices(patch->gtol, &gtolArray);CHKERRQ(ierr);
1765c2e6f3c0SFlorian Wechsung   }
17664bbf5ea8SMatthew G. Knepley   ierr = VecRestoreArrayRead(x, &xArray);CHKERRQ(ierr);
17674bbf5ea8SMatthew G. Knepley   ierr = VecRestoreArray(y, &yArray);CHKERRQ(ierr);
17684bbf5ea8SMatthew G. Knepley   ierr = PetscLogEventEnd(PC_Patch_Scatter, pc, 0, 0, 0);CHKERRQ(ierr);
17694bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
17704bbf5ea8SMatthew G. Knepley }
17714bbf5ea8SMatthew G. Knepley 
1772dadc69c5SMatthew G. Knepley static PetscErrorCode PCSetUp_PATCH_Linear(PC pc)
1773dadc69c5SMatthew G. Knepley {
1774dadc69c5SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
1775dadc69c5SMatthew G. Knepley   const char    *prefix;
1776dadc69c5SMatthew G. Knepley   PetscInt       i;
1777dadc69c5SMatthew G. Knepley   PetscErrorCode ierr;
1778dadc69c5SMatthew G. Knepley 
1779dadc69c5SMatthew G. Knepley   PetscFunctionBegin;
1780dadc69c5SMatthew G. Knepley   if (!pc->setupcalled) {
1781dadc69c5SMatthew G. Knepley     ierr = PetscMalloc1(patch->npatch, &patch->solver);CHKERRQ(ierr);
1782dadc69c5SMatthew G. Knepley     ierr = PCGetOptionsPrefix(pc, &prefix);CHKERRQ(ierr);
1783dadc69c5SMatthew G. Knepley     for (i = 0; i < patch->npatch; ++i) {
1784dadc69c5SMatthew G. Knepley       KSP ksp;
1785dadc69c5SMatthew G. Knepley       PC  subpc;
1786dadc69c5SMatthew G. Knepley 
1787dadc69c5SMatthew G. Knepley       ierr = KSPCreate(PETSC_COMM_SELF, &ksp);CHKERRQ(ierr);
1788dadc69c5SMatthew G. Knepley       ierr = KSPSetOptionsPrefix(ksp, prefix);CHKERRQ(ierr);
1789dadc69c5SMatthew G. Knepley       ierr = KSPAppendOptionsPrefix(ksp, "sub_");CHKERRQ(ierr);
1790dadc69c5SMatthew G. Knepley       ierr = PetscObjectIncrementTabLevel((PetscObject) ksp, (PetscObject) pc, 1);CHKERRQ(ierr);
1791dadc69c5SMatthew G. Knepley       ierr = KSPGetPC(ksp, &subpc);CHKERRQ(ierr);
1792dadc69c5SMatthew G. Knepley       ierr = PetscObjectIncrementTabLevel((PetscObject) subpc, (PetscObject) pc, 1);CHKERRQ(ierr);
1793dadc69c5SMatthew G. Knepley       ierr = PetscLogObjectParent((PetscObject) pc, (PetscObject) ksp);CHKERRQ(ierr);
1794dadc69c5SMatthew G. Knepley       patch->solver[i] = (PetscObject) ksp;
1795dadc69c5SMatthew G. Knepley     }
1796dadc69c5SMatthew G. Knepley   }
1797dadc69c5SMatthew G. Knepley   if (patch->save_operators) {
1798dadc69c5SMatthew G. Knepley     for (i = 0; i < patch->npatch; ++i) {
1799dadc69c5SMatthew G. Knepley       ierr = MatZeroEntries(patch->mat[i]);CHKERRQ(ierr);
180034d8b122SPatrick Farrell       ierr = PCPatchComputeOperator_Internal(pc, NULL, patch->mat[i], i, PETSC_FALSE);CHKERRQ(ierr);
1801dadc69c5SMatthew G. Knepley       ierr = KSPSetOperators((KSP) patch->solver[i], patch->mat[i], patch->mat[i]);CHKERRQ(ierr);
1802dadc69c5SMatthew G. Knepley     }
1803dadc69c5SMatthew G. Knepley   }
180434d8b122SPatrick Farrell   if(patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
180534d8b122SPatrick Farrell     for (i = 0; i < patch->npatch; ++i) {
18061202d238SPatrick Farrell       /* Instead of padding patch->patchUpdate with zeros to get */
18071202d238SPatrick Farrell       /* patch->patchUpdateWithArtificial and then multiplying with the matrix, */
180834d8b122SPatrick Farrell       /* just get rid of the columns that correspond to the dofs with */
180934d8b122SPatrick Farrell       /* artificial bcs. That's of course fairly inefficient, hopefully we */
181034d8b122SPatrick Farrell       /* can just assemble the rectangular matrix in the first place. */
181134d8b122SPatrick Farrell       Mat matSquare;
181234d8b122SPatrick Farrell       IS rowis;
181334d8b122SPatrick Farrell       PetscInt dof;
181434d8b122SPatrick Farrell 
181534d8b122SPatrick Farrell       ierr = MatGetSize(patch->mat[i], &dof, NULL);CHKERRQ(ierr);
181634d8b122SPatrick Farrell       if (dof == 0) {
181734d8b122SPatrick Farrell         patch->matWithArtificial[i] = NULL;
181834d8b122SPatrick Farrell         continue;
181934d8b122SPatrick Farrell       }
182034d8b122SPatrick Farrell 
182134d8b122SPatrick Farrell       ierr = PCPatchCreateMatrix_Private(pc, i, &matSquare, PETSC_TRUE);CHKERRQ(ierr);
182234d8b122SPatrick Farrell       ierr = MatZeroEntries(matSquare);CHKERRQ(ierr);
182334d8b122SPatrick Farrell       ierr = PCPatchComputeOperator_Internal(pc, NULL, matSquare, i, PETSC_TRUE);CHKERRQ(ierr);
182434d8b122SPatrick Farrell 
182534d8b122SPatrick Farrell       ierr = MatGetSize(matSquare, &dof, NULL);CHKERRQ(ierr);
182634d8b122SPatrick Farrell       ierr = ISCreateStride(PETSC_COMM_SELF, dof, 0, 1, &rowis); CHKERRQ(ierr);
182734d8b122SPatrick Farrell       if(pc->setupcalled) {
182834d8b122SPatrick Farrell         ierr = MatCreateSubMatrix(matSquare, rowis, patch->dofMappingWithoutToWithArtificial[i], MAT_REUSE_MATRIX, &patch->matWithArtificial[i]); CHKERRQ(ierr);
182934d8b122SPatrick Farrell       } else {
183034d8b122SPatrick Farrell         ierr = MatCreateSubMatrix(matSquare, rowis, patch->dofMappingWithoutToWithArtificial[i], MAT_INITIAL_MATRIX, &patch->matWithArtificial[i]); CHKERRQ(ierr);
183134d8b122SPatrick Farrell       }
183234d8b122SPatrick Farrell       ierr = ISDestroy(&rowis); CHKERRQ(ierr);
183334d8b122SPatrick Farrell       ierr = MatDestroy(&matSquare);CHKERRQ(ierr);
183434d8b122SPatrick Farrell     }
183534d8b122SPatrick Farrell   }
1836dadc69c5SMatthew G. Knepley   PetscFunctionReturn(0);
1837dadc69c5SMatthew G. Knepley }
1838dadc69c5SMatthew G. Knepley 
18394bbf5ea8SMatthew G. Knepley static PetscErrorCode PCSetUp_PATCH(PC pc)
18404bbf5ea8SMatthew G. Knepley {
18414bbf5ea8SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
1842557beb66SLawrence Mitchell   PetscInt       i;
184339fd2e8aSPatrick Farrell   PetscBool       isNonlinear;
18444bbf5ea8SMatthew G. Knepley   PetscErrorCode ierr;
18454bbf5ea8SMatthew G. Knepley 
18464bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
18474bbf5ea8SMatthew G. Knepley   if (!pc->setupcalled) {
18484bbf5ea8SMatthew G. Knepley     PetscInt pStart, pEnd, p;
18494bbf5ea8SMatthew G. Knepley     PetscInt localSize;
18504bbf5ea8SMatthew G. Knepley 
18514bbf5ea8SMatthew G. Knepley     ierr = PetscLogEventBegin(PC_Patch_CreatePatches, pc, 0, 0, 0);CHKERRQ(ierr);
18524bbf5ea8SMatthew G. Knepley 
1853debbdec3SPatrick Farrell     isNonlinear = patch->isNonlinear;
18545f824522SMatthew G. Knepley     if (!patch->nsubspaces) {
18555f824522SMatthew G. Knepley       DM           dm;
18565f824522SMatthew G. Knepley       PetscDS      prob;
18575f824522SMatthew G. Knepley       PetscSection s;
1858e72c1634SMatthew G. Knepley       PetscInt     cStart, cEnd, c, Nf, f, numGlobalBcs = 0, *globalBcs, *Nb, totNb = 0, **cellDofs;
18595f824522SMatthew G. Knepley 
18605f824522SMatthew G. Knepley       ierr = PCGetDM(pc, &dm);CHKERRQ(ierr);
18615f824522SMatthew G. Knepley       if (!dm) SETERRQ(PetscObjectComm((PetscObject) pc), PETSC_ERR_ARG_WRONG, "Must set DM for PCPATCH or call PCPatchSetDiscretisationInfo()");
18625f824522SMatthew G. Knepley       ierr = DMGetDefaultSection(dm, &s);CHKERRQ(ierr);
18635f824522SMatthew G. Knepley       ierr = PetscSectionGetNumFields(s, &Nf);CHKERRQ(ierr);
18645f824522SMatthew G. Knepley       ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
18655f824522SMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
18665f824522SMatthew G. Knepley         PetscInt cdof;
18675f824522SMatthew G. Knepley         ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
18685f824522SMatthew G. Knepley         numGlobalBcs += cdof;
18695f824522SMatthew G. Knepley       }
18705f824522SMatthew G. Knepley       ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
18715f824522SMatthew G. Knepley       ierr = DMGetDS(dm, &prob);CHKERRQ(ierr);
18725f824522SMatthew G. Knepley       ierr = PetscMalloc3(Nf, &Nb, Nf, &cellDofs, numGlobalBcs, &globalBcs);CHKERRQ(ierr);
18735f824522SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
18745f824522SMatthew G. Knepley         PetscFE        fe;
18755f824522SMatthew G. Knepley         PetscDualSpace sp;
18765f824522SMatthew G. Knepley         PetscInt       cdoff = 0;
18775f824522SMatthew G. Knepley 
18785f824522SMatthew G. Knepley         ierr = PetscDSGetDiscretization(prob, f, (PetscObject *) &fe);CHKERRQ(ierr);
18795f824522SMatthew G. Knepley         /* ierr = PetscFEGetNumComponents(fe, &Nc[f]);CHKERRQ(ierr); */
18805f824522SMatthew G. Knepley         ierr = PetscFEGetDualSpace(fe, &sp);CHKERRQ(ierr);
18815f824522SMatthew G. Knepley         ierr = PetscDualSpaceGetDimension(sp, &Nb[f]);CHKERRQ(ierr);
18825f824522SMatthew G. Knepley         totNb += Nb[f];
18835f824522SMatthew G. Knepley 
18845f824522SMatthew G. Knepley         ierr = PetscMalloc1((cEnd-cStart)*Nb[f], &cellDofs[f]);CHKERRQ(ierr);
18855f824522SMatthew G. Knepley         for (c = cStart; c < cEnd; ++c) {
18865f824522SMatthew G. Knepley           PetscInt *closure = NULL;
18875f824522SMatthew G. Knepley           PetscInt  clSize  = 0, cl;
18885f824522SMatthew G. Knepley 
18895f824522SMatthew G. Knepley           ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
18905f824522SMatthew G. Knepley           for (cl = 0; cl < clSize*2; cl += 2) {
18915f824522SMatthew G. Knepley             const PetscInt p = closure[cl];
18925f824522SMatthew G. Knepley             PetscInt       fdof, d, foff;
18935f824522SMatthew G. Knepley 
18945f824522SMatthew G. Knepley             ierr = PetscSectionGetFieldDof(s, p, f, &fdof);CHKERRQ(ierr);
18955f824522SMatthew G. Knepley             ierr = PetscSectionGetFieldOffset(s, p, f, &foff);CHKERRQ(ierr);
18965f824522SMatthew G. Knepley             for (d = 0; d < fdof; ++d, ++cdoff) cellDofs[f][cdoff] = foff + d;
18975f824522SMatthew G. Knepley           }
18985f824522SMatthew G. Knepley           ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
18995f824522SMatthew G. Knepley         }
19005f824522SMatthew G. Knepley         if (cdoff != (cEnd-cStart)*Nb[f]) SETERRQ4(PetscObjectComm((PetscObject) pc), PETSC_ERR_ARG_SIZ, "Total number of cellDofs %D for field %D should be Nc (%D) * cellDof (%D)", cdoff, f, cEnd-cStart, Nb[f]);
19015f824522SMatthew G. Knepley       }
19025f824522SMatthew G. Knepley       numGlobalBcs = 0;
19035f824522SMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
19045f824522SMatthew G. Knepley         const PetscInt *ind;
19055f824522SMatthew G. Knepley         PetscInt        off, cdof, d;
19065f824522SMatthew G. Knepley 
19075f824522SMatthew G. Knepley         ierr = PetscSectionGetOffset(s, p, &off);CHKERRQ(ierr);
19085f824522SMatthew G. Knepley         ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
19095f824522SMatthew G. Knepley         ierr = PetscSectionGetConstraintIndices(s, p, &ind);CHKERRQ(ierr);
19105f824522SMatthew G. Knepley         for (d = 0; d < cdof; ++d) globalBcs[numGlobalBcs++] = off + ind[d];
19115f824522SMatthew G. Knepley       }
19125f824522SMatthew G. Knepley 
19135f824522SMatthew G. Knepley       ierr = PCPatchSetDiscretisationInfoCombined(pc, dm, Nb, (const PetscInt **) cellDofs, numGlobalBcs, globalBcs, numGlobalBcs, globalBcs);CHKERRQ(ierr);
19145f824522SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
19155f824522SMatthew G. Knepley         ierr = PetscFree(cellDofs[f]);CHKERRQ(ierr);
19165f824522SMatthew G. Knepley       }
19175f824522SMatthew G. Knepley       ierr = PetscFree3(Nb, cellDofs, globalBcs);CHKERRQ(ierr);
191892d50984SMatthew G. Knepley       ierr = PCPatchSetComputeFunction(pc, PCPatchComputeFunction_DMPlex_Private, NULL);CHKERRQ(ierr);
19195f824522SMatthew G. Knepley       ierr = PCPatchSetComputeOperator(pc, PCPatchComputeOperator_DMPlex_Private, NULL);CHKERRQ(ierr);
19205f824522SMatthew G. Knepley     }
19215f824522SMatthew G. Knepley 
19224bbf5ea8SMatthew G. Knepley     localSize = patch->subspaceOffsets[patch->nsubspaces];
19231202d238SPatrick Farrell     ierr = VecCreateSeq(PETSC_COMM_SELF, localSize, &patch->localRHS);CHKERRQ(ierr);
19241202d238SPatrick Farrell     ierr = VecSetUp(patch->localRHS);CHKERRQ(ierr);
19251202d238SPatrick Farrell     ierr = VecDuplicate(patch->localRHS, &patch->localUpdate);CHKERRQ(ierr);
19264bbf5ea8SMatthew G. Knepley     ierr = PCPatchCreateCellPatches(pc);CHKERRQ(ierr);
19274bbf5ea8SMatthew G. Knepley     ierr = PCPatchCreateCellPatchDiscretisationInfo(pc);CHKERRQ(ierr);
19284bbf5ea8SMatthew G. Knepley 
19294bbf5ea8SMatthew G. Knepley     /* OK, now build the work vectors */
19304bbf5ea8SMatthew G. Knepley     ierr = PetscSectionGetChart(patch->gtolCounts, &pStart, &pEnd);CHKERRQ(ierr);
19311202d238SPatrick Farrell     ierr = PetscMalloc1(patch->npatch, &patch->patchRHS);CHKERRQ(ierr);
19321202d238SPatrick Farrell     ierr = PetscMalloc1(patch->npatch, &patch->patchUpdate);CHKERRQ(ierr);
1933c2e6f3c0SFlorian Wechsung 
193461c4b389SFlorian Wechsung     if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
19351202d238SPatrick Farrell       ierr = PetscMalloc1(patch->npatch, &patch->patchRHSWithArtificial);CHKERRQ(ierr);
1936c2e6f3c0SFlorian Wechsung       ierr = PetscMalloc1(patch->npatch, &patch->dofMappingWithoutToWithArtificial);CHKERRQ(ierr);
1937c2e6f3c0SFlorian Wechsung     }
19380904074fSPatrick Farrell     if (isNonlinear) {
19390904074fSPatrick Farrell       ierr = PetscMalloc1(patch->npatch, &patch->dofMappingWithoutToWithAll);CHKERRQ(ierr);
19400904074fSPatrick Farrell     }
19414bbf5ea8SMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
19424bbf5ea8SMatthew G. Knepley       PetscInt dof;
19434bbf5ea8SMatthew G. Knepley 
19444bbf5ea8SMatthew G. Knepley       ierr = PetscSectionGetDof(patch->gtolCounts, p, &dof);CHKERRQ(ierr);
19451202d238SPatrick Farrell       ierr = VecCreateSeq(PETSC_COMM_SELF, dof, &patch->patchRHS[p-pStart]);CHKERRQ(ierr);
19461202d238SPatrick Farrell       ierr = VecSetUp(patch->patchRHS[p-pStart]);CHKERRQ(ierr);
19471202d238SPatrick Farrell       ierr = VecCreateSeq(PETSC_COMM_SELF, dof, &patch->patchUpdate[p-pStart]);CHKERRQ(ierr);
19481202d238SPatrick Farrell       ierr = VecSetUp(patch->patchUpdate[p-pStart]);CHKERRQ(ierr);
19490904074fSPatrick Farrell       if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
19503bb0e8f7SKarl Rupp         const PetscInt    *gtolArray, *gtolArrayWithArtificial = NULL;
19513bb0e8f7SKarl Rupp         PetscInt           numPatchDofs, offset;
19523bb0e8f7SKarl Rupp         PetscInt           numPatchDofsWithArtificial, offsetWithArtificial;
19533bb0e8f7SKarl Rupp         PetscInt           dofWithoutArtificialCounter = 0;
19543bb0e8f7SKarl Rupp         PetscInt          *patchWithoutArtificialToWithArtificialArray;
19553bb0e8f7SKarl Rupp 
1956c2e6f3c0SFlorian Wechsung         ierr = PetscSectionGetDof(patch->gtolCountsWithArtificial, p, &dof);CHKERRQ(ierr);
19571202d238SPatrick Farrell         ierr = VecCreateSeq(PETSC_COMM_SELF, dof, &patch->patchRHSWithArtificial[p-pStart]);CHKERRQ(ierr);
19581202d238SPatrick Farrell         ierr = VecSetUp(patch->patchRHSWithArtificial[p-pStart]);CHKERRQ(ierr);
1959c2e6f3c0SFlorian Wechsung 
1960e047a90bSFlorian Wechsung         /* Now build the mapping that for a dof in a patch WITHOUT dofs that have artificial bcs gives the */
1961e047a90bSFlorian Wechsung         /* the index in the patch with all dofs */
1962c2e6f3c0SFlorian Wechsung         ierr = ISGetIndices(patch->gtol, &gtolArray);CHKERRQ(ierr);
196363deea8eSPatrick Farrell 
1964c2e6f3c0SFlorian Wechsung         ierr = PetscSectionGetDof(patch->gtolCounts, p, &numPatchDofs);CHKERRQ(ierr);
196563deea8eSPatrick Farrell 
1966c2e6f3c0SFlorian Wechsung         ierr = PetscSectionGetOffset(patch->gtolCounts, p, &offset);CHKERRQ(ierr);
1967c2e6f3c0SFlorian Wechsung         ierr = ISGetIndices(patch->gtolWithArtificial, &gtolArrayWithArtificial);CHKERRQ(ierr);
1968c2e6f3c0SFlorian Wechsung         ierr = PetscSectionGetDof(patch->gtolCountsWithArtificial, p, &numPatchDofsWithArtificial);CHKERRQ(ierr);
1969c2e6f3c0SFlorian Wechsung         ierr = PetscSectionGetOffset(patch->gtolCountsWithArtificial, p, &offsetWithArtificial);CHKERRQ(ierr);
1970c2e6f3c0SFlorian Wechsung 
1971c2e6f3c0SFlorian Wechsung         ierr = PetscMalloc1(numPatchDofs, &patchWithoutArtificialToWithArtificialArray);CHKERRQ(ierr);
1972c2e6f3c0SFlorian Wechsung 
19733bb0e8f7SKarl Rupp         ierr = ISCreateGeneral(PETSC_COMM_SELF, numPatchDofs, patchWithoutArtificialToWithArtificialArray, PETSC_OWN_POINTER, &patch->dofMappingWithoutToWithArtificial[p-pStart]);CHKERRQ(ierr);
19747e6cf999SPatrick Farrell         if (numPatchDofs == 0) continue;
1975b0c21b6aSKarl Rupp         for (i=0; i<numPatchDofsWithArtificial; i++) {
1976e047a90bSFlorian Wechsung           if (gtolArrayWithArtificial[i+offsetWithArtificial] == gtolArray[offset+dofWithoutArtificialCounter]) {
1977c2e6f3c0SFlorian Wechsung             patchWithoutArtificialToWithArtificialArray[dofWithoutArtificialCounter] = i;
1978c2e6f3c0SFlorian Wechsung             dofWithoutArtificialCounter++;
1979c2e6f3c0SFlorian Wechsung             if (dofWithoutArtificialCounter == numPatchDofs)
1980c2e6f3c0SFlorian Wechsung               break;
1981c2e6f3c0SFlorian Wechsung           }
1982c2e6f3c0SFlorian Wechsung         }
1983c2e6f3c0SFlorian Wechsung         ierr = ISRestoreIndices(patch->gtol, &gtolArray);CHKERRQ(ierr);
1984c2e6f3c0SFlorian Wechsung         ierr = ISRestoreIndices(patch->gtolWithArtificial, &gtolArrayWithArtificial);CHKERRQ(ierr);
1985c2e6f3c0SFlorian Wechsung       }
19860904074fSPatrick Farrell       if (isNonlinear) {
19870904074fSPatrick Farrell         const PetscInt    *gtolArray, *gtolArrayWithAll = NULL;
19880904074fSPatrick Farrell         PetscInt           numPatchDofs, offset;
19890904074fSPatrick Farrell         PetscInt           numPatchDofsWithAll, offsetWithAll;
19900904074fSPatrick Farrell         PetscInt           dofWithoutAllCounter = 0;
19910904074fSPatrick Farrell         PetscInt          *patchWithoutAllToWithAllArray;
19920904074fSPatrick Farrell 
19930904074fSPatrick Farrell         /* Now build the mapping that for a dof in a patch WITHOUT dofs that have artificial bcs gives the */
19940904074fSPatrick Farrell         /* the index in the patch with all dofs */
19950904074fSPatrick Farrell         ierr = ISGetIndices(patch->gtol, &gtolArray);CHKERRQ(ierr);
19960904074fSPatrick Farrell 
19970904074fSPatrick Farrell         ierr = PetscSectionGetDof(patch->gtolCounts, p, &numPatchDofs);CHKERRQ(ierr);
19980904074fSPatrick Farrell 
19990904074fSPatrick Farrell         ierr = PetscSectionGetOffset(patch->gtolCounts, p, &offset);CHKERRQ(ierr);
20000904074fSPatrick Farrell         ierr = ISGetIndices(patch->gtolWithAll, &gtolArrayWithAll);CHKERRQ(ierr);
20010904074fSPatrick Farrell         ierr = PetscSectionGetDof(patch->gtolCountsWithAll, p, &numPatchDofsWithAll);CHKERRQ(ierr);
20020904074fSPatrick Farrell         ierr = PetscSectionGetOffset(patch->gtolCountsWithAll, p, &offsetWithAll);CHKERRQ(ierr);
20030904074fSPatrick Farrell 
20040904074fSPatrick Farrell         ierr = PetscMalloc1(numPatchDofs, &patchWithoutAllToWithAllArray);CHKERRQ(ierr);
20050904074fSPatrick Farrell 
20060904074fSPatrick Farrell         ierr = ISCreateGeneral(PETSC_COMM_SELF, numPatchDofs, patchWithoutAllToWithAllArray, PETSC_OWN_POINTER, &patch->dofMappingWithoutToWithAll[p-pStart]);CHKERRQ(ierr);
20070904074fSPatrick Farrell         if (numPatchDofs == 0) continue;
20080904074fSPatrick Farrell         for (i=0; i<numPatchDofsWithAll; i++) {
20090904074fSPatrick Farrell           if (gtolArrayWithAll[i+offsetWithAll] == gtolArray[offset+dofWithoutAllCounter]) {
20100904074fSPatrick Farrell             patchWithoutAllToWithAllArray[dofWithoutAllCounter] = i;
20110904074fSPatrick Farrell             dofWithoutAllCounter++;
20120904074fSPatrick Farrell             if (dofWithoutAllCounter == numPatchDofs)
20130904074fSPatrick Farrell               break;
20140904074fSPatrick Farrell           }
20150904074fSPatrick Farrell         }
20160904074fSPatrick Farrell         ierr = ISRestoreIndices(patch->gtol, &gtolArray);CHKERRQ(ierr);
20170904074fSPatrick Farrell         ierr = ISRestoreIndices(patch->gtolWithAll, &gtolArrayWithAll);CHKERRQ(ierr);
20180904074fSPatrick Farrell       }
20194bbf5ea8SMatthew G. Knepley     }
20204bbf5ea8SMatthew G. Knepley     if (patch->save_operators) {
20214bbf5ea8SMatthew G. Knepley       ierr = PetscMalloc1(patch->npatch, &patch->mat);CHKERRQ(ierr);
20224bbf5ea8SMatthew G. Knepley       for (i = 0; i < patch->npatch; ++i) {
2023c2e6f3c0SFlorian Wechsung         ierr = PCPatchCreateMatrix_Private(pc, i, &patch->mat[i], PETSC_FALSE);CHKERRQ(ierr);
20244bbf5ea8SMatthew G. Knepley       }
20254bbf5ea8SMatthew G. Knepley     }
20264bbf5ea8SMatthew G. Knepley     ierr = PetscLogEventEnd(PC_Patch_CreatePatches, pc, 0, 0, 0);CHKERRQ(ierr);
20274bbf5ea8SMatthew G. Knepley 
20284bbf5ea8SMatthew G. Knepley     /* If desired, calculate weights for dof multiplicity */
20294bbf5ea8SMatthew G. Knepley     if (patch->partition_of_unity) {
20303bb0e8f7SKarl Rupp       PetscScalar *input = NULL;
20313bb0e8f7SKarl Rupp       PetscScalar *output = NULL;
20323bb0e8f7SKarl Rupp       Vec global;
20333bb0e8f7SKarl Rupp 
20341202d238SPatrick Farrell       ierr = VecDuplicate(patch->localRHS, &patch->dof_weights);CHKERRQ(ierr);
203561c4b389SFlorian Wechsung       if(patch->local_composition_type == PC_COMPOSITE_ADDITIVE) {
20364bbf5ea8SMatthew G. Knepley         for (i = 0; i < patch->npatch; ++i) {
20374bbf5ea8SMatthew G. Knepley           PetscInt dof;
20384bbf5ea8SMatthew G. Knepley 
20394bbf5ea8SMatthew G. Knepley           ierr = PetscSectionGetDof(patch->gtolCounts, i+pStart, &dof);CHKERRQ(ierr);
20404bbf5ea8SMatthew G. Knepley           if (dof <= 0) continue;
20411202d238SPatrick Farrell           ierr = VecSet(patch->patchRHS[i], 1.0);CHKERRQ(ierr);
20420904074fSPatrick Farrell           ierr = PCPatch_ScatterLocal_Private(pc, i+pStart, patch->patchRHS[i], patch->dof_weights, ADD_VALUES, SCATTER_REVERSE, SCATTER_INTERIOR);CHKERRQ(ierr);
20434bbf5ea8SMatthew G. Knepley         }
2044c2e6f3c0SFlorian Wechsung       } else {
2045e047a90bSFlorian Wechsung         /* multiplicative is actually only locally multiplicative and globally additive. need the pou where the mesh decomposition overlaps */
2046c2e6f3c0SFlorian Wechsung         ierr = VecSet(patch->dof_weights, 1.0);CHKERRQ(ierr);
20474bbf5ea8SMatthew G. Knepley       }
2048d132cafaSFlorian Wechsung 
2049d132cafaSFlorian Wechsung       VecDuplicate(patch->dof_weights, &global);
2050d132cafaSFlorian Wechsung       VecSet(global, 0.);
2051d132cafaSFlorian Wechsung 
2052d132cafaSFlorian Wechsung       ierr = VecGetArray(patch->dof_weights, &input);CHKERRQ(ierr);
2053d132cafaSFlorian Wechsung       ierr = VecGetArray(global, &output);CHKERRQ(ierr);
2054d132cafaSFlorian Wechsung       ierr = PetscSFReduceBegin(patch->defaultSF, MPIU_SCALAR, input, output, MPI_SUM);CHKERRQ(ierr);
2055d132cafaSFlorian Wechsung       ierr = PetscSFReduceEnd(patch->defaultSF, MPIU_SCALAR, input, output, MPI_SUM);CHKERRQ(ierr);
2056d132cafaSFlorian Wechsung       ierr = VecRestoreArray(patch->dof_weights, &input);CHKERRQ(ierr);
2057d132cafaSFlorian Wechsung       ierr = VecRestoreArray(global, &output);CHKERRQ(ierr);
2058d132cafaSFlorian Wechsung 
205905528938SFlorian Wechsung       ierr = VecReciprocal(global);CHKERRQ(ierr);
2060d132cafaSFlorian Wechsung 
2061d132cafaSFlorian Wechsung       ierr = VecGetArray(patch->dof_weights, &output);CHKERRQ(ierr);
2062d132cafaSFlorian Wechsung       ierr = VecGetArray(global, &input);CHKERRQ(ierr);
2063d132cafaSFlorian Wechsung       ierr = PetscSFBcastBegin(patch->defaultSF, MPIU_SCALAR, input, output);CHKERRQ(ierr);
2064d132cafaSFlorian Wechsung       ierr = PetscSFBcastEnd(patch->defaultSF, MPIU_SCALAR, input, output);CHKERRQ(ierr);
2065d132cafaSFlorian Wechsung       ierr = VecRestoreArray(patch->dof_weights, &output);CHKERRQ(ierr);
2066d132cafaSFlorian Wechsung       ierr = VecRestoreArray(global, &input);CHKERRQ(ierr);
2067d132cafaSFlorian Wechsung       ierr = VecDestroy(&global);CHKERRQ(ierr);
20684bbf5ea8SMatthew G. Knepley     }
206961c4b389SFlorian Wechsung     if(patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE && patch->save_operators) {
207096b79ebeSFlorian Wechsung       ierr = PetscMalloc1(patch->npatch, &patch->matWithArtificial);CHKERRQ(ierr);
20714bbf5ea8SMatthew G. Knepley     }
20724bbf5ea8SMatthew G. Knepley   }
2073dadc69c5SMatthew G. Knepley   ierr = (*patch->setupsolver)(pc);CHKERRQ(ierr);
2074dadc69c5SMatthew G. Knepley   PetscFunctionReturn(0);
20754bbf5ea8SMatthew G. Knepley }
2076dadc69c5SMatthew G. Knepley 
2077dadc69c5SMatthew G. Knepley static PetscErrorCode PCApply_PATCH_Linear(PC pc, PetscInt i, Vec x, Vec y)
2078dadc69c5SMatthew G. Knepley {
2079dadc69c5SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
2080dadc69c5SMatthew G. Knepley   KSP            ksp   = (KSP) patch->solver[i];
2081dadc69c5SMatthew G. Knepley   PetscErrorCode ierr;
2082dadc69c5SMatthew G. Knepley 
2083dadc69c5SMatthew G. Knepley   PetscFunctionBegin;
2084dadc69c5SMatthew G. Knepley   if (!patch->save_operators) {
2085dadc69c5SMatthew G. Knepley     Mat mat;
2086dadc69c5SMatthew G. Knepley 
208734d8b122SPatrick Farrell     ierr = PCPatchCreateMatrix_Private(pc, i, &mat, PETSC_FALSE);CHKERRQ(ierr);
2088dadc69c5SMatthew G. Knepley     /* Populate operator here. */
208934d8b122SPatrick Farrell     ierr = PCPatchComputeOperator_Internal(pc, NULL, mat, i, PETSC_FALSE);CHKERRQ(ierr);
2090dadc69c5SMatthew G. Knepley     ierr = KSPSetOperators(ksp, mat, mat);CHKERRQ(ierr);
2091dadc69c5SMatthew G. Knepley     /* Drop reference so the KSPSetOperators below will blow it away. */
2092dadc69c5SMatthew G. Knepley     ierr = MatDestroy(&mat);CHKERRQ(ierr);
2093dadc69c5SMatthew G. Knepley   }
2094dadc69c5SMatthew G. Knepley   ierr = PetscLogEventBegin(PC_Patch_Solve, pc, 0, 0, 0);CHKERRQ(ierr);
2095dadc69c5SMatthew G. Knepley   if (!ksp->setfromoptionscalled) {
2096dadc69c5SMatthew G. Knepley     ierr = KSPSetFromOptions(ksp);CHKERRQ(ierr);
2097dadc69c5SMatthew G. Knepley   }
2098dadc69c5SMatthew G. Knepley   ierr = KSPSolve(ksp, x, y);CHKERRQ(ierr);
2099dadc69c5SMatthew G. Knepley   ierr = PetscLogEventEnd(PC_Patch_Solve, pc, 0, 0, 0);CHKERRQ(ierr);
2100dadc69c5SMatthew G. Knepley   if (!patch->save_operators) {
2101dadc69c5SMatthew G. Knepley     PC pc;
2102dadc69c5SMatthew G. Knepley     ierr = KSPSetOperators(ksp, NULL, NULL);CHKERRQ(ierr);
2103dadc69c5SMatthew G. Knepley     ierr = KSPGetPC(ksp, &pc);CHKERRQ(ierr);
2104dadc69c5SMatthew G. Knepley     /* Destroy PC context too, otherwise the factored matrix hangs around. */
2105dadc69c5SMatthew G. Knepley     ierr = PCReset(pc);CHKERRQ(ierr);
21064bbf5ea8SMatthew G. Knepley   }
21074bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
21084bbf5ea8SMatthew G. Knepley }
21094bbf5ea8SMatthew G. Knepley 
21106c9c532dSPatrick Farrell static PetscErrorCode PCUpdateMultiplicative_PATCH_Linear(PC pc, PetscInt i, PetscInt pStart)
21116c9c532dSPatrick Farrell {
21126c9c532dSPatrick Farrell   PC_PATCH      *patch = (PC_PATCH *) pc->data;
21136c9c532dSPatrick Farrell   Mat multMat;
21146c9c532dSPatrick Farrell   PetscErrorCode ierr;
21156c9c532dSPatrick Farrell 
21164d04e9f1SPatrick Farrell   PetscFunctionBegin;
21174d04e9f1SPatrick Farrell 
21186c9c532dSPatrick Farrell   if (patch->save_operators) {
21196c9c532dSPatrick Farrell     multMat = patch->matWithArtificial[i];
21206c9c532dSPatrick Farrell   } else {
21216c9c532dSPatrick Farrell     /*Very inefficient, hopefully we can just assemble the rectangular matrix in the first place.*/
21226c9c532dSPatrick Farrell     Mat matSquare;
21236c9c532dSPatrick Farrell     PetscInt dof;
21246c9c532dSPatrick Farrell     IS rowis;
21256c9c532dSPatrick Farrell     ierr = PCPatchCreateMatrix_Private(pc, i, &matSquare, PETSC_TRUE);CHKERRQ(ierr);
21266c9c532dSPatrick Farrell     ierr = MatZeroEntries(matSquare);CHKERRQ(ierr);
21276c9c532dSPatrick Farrell     ierr = PCPatchComputeOperator_Internal(pc, NULL, matSquare, i, PETSC_TRUE);CHKERRQ(ierr);
21286c9c532dSPatrick Farrell     ierr = MatGetSize(matSquare, &dof, NULL);CHKERRQ(ierr);
21296c9c532dSPatrick Farrell     ierr = ISCreateStride(PETSC_COMM_SELF, dof, 0, 1, &rowis); CHKERRQ(ierr);
21306c9c532dSPatrick Farrell     ierr = MatCreateSubMatrix(matSquare, rowis, patch->dofMappingWithoutToWithArtificial[i], MAT_INITIAL_MATRIX, &multMat); CHKERRQ(ierr);
21316c9c532dSPatrick Farrell     ierr = MatDestroy(&matSquare);CHKERRQ(ierr);
21326c9c532dSPatrick Farrell     ierr = ISDestroy(&rowis); CHKERRQ(ierr);
21336c9c532dSPatrick Farrell   }
21346c9c532dSPatrick Farrell   ierr = MatMult(multMat, patch->patchUpdate[i], patch->patchRHSWithArtificial[i]); CHKERRQ(ierr);
21356c9c532dSPatrick Farrell   ierr = VecScale(patch->patchRHSWithArtificial[i], -1.0); CHKERRQ(ierr);
21360904074fSPatrick Farrell   ierr = PCPatch_ScatterLocal_Private(pc, i + pStart, patch->patchRHSWithArtificial[i], patch->localRHS, ADD_VALUES, SCATTER_REVERSE, SCATTER_WITHARTIFICIAL); CHKERRQ(ierr);
21376c9c532dSPatrick Farrell   if (!patch->save_operators) {
21386c9c532dSPatrick Farrell     ierr = MatDestroy(&multMat); CHKERRQ(ierr);
21396c9c532dSPatrick Farrell   }
21404d04e9f1SPatrick Farrell   PetscFunctionReturn(0);
21416c9c532dSPatrick Farrell }
21426c9c532dSPatrick Farrell 
21434bbf5ea8SMatthew G. Knepley static PetscErrorCode PCApply_PATCH(PC pc, Vec x, Vec y)
21444bbf5ea8SMatthew G. Knepley {
21454bbf5ea8SMatthew G. Knepley   PC_PATCH          *patch    = (PC_PATCH *) pc->data;
21461202d238SPatrick Farrell   const PetscScalar *globalRHS  = NULL;
21471202d238SPatrick Farrell   PetscScalar       *localRHS   = NULL;
21481202d238SPatrick Farrell   PetscScalar       *globalUpdate  = NULL;
21494bbf5ea8SMatthew G. Knepley   const PetscInt    *bcNodes  = NULL;
21504bbf5ea8SMatthew G. Knepley   PetscInt           nsweep   = patch->symmetrise_sweep ? 2 : 1;
21514bbf5ea8SMatthew G. Knepley   PetscInt           start[2] = {0, 0};
21524bbf5ea8SMatthew G. Knepley   PetscInt           end[2]   = {-1, -1};
21534bbf5ea8SMatthew G. Knepley   const PetscInt     inc[2]   = {1, -1};
21541202d238SPatrick Farrell   const PetscScalar *localUpdate;
21554bbf5ea8SMatthew G. Knepley   const PetscInt    *iterationSet;
21564bbf5ea8SMatthew G. Knepley   PetscInt           pStart, numBcs, n, sweep, bc, j;
21574bbf5ea8SMatthew G. Knepley   PetscErrorCode     ierr;
21584bbf5ea8SMatthew G. Knepley 
21594bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
21604bbf5ea8SMatthew G. Knepley   ierr = PetscLogEventBegin(PC_Patch_Apply, pc, 0, 0, 0);CHKERRQ(ierr);
21614bbf5ea8SMatthew G. Knepley   ierr = PetscOptionsPushGetViewerOff(PETSC_TRUE);CHKERRQ(ierr);
216292d50984SMatthew G. Knepley   /* start, end, inc have 2 entries to manage a second backward sweep if we symmetrize */
21634bbf5ea8SMatthew G. Knepley   end[0]   = patch->npatch;
21644bbf5ea8SMatthew G. Knepley   start[1] = patch->npatch-1;
21654bbf5ea8SMatthew G. Knepley   if (patch->user_patches) {
21664bbf5ea8SMatthew G. Knepley     ierr = ISGetLocalSize(patch->iterationSet, &end[0]);CHKERRQ(ierr);
21674bbf5ea8SMatthew G. Knepley     start[1] = end[0] - 1;
21684bbf5ea8SMatthew G. Knepley     ierr = ISGetIndices(patch->iterationSet, &iterationSet);CHKERRQ(ierr);
21694bbf5ea8SMatthew G. Knepley   }
21704bbf5ea8SMatthew G. Knepley   /* Scatter from global space into overlapped local spaces */
21711202d238SPatrick Farrell   ierr = VecGetArrayRead(x, &globalRHS);CHKERRQ(ierr);
21721202d238SPatrick Farrell   ierr = VecGetArray(patch->localRHS, &localRHS);CHKERRQ(ierr);
21731202d238SPatrick Farrell   ierr = PetscSFBcastBegin(patch->defaultSF, MPIU_SCALAR, globalRHS, localRHS);CHKERRQ(ierr);
21741202d238SPatrick Farrell   ierr = PetscSFBcastEnd(patch->defaultSF, MPIU_SCALAR, globalRHS, localRHS);CHKERRQ(ierr);
21751202d238SPatrick Farrell   ierr = VecRestoreArrayRead(x, &globalRHS);CHKERRQ(ierr);
21761202d238SPatrick Farrell   ierr = VecRestoreArray(patch->localRHS, &localRHS);CHKERRQ(ierr);
21774bbf5ea8SMatthew G. Knepley 
21781202d238SPatrick Farrell   ierr = VecSet(patch->localUpdate, 0.0);CHKERRQ(ierr);
21794bbf5ea8SMatthew G. Knepley   ierr = PetscSectionGetChart(patch->gtolCounts, &pStart, NULL);CHKERRQ(ierr);
21804bbf5ea8SMatthew G. Knepley   for (sweep = 0; sweep < nsweep; sweep++) {
21814bbf5ea8SMatthew G. Knepley     for (j = start[sweep]; j*inc[sweep] < end[sweep]*inc[sweep]; j += inc[sweep]) {
21824bbf5ea8SMatthew G. Knepley       PetscInt i       = patch->user_patches ? iterationSet[j] : j;
21834bbf5ea8SMatthew G. Knepley       PetscInt start, len;
21844bbf5ea8SMatthew G. Knepley 
21854bbf5ea8SMatthew G. Knepley       ierr = PetscSectionGetDof(patch->gtolCounts, i+pStart, &len);CHKERRQ(ierr);
21864bbf5ea8SMatthew G. Knepley       ierr = PetscSectionGetOffset(patch->gtolCounts, i+pStart, &start);CHKERRQ(ierr);
21874bbf5ea8SMatthew G. Knepley       /* TODO: Squash out these guys in the setup as well. */
21884bbf5ea8SMatthew G. Knepley       if (len <= 0) continue;
21894bbf5ea8SMatthew G. Knepley       /* TODO: Do we need different scatters for X and Y? */
21900904074fSPatrick Farrell       ierr = PCPatch_ScatterLocal_Private(pc, i+pStart, patch->localRHS, patch->patchRHS[i], INSERT_VALUES, SCATTER_FORWARD, SCATTER_INTERIOR);CHKERRQ(ierr);
21911202d238SPatrick Farrell       ierr = (*patch->applysolver)(pc, i, patch->patchRHS[i], patch->patchUpdate[i]);CHKERRQ(ierr);
21920904074fSPatrick Farrell       ierr = PCPatch_ScatterLocal_Private(pc, i+pStart, patch->patchUpdate[i], patch->localUpdate, ADD_VALUES, SCATTER_REVERSE, SCATTER_INTERIOR);CHKERRQ(ierr);
219361c4b389SFlorian Wechsung       if(patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
21946c9c532dSPatrick Farrell         ierr = (*patch->updatemultiplicative)(pc, i, pStart);CHKERRQ(ierr);
2195c2e6f3c0SFlorian Wechsung       }
21964bbf5ea8SMatthew G. Knepley     }
21974bbf5ea8SMatthew G. Knepley   }
21984bbf5ea8SMatthew G. Knepley   if (patch->user_patches) {ierr = ISRestoreIndices(patch->iterationSet, &iterationSet);CHKERRQ(ierr);}
21994bbf5ea8SMatthew G. Knepley   /* XXX: should we do this on the global vector? */
220073ec7555SLawrence Mitchell   if (patch->partition_of_unity) {
22011202d238SPatrick Farrell     ierr = VecPointwiseMult(patch->localUpdate, patch->localUpdate, patch->dof_weights);CHKERRQ(ierr);
22024bbf5ea8SMatthew G. Knepley   }
22031202d238SPatrick Farrell   /* Now patch->localUpdate contains the solution of the patch solves, so we need to combine them all. */
22044bbf5ea8SMatthew G. Knepley   ierr = VecSet(y, 0.0);CHKERRQ(ierr);
22051202d238SPatrick Farrell   ierr = VecGetArray(y, &globalUpdate);CHKERRQ(ierr);
22061202d238SPatrick Farrell   ierr = VecGetArrayRead(patch->localUpdate, &localUpdate);CHKERRQ(ierr);
22071202d238SPatrick Farrell   ierr = PetscSFReduceBegin(patch->defaultSF, MPIU_SCALAR, localUpdate, globalUpdate, MPI_SUM);CHKERRQ(ierr);
22081202d238SPatrick Farrell   ierr = PetscSFReduceEnd(patch->defaultSF, MPIU_SCALAR, localUpdate, globalUpdate, MPI_SUM);CHKERRQ(ierr);
22091202d238SPatrick Farrell   ierr = VecRestoreArrayRead(patch->localUpdate, &localUpdate);CHKERRQ(ierr);
22104bbf5ea8SMatthew G. Knepley 
22114bbf5ea8SMatthew G. Knepley   /* Now we need to send the global BC values through */
22121202d238SPatrick Farrell   ierr = VecGetArrayRead(x, &globalRHS);CHKERRQ(ierr);
22134bbf5ea8SMatthew G. Knepley   ierr = ISGetSize(patch->globalBcNodes, &numBcs);CHKERRQ(ierr);
22144bbf5ea8SMatthew G. Knepley   ierr = ISGetIndices(patch->globalBcNodes, &bcNodes);CHKERRQ(ierr);
22154bbf5ea8SMatthew G. Knepley   ierr = VecGetLocalSize(x, &n);CHKERRQ(ierr);
22164bbf5ea8SMatthew G. Knepley   for (bc = 0; bc < numBcs; ++bc) {
22174bbf5ea8SMatthew G. Knepley     const PetscInt idx = bcNodes[bc];
22181202d238SPatrick Farrell     if (idx < n) globalUpdate[idx] = globalRHS[idx];
22194bbf5ea8SMatthew G. Knepley   }
22204bbf5ea8SMatthew G. Knepley 
22214bbf5ea8SMatthew G. Knepley   ierr = ISRestoreIndices(patch->globalBcNodes, &bcNodes);CHKERRQ(ierr);
22221202d238SPatrick Farrell   ierr = VecRestoreArrayRead(x, &globalRHS);CHKERRQ(ierr);
22231202d238SPatrick Farrell   ierr = VecRestoreArray(y, &globalUpdate);CHKERRQ(ierr);
22244bbf5ea8SMatthew G. Knepley 
22254bbf5ea8SMatthew G. Knepley   ierr = PetscOptionsPopGetViewerOff();CHKERRQ(ierr);
22264bbf5ea8SMatthew G. Knepley   ierr = PetscLogEventEnd(PC_Patch_Apply, pc, 0, 0, 0);CHKERRQ(ierr);
22274bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
22284bbf5ea8SMatthew G. Knepley }
22294bbf5ea8SMatthew G. Knepley 
2230dadc69c5SMatthew G. Knepley static PetscErrorCode PCReset_PATCH_Linear(PC pc)
2231dadc69c5SMatthew G. Knepley {
2232dadc69c5SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
2233dadc69c5SMatthew G. Knepley   PetscInt       i;
2234dadc69c5SMatthew G. Knepley   PetscErrorCode ierr;
2235dadc69c5SMatthew G. Knepley 
2236dadc69c5SMatthew G. Knepley   PetscFunctionBegin;
2237dadc69c5SMatthew G. Knepley   if (patch->solver) {
2238dadc69c5SMatthew G. Knepley     for (i = 0; i < patch->npatch; ++i) {ierr = KSPReset((KSP) patch->solver[i]);CHKERRQ(ierr);}
2239dadc69c5SMatthew G. Knepley   }
2240dadc69c5SMatthew G. Knepley   PetscFunctionReturn(0);
2241dadc69c5SMatthew G. Knepley }
2242dadc69c5SMatthew G. Knepley 
22434bbf5ea8SMatthew G. Knepley static PetscErrorCode PCReset_PATCH(PC pc)
22444bbf5ea8SMatthew G. Knepley {
22454bbf5ea8SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
22464bbf5ea8SMatthew G. Knepley   PetscInt       i;
22474bbf5ea8SMatthew G. Knepley   PetscErrorCode ierr;
22484bbf5ea8SMatthew G. Knepley 
22494bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
22504bbf5ea8SMatthew G. Knepley   /* TODO: Get rid of all these ifs */
22514bbf5ea8SMatthew G. Knepley   ierr = PetscSFDestroy(&patch->defaultSF);CHKERRQ(ierr);
22524bbf5ea8SMatthew G. Knepley   ierr = PetscSectionDestroy(&patch->cellCounts);CHKERRQ(ierr);
22535f824522SMatthew G. Knepley   ierr = PetscSectionDestroy(&patch->pointCounts);CHKERRQ(ierr);
22544bbf5ea8SMatthew G. Knepley   ierr = PetscSectionDestroy(&patch->cellNumbering);CHKERRQ(ierr);
22554bbf5ea8SMatthew G. Knepley   ierr = PetscSectionDestroy(&patch->gtolCounts);CHKERRQ(ierr);
22564bbf5ea8SMatthew G. Knepley   ierr = ISDestroy(&patch->gtol);CHKERRQ(ierr);
22574bbf5ea8SMatthew G. Knepley   ierr = ISDestroy(&patch->cells);CHKERRQ(ierr);
22585f824522SMatthew G. Knepley   ierr = ISDestroy(&patch->points);CHKERRQ(ierr);
22594bbf5ea8SMatthew G. Knepley   ierr = ISDestroy(&patch->dofs);CHKERRQ(ierr);
22605f824522SMatthew G. Knepley   ierr = ISDestroy(&patch->offs);CHKERRQ(ierr);
22615f824522SMatthew G. Knepley   ierr = PetscSectionDestroy(&patch->patchSection);CHKERRQ(ierr);
22624bbf5ea8SMatthew G. Knepley   ierr = ISDestroy(&patch->ghostBcNodes);CHKERRQ(ierr);
22634bbf5ea8SMatthew G. Knepley   ierr = ISDestroy(&patch->globalBcNodes);CHKERRQ(ierr);
226411ac8bb0SFlorian Wechsung   ierr = PetscSectionDestroy(&patch->gtolCountsWithArtificial);CHKERRQ(ierr);
226511ac8bb0SFlorian Wechsung   ierr = ISDestroy(&patch->gtolWithArtificial);CHKERRQ(ierr);
226611ac8bb0SFlorian Wechsung   ierr = ISDestroy(&patch->dofsWithArtificial);CHKERRQ(ierr);
226711ac8bb0SFlorian Wechsung   ierr = ISDestroy(&patch->offsWithArtificial);CHKERRQ(ierr);
22680904074fSPatrick Farrell   ierr = PetscSectionDestroy(&patch->gtolCountsWithAll);CHKERRQ(ierr);
22690904074fSPatrick Farrell   ierr = ISDestroy(&patch->gtolWithAll);CHKERRQ(ierr);
22700904074fSPatrick Farrell   ierr = ISDestroy(&patch->dofsWithAll);CHKERRQ(ierr);
22710904074fSPatrick Farrell   ierr = ISDestroy(&patch->offsWithAll);CHKERRQ(ierr);
227211ac8bb0SFlorian Wechsung 
22734bbf5ea8SMatthew G. Knepley 
22745f824522SMatthew G. Knepley   if (patch->dofSection) for (i = 0; i < patch->nsubspaces; i++) {ierr = PetscSectionDestroy(&patch->dofSection[i]);CHKERRQ(ierr);}
22754bbf5ea8SMatthew G. Knepley   ierr = PetscFree(patch->dofSection);CHKERRQ(ierr);
22764bbf5ea8SMatthew G. Knepley   ierr = PetscFree(patch->bs);CHKERRQ(ierr);
22774bbf5ea8SMatthew G. Knepley   ierr = PetscFree(patch->nodesPerCell);CHKERRQ(ierr);
22785f824522SMatthew G. Knepley   if (patch->cellNodeMap) for (i = 0; i < patch->nsubspaces; i++) {ierr = PetscFree(patch->cellNodeMap[i]);CHKERRQ(ierr);}
22794bbf5ea8SMatthew G. Knepley   ierr = PetscFree(patch->cellNodeMap);CHKERRQ(ierr);
22804bbf5ea8SMatthew G. Knepley   ierr = PetscFree(patch->subspaceOffsets);CHKERRQ(ierr);
22814bbf5ea8SMatthew G. Knepley 
2282dadc69c5SMatthew G. Knepley   ierr = (*patch->resetsolver)(pc);CHKERRQ(ierr);
22834bbf5ea8SMatthew G. Knepley 
2284e4c66b91SPatrick Farrell   if (patch->subspaces_to_exclude) {
2285e4c66b91SPatrick Farrell     PetscHSetIDestroy(&patch->subspaces_to_exclude);
2286e4c66b91SPatrick Farrell   }
2287e4c66b91SPatrick Farrell 
22881202d238SPatrick Farrell   ierr = VecDestroy(&patch->localRHS);CHKERRQ(ierr);
22891202d238SPatrick Farrell   ierr = VecDestroy(&patch->localUpdate);CHKERRQ(ierr);
22901202d238SPatrick Farrell   if (patch->patchRHS) {
22911202d238SPatrick Farrell     for (i = 0; i < patch->npatch; ++i) {ierr = VecDestroy(&patch->patchRHS[i]);CHKERRQ(ierr);}
22921202d238SPatrick Farrell     ierr = PetscFree(patch->patchRHS);CHKERRQ(ierr);
22934bbf5ea8SMatthew G. Knepley   }
22941202d238SPatrick Farrell   if (patch->patchUpdate) {
22951202d238SPatrick Farrell     for (i = 0; i < patch->npatch; ++i) {ierr = VecDestroy(&patch->patchUpdate[i]);CHKERRQ(ierr);}
22961202d238SPatrick Farrell     ierr = PetscFree(patch->patchUpdate);CHKERRQ(ierr);
22974bbf5ea8SMatthew G. Knepley   }
22984bbf5ea8SMatthew G. Knepley   ierr = VecDestroy(&patch->dof_weights);CHKERRQ(ierr);
22994bbf5ea8SMatthew G. Knepley   if (patch->patch_dof_weights) {
23005f824522SMatthew G. Knepley     for (i = 0; i < patch->npatch; ++i) {ierr = VecDestroy(&patch->patch_dof_weights[i]);CHKERRQ(ierr);}
23014bbf5ea8SMatthew G. Knepley     ierr = PetscFree(patch->patch_dof_weights);CHKERRQ(ierr);
23024bbf5ea8SMatthew G. Knepley   }
23034bbf5ea8SMatthew G. Knepley   if (patch->mat) {
23045f824522SMatthew G. Knepley     for (i = 0; i < patch->npatch; ++i) {ierr = MatDestroy(&patch->mat[i]);CHKERRQ(ierr);}
23054bbf5ea8SMatthew G. Knepley     ierr = PetscFree(patch->mat);CHKERRQ(ierr);
23065f824522SMatthew G. Knepley   }
230711ac8bb0SFlorian Wechsung   if (patch->matWithArtificial) {
230811ac8bb0SFlorian Wechsung     for (i = 0; i < patch->npatch; ++i) {ierr = MatDestroy(&patch->matWithArtificial[i]);CHKERRQ(ierr);}
230911ac8bb0SFlorian Wechsung     ierr = PetscFree(patch->matWithArtificial);CHKERRQ(ierr);
231011ac8bb0SFlorian Wechsung   }
23111202d238SPatrick Farrell   if (patch->patchRHSWithArtificial) {
23121202d238SPatrick Farrell     for (i = 0; i < patch->npatch; ++i) {ierr = VecDestroy(&patch->patchRHSWithArtificial[i]);CHKERRQ(ierr);}
23131202d238SPatrick Farrell     ierr = PetscFree(patch->patchRHSWithArtificial);CHKERRQ(ierr);
231411ac8bb0SFlorian Wechsung   }
231596b79ebeSFlorian Wechsung   if(patch->dofMappingWithoutToWithArtificial) {
231696b79ebeSFlorian Wechsung     for (i = 0; i < patch->npatch; ++i) {ierr = ISDestroy(&patch->dofMappingWithoutToWithArtificial[i]);CHKERRQ(ierr);}
231796b79ebeSFlorian Wechsung     ierr = PetscFree(patch->dofMappingWithoutToWithArtificial);CHKERRQ(ierr);
231896b79ebeSFlorian Wechsung 
231996b79ebeSFlorian Wechsung   }
23200904074fSPatrick Farrell   if(patch->dofMappingWithoutToWithAll) {
23210904074fSPatrick Farrell     for (i = 0; i < patch->npatch; ++i) {ierr = ISDestroy(&patch->dofMappingWithoutToWithAll[i]);CHKERRQ(ierr);}
23220904074fSPatrick Farrell     ierr = PetscFree(patch->dofMappingWithoutToWithAll);CHKERRQ(ierr);
23230904074fSPatrick Farrell 
23240904074fSPatrick Farrell   }
23254bbf5ea8SMatthew G. Knepley   ierr = PetscFree(patch->sub_mat_type);CHKERRQ(ierr);
23265f824522SMatthew G. Knepley   if (patch->userIS) {
23275f824522SMatthew G. Knepley     for (i = 0; i < patch->npatch; ++i) {ierr = ISDestroy(&patch->userIS[i]);CHKERRQ(ierr);}
23285f824522SMatthew G. Knepley     ierr = PetscFree(patch->userIS);CHKERRQ(ierr);
23295f824522SMatthew G. Knepley   }
23304bbf5ea8SMatthew G. Knepley   patch->bs          = 0;
23314bbf5ea8SMatthew G. Knepley   patch->cellNodeMap = NULL;
23327974b488SMatthew G. Knepley   patch->nsubspaces  = 0;
23334bbf5ea8SMatthew G. Knepley   ierr = ISDestroy(&patch->iterationSet);CHKERRQ(ierr);
23345f824522SMatthew G. Knepley 
23355f824522SMatthew G. Knepley   ierr = PetscViewerDestroy(&patch->viewerSection);CHKERRQ(ierr);
23364bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
23374bbf5ea8SMatthew G. Knepley }
23384bbf5ea8SMatthew G. Knepley 
2339dadc69c5SMatthew G. Knepley static PetscErrorCode PCDestroy_PATCH_Linear(PC pc)
23404bbf5ea8SMatthew G. Knepley {
23414bbf5ea8SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
23424bbf5ea8SMatthew G. Knepley   PetscInt       i;
23434bbf5ea8SMatthew G. Knepley   PetscErrorCode ierr;
23444bbf5ea8SMatthew G. Knepley 
23454bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
2346dadc69c5SMatthew G. Knepley   if (patch->solver) {
2347dadc69c5SMatthew G. Knepley     for (i = 0; i < patch->npatch; ++i) {ierr = KSPDestroy((KSP *) &patch->solver[i]);CHKERRQ(ierr);}
2348dadc69c5SMatthew G. Knepley     ierr = PetscFree(patch->solver);CHKERRQ(ierr);
23494bbf5ea8SMatthew G. Knepley   }
2350dadc69c5SMatthew G. Knepley   PetscFunctionReturn(0);
2351dadc69c5SMatthew G. Knepley }
2352dadc69c5SMatthew G. Knepley 
2353dadc69c5SMatthew G. Knepley static PetscErrorCode PCDestroy_PATCH(PC pc)
2354dadc69c5SMatthew G. Knepley {
2355dadc69c5SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
2356dadc69c5SMatthew G. Knepley   PetscErrorCode ierr;
2357dadc69c5SMatthew G. Knepley 
2358dadc69c5SMatthew G. Knepley   PetscFunctionBegin;
2359dadc69c5SMatthew G. Knepley   ierr = PCReset_PATCH(pc);CHKERRQ(ierr);
2360dadc69c5SMatthew G. Knepley   ierr = (*patch->destroysolver)(pc);CHKERRQ(ierr);
23614bbf5ea8SMatthew G. Knepley   ierr = PetscFree(pc->data);CHKERRQ(ierr);
23624bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
23634bbf5ea8SMatthew G. Knepley }
23644bbf5ea8SMatthew G. Knepley 
23654bbf5ea8SMatthew G. Knepley static PetscErrorCode PCSetFromOptions_PATCH(PetscOptionItems *PetscOptionsObject, PC pc)
23664bbf5ea8SMatthew G. Knepley {
23674bbf5ea8SMatthew G. Knepley   PC_PATCH            *patch = (PC_PATCH *) pc->data;
23684bbf5ea8SMatthew G. Knepley   PCPatchConstructType patchConstructionType = PC_PATCH_STAR;
23695f824522SMatthew G. Knepley   char                 sub_mat_type[PETSC_MAX_PATH_LEN];
237010534d48SPatrick Farrell   char                 option[PETSC_MAX_PATH_LEN];
23715f824522SMatthew G. Knepley   const char          *prefix;
23724bbf5ea8SMatthew G. Knepley   PetscBool            flg, dimflg, codimflg;
23735f824522SMatthew G. Knepley   MPI_Comm             comm;
2374a48c39c8SPatrick Farrell   PetscInt            *ifields, nfields, k;
23754bbf5ea8SMatthew G. Knepley   PetscErrorCode       ierr;
237661c4b389SFlorian Wechsung   PCCompositeType loctype = PC_COMPOSITE_ADDITIVE;
23774bbf5ea8SMatthew G. Knepley 
23784bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
23795f824522SMatthew G. Knepley   ierr = PetscObjectGetComm((PetscObject) pc, &comm);CHKERRQ(ierr);
23805f824522SMatthew G. Knepley   ierr = PetscObjectGetOptionsPrefix((PetscObject) pc, &prefix);CHKERRQ(ierr);
238110534d48SPatrick Farrell   ierr = PetscOptionsHead(PetscOptionsObject, "Patch solver options");CHKERRQ(ierr);
238210534d48SPatrick Farrell 
238310534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_save_operators", patch->classname);
238410534d48SPatrick Farrell   ierr = PetscOptionsBool(option,  "Store all patch operators for lifetime of object?", "PCPatchSetSaveOperators", patch->save_operators, &patch->save_operators, &flg);CHKERRQ(ierr);
238510534d48SPatrick Farrell 
238610534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_partition_of_unity", patch->classname);
238710534d48SPatrick Farrell   ierr = PetscOptionsBool(option, "Weight contributions by dof multiplicity?", "PCPatchSetPartitionOfUnity", patch->partition_of_unity, &patch->partition_of_unity, &flg);CHKERRQ(ierr);
238810534d48SPatrick Farrell 
238910534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_local_type", patch->classname);
239010534d48SPatrick Farrell   ierr = PetscOptionsEnum(option,"Type of local solver composition (additive or multiplicative)","PCPatchSetLocalComposition",PCCompositeTypes,(PetscEnum)loctype,(PetscEnum*)&loctype,&flg);CHKERRQ(ierr);
239161c4b389SFlorian Wechsung   if(flg) { ierr = PCPatchSetLocalComposition(pc, loctype);CHKERRQ(ierr);}
239210534d48SPatrick Farrell 
239310534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_construct_dim", patch->classname);
239410534d48SPatrick Farrell   ierr = PetscOptionsInt(option, "What dimension of mesh point to construct patches by? (0 = vertices)", "PCPATCH", patch->dim, &patch->dim, &dimflg);CHKERRQ(ierr);
239510534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_construct_codim", patch->classname);
239610534d48SPatrick Farrell   ierr = PetscOptionsInt(option, "What co-dimension of mesh point to construct patches by? (0 = cells)", "PCPATCH", patch->codim, &patch->codim, &codimflg);CHKERRQ(ierr);
239761c4b389SFlorian Wechsung   if (dimflg && codimflg) {SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Can only set one of dimension or co-dimension");CHKERRQ(ierr);}
239810534d48SPatrick Farrell 
239910534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_construct_type", patch->classname);
240010534d48SPatrick Farrell   ierr = PetscOptionsEnum(option, "How should the patches be constructed?", "PCPatchSetConstructType", PCPatchConstructTypes, (PetscEnum) patchConstructionType, (PetscEnum *) &patchConstructionType, &flg);CHKERRQ(ierr);
24014bbf5ea8SMatthew G. Knepley   if (flg) {ierr = PCPatchSetConstructType(pc, patchConstructionType, NULL, NULL);CHKERRQ(ierr);}
240210534d48SPatrick Farrell 
240310534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_vanka_dim", patch->classname);
240410534d48SPatrick Farrell   ierr = PetscOptionsInt(option, "Topological dimension of entities for Vanka to ignore", "PCPATCH", patch->vankadim, &patch->vankadim, &flg);CHKERRQ(ierr);
240510534d48SPatrick Farrell 
240610534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_ignore_dim", patch->classname);
240710534d48SPatrick Farrell   ierr = PetscOptionsInt(option, "Topological dimension of entities for completion to ignore", "PCPATCH", patch->ignoredim, &patch->ignoredim, &flg);CHKERRQ(ierr);
240810534d48SPatrick Farrell 
240910534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_sub_mat_type", patch->classname);
241010534d48SPatrick Farrell   ierr = PetscOptionsFList(option, "Matrix type for patch solves", "PCPatchSetSubMatType", MatList, NULL, sub_mat_type, PETSC_MAX_PATH_LEN, &flg);CHKERRQ(ierr);
24114bbf5ea8SMatthew G. Knepley   if (flg) {ierr = PCPatchSetSubMatType(pc, sub_mat_type);CHKERRQ(ierr);}
241210534d48SPatrick Farrell 
241310534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_symmetrise_sweep", patch->classname);
241410534d48SPatrick Farrell   ierr = PetscOptionsBool(option, "Go start->end, end->start?", "PCPATCH", patch->symmetrise_sweep, &patch->symmetrise_sweep, &flg);CHKERRQ(ierr);
2415e4c66b91SPatrick Farrell 
2416a48c39c8SPatrick Farrell   /* If the user has set the number of subspaces, use that for the buffer size,
2417a48c39c8SPatrick Farrell      otherwise use a large number */
2418a48c39c8SPatrick Farrell   if (patch->nsubspaces <= 0) {
2419a48c39c8SPatrick Farrell     nfields = 128;
2420a48c39c8SPatrick Farrell   } else {
2421a48c39c8SPatrick Farrell     nfields = patch->nsubspaces;
2422a48c39c8SPatrick Farrell   }
2423a48c39c8SPatrick Farrell   ierr = PetscMalloc1(nfields, &ifields);CHKERRQ(ierr);
242410534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_exclude_subspaces", patch->classname);
242510534d48SPatrick Farrell   ierr = PetscOptionsGetIntArray(((PetscObject)pc)->options,((PetscObject)pc)->prefix,option,ifields,&nfields,&flg);CHKERRQ(ierr);
2426e4c66b91SPatrick Farrell   if (flg && (patchConstructionType == PC_PATCH_USER)) SETERRQ(comm, PETSC_ERR_ARG_INCOMP, "We cannot support excluding a subspace with user patches because we do not index patches with a mesh point");
2427e4c66b91SPatrick Farrell   if (flg) {
2428e4c66b91SPatrick Farrell     PetscHSetIClear(patch->subspaces_to_exclude);
242959b66c28SPatrick Farrell     for (k = 0; k < nfields; k++) {
2430e4c66b91SPatrick Farrell       PetscHSetIAdd(patch->subspaces_to_exclude, ifields[k]);
2431e4c66b91SPatrick Farrell     }
2432e4c66b91SPatrick Farrell   }
243359b66c28SPatrick Farrell   ierr = PetscFree(ifields);CHKERRQ(ierr);
24345f824522SMatthew G. Knepley 
243510534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_patches_view", patch->classname);
243610534d48SPatrick Farrell   ierr = PetscOptionsBool(option, "Print out information during patch construction", "PCPATCH", patch->viewPatches, &patch->viewPatches, &flg);CHKERRQ(ierr);
243710534d48SPatrick Farrell 
243810534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_cells_view", patch->classname);
243910534d48SPatrick Farrell   ierr = PetscOptionsGetViewer(comm,((PetscObject) pc)->options,prefix, option,   &patch->viewerCells,   &patch->formatCells,   &patch->viewCells);CHKERRQ(ierr);
244010534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_points_view", patch->classname);
244110534d48SPatrick Farrell   ierr = PetscOptionsGetViewer(comm,((PetscObject) pc)->options,prefix, option,  &patch->viewerPoints,  &patch->formatPoints,  &patch->viewPoints);CHKERRQ(ierr);
244210534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_section_view", patch->classname);
244310534d48SPatrick Farrell   ierr = PetscOptionsGetViewer(comm,((PetscObject) pc)->options,prefix, option, &patch->viewerSection, &patch->formatSection, &patch->viewSection);CHKERRQ(ierr);
244410534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_mat_view", patch->classname);
244510534d48SPatrick Farrell   ierr = PetscOptionsGetViewer(comm,((PetscObject) pc)->options,prefix, option,     &patch->viewerMatrix,  &patch->formatMatrix,  &patch->viewMatrix);CHKERRQ(ierr);
24464bbf5ea8SMatthew G. Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
24475f824522SMatthew G. Knepley   patch->optionsSet = PETSC_TRUE;
24484bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
24494bbf5ea8SMatthew G. Knepley }
24504bbf5ea8SMatthew G. Knepley 
24514bbf5ea8SMatthew G. Knepley static PetscErrorCode PCSetUpOnBlocks_PATCH(PC pc)
24524bbf5ea8SMatthew G. Knepley {
24534bbf5ea8SMatthew G. Knepley   PC_PATCH          *patch = (PC_PATCH*) pc->data;
24544bbf5ea8SMatthew G. Knepley   KSPConvergedReason reason;
24554bbf5ea8SMatthew G. Knepley   PetscInt           i;
24564bbf5ea8SMatthew G. Knepley   PetscErrorCode     ierr;
24574bbf5ea8SMatthew G. Knepley 
24584bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
2459a1eac568SLawrence Mitchell   if (!patch->save_operators) {
2460a1eac568SLawrence Mitchell     /* Can't do this here because the sub KSPs don't have an operator attached yet. */
2461a1eac568SLawrence Mitchell     PetscFunctionReturn(0);
2462a1eac568SLawrence Mitchell   }
24634bbf5ea8SMatthew G. Knepley   for (i = 0; i < patch->npatch; ++i) {
2464dadc69c5SMatthew G. Knepley     if (!((KSP) patch->solver[i])->setfromoptionscalled) {
2465dadc69c5SMatthew G. Knepley       ierr = KSPSetFromOptions((KSP) patch->solver[i]);CHKERRQ(ierr);
2466a1eac568SLawrence Mitchell     }
2467dadc69c5SMatthew G. Knepley     ierr = KSPSetUp((KSP) patch->solver[i]);CHKERRQ(ierr);
2468dadc69c5SMatthew G. Knepley     ierr = KSPGetConvergedReason((KSP) patch->solver[i], &reason);CHKERRQ(ierr);
24694bbf5ea8SMatthew G. Knepley     if (reason == KSP_DIVERGED_PCSETUP_FAILED) pc->failedreason = PC_SUBPC_ERROR;
24704bbf5ea8SMatthew G. Knepley   }
24714bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
24724bbf5ea8SMatthew G. Knepley }
24734bbf5ea8SMatthew G. Knepley 
24744bbf5ea8SMatthew G. Knepley static PetscErrorCode PCView_PATCH(PC pc, PetscViewer viewer)
24754bbf5ea8SMatthew G. Knepley {
24764bbf5ea8SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
24774bbf5ea8SMatthew G. Knepley   PetscViewer    sviewer;
24784bbf5ea8SMatthew G. Knepley   PetscBool      isascii;
24794bbf5ea8SMatthew G. Knepley   PetscMPIInt    rank;
24804bbf5ea8SMatthew G. Knepley   PetscErrorCode ierr;
24814bbf5ea8SMatthew G. Knepley 
24824bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
24834bbf5ea8SMatthew G. Knepley   /* TODO Redo tabbing with set tbas in new style */
24844bbf5ea8SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &isascii);CHKERRQ(ierr);
24854bbf5ea8SMatthew G. Knepley   if (!isascii) PetscFunctionReturn(0);
24864bbf5ea8SMatthew G. Knepley   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) pc), &rank);CHKERRQ(ierr);
24874bbf5ea8SMatthew G. Knepley   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
24884bbf5ea8SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "Subspace Correction preconditioner with %d patches\n", patch->npatch);CHKERRQ(ierr);
248961c4b389SFlorian Wechsung   if(patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
2490c2e6f3c0SFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Schwarz type: multiplicative\n");CHKERRQ(ierr);
2491e047a90bSFlorian Wechsung   } else {
249273ec7555SLawrence Mitchell     ierr = PetscViewerASCIIPrintf(viewer, "Schwarz type: additive\n");CHKERRQ(ierr);
2493c2e6f3c0SFlorian Wechsung   }
24944bbf5ea8SMatthew G. Knepley   if (patch->partition_of_unity) {ierr = PetscViewerASCIIPrintf(viewer, "Weighting by partition of unity\n");CHKERRQ(ierr);}
24954bbf5ea8SMatthew G. Knepley   else                           {ierr = PetscViewerASCIIPrintf(viewer, "Not weighting by partition of unity\n");CHKERRQ(ierr);}
24964bbf5ea8SMatthew G. Knepley   if (patch->symmetrise_sweep) {ierr = PetscViewerASCIIPrintf(viewer, "Symmetrising sweep (start->end, then end->start)\n");CHKERRQ(ierr);}
24974bbf5ea8SMatthew G. Knepley   else                         {ierr = PetscViewerASCIIPrintf(viewer, "Not symmetrising sweep\n");CHKERRQ(ierr);}
24984bbf5ea8SMatthew G. Knepley   if (!patch->save_operators) {ierr = PetscViewerASCIIPrintf(viewer, "Not saving patch operators (rebuilt every PCApply)\n");CHKERRQ(ierr);}
24994bbf5ea8SMatthew G. Knepley   else                        {ierr = PetscViewerASCIIPrintf(viewer, "Saving patch operators (rebuilt every PCSetUp)\n");CHKERRQ(ierr);}
25004bbf5ea8SMatthew G. Knepley   if (patch->patchconstructop == PCPatchConstruct_Star)       {ierr = PetscViewerASCIIPrintf(viewer, "Patch construction operator: star\n");CHKERRQ(ierr);}
25014bbf5ea8SMatthew G. Knepley   else if (patch->patchconstructop == PCPatchConstruct_Vanka) {ierr = PetscViewerASCIIPrintf(viewer, "Patch construction operator: Vanka\n");CHKERRQ(ierr);}
25024bbf5ea8SMatthew G. Knepley   else if (patch->patchconstructop == PCPatchConstruct_User)  {ierr = PetscViewerASCIIPrintf(viewer, "Patch construction operator: user-specified\n");CHKERRQ(ierr);}
25034bbf5ea8SMatthew G. Knepley   else                                                        {ierr = PetscViewerASCIIPrintf(viewer, "Patch construction operator: unknown\n");CHKERRQ(ierr);}
2504dadc69c5SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "Solver on patches (all same):\n");CHKERRQ(ierr);
2505dadc69c5SMatthew G. Knepley   if (patch->solver) {
25064bbf5ea8SMatthew G. Knepley     ierr = PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer);CHKERRQ(ierr);
25074bbf5ea8SMatthew G. Knepley     if (!rank) {
25084bbf5ea8SMatthew G. Knepley       ierr = PetscViewerASCIIPushTab(sviewer);CHKERRQ(ierr);
2509dadc69c5SMatthew G. Knepley       ierr = PetscObjectView(patch->solver[0], sviewer);CHKERRQ(ierr);
25104bbf5ea8SMatthew G. Knepley       ierr = PetscViewerASCIIPopTab(sviewer);CHKERRQ(ierr);
25114bbf5ea8SMatthew G. Knepley     }
25124bbf5ea8SMatthew G. Knepley     ierr = PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer);CHKERRQ(ierr);
25134bbf5ea8SMatthew G. Knepley   } else {
25144bbf5ea8SMatthew G. Knepley     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
2515dadc69c5SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(viewer, "Solver not yet set.\n");CHKERRQ(ierr);
25164bbf5ea8SMatthew G. Knepley     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
25174bbf5ea8SMatthew G. Knepley   }
25184bbf5ea8SMatthew G. Knepley   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
25194bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
25204bbf5ea8SMatthew G. Knepley }
25214bbf5ea8SMatthew G. Knepley 
2522e5893cccSMatthew G. Knepley /*MC
252398ed095eSMatthew G. Knepley   PCPATCH - A PC object that encapsulates flexible definition of blocks for overlapping and non-overlapping
252498ed095eSMatthew G. Knepley             small block additive preconditioners. Block definition is based on topology from
2525e5893cccSMatthew G. Knepley             a DM and equation numbering from a PetscSection.
2526e5893cccSMatthew G. Knepley 
2527e5893cccSMatthew G. Knepley   Options Database Keys:
2528e5893cccSMatthew G. Knepley + -pc_patch_cells_view   - Views the process local cell numbers for each patch
2529e5893cccSMatthew G. Knepley . -pc_patch_points_view  - Views the process local mesh point numbers for each patch
2530e5893cccSMatthew G. Knepley . -pc_patch_g2l_view     - Views the map between global dofs and patch local dofs for each patch
2531e5893cccSMatthew G. Knepley . -pc_patch_patches_view - Views the global dofs associated with each patch and its boundary
2532e5893cccSMatthew G. Knepley - -pc_patch_sub_mat_view - Views the matrix associated with each patch
2533e5893cccSMatthew G. Knepley 
2534e5893cccSMatthew G. Knepley   Level: intermediate
2535e5893cccSMatthew G. Knepley 
2536e5893cccSMatthew G. Knepley .seealso: PCType, PCCreate(), PCSetType()
2537e5893cccSMatthew G. Knepley M*/
2538642283e9SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PCCreate_Patch(PC pc)
25394bbf5ea8SMatthew G. Knepley {
25404bbf5ea8SMatthew G. Knepley   PC_PATCH      *patch;
25414bbf5ea8SMatthew G. Knepley   PetscErrorCode ierr;
25424bbf5ea8SMatthew G. Knepley 
25434bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
25444bbf5ea8SMatthew G. Knepley   ierr = PetscNewLog(pc, &patch);CHKERRQ(ierr);
25454bbf5ea8SMatthew G. Knepley 
2546e4c66b91SPatrick Farrell   if (patch->subspaces_to_exclude) {
2547e4c66b91SPatrick Farrell     PetscHSetIDestroy(&patch->subspaces_to_exclude);
2548e4c66b91SPatrick Farrell   }
2549e4c66b91SPatrick Farrell   PetscHSetICreate(&patch->subspaces_to_exclude);
2550e4c66b91SPatrick Farrell 
255110534d48SPatrick Farrell   patch->classname = "pc";
2552debbdec3SPatrick Farrell   patch->isNonlinear = PETSC_FALSE;
255310534d48SPatrick Farrell 
25544bbf5ea8SMatthew G. Knepley   /* Set some defaults */
25555f824522SMatthew G. Knepley   patch->combined           = PETSC_FALSE;
25564bbf5ea8SMatthew G. Knepley   patch->save_operators     = PETSC_TRUE;
255761c4b389SFlorian Wechsung   patch->local_composition_type = PC_COMPOSITE_ADDITIVE;
25584bbf5ea8SMatthew G. Knepley   patch->partition_of_unity = PETSC_FALSE;
25594bbf5ea8SMatthew G. Knepley   patch->codim              = -1;
25604bbf5ea8SMatthew G. Knepley   patch->dim                = -1;
25614bbf5ea8SMatthew G. Knepley   patch->vankadim           = -1;
25625f824522SMatthew G. Knepley   patch->ignoredim          = -1;
25634bbf5ea8SMatthew G. Knepley   patch->patchconstructop   = PCPatchConstruct_Star;
25644bbf5ea8SMatthew G. Knepley   patch->symmetrise_sweep   = PETSC_FALSE;
25655f824522SMatthew G. Knepley   patch->npatch             = 0;
25664bbf5ea8SMatthew G. Knepley   patch->userIS             = NULL;
25675f824522SMatthew G. Knepley   patch->optionsSet         = PETSC_FALSE;
25684bbf5ea8SMatthew G. Knepley   patch->iterationSet       = NULL;
25694bbf5ea8SMatthew G. Knepley   patch->user_patches       = PETSC_FALSE;
25705f824522SMatthew G. Knepley   ierr = PetscStrallocpy(MATDENSE, (char **) &patch->sub_mat_type);CHKERRQ(ierr);
25715f824522SMatthew G. Knepley   patch->viewPatches        = PETSC_FALSE;
25725f824522SMatthew G. Knepley   patch->viewCells          = PETSC_FALSE;
25735f824522SMatthew G. Knepley   patch->viewPoints         = PETSC_FALSE;
25745f824522SMatthew G. Knepley   patch->viewSection        = PETSC_FALSE;
25755f824522SMatthew G. Knepley   patch->viewMatrix         = PETSC_FALSE;
2576dadc69c5SMatthew G. Knepley   patch->setupsolver        = PCSetUp_PATCH_Linear;
2577dadc69c5SMatthew G. Knepley   patch->applysolver        = PCApply_PATCH_Linear;
2578dadc69c5SMatthew G. Knepley   patch->resetsolver        = PCReset_PATCH_Linear;
2579dadc69c5SMatthew G. Knepley   patch->destroysolver      = PCDestroy_PATCH_Linear;
25806c9c532dSPatrick Farrell   patch->updatemultiplicative = PCUpdateMultiplicative_PATCH_Linear;
25814bbf5ea8SMatthew G. Knepley 
25824bbf5ea8SMatthew G. Knepley   pc->data                 = (void *) patch;
25834bbf5ea8SMatthew G. Knepley   pc->ops->apply           = PCApply_PATCH;
25844bbf5ea8SMatthew G. Knepley   pc->ops->applytranspose  = 0; /* PCApplyTranspose_PATCH; */
25854bbf5ea8SMatthew G. Knepley   pc->ops->setup           = PCSetUp_PATCH;
25864bbf5ea8SMatthew G. Knepley   pc->ops->reset           = PCReset_PATCH;
25874bbf5ea8SMatthew G. Knepley   pc->ops->destroy         = PCDestroy_PATCH;
25884bbf5ea8SMatthew G. Knepley   pc->ops->setfromoptions  = PCSetFromOptions_PATCH;
25894bbf5ea8SMatthew G. Knepley   pc->ops->setuponblocks   = PCSetUpOnBlocks_PATCH;
25904bbf5ea8SMatthew G. Knepley   pc->ops->view            = PCView_PATCH;
25914bbf5ea8SMatthew G. Knepley   pc->ops->applyrichardson = 0;
25924bbf5ea8SMatthew G. Knepley 
25934bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
25944bbf5ea8SMatthew G. Knepley }
2595