xref: /petsc/src/ksp/pc/impls/patch/pcpatch.c (revision e5b9877fd3e1272f23659a4ca92cd8e8fe28a052)
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*e5b9877fSPatrick Farrell static PetscErrorCode PCPatchConstruct_Pardecomp(void *vpatch, DM dm, PetscInt point, PetscHSetI ht)
800a390943SPatrick Farrell {
810a390943SPatrick Farrell   DMLabel         ghost = NULL;
820a390943SPatrick Farrell   const PetscInt *leaves;
830a390943SPatrick Farrell   PetscInt        nleaves, pStart, pEnd, loc;
840a390943SPatrick Farrell   PetscBool       isFiredrake;
850a390943SPatrick Farrell   DM              plex;
860a390943SPatrick Farrell   PetscBool       flg;
870a390943SPatrick Farrell   PetscErrorCode ierr;
880a390943SPatrick Farrell 
890a390943SPatrick Farrell   PetscFunctionBegin;
900a390943SPatrick Farrell   PetscHSetIClear(ht);
910a390943SPatrick Farrell 
920a390943SPatrick Farrell   ierr = DMConvert(dm, DMPLEX, &plex);CHKERRQ(ierr);
930a390943SPatrick Farrell   ierr = DMPlexGetChart(plex, &pStart, &pEnd);CHKERRQ(ierr);
940a390943SPatrick Farrell 
950a390943SPatrick Farrell   ierr = DMHasLabel(dm, "pyop2_ghost", &isFiredrake);CHKERRQ(ierr);
960a390943SPatrick Farrell   if (isFiredrake) {
970a390943SPatrick Farrell     ierr = DMGetLabel(dm, "pyop2_ghost", &ghost);CHKERRQ(ierr);
980a390943SPatrick Farrell     ierr = DMLabelCreateIndex(ghost, pStart, pEnd);CHKERRQ(ierr);
990a390943SPatrick Farrell   } else {
1000a390943SPatrick Farrell     PetscSF sf;
1010a390943SPatrick Farrell     ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
1020a390943SPatrick Farrell     ierr = PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL);CHKERRQ(ierr);
1030a390943SPatrick Farrell     nleaves = PetscMax(nleaves, 0);
1040a390943SPatrick Farrell   }
1050a390943SPatrick Farrell 
1060a390943SPatrick Farrell   for (PetscInt point = pStart; point < pEnd; ++point) {
1070a390943SPatrick Farrell     if (ghost) {ierr = DMLabelHasPoint(ghost, point, &flg);CHKERRQ(ierr);}
1080a390943SPatrick Farrell     else       {ierr = PetscFindInt(point, nleaves, leaves, &loc);CHKERRQ(ierr); flg = loc >=0 ? PETSC_TRUE : PETSC_FALSE;}
1090a390943SPatrick Farrell     /* Not an owned entity, don't make a cell patch. */
1100a390943SPatrick Farrell     if (flg) continue;
1110a390943SPatrick Farrell     ierr = PetscHSetIAdd(ht, point);CHKERRQ(ierr);
1120a390943SPatrick Farrell   }
1130a390943SPatrick Farrell 
1140a390943SPatrick Farrell   PetscFunctionReturn(0);
1150a390943SPatrick Farrell }
1160a390943SPatrick 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*e5b9877fSPatrick Farrell   case PC_PATCH_PARDECOMP:
4010a390943SPatrick Farrell     patch->user_patches     = PETSC_FALSE;
402*e5b9877fSPatrick Farrell     patch->patchconstructop = PCPatchConstruct_Pardecomp;
4030a390943SPatrick 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*e5b9877fSPatrick Farrell   case PC_PATCH_PARDECOMP:
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*e5b9877fSPatrick Farrell   } else if (patch->ctype == PC_PATCH_PARDECOMP) {
7890a390943SPatrick 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 = PetscLogEventBegin(PC_Patch_Prealloc, pc, 0, 0, 0);CHKERRQ(ierr);
1510b2866507SPatrick Farrell     /* A PetscBT uses N^2 bits to store the sparsity pattern on a
15114bbf5ea8SMatthew G. Knepley      * patch. This is probably OK if the patches are not too big,
1512b2866507SPatrick Farrell      * but uses too much memory. We therefore switch based on rsize. */
1513b2866507SPatrick Farrell     if (rsize < 3000) { /* FIXME: I picked this switch value out of my hat */
1514b2866507SPatrick Farrell       ierr = PetscCalloc1(rsize, &dnnz);CHKERRQ(ierr);
15154bbf5ea8SMatthew G. Knepley       ierr = PetscBTCreate(rsize*rsize, &bt);CHKERRQ(ierr);
15164bbf5ea8SMatthew G. Knepley       for (c = 0; c < ncell; ++c) {
15174bbf5ea8SMatthew G. Knepley         const PetscInt *idx = dofsArray + (offset + c)*patch->totalDofsPerCell;
15184bbf5ea8SMatthew G. Knepley         for (i = 0; i < patch->totalDofsPerCell; ++i) {
15194bbf5ea8SMatthew G. Knepley           const PetscInt row = idx[i];
1520557beb66SLawrence Mitchell           if (row < 0) continue;
15214bbf5ea8SMatthew G. Knepley           for (j = 0; j < patch->totalDofsPerCell; ++j) {
15224bbf5ea8SMatthew G. Knepley             const PetscInt col = idx[j];
15234bbf5ea8SMatthew G. Knepley             const PetscInt key = row*rsize + col;
1524557beb66SLawrence Mitchell             if (col < 0) continue;
15254bbf5ea8SMatthew G. Knepley             if (!PetscBTLookupSet(bt, key)) ++dnnz[row];
15264bbf5ea8SMatthew G. Knepley           }
15274bbf5ea8SMatthew G. Knepley         }
15284bbf5ea8SMatthew G. Knepley       }
15294bbf5ea8SMatthew G. Knepley       ierr = PetscBTDestroy(&bt);CHKERRQ(ierr);
15304bbf5ea8SMatthew G. Knepley       ierr = MatXAIJSetPreallocation(*mat, 1, dnnz, NULL, NULL, NULL);CHKERRQ(ierr);
15314bbf5ea8SMatthew G. Knepley       ierr = PetscFree(dnnz);CHKERRQ(ierr);
15324bbf5ea8SMatthew G. Knepley       ierr = PCPatchZeroFillMatrix_Private(*mat, ncell, patch->totalDofsPerCell, &dofsArray[offset*patch->totalDofsPerCell]);CHKERRQ(ierr);
1533b2866507SPatrick Farrell     } else { /* rsize too big, use MATPREALLOCATOR */
1534b2866507SPatrick Farrell       Mat preallocator;
1535b2866507SPatrick Farrell       PetscScalar* vals;
1536b2866507SPatrick Farrell 
1537b2866507SPatrick Farrell       ierr = PetscCalloc1(patch->totalDofsPerCell*patch->totalDofsPerCell, &vals);CHKERRQ(ierr);
1538b2866507SPatrick Farrell       ierr = MatCreate(PETSC_COMM_SELF, &preallocator);CHKERRQ(ierr);
1539b2866507SPatrick Farrell       ierr = MatSetType(preallocator, MATPREALLOCATOR);CHKERRQ(ierr);
1540b2866507SPatrick Farrell       ierr = MatSetSizes(preallocator, rsize, rsize, rsize, rsize);CHKERRQ(ierr);
1541b2866507SPatrick Farrell       ierr = MatSetUp(preallocator);CHKERRQ(ierr);
1542b2866507SPatrick Farrell       for (c = 0; c < ncell; ++c) {
1543b2866507SPatrick Farrell         const PetscInt *idx = dofsArray + (offset + c)*patch->totalDofsPerCell;
1544b2866507SPatrick Farrell         ierr = MatSetValues(preallocator, patch->totalDofsPerCell, idx, patch->totalDofsPerCell, idx, vals, INSERT_VALUES);CHKERRQ(ierr);
1545b2866507SPatrick Farrell       }
1546b2866507SPatrick Farrell       ierr = PetscFree(vals);CHKERRQ(ierr);
1547b2866507SPatrick Farrell       ierr = MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1548b2866507SPatrick Farrell       ierr = MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1549b2866507SPatrick Farrell       ierr = MatPreallocatorPreallocate(preallocator, PETSC_TRUE, *mat);CHKERRQ(ierr);
1550b2866507SPatrick Farrell       ierr = MatDestroy(&preallocator);CHKERRQ(ierr);
1551b2866507SPatrick Farrell     }
15524bbf5ea8SMatthew G. Knepley     ierr = PetscLogEventEnd(PC_Patch_Prealloc, pc, 0, 0, 0);CHKERRQ(ierr);
1553fe117d09SFlorian Wechsung     if(withArtificial) {
1554fe117d09SFlorian Wechsung       ierr = ISRestoreIndices(patch->dofsWithArtificial, &dofsArray);CHKERRQ(ierr);
1555fe117d09SFlorian Wechsung     } else {
15564bbf5ea8SMatthew G. Knepley       ierr = ISRestoreIndices(patch->dofs, &dofsArray);CHKERRQ(ierr);
15574bbf5ea8SMatthew G. Knepley     }
1558fe117d09SFlorian Wechsung   }
15594bbf5ea8SMatthew G. Knepley   ierr = MatSetUp(*mat);CHKERRQ(ierr);
15604bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
15614bbf5ea8SMatthew G. Knepley }
15624bbf5ea8SMatthew G. Knepley 
15630904074fSPatrick 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)
156492d50984SMatthew G. Knepley {
156592d50984SMatthew G. Knepley   PC_PATCH       *patch = (PC_PATCH *) pc->data;
156692d50984SMatthew G. Knepley   DM              dm;
156792d50984SMatthew G. Knepley   PetscSection    s;
156892d50984SMatthew G. Knepley   const PetscInt *parray, *oarray;
156992d50984SMatthew G. Knepley   PetscInt        Nf = patch->nsubspaces, Np, poff, p, f;
157092d50984SMatthew G. Knepley   PetscErrorCode  ierr;
157192d50984SMatthew G. Knepley 
157292d50984SMatthew G. Knepley   PetscFunctionBegin;
157392d50984SMatthew G. Knepley   ierr = PCGetDM(pc, &dm);CHKERRQ(ierr);
157492d50984SMatthew G. Knepley   ierr = DMGetDefaultSection(dm, &s);CHKERRQ(ierr);
157592d50984SMatthew G. Knepley   /* Set offset into patch */
157692d50984SMatthew G. Knepley   ierr = PetscSectionGetDof(patch->pointCounts, patchNum, &Np);CHKERRQ(ierr);
157792d50984SMatthew G. Knepley   ierr = PetscSectionGetOffset(patch->pointCounts, patchNum, &poff);CHKERRQ(ierr);
157892d50984SMatthew G. Knepley   ierr = ISGetIndices(patch->points, &parray);CHKERRQ(ierr);
157992d50984SMatthew G. Knepley   ierr = ISGetIndices(patch->offs,   &oarray);CHKERRQ(ierr);
158092d50984SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
158192d50984SMatthew G. Knepley     for (p = 0; p < Np; ++p) {
158292d50984SMatthew G. Knepley       const PetscInt point = parray[poff+p];
158392d50984SMatthew G. Knepley       PetscInt       dof;
158492d50984SMatthew G. Knepley 
158592d50984SMatthew G. Knepley       ierr = PetscSectionGetFieldDof(patch->patchSection, point, f, &dof);CHKERRQ(ierr);
158692d50984SMatthew G. Knepley       ierr = PetscSectionSetFieldOffset(patch->patchSection, point, f, oarray[(poff+p)*Nf+f]);CHKERRQ(ierr);
158792d50984SMatthew G. Knepley       if (patch->nsubspaces == 1) {ierr = PetscSectionSetOffset(patch->patchSection, point, oarray[(poff+p)*Nf+f]);CHKERRQ(ierr);}
158892d50984SMatthew G. Knepley       else                        {ierr = PetscSectionSetOffset(patch->patchSection, point, -1);CHKERRQ(ierr);}
158992d50984SMatthew G. Knepley     }
159092d50984SMatthew G. Knepley   }
159192d50984SMatthew G. Knepley   ierr = ISRestoreIndices(patch->points, &parray);CHKERRQ(ierr);
159292d50984SMatthew G. Knepley   ierr = ISRestoreIndices(patch->offs,   &oarray);CHKERRQ(ierr);
159392d50984SMatthew G. Knepley   if (patch->viewSection) {ierr = ObjectView((PetscObject) patch->patchSection, patch->viewerSection, patch->formatSection);CHKERRQ(ierr);}
159492d50984SMatthew G. Knepley   ierr = DMPlexComputeResidual_Patch_Internal(pc->dm, patch->patchSection, cellIS, 0.0, x, NULL, F, ctx);CHKERRQ(ierr);
159592d50984SMatthew G. Knepley   PetscFunctionReturn(0);
159692d50984SMatthew G. Knepley }
159792d50984SMatthew G. Knepley 
159892d50984SMatthew G. Knepley PetscErrorCode PCPatchComputeFunction_Internal(PC pc, Vec x, Vec F, PetscInt point)
159992d50984SMatthew G. Knepley {
160092d50984SMatthew G. Knepley   PC_PATCH       *patch = (PC_PATCH *) pc->data;
160192d50984SMatthew G. Knepley   const PetscInt *dofsArray;
16020904074fSPatrick Farrell   const PetscInt *dofsArrayWithAll;
160392d50984SMatthew G. Knepley   const PetscInt *cellsArray;
160492d50984SMatthew G. Knepley   PetscInt        ncell, offset, pStart, pEnd;
160592d50984SMatthew G. Knepley   PetscErrorCode  ierr;
160692d50984SMatthew G. Knepley 
160792d50984SMatthew G. Knepley   PetscFunctionBegin;
160892d50984SMatthew G. Knepley   ierr = PetscLogEventBegin(PC_Patch_ComputeOp, pc, 0, 0, 0);CHKERRQ(ierr);
160992d50984SMatthew G. Knepley   if (!patch->usercomputeop) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call PCPatchSetComputeOperator() to set user callback\n");
161092d50984SMatthew G. Knepley   ierr = ISGetIndices(patch->dofs, &dofsArray);CHKERRQ(ierr);
16110904074fSPatrick Farrell   ierr = ISGetIndices(patch->dofsWithAll, &dofsArrayWithAll);CHKERRQ(ierr);
161292d50984SMatthew G. Knepley   ierr = ISGetIndices(patch->cells, &cellsArray);CHKERRQ(ierr);
161392d50984SMatthew G. Knepley   ierr = PetscSectionGetChart(patch->cellCounts, &pStart, &pEnd);CHKERRQ(ierr);
161492d50984SMatthew G. Knepley 
161592d50984SMatthew G. Knepley   point += pStart;
161692d50984SMatthew 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);
161792d50984SMatthew G. Knepley 
161892d50984SMatthew G. Knepley   ierr = PetscSectionGetDof(patch->cellCounts, point, &ncell);CHKERRQ(ierr);
161992d50984SMatthew G. Knepley   ierr = PetscSectionGetOffset(patch->cellCounts, point, &offset);CHKERRQ(ierr);
162092d50984SMatthew G. Knepley   if (ncell <= 0) {
162192d50984SMatthew G. Knepley     ierr = PetscLogEventEnd(PC_Patch_ComputeOp, pc, 0, 0, 0);CHKERRQ(ierr);
162292d50984SMatthew G. Knepley     PetscFunctionReturn(0);
162392d50984SMatthew G. Knepley   }
162492d50984SMatthew G. Knepley   PetscStackPush("PCPatch user callback");
162592d50984SMatthew G. Knepley   /* Cannot reuse the same IS because the geometry info is being cached in it */
162692d50984SMatthew G. Knepley   ierr = ISCreateGeneral(PETSC_COMM_SELF, ncell, cellsArray + offset, PETSC_USE_POINTER, &patch->cellIS);CHKERRQ(ierr);
162739fd2e8aSPatrick Farrell   ierr = patch->usercomputef(pc, point, x, F, patch->cellIS, ncell*patch->totalDofsPerCell, dofsArray + offset*patch->totalDofsPerCell,
16280904074fSPatrick Farrell                                                                                             dofsArrayWithAll + offset*patch->totalDofsPerCell,
162939fd2e8aSPatrick Farrell                                                                                             patch->usercomputefctx);CHKERRQ(ierr);
163092d50984SMatthew G. Knepley   PetscStackPop;
163192d50984SMatthew G. Knepley   ierr = ISDestroy(&patch->cellIS);CHKERRQ(ierr);
163292d50984SMatthew G. Knepley   ierr = ISRestoreIndices(patch->dofs, &dofsArray);CHKERRQ(ierr);
16330904074fSPatrick Farrell   ierr = ISRestoreIndices(patch->dofsWithAll, &dofsArrayWithAll);CHKERRQ(ierr);
163492d50984SMatthew G. Knepley   ierr = ISRestoreIndices(patch->cells, &cellsArray);CHKERRQ(ierr);
163592d50984SMatthew G. Knepley   if (patch->viewMatrix) {
163692d50984SMatthew G. Knepley     char name[PETSC_MAX_PATH_LEN];
163792d50984SMatthew G. Knepley 
163892d50984SMatthew G. Knepley     ierr = PetscSNPrintf(name, PETSC_MAX_PATH_LEN-1, "Patch vector for Point %D", point);CHKERRQ(ierr);
163992d50984SMatthew G. Knepley     ierr = PetscObjectSetName((PetscObject) F, name);CHKERRQ(ierr);
164092d50984SMatthew G. Knepley     ierr = ObjectView((PetscObject) F, patch->viewerMatrix, patch->formatMatrix);CHKERRQ(ierr);
164192d50984SMatthew G. Knepley   }
164292d50984SMatthew G. Knepley   ierr = PetscLogEventEnd(PC_Patch_ComputeOp, pc, 0, 0, 0);CHKERRQ(ierr);
164392d50984SMatthew G. Knepley   PetscFunctionReturn(0);
164492d50984SMatthew G. Knepley }
164592d50984SMatthew G. Knepley 
16460904074fSPatrick 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)
16475f824522SMatthew G. Knepley {
16485f824522SMatthew G. Knepley   PC_PATCH       *patch = (PC_PATCH *) pc->data;
16495f824522SMatthew G. Knepley   DM              dm;
16505f824522SMatthew G. Knepley   PetscSection    s;
16515f824522SMatthew G. Knepley   const PetscInt *parray, *oarray;
16525f824522SMatthew G. Knepley   PetscInt        Nf = patch->nsubspaces, Np, poff, p, f;
16535f824522SMatthew G. Knepley   PetscErrorCode  ierr;
16545f824522SMatthew G. Knepley 
16555f824522SMatthew G. Knepley   PetscFunctionBegin;
16565f824522SMatthew G. Knepley   ierr = PCGetDM(pc, &dm);CHKERRQ(ierr);
16575f824522SMatthew G. Knepley   ierr = DMGetDefaultSection(dm, &s);CHKERRQ(ierr);
16585f824522SMatthew G. Knepley   /* Set offset into patch */
16595f824522SMatthew G. Knepley   ierr = PetscSectionGetDof(patch->pointCounts, patchNum, &Np);CHKERRQ(ierr);
16605f824522SMatthew G. Knepley   ierr = PetscSectionGetOffset(patch->pointCounts, patchNum, &poff);CHKERRQ(ierr);
16615f824522SMatthew G. Knepley   ierr = ISGetIndices(patch->points, &parray);CHKERRQ(ierr);
16625f824522SMatthew G. Knepley   ierr = ISGetIndices(patch->offs,   &oarray);CHKERRQ(ierr);
16635f824522SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
16645f824522SMatthew G. Knepley     for (p = 0; p < Np; ++p) {
16655f824522SMatthew G. Knepley       const PetscInt point = parray[poff+p];
16665f824522SMatthew G. Knepley       PetscInt       dof;
16675f824522SMatthew G. Knepley 
16685f824522SMatthew G. Knepley       ierr = PetscSectionGetFieldDof(patch->patchSection, point, f, &dof);CHKERRQ(ierr);
16695f824522SMatthew G. Knepley       ierr = PetscSectionSetFieldOffset(patch->patchSection, point, f, oarray[(poff+p)*Nf+f]);CHKERRQ(ierr);
16705f824522SMatthew G. Knepley       if (patch->nsubspaces == 1) {ierr = PetscSectionSetOffset(patch->patchSection, point, oarray[(poff+p)*Nf+f]);CHKERRQ(ierr);}
16715f824522SMatthew G. Knepley       else                        {ierr = PetscSectionSetOffset(patch->patchSection, point, -1);CHKERRQ(ierr);}
16725f824522SMatthew G. Knepley     }
16735f824522SMatthew G. Knepley   }
16745f824522SMatthew G. Knepley   ierr = ISRestoreIndices(patch->points, &parray);CHKERRQ(ierr);
16755f824522SMatthew G. Knepley   ierr = ISRestoreIndices(patch->offs,   &oarray);CHKERRQ(ierr);
16765f824522SMatthew G. Knepley   if (patch->viewSection) {ierr = ObjectView((PetscObject) patch->patchSection, patch->viewerSection, patch->formatSection);CHKERRQ(ierr);}
16775f824522SMatthew G. Knepley   /* TODO Shut off MatViewFromOptions() in MatAssemblyEnd() here */
1678723f9013SMatthew G. Knepley   ierr = DMPlexComputeJacobian_Patch_Internal(pc->dm, patch->patchSection, patch->patchSection, cellIS, 0.0, 0.0, x, NULL, J, J, ctx);CHKERRQ(ierr);
16795f824522SMatthew G. Knepley   PetscFunctionReturn(0);
16805f824522SMatthew G. Knepley }
16815f824522SMatthew G. Knepley 
168234d8b122SPatrick Farrell PetscErrorCode PCPatchComputeOperator_Internal(PC pc, Vec x, Mat mat, PetscInt point, PetscBool withArtificial)
16834bbf5ea8SMatthew G. Knepley {
16844bbf5ea8SMatthew G. Knepley   PC_PATCH       *patch = (PC_PATCH *) pc->data;
16854bbf5ea8SMatthew G. Knepley   const PetscInt *dofsArray;
16864d04e9f1SPatrick Farrell   const PetscInt *dofsArrayWithArtificial = NULL;
16870904074fSPatrick Farrell   const PetscInt *dofsArrayWithAll = NULL;
16884bbf5ea8SMatthew G. Knepley   const PetscInt *cellsArray;
16894bbf5ea8SMatthew G. Knepley   PetscInt        ncell, offset, pStart, pEnd;
16904d04e9f1SPatrick Farrell   PetscBool       isNonlinear;
16914bbf5ea8SMatthew G. Knepley   PetscErrorCode  ierr;
16924bbf5ea8SMatthew G. Knepley 
16934bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
16944bbf5ea8SMatthew G. Knepley   ierr = PetscLogEventBegin(PC_Patch_ComputeOp, pc, 0, 0, 0);CHKERRQ(ierr);
1695debbdec3SPatrick Farrell   isNonlinear = patch->isNonlinear;
16964bbf5ea8SMatthew G. Knepley   if (!patch->usercomputeop) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call PCPatchSetComputeOperator() to set user callback\n");
1697c2e6f3c0SFlorian Wechsung   if(withArtificial) {
1698c2e6f3c0SFlorian Wechsung     ierr = ISGetIndices(patch->dofsWithArtificial, &dofsArray);CHKERRQ(ierr);
1699c2e6f3c0SFlorian Wechsung   } else {
17004bbf5ea8SMatthew G. Knepley     ierr = ISGetIndices(patch->dofs, &dofsArray);CHKERRQ(ierr);
1701c2e6f3c0SFlorian Wechsung   }
17024d04e9f1SPatrick Farrell   if (isNonlinear) {
17030904074fSPatrick Farrell     ierr = ISGetIndices(patch->dofsWithAll, &dofsArrayWithAll);CHKERRQ(ierr);
17044d04e9f1SPatrick Farrell   }
17054bbf5ea8SMatthew G. Knepley   ierr = ISGetIndices(patch->cells, &cellsArray);CHKERRQ(ierr);
17064bbf5ea8SMatthew G. Knepley   ierr = PetscSectionGetChart(patch->cellCounts, &pStart, &pEnd);CHKERRQ(ierr);
17074bbf5ea8SMatthew G. Knepley 
17084bbf5ea8SMatthew G. Knepley   point += pStart;
17094bbf5ea8SMatthew 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);
17104bbf5ea8SMatthew G. Knepley 
17114bbf5ea8SMatthew G. Knepley   ierr = PetscSectionGetDof(patch->cellCounts, point, &ncell);CHKERRQ(ierr);
17124bbf5ea8SMatthew G. Knepley   ierr = PetscSectionGetOffset(patch->cellCounts, point, &offset);CHKERRQ(ierr);
17134bbf5ea8SMatthew G. Knepley   if (ncell <= 0) {
17144bbf5ea8SMatthew G. Knepley     ierr = PetscLogEventEnd(PC_Patch_ComputeOp, pc, 0, 0, 0);CHKERRQ(ierr);
17154bbf5ea8SMatthew G. Knepley     PetscFunctionReturn(0);
17164bbf5ea8SMatthew G. Knepley   }
17174bbf5ea8SMatthew G. Knepley   PetscStackPush("PCPatch user callback");
17182aa6f319SMatthew G. Knepley   /* Cannot reuse the same IS because the geometry info is being cached in it */
17192aa6f319SMatthew G. Knepley   ierr = ISCreateGeneral(PETSC_COMM_SELF, ncell, cellsArray + offset, PETSC_USE_POINTER, &patch->cellIS);CHKERRQ(ierr);
17200904074fSPatrick 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);
17214bbf5ea8SMatthew G. Knepley   PetscStackPop;
17222aa6f319SMatthew G. Knepley   ierr = ISDestroy(&patch->cellIS);CHKERRQ(ierr);
17234d04e9f1SPatrick Farrell   if(withArtificial) {
1724c2e6f3c0SFlorian Wechsung     ierr = ISRestoreIndices(patch->dofsWithArtificial, &dofsArray);CHKERRQ(ierr);
1725c2e6f3c0SFlorian Wechsung   } else {
17264bbf5ea8SMatthew G. Knepley     ierr = ISRestoreIndices(patch->dofs, &dofsArray);CHKERRQ(ierr);
1727c2e6f3c0SFlorian Wechsung   }
17284d04e9f1SPatrick Farrell   if (isNonlinear) {
17290904074fSPatrick Farrell     ierr = ISRestoreIndices(patch->dofsWithAll, &dofsArrayWithAll);CHKERRQ(ierr);
17304d04e9f1SPatrick Farrell   }
17314bbf5ea8SMatthew G. Knepley   ierr = ISRestoreIndices(patch->cells, &cellsArray);CHKERRQ(ierr);
17322aa6f319SMatthew G. Knepley   if (patch->viewMatrix) {
17332aa6f319SMatthew G. Knepley     char name[PETSC_MAX_PATH_LEN];
17342aa6f319SMatthew G. Knepley 
17352aa6f319SMatthew G. Knepley     ierr = PetscSNPrintf(name, PETSC_MAX_PATH_LEN-1, "Patch matrix for Point %D", point);CHKERRQ(ierr);
17362aa6f319SMatthew G. Knepley     ierr = PetscObjectSetName((PetscObject) mat, name);CHKERRQ(ierr);
17372aa6f319SMatthew G. Knepley     ierr = ObjectView((PetscObject) mat, patch->viewerMatrix, patch->formatMatrix);CHKERRQ(ierr);
17382aa6f319SMatthew G. Knepley   }
17394bbf5ea8SMatthew G. Knepley   ierr = PetscLogEventEnd(PC_Patch_ComputeOp, pc, 0, 0, 0);CHKERRQ(ierr);
17404bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
17414bbf5ea8SMatthew G. Knepley }
17424bbf5ea8SMatthew G. Knepley 
17430904074fSPatrick Farrell PetscErrorCode PCPatch_ScatterLocal_Private(PC pc, PetscInt p, Vec x, Vec y, InsertMode mode, ScatterMode scat, PatchScatterType scattertype)
17444bbf5ea8SMatthew G. Knepley {
17454bbf5ea8SMatthew G. Knepley   PC_PATCH          *patch     = (PC_PATCH *) pc->data;
17464bbf5ea8SMatthew G. Knepley   const PetscScalar *xArray    = NULL;
17474bbf5ea8SMatthew G. Knepley   PetscScalar       *yArray    = NULL;
17484bbf5ea8SMatthew G. Knepley   const PetscInt    *gtolArray = NULL;
17494bbf5ea8SMatthew G. Knepley   PetscInt           dof, offset, lidx;
17504bbf5ea8SMatthew G. Knepley   PetscErrorCode     ierr;
17514bbf5ea8SMatthew G. Knepley 
17524bbf5ea8SMatthew G. Knepley   PetscFunctionBeginHot;
17534bbf5ea8SMatthew G. Knepley   ierr = PetscLogEventBegin(PC_Patch_Scatter, pc, 0, 0, 0);CHKERRQ(ierr);
17544bbf5ea8SMatthew G. Knepley   ierr = VecGetArrayRead(x, &xArray);CHKERRQ(ierr);
17554bbf5ea8SMatthew G. Knepley   ierr = VecGetArray(y, &yArray);CHKERRQ(ierr);
17560904074fSPatrick Farrell   if (scattertype == SCATTER_WITHARTIFICIAL) {
1757c2e6f3c0SFlorian Wechsung     ierr = PetscSectionGetDof(patch->gtolCountsWithArtificial, p, &dof);CHKERRQ(ierr);
1758c2e6f3c0SFlorian Wechsung     ierr = PetscSectionGetOffset(patch->gtolCountsWithArtificial, p, &offset);CHKERRQ(ierr);
1759c2e6f3c0SFlorian Wechsung     ierr = ISGetIndices(patch->gtolWithArtificial, &gtolArray);CHKERRQ(ierr);
17600904074fSPatrick Farrell   } else if (scattertype == SCATTER_WITHALL) {
17610904074fSPatrick Farrell     ierr = PetscSectionGetDof(patch->gtolCountsWithAll, p, &dof);CHKERRQ(ierr);
17620904074fSPatrick Farrell     ierr = PetscSectionGetOffset(patch->gtolCountsWithAll, p, &offset);CHKERRQ(ierr);
17630904074fSPatrick Farrell     ierr = ISGetIndices(patch->gtolWithAll, &gtolArray);CHKERRQ(ierr);
1764c2e6f3c0SFlorian Wechsung   } else {
17654bbf5ea8SMatthew G. Knepley     ierr = PetscSectionGetDof(patch->gtolCounts, p, &dof);CHKERRQ(ierr);
17664bbf5ea8SMatthew G. Knepley     ierr = PetscSectionGetOffset(patch->gtolCounts, p, &offset);CHKERRQ(ierr);
17674bbf5ea8SMatthew G. Knepley     ierr = ISGetIndices(patch->gtol, &gtolArray);CHKERRQ(ierr);
1768c2e6f3c0SFlorian Wechsung   }
17694bbf5ea8SMatthew 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");
17704bbf5ea8SMatthew 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");
17714bbf5ea8SMatthew G. Knepley   for (lidx = 0; lidx < dof; ++lidx) {
17724bbf5ea8SMatthew G. Knepley     const PetscInt gidx = gtolArray[offset+lidx];
17734bbf5ea8SMatthew G. Knepley 
17744bbf5ea8SMatthew G. Knepley     if (mode == INSERT_VALUES) yArray[lidx]  = xArray[gidx]; /* Forward */
17754bbf5ea8SMatthew G. Knepley     else                       yArray[gidx] += xArray[lidx]; /* Reverse */
17764bbf5ea8SMatthew G. Knepley   }
17770904074fSPatrick Farrell   if (scattertype == SCATTER_WITHARTIFICIAL) {
1778c2e6f3c0SFlorian Wechsung     ierr = ISRestoreIndices(patch->gtolWithArtificial, &gtolArray);CHKERRQ(ierr);
17790904074fSPatrick Farrell   } else if (scattertype == SCATTER_WITHALL) {
17800904074fSPatrick Farrell     ierr = ISRestoreIndices(patch->gtolWithAll, &gtolArray);CHKERRQ(ierr);
1781c2e6f3c0SFlorian Wechsung   } else {
17824bbf5ea8SMatthew G. Knepley     ierr = ISRestoreIndices(patch->gtol, &gtolArray);CHKERRQ(ierr);
1783c2e6f3c0SFlorian Wechsung   }
17844bbf5ea8SMatthew G. Knepley   ierr = VecRestoreArrayRead(x, &xArray);CHKERRQ(ierr);
17854bbf5ea8SMatthew G. Knepley   ierr = VecRestoreArray(y, &yArray);CHKERRQ(ierr);
17864bbf5ea8SMatthew G. Knepley   ierr = PetscLogEventEnd(PC_Patch_Scatter, pc, 0, 0, 0);CHKERRQ(ierr);
17874bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
17884bbf5ea8SMatthew G. Knepley }
17894bbf5ea8SMatthew G. Knepley 
1790dadc69c5SMatthew G. Knepley static PetscErrorCode PCSetUp_PATCH_Linear(PC pc)
1791dadc69c5SMatthew G. Knepley {
1792dadc69c5SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
1793dadc69c5SMatthew G. Knepley   const char    *prefix;
1794dadc69c5SMatthew G. Knepley   PetscInt       i;
1795dadc69c5SMatthew G. Knepley   PetscErrorCode ierr;
1796dadc69c5SMatthew G. Knepley 
1797dadc69c5SMatthew G. Knepley   PetscFunctionBegin;
1798dadc69c5SMatthew G. Knepley   if (!pc->setupcalled) {
1799dadc69c5SMatthew G. Knepley     ierr = PetscMalloc1(patch->npatch, &patch->solver);CHKERRQ(ierr);
1800dadc69c5SMatthew G. Knepley     ierr = PCGetOptionsPrefix(pc, &prefix);CHKERRQ(ierr);
1801dadc69c5SMatthew G. Knepley     for (i = 0; i < patch->npatch; ++i) {
1802dadc69c5SMatthew G. Knepley       KSP ksp;
1803dadc69c5SMatthew G. Knepley       PC  subpc;
1804dadc69c5SMatthew G. Knepley 
1805dadc69c5SMatthew G. Knepley       ierr = KSPCreate(PETSC_COMM_SELF, &ksp);CHKERRQ(ierr);
1806dadc69c5SMatthew G. Knepley       ierr = KSPSetOptionsPrefix(ksp, prefix);CHKERRQ(ierr);
1807dadc69c5SMatthew G. Knepley       ierr = KSPAppendOptionsPrefix(ksp, "sub_");CHKERRQ(ierr);
1808dadc69c5SMatthew G. Knepley       ierr = PetscObjectIncrementTabLevel((PetscObject) ksp, (PetscObject) pc, 1);CHKERRQ(ierr);
1809dadc69c5SMatthew G. Knepley       ierr = KSPGetPC(ksp, &subpc);CHKERRQ(ierr);
1810dadc69c5SMatthew G. Knepley       ierr = PetscObjectIncrementTabLevel((PetscObject) subpc, (PetscObject) pc, 1);CHKERRQ(ierr);
1811dadc69c5SMatthew G. Knepley       ierr = PetscLogObjectParent((PetscObject) pc, (PetscObject) ksp);CHKERRQ(ierr);
1812dadc69c5SMatthew G. Knepley       patch->solver[i] = (PetscObject) ksp;
1813dadc69c5SMatthew G. Knepley     }
1814dadc69c5SMatthew G. Knepley   }
1815dadc69c5SMatthew G. Knepley   if (patch->save_operators) {
1816dadc69c5SMatthew G. Knepley     for (i = 0; i < patch->npatch; ++i) {
1817dadc69c5SMatthew G. Knepley       ierr = MatZeroEntries(patch->mat[i]);CHKERRQ(ierr);
181834d8b122SPatrick Farrell       ierr = PCPatchComputeOperator_Internal(pc, NULL, patch->mat[i], i, PETSC_FALSE);CHKERRQ(ierr);
1819dadc69c5SMatthew G. Knepley       ierr = KSPSetOperators((KSP) patch->solver[i], patch->mat[i], patch->mat[i]);CHKERRQ(ierr);
1820dadc69c5SMatthew G. Knepley     }
1821dadc69c5SMatthew G. Knepley   }
182234d8b122SPatrick Farrell   if(patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
182334d8b122SPatrick Farrell     for (i = 0; i < patch->npatch; ++i) {
18241202d238SPatrick Farrell       /* Instead of padding patch->patchUpdate with zeros to get */
18251202d238SPatrick Farrell       /* patch->patchUpdateWithArtificial and then multiplying with the matrix, */
182634d8b122SPatrick Farrell       /* just get rid of the columns that correspond to the dofs with */
182734d8b122SPatrick Farrell       /* artificial bcs. That's of course fairly inefficient, hopefully we */
182834d8b122SPatrick Farrell       /* can just assemble the rectangular matrix in the first place. */
182934d8b122SPatrick Farrell       Mat matSquare;
183034d8b122SPatrick Farrell       IS rowis;
183134d8b122SPatrick Farrell       PetscInt dof;
183234d8b122SPatrick Farrell 
183334d8b122SPatrick Farrell       ierr = MatGetSize(patch->mat[i], &dof, NULL);CHKERRQ(ierr);
183434d8b122SPatrick Farrell       if (dof == 0) {
183534d8b122SPatrick Farrell         patch->matWithArtificial[i] = NULL;
183634d8b122SPatrick Farrell         continue;
183734d8b122SPatrick Farrell       }
183834d8b122SPatrick Farrell 
183934d8b122SPatrick Farrell       ierr = PCPatchCreateMatrix_Private(pc, i, &matSquare, PETSC_TRUE);CHKERRQ(ierr);
184034d8b122SPatrick Farrell       ierr = MatZeroEntries(matSquare);CHKERRQ(ierr);
184134d8b122SPatrick Farrell       ierr = PCPatchComputeOperator_Internal(pc, NULL, matSquare, i, PETSC_TRUE);CHKERRQ(ierr);
184234d8b122SPatrick Farrell 
184334d8b122SPatrick Farrell       ierr = MatGetSize(matSquare, &dof, NULL);CHKERRQ(ierr);
184434d8b122SPatrick Farrell       ierr = ISCreateStride(PETSC_COMM_SELF, dof, 0, 1, &rowis); CHKERRQ(ierr);
184534d8b122SPatrick Farrell       if(pc->setupcalled) {
184634d8b122SPatrick Farrell         ierr = MatCreateSubMatrix(matSquare, rowis, patch->dofMappingWithoutToWithArtificial[i], MAT_REUSE_MATRIX, &patch->matWithArtificial[i]); CHKERRQ(ierr);
184734d8b122SPatrick Farrell       } else {
184834d8b122SPatrick Farrell         ierr = MatCreateSubMatrix(matSquare, rowis, patch->dofMappingWithoutToWithArtificial[i], MAT_INITIAL_MATRIX, &patch->matWithArtificial[i]); CHKERRQ(ierr);
184934d8b122SPatrick Farrell       }
185034d8b122SPatrick Farrell       ierr = ISDestroy(&rowis); CHKERRQ(ierr);
185134d8b122SPatrick Farrell       ierr = MatDestroy(&matSquare);CHKERRQ(ierr);
185234d8b122SPatrick Farrell     }
185334d8b122SPatrick Farrell   }
1854dadc69c5SMatthew G. Knepley   PetscFunctionReturn(0);
1855dadc69c5SMatthew G. Knepley }
1856dadc69c5SMatthew G. Knepley 
18574bbf5ea8SMatthew G. Knepley static PetscErrorCode PCSetUp_PATCH(PC pc)
18584bbf5ea8SMatthew G. Knepley {
18594bbf5ea8SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
1860557beb66SLawrence Mitchell   PetscInt       i;
186139fd2e8aSPatrick Farrell   PetscBool       isNonlinear;
18624bbf5ea8SMatthew G. Knepley   PetscErrorCode ierr;
18634bbf5ea8SMatthew G. Knepley 
18644bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
18654bbf5ea8SMatthew G. Knepley   if (!pc->setupcalled) {
18664bbf5ea8SMatthew G. Knepley     PetscInt pStart, pEnd, p;
18674bbf5ea8SMatthew G. Knepley     PetscInt localSize;
18684bbf5ea8SMatthew G. Knepley 
18694bbf5ea8SMatthew G. Knepley     ierr = PetscLogEventBegin(PC_Patch_CreatePatches, pc, 0, 0, 0);CHKERRQ(ierr);
18704bbf5ea8SMatthew G. Knepley 
1871debbdec3SPatrick Farrell     isNonlinear = patch->isNonlinear;
18725f824522SMatthew G. Knepley     if (!patch->nsubspaces) {
18735f824522SMatthew G. Knepley       DM           dm;
18745f824522SMatthew G. Knepley       PetscDS      prob;
18755f824522SMatthew G. Knepley       PetscSection s;
1876e72c1634SMatthew G. Knepley       PetscInt     cStart, cEnd, c, Nf, f, numGlobalBcs = 0, *globalBcs, *Nb, totNb = 0, **cellDofs;
18775f824522SMatthew G. Knepley 
18785f824522SMatthew G. Knepley       ierr = PCGetDM(pc, &dm);CHKERRQ(ierr);
18795f824522SMatthew G. Knepley       if (!dm) SETERRQ(PetscObjectComm((PetscObject) pc), PETSC_ERR_ARG_WRONG, "Must set DM for PCPATCH or call PCPatchSetDiscretisationInfo()");
18805f824522SMatthew G. Knepley       ierr = DMGetDefaultSection(dm, &s);CHKERRQ(ierr);
18815f824522SMatthew G. Knepley       ierr = PetscSectionGetNumFields(s, &Nf);CHKERRQ(ierr);
18825f824522SMatthew G. Knepley       ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
18835f824522SMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
18845f824522SMatthew G. Knepley         PetscInt cdof;
18855f824522SMatthew G. Knepley         ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
18865f824522SMatthew G. Knepley         numGlobalBcs += cdof;
18875f824522SMatthew G. Knepley       }
18885f824522SMatthew G. Knepley       ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
18895f824522SMatthew G. Knepley       ierr = DMGetDS(dm, &prob);CHKERRQ(ierr);
18905f824522SMatthew G. Knepley       ierr = PetscMalloc3(Nf, &Nb, Nf, &cellDofs, numGlobalBcs, &globalBcs);CHKERRQ(ierr);
18915f824522SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
18925f824522SMatthew G. Knepley         PetscFE        fe;
18935f824522SMatthew G. Knepley         PetscDualSpace sp;
18945f824522SMatthew G. Knepley         PetscInt       cdoff = 0;
18955f824522SMatthew G. Knepley 
18965f824522SMatthew G. Knepley         ierr = PetscDSGetDiscretization(prob, f, (PetscObject *) &fe);CHKERRQ(ierr);
18975f824522SMatthew G. Knepley         /* ierr = PetscFEGetNumComponents(fe, &Nc[f]);CHKERRQ(ierr); */
18985f824522SMatthew G. Knepley         ierr = PetscFEGetDualSpace(fe, &sp);CHKERRQ(ierr);
18995f824522SMatthew G. Knepley         ierr = PetscDualSpaceGetDimension(sp, &Nb[f]);CHKERRQ(ierr);
19005f824522SMatthew G. Knepley         totNb += Nb[f];
19015f824522SMatthew G. Knepley 
19025f824522SMatthew G. Knepley         ierr = PetscMalloc1((cEnd-cStart)*Nb[f], &cellDofs[f]);CHKERRQ(ierr);
19035f824522SMatthew G. Knepley         for (c = cStart; c < cEnd; ++c) {
19045f824522SMatthew G. Knepley           PetscInt *closure = NULL;
19055f824522SMatthew G. Knepley           PetscInt  clSize  = 0, cl;
19065f824522SMatthew G. Knepley 
19075f824522SMatthew G. Knepley           ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
19085f824522SMatthew G. Knepley           for (cl = 0; cl < clSize*2; cl += 2) {
19095f824522SMatthew G. Knepley             const PetscInt p = closure[cl];
19105f824522SMatthew G. Knepley             PetscInt       fdof, d, foff;
19115f824522SMatthew G. Knepley 
19125f824522SMatthew G. Knepley             ierr = PetscSectionGetFieldDof(s, p, f, &fdof);CHKERRQ(ierr);
19135f824522SMatthew G. Knepley             ierr = PetscSectionGetFieldOffset(s, p, f, &foff);CHKERRQ(ierr);
19145f824522SMatthew G. Knepley             for (d = 0; d < fdof; ++d, ++cdoff) cellDofs[f][cdoff] = foff + d;
19155f824522SMatthew G. Knepley           }
19165f824522SMatthew G. Knepley           ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
19175f824522SMatthew G. Knepley         }
19185f824522SMatthew 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]);
19195f824522SMatthew G. Knepley       }
19205f824522SMatthew G. Knepley       numGlobalBcs = 0;
19215f824522SMatthew G. Knepley       for (p = pStart; p < pEnd; ++p) {
19225f824522SMatthew G. Knepley         const PetscInt *ind;
19235f824522SMatthew G. Knepley         PetscInt        off, cdof, d;
19245f824522SMatthew G. Knepley 
19255f824522SMatthew G. Knepley         ierr = PetscSectionGetOffset(s, p, &off);CHKERRQ(ierr);
19265f824522SMatthew G. Knepley         ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
19275f824522SMatthew G. Knepley         ierr = PetscSectionGetConstraintIndices(s, p, &ind);CHKERRQ(ierr);
19285f824522SMatthew G. Knepley         for (d = 0; d < cdof; ++d) globalBcs[numGlobalBcs++] = off + ind[d];
19295f824522SMatthew G. Knepley       }
19305f824522SMatthew G. Knepley 
19315f824522SMatthew G. Knepley       ierr = PCPatchSetDiscretisationInfoCombined(pc, dm, Nb, (const PetscInt **) cellDofs, numGlobalBcs, globalBcs, numGlobalBcs, globalBcs);CHKERRQ(ierr);
19325f824522SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
19335f824522SMatthew G. Knepley         ierr = PetscFree(cellDofs[f]);CHKERRQ(ierr);
19345f824522SMatthew G. Knepley       }
19355f824522SMatthew G. Knepley       ierr = PetscFree3(Nb, cellDofs, globalBcs);CHKERRQ(ierr);
193692d50984SMatthew G. Knepley       ierr = PCPatchSetComputeFunction(pc, PCPatchComputeFunction_DMPlex_Private, NULL);CHKERRQ(ierr);
19375f824522SMatthew G. Knepley       ierr = PCPatchSetComputeOperator(pc, PCPatchComputeOperator_DMPlex_Private, NULL);CHKERRQ(ierr);
19385f824522SMatthew G. Knepley     }
19395f824522SMatthew G. Knepley 
19404bbf5ea8SMatthew G. Knepley     localSize = patch->subspaceOffsets[patch->nsubspaces];
19411202d238SPatrick Farrell     ierr = VecCreateSeq(PETSC_COMM_SELF, localSize, &patch->localRHS);CHKERRQ(ierr);
19421202d238SPatrick Farrell     ierr = VecSetUp(patch->localRHS);CHKERRQ(ierr);
19431202d238SPatrick Farrell     ierr = VecDuplicate(patch->localRHS, &patch->localUpdate);CHKERRQ(ierr);
19444bbf5ea8SMatthew G. Knepley     ierr = PCPatchCreateCellPatches(pc);CHKERRQ(ierr);
19454bbf5ea8SMatthew G. Knepley     ierr = PCPatchCreateCellPatchDiscretisationInfo(pc);CHKERRQ(ierr);
19464bbf5ea8SMatthew G. Knepley 
19474bbf5ea8SMatthew G. Knepley     /* OK, now build the work vectors */
19484bbf5ea8SMatthew G. Knepley     ierr = PetscSectionGetChart(patch->gtolCounts, &pStart, &pEnd);CHKERRQ(ierr);
19491202d238SPatrick Farrell     ierr = PetscMalloc1(patch->npatch, &patch->patchRHS);CHKERRQ(ierr);
19501202d238SPatrick Farrell     ierr = PetscMalloc1(patch->npatch, &patch->patchUpdate);CHKERRQ(ierr);
1951c2e6f3c0SFlorian Wechsung 
195261c4b389SFlorian Wechsung     if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
19531202d238SPatrick Farrell       ierr = PetscMalloc1(patch->npatch, &patch->patchRHSWithArtificial);CHKERRQ(ierr);
1954c2e6f3c0SFlorian Wechsung       ierr = PetscMalloc1(patch->npatch, &patch->dofMappingWithoutToWithArtificial);CHKERRQ(ierr);
1955c2e6f3c0SFlorian Wechsung     }
19560904074fSPatrick Farrell     if (isNonlinear) {
19570904074fSPatrick Farrell       ierr = PetscMalloc1(patch->npatch, &patch->dofMappingWithoutToWithAll);CHKERRQ(ierr);
19580904074fSPatrick Farrell     }
19594bbf5ea8SMatthew G. Knepley     for (p = pStart; p < pEnd; ++p) {
19604bbf5ea8SMatthew G. Knepley       PetscInt dof;
19614bbf5ea8SMatthew G. Knepley 
19624bbf5ea8SMatthew G. Knepley       ierr = PetscSectionGetDof(patch->gtolCounts, p, &dof);CHKERRQ(ierr);
19631202d238SPatrick Farrell       ierr = VecCreateSeq(PETSC_COMM_SELF, dof, &patch->patchRHS[p-pStart]);CHKERRQ(ierr);
19641202d238SPatrick Farrell       ierr = VecSetUp(patch->patchRHS[p-pStart]);CHKERRQ(ierr);
19651202d238SPatrick Farrell       ierr = VecCreateSeq(PETSC_COMM_SELF, dof, &patch->patchUpdate[p-pStart]);CHKERRQ(ierr);
19661202d238SPatrick Farrell       ierr = VecSetUp(patch->patchUpdate[p-pStart]);CHKERRQ(ierr);
19670904074fSPatrick Farrell       if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
19683bb0e8f7SKarl Rupp         const PetscInt    *gtolArray, *gtolArrayWithArtificial = NULL;
19693bb0e8f7SKarl Rupp         PetscInt           numPatchDofs, offset;
19703bb0e8f7SKarl Rupp         PetscInt           numPatchDofsWithArtificial, offsetWithArtificial;
19713bb0e8f7SKarl Rupp         PetscInt           dofWithoutArtificialCounter = 0;
19723bb0e8f7SKarl Rupp         PetscInt          *patchWithoutArtificialToWithArtificialArray;
19733bb0e8f7SKarl Rupp 
1974c2e6f3c0SFlorian Wechsung         ierr = PetscSectionGetDof(patch->gtolCountsWithArtificial, p, &dof);CHKERRQ(ierr);
19751202d238SPatrick Farrell         ierr = VecCreateSeq(PETSC_COMM_SELF, dof, &patch->patchRHSWithArtificial[p-pStart]);CHKERRQ(ierr);
19761202d238SPatrick Farrell         ierr = VecSetUp(patch->patchRHSWithArtificial[p-pStart]);CHKERRQ(ierr);
1977c2e6f3c0SFlorian Wechsung 
1978e047a90bSFlorian Wechsung         /* Now build the mapping that for a dof in a patch WITHOUT dofs that have artificial bcs gives the */
1979e047a90bSFlorian Wechsung         /* the index in the patch with all dofs */
1980c2e6f3c0SFlorian Wechsung         ierr = ISGetIndices(patch->gtol, &gtolArray);CHKERRQ(ierr);
198163deea8eSPatrick Farrell 
1982c2e6f3c0SFlorian Wechsung         ierr = PetscSectionGetDof(patch->gtolCounts, p, &numPatchDofs);CHKERRQ(ierr);
198363deea8eSPatrick Farrell 
1984c2e6f3c0SFlorian Wechsung         ierr = PetscSectionGetOffset(patch->gtolCounts, p, &offset);CHKERRQ(ierr);
1985c2e6f3c0SFlorian Wechsung         ierr = ISGetIndices(patch->gtolWithArtificial, &gtolArrayWithArtificial);CHKERRQ(ierr);
1986c2e6f3c0SFlorian Wechsung         ierr = PetscSectionGetDof(patch->gtolCountsWithArtificial, p, &numPatchDofsWithArtificial);CHKERRQ(ierr);
1987c2e6f3c0SFlorian Wechsung         ierr = PetscSectionGetOffset(patch->gtolCountsWithArtificial, p, &offsetWithArtificial);CHKERRQ(ierr);
1988c2e6f3c0SFlorian Wechsung 
1989c2e6f3c0SFlorian Wechsung         ierr = PetscMalloc1(numPatchDofs, &patchWithoutArtificialToWithArtificialArray);CHKERRQ(ierr);
1990c2e6f3c0SFlorian Wechsung 
19913bb0e8f7SKarl Rupp         ierr = ISCreateGeneral(PETSC_COMM_SELF, numPatchDofs, patchWithoutArtificialToWithArtificialArray, PETSC_OWN_POINTER, &patch->dofMappingWithoutToWithArtificial[p-pStart]);CHKERRQ(ierr);
19927e6cf999SPatrick Farrell         if (numPatchDofs == 0) continue;
1993b0c21b6aSKarl Rupp         for (i=0; i<numPatchDofsWithArtificial; i++) {
1994e047a90bSFlorian Wechsung           if (gtolArrayWithArtificial[i+offsetWithArtificial] == gtolArray[offset+dofWithoutArtificialCounter]) {
1995c2e6f3c0SFlorian Wechsung             patchWithoutArtificialToWithArtificialArray[dofWithoutArtificialCounter] = i;
1996c2e6f3c0SFlorian Wechsung             dofWithoutArtificialCounter++;
1997c2e6f3c0SFlorian Wechsung             if (dofWithoutArtificialCounter == numPatchDofs)
1998c2e6f3c0SFlorian Wechsung               break;
1999c2e6f3c0SFlorian Wechsung           }
2000c2e6f3c0SFlorian Wechsung         }
2001c2e6f3c0SFlorian Wechsung         ierr = ISRestoreIndices(patch->gtol, &gtolArray);CHKERRQ(ierr);
2002c2e6f3c0SFlorian Wechsung         ierr = ISRestoreIndices(patch->gtolWithArtificial, &gtolArrayWithArtificial);CHKERRQ(ierr);
2003c2e6f3c0SFlorian Wechsung       }
20040904074fSPatrick Farrell       if (isNonlinear) {
20050904074fSPatrick Farrell         const PetscInt    *gtolArray, *gtolArrayWithAll = NULL;
20060904074fSPatrick Farrell         PetscInt           numPatchDofs, offset;
20070904074fSPatrick Farrell         PetscInt           numPatchDofsWithAll, offsetWithAll;
20080904074fSPatrick Farrell         PetscInt           dofWithoutAllCounter = 0;
20090904074fSPatrick Farrell         PetscInt          *patchWithoutAllToWithAllArray;
20100904074fSPatrick Farrell 
20110904074fSPatrick Farrell         /* Now build the mapping that for a dof in a patch WITHOUT dofs that have artificial bcs gives the */
20120904074fSPatrick Farrell         /* the index in the patch with all dofs */
20130904074fSPatrick Farrell         ierr = ISGetIndices(patch->gtol, &gtolArray);CHKERRQ(ierr);
20140904074fSPatrick Farrell 
20150904074fSPatrick Farrell         ierr = PetscSectionGetDof(patch->gtolCounts, p, &numPatchDofs);CHKERRQ(ierr);
20160904074fSPatrick Farrell 
20170904074fSPatrick Farrell         ierr = PetscSectionGetOffset(patch->gtolCounts, p, &offset);CHKERRQ(ierr);
20180904074fSPatrick Farrell         ierr = ISGetIndices(patch->gtolWithAll, &gtolArrayWithAll);CHKERRQ(ierr);
20190904074fSPatrick Farrell         ierr = PetscSectionGetDof(patch->gtolCountsWithAll, p, &numPatchDofsWithAll);CHKERRQ(ierr);
20200904074fSPatrick Farrell         ierr = PetscSectionGetOffset(patch->gtolCountsWithAll, p, &offsetWithAll);CHKERRQ(ierr);
20210904074fSPatrick Farrell 
20220904074fSPatrick Farrell         ierr = PetscMalloc1(numPatchDofs, &patchWithoutAllToWithAllArray);CHKERRQ(ierr);
20230904074fSPatrick Farrell 
20240904074fSPatrick Farrell         ierr = ISCreateGeneral(PETSC_COMM_SELF, numPatchDofs, patchWithoutAllToWithAllArray, PETSC_OWN_POINTER, &patch->dofMappingWithoutToWithAll[p-pStart]);CHKERRQ(ierr);
20250904074fSPatrick Farrell         if (numPatchDofs == 0) continue;
20260904074fSPatrick Farrell         for (i=0; i<numPatchDofsWithAll; i++) {
20270904074fSPatrick Farrell           if (gtolArrayWithAll[i+offsetWithAll] == gtolArray[offset+dofWithoutAllCounter]) {
20280904074fSPatrick Farrell             patchWithoutAllToWithAllArray[dofWithoutAllCounter] = i;
20290904074fSPatrick Farrell             dofWithoutAllCounter++;
20300904074fSPatrick Farrell             if (dofWithoutAllCounter == numPatchDofs)
20310904074fSPatrick Farrell               break;
20320904074fSPatrick Farrell           }
20330904074fSPatrick Farrell         }
20340904074fSPatrick Farrell         ierr = ISRestoreIndices(patch->gtol, &gtolArray);CHKERRQ(ierr);
20350904074fSPatrick Farrell         ierr = ISRestoreIndices(patch->gtolWithAll, &gtolArrayWithAll);CHKERRQ(ierr);
20360904074fSPatrick Farrell       }
20374bbf5ea8SMatthew G. Knepley     }
20384bbf5ea8SMatthew G. Knepley     if (patch->save_operators) {
20394bbf5ea8SMatthew G. Knepley       ierr = PetscMalloc1(patch->npatch, &patch->mat);CHKERRQ(ierr);
20404bbf5ea8SMatthew G. Knepley       for (i = 0; i < patch->npatch; ++i) {
2041c2e6f3c0SFlorian Wechsung         ierr = PCPatchCreateMatrix_Private(pc, i, &patch->mat[i], PETSC_FALSE);CHKERRQ(ierr);
20424bbf5ea8SMatthew G. Knepley       }
20434bbf5ea8SMatthew G. Knepley     }
20444bbf5ea8SMatthew G. Knepley     ierr = PetscLogEventEnd(PC_Patch_CreatePatches, pc, 0, 0, 0);CHKERRQ(ierr);
20454bbf5ea8SMatthew G. Knepley 
20464bbf5ea8SMatthew G. Knepley     /* If desired, calculate weights for dof multiplicity */
20474bbf5ea8SMatthew G. Knepley     if (patch->partition_of_unity) {
20483bb0e8f7SKarl Rupp       PetscScalar *input = NULL;
20493bb0e8f7SKarl Rupp       PetscScalar *output = NULL;
20503bb0e8f7SKarl Rupp       Vec global;
20513bb0e8f7SKarl Rupp 
20521202d238SPatrick Farrell       ierr = VecDuplicate(patch->localRHS, &patch->dof_weights);CHKERRQ(ierr);
205361c4b389SFlorian Wechsung       if(patch->local_composition_type == PC_COMPOSITE_ADDITIVE) {
20544bbf5ea8SMatthew G. Knepley         for (i = 0; i < patch->npatch; ++i) {
20554bbf5ea8SMatthew G. Knepley           PetscInt dof;
20564bbf5ea8SMatthew G. Knepley 
20574bbf5ea8SMatthew G. Knepley           ierr = PetscSectionGetDof(patch->gtolCounts, i+pStart, &dof);CHKERRQ(ierr);
20584bbf5ea8SMatthew G. Knepley           if (dof <= 0) continue;
20591202d238SPatrick Farrell           ierr = VecSet(patch->patchRHS[i], 1.0);CHKERRQ(ierr);
20600904074fSPatrick Farrell           ierr = PCPatch_ScatterLocal_Private(pc, i+pStart, patch->patchRHS[i], patch->dof_weights, ADD_VALUES, SCATTER_REVERSE, SCATTER_INTERIOR);CHKERRQ(ierr);
20614bbf5ea8SMatthew G. Knepley         }
2062c2e6f3c0SFlorian Wechsung       } else {
2063e047a90bSFlorian Wechsung         /* multiplicative is actually only locally multiplicative and globally additive. need the pou where the mesh decomposition overlaps */
2064c2e6f3c0SFlorian Wechsung         ierr = VecSet(patch->dof_weights, 1.0);CHKERRQ(ierr);
20654bbf5ea8SMatthew G. Knepley       }
2066d132cafaSFlorian Wechsung 
2067d132cafaSFlorian Wechsung       VecDuplicate(patch->dof_weights, &global);
2068d132cafaSFlorian Wechsung       VecSet(global, 0.);
2069d132cafaSFlorian Wechsung 
2070d132cafaSFlorian Wechsung       ierr = VecGetArray(patch->dof_weights, &input);CHKERRQ(ierr);
2071d132cafaSFlorian Wechsung       ierr = VecGetArray(global, &output);CHKERRQ(ierr);
2072d132cafaSFlorian Wechsung       ierr = PetscSFReduceBegin(patch->defaultSF, MPIU_SCALAR, input, output, MPI_SUM);CHKERRQ(ierr);
2073d132cafaSFlorian Wechsung       ierr = PetscSFReduceEnd(patch->defaultSF, MPIU_SCALAR, input, output, MPI_SUM);CHKERRQ(ierr);
2074d132cafaSFlorian Wechsung       ierr = VecRestoreArray(patch->dof_weights, &input);CHKERRQ(ierr);
2075d132cafaSFlorian Wechsung       ierr = VecRestoreArray(global, &output);CHKERRQ(ierr);
2076d132cafaSFlorian Wechsung 
207705528938SFlorian Wechsung       ierr = VecReciprocal(global);CHKERRQ(ierr);
2078d132cafaSFlorian Wechsung 
2079d132cafaSFlorian Wechsung       ierr = VecGetArray(patch->dof_weights, &output);CHKERRQ(ierr);
2080d132cafaSFlorian Wechsung       ierr = VecGetArray(global, &input);CHKERRQ(ierr);
2081d132cafaSFlorian Wechsung       ierr = PetscSFBcastBegin(patch->defaultSF, MPIU_SCALAR, input, output);CHKERRQ(ierr);
2082d132cafaSFlorian Wechsung       ierr = PetscSFBcastEnd(patch->defaultSF, MPIU_SCALAR, input, output);CHKERRQ(ierr);
2083d132cafaSFlorian Wechsung       ierr = VecRestoreArray(patch->dof_weights, &output);CHKERRQ(ierr);
2084d132cafaSFlorian Wechsung       ierr = VecRestoreArray(global, &input);CHKERRQ(ierr);
2085d132cafaSFlorian Wechsung       ierr = VecDestroy(&global);CHKERRQ(ierr);
20864bbf5ea8SMatthew G. Knepley     }
208761c4b389SFlorian Wechsung     if(patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE && patch->save_operators) {
208896b79ebeSFlorian Wechsung       ierr = PetscMalloc1(patch->npatch, &patch->matWithArtificial);CHKERRQ(ierr);
20894bbf5ea8SMatthew G. Knepley     }
20904bbf5ea8SMatthew G. Knepley   }
2091dadc69c5SMatthew G. Knepley   ierr = (*patch->setupsolver)(pc);CHKERRQ(ierr);
2092dadc69c5SMatthew G. Knepley   PetscFunctionReturn(0);
20934bbf5ea8SMatthew G. Knepley }
2094dadc69c5SMatthew G. Knepley 
2095dadc69c5SMatthew G. Knepley static PetscErrorCode PCApply_PATCH_Linear(PC pc, PetscInt i, Vec x, Vec y)
2096dadc69c5SMatthew G. Knepley {
2097dadc69c5SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
2098dadc69c5SMatthew G. Knepley   KSP            ksp   = (KSP) patch->solver[i];
2099dadc69c5SMatthew G. Knepley   PetscErrorCode ierr;
2100dadc69c5SMatthew G. Knepley 
2101dadc69c5SMatthew G. Knepley   PetscFunctionBegin;
2102dadc69c5SMatthew G. Knepley   if (!patch->save_operators) {
2103dadc69c5SMatthew G. Knepley     Mat mat;
2104dadc69c5SMatthew G. Knepley 
210534d8b122SPatrick Farrell     ierr = PCPatchCreateMatrix_Private(pc, i, &mat, PETSC_FALSE);CHKERRQ(ierr);
2106dadc69c5SMatthew G. Knepley     /* Populate operator here. */
210734d8b122SPatrick Farrell     ierr = PCPatchComputeOperator_Internal(pc, NULL, mat, i, PETSC_FALSE);CHKERRQ(ierr);
2108dadc69c5SMatthew G. Knepley     ierr = KSPSetOperators(ksp, mat, mat);CHKERRQ(ierr);
2109dadc69c5SMatthew G. Knepley     /* Drop reference so the KSPSetOperators below will blow it away. */
2110dadc69c5SMatthew G. Knepley     ierr = MatDestroy(&mat);CHKERRQ(ierr);
2111dadc69c5SMatthew G. Knepley   }
2112dadc69c5SMatthew G. Knepley   ierr = PetscLogEventBegin(PC_Patch_Solve, pc, 0, 0, 0);CHKERRQ(ierr);
2113dadc69c5SMatthew G. Knepley   if (!ksp->setfromoptionscalled) {
2114dadc69c5SMatthew G. Knepley     ierr = KSPSetFromOptions(ksp);CHKERRQ(ierr);
2115dadc69c5SMatthew G. Knepley   }
2116dadc69c5SMatthew G. Knepley   ierr = KSPSolve(ksp, x, y);CHKERRQ(ierr);
2117dadc69c5SMatthew G. Knepley   ierr = PetscLogEventEnd(PC_Patch_Solve, pc, 0, 0, 0);CHKERRQ(ierr);
2118dadc69c5SMatthew G. Knepley   if (!patch->save_operators) {
2119dadc69c5SMatthew G. Knepley     PC pc;
2120dadc69c5SMatthew G. Knepley     ierr = KSPSetOperators(ksp, NULL, NULL);CHKERRQ(ierr);
2121dadc69c5SMatthew G. Knepley     ierr = KSPGetPC(ksp, &pc);CHKERRQ(ierr);
2122dadc69c5SMatthew G. Knepley     /* Destroy PC context too, otherwise the factored matrix hangs around. */
2123dadc69c5SMatthew G. Knepley     ierr = PCReset(pc);CHKERRQ(ierr);
21244bbf5ea8SMatthew G. Knepley   }
21254bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
21264bbf5ea8SMatthew G. Knepley }
21274bbf5ea8SMatthew G. Knepley 
21286c9c532dSPatrick Farrell static PetscErrorCode PCUpdateMultiplicative_PATCH_Linear(PC pc, PetscInt i, PetscInt pStart)
21296c9c532dSPatrick Farrell {
21306c9c532dSPatrick Farrell   PC_PATCH      *patch = (PC_PATCH *) pc->data;
21316c9c532dSPatrick Farrell   Mat multMat;
21326c9c532dSPatrick Farrell   PetscErrorCode ierr;
21336c9c532dSPatrick Farrell 
21344d04e9f1SPatrick Farrell   PetscFunctionBegin;
21354d04e9f1SPatrick Farrell 
21366c9c532dSPatrick Farrell   if (patch->save_operators) {
21376c9c532dSPatrick Farrell     multMat = patch->matWithArtificial[i];
21386c9c532dSPatrick Farrell   } else {
21396c9c532dSPatrick Farrell     /*Very inefficient, hopefully we can just assemble the rectangular matrix in the first place.*/
21406c9c532dSPatrick Farrell     Mat matSquare;
21416c9c532dSPatrick Farrell     PetscInt dof;
21426c9c532dSPatrick Farrell     IS rowis;
21436c9c532dSPatrick Farrell     ierr = PCPatchCreateMatrix_Private(pc, i, &matSquare, PETSC_TRUE);CHKERRQ(ierr);
21446c9c532dSPatrick Farrell     ierr = MatZeroEntries(matSquare);CHKERRQ(ierr);
21456c9c532dSPatrick Farrell     ierr = PCPatchComputeOperator_Internal(pc, NULL, matSquare, i, PETSC_TRUE);CHKERRQ(ierr);
21466c9c532dSPatrick Farrell     ierr = MatGetSize(matSquare, &dof, NULL);CHKERRQ(ierr);
21476c9c532dSPatrick Farrell     ierr = ISCreateStride(PETSC_COMM_SELF, dof, 0, 1, &rowis); CHKERRQ(ierr);
21486c9c532dSPatrick Farrell     ierr = MatCreateSubMatrix(matSquare, rowis, patch->dofMappingWithoutToWithArtificial[i], MAT_INITIAL_MATRIX, &multMat); CHKERRQ(ierr);
21496c9c532dSPatrick Farrell     ierr = MatDestroy(&matSquare);CHKERRQ(ierr);
21506c9c532dSPatrick Farrell     ierr = ISDestroy(&rowis); CHKERRQ(ierr);
21516c9c532dSPatrick Farrell   }
21526c9c532dSPatrick Farrell   ierr = MatMult(multMat, patch->patchUpdate[i], patch->patchRHSWithArtificial[i]); CHKERRQ(ierr);
21536c9c532dSPatrick Farrell   ierr = VecScale(patch->patchRHSWithArtificial[i], -1.0); CHKERRQ(ierr);
21540904074fSPatrick Farrell   ierr = PCPatch_ScatterLocal_Private(pc, i + pStart, patch->patchRHSWithArtificial[i], patch->localRHS, ADD_VALUES, SCATTER_REVERSE, SCATTER_WITHARTIFICIAL); CHKERRQ(ierr);
21556c9c532dSPatrick Farrell   if (!patch->save_operators) {
21566c9c532dSPatrick Farrell     ierr = MatDestroy(&multMat); CHKERRQ(ierr);
21576c9c532dSPatrick Farrell   }
21584d04e9f1SPatrick Farrell   PetscFunctionReturn(0);
21596c9c532dSPatrick Farrell }
21606c9c532dSPatrick Farrell 
21614bbf5ea8SMatthew G. Knepley static PetscErrorCode PCApply_PATCH(PC pc, Vec x, Vec y)
21624bbf5ea8SMatthew G. Knepley {
21634bbf5ea8SMatthew G. Knepley   PC_PATCH          *patch    = (PC_PATCH *) pc->data;
21641202d238SPatrick Farrell   const PetscScalar *globalRHS  = NULL;
21651202d238SPatrick Farrell   PetscScalar       *localRHS   = NULL;
21661202d238SPatrick Farrell   PetscScalar       *globalUpdate  = NULL;
21674bbf5ea8SMatthew G. Knepley   const PetscInt    *bcNodes  = NULL;
21684bbf5ea8SMatthew G. Knepley   PetscInt           nsweep   = patch->symmetrise_sweep ? 2 : 1;
21694bbf5ea8SMatthew G. Knepley   PetscInt           start[2] = {0, 0};
21704bbf5ea8SMatthew G. Knepley   PetscInt           end[2]   = {-1, -1};
21714bbf5ea8SMatthew G. Knepley   const PetscInt     inc[2]   = {1, -1};
21721202d238SPatrick Farrell   const PetscScalar *localUpdate;
21734bbf5ea8SMatthew G. Knepley   const PetscInt    *iterationSet;
21744bbf5ea8SMatthew G. Knepley   PetscInt           pStart, numBcs, n, sweep, bc, j;
21754bbf5ea8SMatthew G. Knepley   PetscErrorCode     ierr;
21764bbf5ea8SMatthew G. Knepley 
21774bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
21784bbf5ea8SMatthew G. Knepley   ierr = PetscLogEventBegin(PC_Patch_Apply, pc, 0, 0, 0);CHKERRQ(ierr);
21794bbf5ea8SMatthew G. Knepley   ierr = PetscOptionsPushGetViewerOff(PETSC_TRUE);CHKERRQ(ierr);
218092d50984SMatthew G. Knepley   /* start, end, inc have 2 entries to manage a second backward sweep if we symmetrize */
21814bbf5ea8SMatthew G. Knepley   end[0]   = patch->npatch;
21824bbf5ea8SMatthew G. Knepley   start[1] = patch->npatch-1;
21834bbf5ea8SMatthew G. Knepley   if (patch->user_patches) {
21844bbf5ea8SMatthew G. Knepley     ierr = ISGetLocalSize(patch->iterationSet, &end[0]);CHKERRQ(ierr);
21854bbf5ea8SMatthew G. Knepley     start[1] = end[0] - 1;
21864bbf5ea8SMatthew G. Knepley     ierr = ISGetIndices(patch->iterationSet, &iterationSet);CHKERRQ(ierr);
21874bbf5ea8SMatthew G. Knepley   }
21884bbf5ea8SMatthew G. Knepley   /* Scatter from global space into overlapped local spaces */
21891202d238SPatrick Farrell   ierr = VecGetArrayRead(x, &globalRHS);CHKERRQ(ierr);
21901202d238SPatrick Farrell   ierr = VecGetArray(patch->localRHS, &localRHS);CHKERRQ(ierr);
21911202d238SPatrick Farrell   ierr = PetscSFBcastBegin(patch->defaultSF, MPIU_SCALAR, globalRHS, localRHS);CHKERRQ(ierr);
21921202d238SPatrick Farrell   ierr = PetscSFBcastEnd(patch->defaultSF, MPIU_SCALAR, globalRHS, localRHS);CHKERRQ(ierr);
21931202d238SPatrick Farrell   ierr = VecRestoreArrayRead(x, &globalRHS);CHKERRQ(ierr);
21941202d238SPatrick Farrell   ierr = VecRestoreArray(patch->localRHS, &localRHS);CHKERRQ(ierr);
21954bbf5ea8SMatthew G. Knepley 
21961202d238SPatrick Farrell   ierr = VecSet(patch->localUpdate, 0.0);CHKERRQ(ierr);
21974bbf5ea8SMatthew G. Knepley   ierr = PetscSectionGetChart(patch->gtolCounts, &pStart, NULL);CHKERRQ(ierr);
21984bbf5ea8SMatthew G. Knepley   for (sweep = 0; sweep < nsweep; sweep++) {
21994bbf5ea8SMatthew G. Knepley     for (j = start[sweep]; j*inc[sweep] < end[sweep]*inc[sweep]; j += inc[sweep]) {
22004bbf5ea8SMatthew G. Knepley       PetscInt i       = patch->user_patches ? iterationSet[j] : j;
22014bbf5ea8SMatthew G. Knepley       PetscInt start, len;
22024bbf5ea8SMatthew G. Knepley 
22034bbf5ea8SMatthew G. Knepley       ierr = PetscSectionGetDof(patch->gtolCounts, i+pStart, &len);CHKERRQ(ierr);
22044bbf5ea8SMatthew G. Knepley       ierr = PetscSectionGetOffset(patch->gtolCounts, i+pStart, &start);CHKERRQ(ierr);
22054bbf5ea8SMatthew G. Knepley       /* TODO: Squash out these guys in the setup as well. */
22064bbf5ea8SMatthew G. Knepley       if (len <= 0) continue;
22074bbf5ea8SMatthew G. Knepley       /* TODO: Do we need different scatters for X and Y? */
22080904074fSPatrick Farrell       ierr = PCPatch_ScatterLocal_Private(pc, i+pStart, patch->localRHS, patch->patchRHS[i], INSERT_VALUES, SCATTER_FORWARD, SCATTER_INTERIOR);CHKERRQ(ierr);
22091202d238SPatrick Farrell       ierr = (*patch->applysolver)(pc, i, patch->patchRHS[i], patch->patchUpdate[i]);CHKERRQ(ierr);
22100904074fSPatrick Farrell       ierr = PCPatch_ScatterLocal_Private(pc, i+pStart, patch->patchUpdate[i], patch->localUpdate, ADD_VALUES, SCATTER_REVERSE, SCATTER_INTERIOR);CHKERRQ(ierr);
221161c4b389SFlorian Wechsung       if(patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
22126c9c532dSPatrick Farrell         ierr = (*patch->updatemultiplicative)(pc, i, pStart);CHKERRQ(ierr);
2213c2e6f3c0SFlorian Wechsung       }
22144bbf5ea8SMatthew G. Knepley     }
22154bbf5ea8SMatthew G. Knepley   }
22164bbf5ea8SMatthew G. Knepley   if (patch->user_patches) {ierr = ISRestoreIndices(patch->iterationSet, &iterationSet);CHKERRQ(ierr);}
22174bbf5ea8SMatthew G. Knepley   /* XXX: should we do this on the global vector? */
221873ec7555SLawrence Mitchell   if (patch->partition_of_unity) {
22191202d238SPatrick Farrell     ierr = VecPointwiseMult(patch->localUpdate, patch->localUpdate, patch->dof_weights);CHKERRQ(ierr);
22204bbf5ea8SMatthew G. Knepley   }
22211202d238SPatrick Farrell   /* Now patch->localUpdate contains the solution of the patch solves, so we need to combine them all. */
22224bbf5ea8SMatthew G. Knepley   ierr = VecSet(y, 0.0);CHKERRQ(ierr);
22231202d238SPatrick Farrell   ierr = VecGetArray(y, &globalUpdate);CHKERRQ(ierr);
22241202d238SPatrick Farrell   ierr = VecGetArrayRead(patch->localUpdate, &localUpdate);CHKERRQ(ierr);
22251202d238SPatrick Farrell   ierr = PetscSFReduceBegin(patch->defaultSF, MPIU_SCALAR, localUpdate, globalUpdate, MPI_SUM);CHKERRQ(ierr);
22261202d238SPatrick Farrell   ierr = PetscSFReduceEnd(patch->defaultSF, MPIU_SCALAR, localUpdate, globalUpdate, MPI_SUM);CHKERRQ(ierr);
22271202d238SPatrick Farrell   ierr = VecRestoreArrayRead(patch->localUpdate, &localUpdate);CHKERRQ(ierr);
22284bbf5ea8SMatthew G. Knepley 
22294bbf5ea8SMatthew G. Knepley   /* Now we need to send the global BC values through */
22301202d238SPatrick Farrell   ierr = VecGetArrayRead(x, &globalRHS);CHKERRQ(ierr);
22314bbf5ea8SMatthew G. Knepley   ierr = ISGetSize(patch->globalBcNodes, &numBcs);CHKERRQ(ierr);
22324bbf5ea8SMatthew G. Knepley   ierr = ISGetIndices(patch->globalBcNodes, &bcNodes);CHKERRQ(ierr);
22334bbf5ea8SMatthew G. Knepley   ierr = VecGetLocalSize(x, &n);CHKERRQ(ierr);
22344bbf5ea8SMatthew G. Knepley   for (bc = 0; bc < numBcs; ++bc) {
22354bbf5ea8SMatthew G. Knepley     const PetscInt idx = bcNodes[bc];
22361202d238SPatrick Farrell     if (idx < n) globalUpdate[idx] = globalRHS[idx];
22374bbf5ea8SMatthew G. Knepley   }
22384bbf5ea8SMatthew G. Knepley 
22394bbf5ea8SMatthew G. Knepley   ierr = ISRestoreIndices(patch->globalBcNodes, &bcNodes);CHKERRQ(ierr);
22401202d238SPatrick Farrell   ierr = VecRestoreArrayRead(x, &globalRHS);CHKERRQ(ierr);
22411202d238SPatrick Farrell   ierr = VecRestoreArray(y, &globalUpdate);CHKERRQ(ierr);
22424bbf5ea8SMatthew G. Knepley 
22434bbf5ea8SMatthew G. Knepley   ierr = PetscOptionsPopGetViewerOff();CHKERRQ(ierr);
22444bbf5ea8SMatthew G. Knepley   ierr = PetscLogEventEnd(PC_Patch_Apply, pc, 0, 0, 0);CHKERRQ(ierr);
22454bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
22464bbf5ea8SMatthew G. Knepley }
22474bbf5ea8SMatthew G. Knepley 
2248dadc69c5SMatthew G. Knepley static PetscErrorCode PCReset_PATCH_Linear(PC pc)
2249dadc69c5SMatthew G. Knepley {
2250dadc69c5SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
2251dadc69c5SMatthew G. Knepley   PetscInt       i;
2252dadc69c5SMatthew G. Knepley   PetscErrorCode ierr;
2253dadc69c5SMatthew G. Knepley 
2254dadc69c5SMatthew G. Knepley   PetscFunctionBegin;
2255dadc69c5SMatthew G. Knepley   if (patch->solver) {
2256dadc69c5SMatthew G. Knepley     for (i = 0; i < patch->npatch; ++i) {ierr = KSPReset((KSP) patch->solver[i]);CHKERRQ(ierr);}
2257dadc69c5SMatthew G. Knepley   }
2258dadc69c5SMatthew G. Knepley   PetscFunctionReturn(0);
2259dadc69c5SMatthew G. Knepley }
2260dadc69c5SMatthew G. Knepley 
22614bbf5ea8SMatthew G. Knepley static PetscErrorCode PCReset_PATCH(PC pc)
22624bbf5ea8SMatthew G. Knepley {
22634bbf5ea8SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
22644bbf5ea8SMatthew G. Knepley   PetscInt       i;
22654bbf5ea8SMatthew G. Knepley   PetscErrorCode ierr;
22664bbf5ea8SMatthew G. Knepley 
22674bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
22684bbf5ea8SMatthew G. Knepley   /* TODO: Get rid of all these ifs */
22694bbf5ea8SMatthew G. Knepley   ierr = PetscSFDestroy(&patch->defaultSF);CHKERRQ(ierr);
22704bbf5ea8SMatthew G. Knepley   ierr = PetscSectionDestroy(&patch->cellCounts);CHKERRQ(ierr);
22715f824522SMatthew G. Knepley   ierr = PetscSectionDestroy(&patch->pointCounts);CHKERRQ(ierr);
22724bbf5ea8SMatthew G. Knepley   ierr = PetscSectionDestroy(&patch->cellNumbering);CHKERRQ(ierr);
22734bbf5ea8SMatthew G. Knepley   ierr = PetscSectionDestroy(&patch->gtolCounts);CHKERRQ(ierr);
22744bbf5ea8SMatthew G. Knepley   ierr = ISDestroy(&patch->gtol);CHKERRQ(ierr);
22754bbf5ea8SMatthew G. Knepley   ierr = ISDestroy(&patch->cells);CHKERRQ(ierr);
22765f824522SMatthew G. Knepley   ierr = ISDestroy(&patch->points);CHKERRQ(ierr);
22774bbf5ea8SMatthew G. Knepley   ierr = ISDestroy(&patch->dofs);CHKERRQ(ierr);
22785f824522SMatthew G. Knepley   ierr = ISDestroy(&patch->offs);CHKERRQ(ierr);
22795f824522SMatthew G. Knepley   ierr = PetscSectionDestroy(&patch->patchSection);CHKERRQ(ierr);
22804bbf5ea8SMatthew G. Knepley   ierr = ISDestroy(&patch->ghostBcNodes);CHKERRQ(ierr);
22814bbf5ea8SMatthew G. Knepley   ierr = ISDestroy(&patch->globalBcNodes);CHKERRQ(ierr);
228211ac8bb0SFlorian Wechsung   ierr = PetscSectionDestroy(&patch->gtolCountsWithArtificial);CHKERRQ(ierr);
228311ac8bb0SFlorian Wechsung   ierr = ISDestroy(&patch->gtolWithArtificial);CHKERRQ(ierr);
228411ac8bb0SFlorian Wechsung   ierr = ISDestroy(&patch->dofsWithArtificial);CHKERRQ(ierr);
228511ac8bb0SFlorian Wechsung   ierr = ISDestroy(&patch->offsWithArtificial);CHKERRQ(ierr);
22860904074fSPatrick Farrell   ierr = PetscSectionDestroy(&patch->gtolCountsWithAll);CHKERRQ(ierr);
22870904074fSPatrick Farrell   ierr = ISDestroy(&patch->gtolWithAll);CHKERRQ(ierr);
22880904074fSPatrick Farrell   ierr = ISDestroy(&patch->dofsWithAll);CHKERRQ(ierr);
22890904074fSPatrick Farrell   ierr = ISDestroy(&patch->offsWithAll);CHKERRQ(ierr);
229011ac8bb0SFlorian Wechsung 
22914bbf5ea8SMatthew G. Knepley 
22925f824522SMatthew G. Knepley   if (patch->dofSection) for (i = 0; i < patch->nsubspaces; i++) {ierr = PetscSectionDestroy(&patch->dofSection[i]);CHKERRQ(ierr);}
22934bbf5ea8SMatthew G. Knepley   ierr = PetscFree(patch->dofSection);CHKERRQ(ierr);
22944bbf5ea8SMatthew G. Knepley   ierr = PetscFree(patch->bs);CHKERRQ(ierr);
22954bbf5ea8SMatthew G. Knepley   ierr = PetscFree(patch->nodesPerCell);CHKERRQ(ierr);
22965f824522SMatthew G. Knepley   if (patch->cellNodeMap) for (i = 0; i < patch->nsubspaces; i++) {ierr = PetscFree(patch->cellNodeMap[i]);CHKERRQ(ierr);}
22974bbf5ea8SMatthew G. Knepley   ierr = PetscFree(patch->cellNodeMap);CHKERRQ(ierr);
22984bbf5ea8SMatthew G. Knepley   ierr = PetscFree(patch->subspaceOffsets);CHKERRQ(ierr);
22994bbf5ea8SMatthew G. Knepley 
2300dadc69c5SMatthew G. Knepley   ierr = (*patch->resetsolver)(pc);CHKERRQ(ierr);
23014bbf5ea8SMatthew G. Knepley 
2302e4c66b91SPatrick Farrell   if (patch->subspaces_to_exclude) {
2303e4c66b91SPatrick Farrell     PetscHSetIDestroy(&patch->subspaces_to_exclude);
2304e4c66b91SPatrick Farrell   }
2305e4c66b91SPatrick Farrell 
23061202d238SPatrick Farrell   ierr = VecDestroy(&patch->localRHS);CHKERRQ(ierr);
23071202d238SPatrick Farrell   ierr = VecDestroy(&patch->localUpdate);CHKERRQ(ierr);
23081202d238SPatrick Farrell   if (patch->patchRHS) {
23091202d238SPatrick Farrell     for (i = 0; i < patch->npatch; ++i) {ierr = VecDestroy(&patch->patchRHS[i]);CHKERRQ(ierr);}
23101202d238SPatrick Farrell     ierr = PetscFree(patch->patchRHS);CHKERRQ(ierr);
23114bbf5ea8SMatthew G. Knepley   }
23121202d238SPatrick Farrell   if (patch->patchUpdate) {
23131202d238SPatrick Farrell     for (i = 0; i < patch->npatch; ++i) {ierr = VecDestroy(&patch->patchUpdate[i]);CHKERRQ(ierr);}
23141202d238SPatrick Farrell     ierr = PetscFree(patch->patchUpdate);CHKERRQ(ierr);
23154bbf5ea8SMatthew G. Knepley   }
23164bbf5ea8SMatthew G. Knepley   ierr = VecDestroy(&patch->dof_weights);CHKERRQ(ierr);
23174bbf5ea8SMatthew G. Knepley   if (patch->patch_dof_weights) {
23185f824522SMatthew G. Knepley     for (i = 0; i < patch->npatch; ++i) {ierr = VecDestroy(&patch->patch_dof_weights[i]);CHKERRQ(ierr);}
23194bbf5ea8SMatthew G. Knepley     ierr = PetscFree(patch->patch_dof_weights);CHKERRQ(ierr);
23204bbf5ea8SMatthew G. Knepley   }
23214bbf5ea8SMatthew G. Knepley   if (patch->mat) {
23225f824522SMatthew G. Knepley     for (i = 0; i < patch->npatch; ++i) {ierr = MatDestroy(&patch->mat[i]);CHKERRQ(ierr);}
23234bbf5ea8SMatthew G. Knepley     ierr = PetscFree(patch->mat);CHKERRQ(ierr);
23245f824522SMatthew G. Knepley   }
232511ac8bb0SFlorian Wechsung   if (patch->matWithArtificial) {
232611ac8bb0SFlorian Wechsung     for (i = 0; i < patch->npatch; ++i) {ierr = MatDestroy(&patch->matWithArtificial[i]);CHKERRQ(ierr);}
232711ac8bb0SFlorian Wechsung     ierr = PetscFree(patch->matWithArtificial);CHKERRQ(ierr);
232811ac8bb0SFlorian Wechsung   }
23291202d238SPatrick Farrell   if (patch->patchRHSWithArtificial) {
23301202d238SPatrick Farrell     for (i = 0; i < patch->npatch; ++i) {ierr = VecDestroy(&patch->patchRHSWithArtificial[i]);CHKERRQ(ierr);}
23311202d238SPatrick Farrell     ierr = PetscFree(patch->patchRHSWithArtificial);CHKERRQ(ierr);
233211ac8bb0SFlorian Wechsung   }
233396b79ebeSFlorian Wechsung   if(patch->dofMappingWithoutToWithArtificial) {
233496b79ebeSFlorian Wechsung     for (i = 0; i < patch->npatch; ++i) {ierr = ISDestroy(&patch->dofMappingWithoutToWithArtificial[i]);CHKERRQ(ierr);}
233596b79ebeSFlorian Wechsung     ierr = PetscFree(patch->dofMappingWithoutToWithArtificial);CHKERRQ(ierr);
233696b79ebeSFlorian Wechsung 
233796b79ebeSFlorian Wechsung   }
23380904074fSPatrick Farrell   if(patch->dofMappingWithoutToWithAll) {
23390904074fSPatrick Farrell     for (i = 0; i < patch->npatch; ++i) {ierr = ISDestroy(&patch->dofMappingWithoutToWithAll[i]);CHKERRQ(ierr);}
23400904074fSPatrick Farrell     ierr = PetscFree(patch->dofMappingWithoutToWithAll);CHKERRQ(ierr);
23410904074fSPatrick Farrell 
23420904074fSPatrick Farrell   }
23434bbf5ea8SMatthew G. Knepley   ierr = PetscFree(patch->sub_mat_type);CHKERRQ(ierr);
23445f824522SMatthew G. Knepley   if (patch->userIS) {
23455f824522SMatthew G. Knepley     for (i = 0; i < patch->npatch; ++i) {ierr = ISDestroy(&patch->userIS[i]);CHKERRQ(ierr);}
23465f824522SMatthew G. Knepley     ierr = PetscFree(patch->userIS);CHKERRQ(ierr);
23475f824522SMatthew G. Knepley   }
23484bbf5ea8SMatthew G. Knepley   patch->bs          = 0;
23494bbf5ea8SMatthew G. Knepley   patch->cellNodeMap = NULL;
23507974b488SMatthew G. Knepley   patch->nsubspaces  = 0;
23514bbf5ea8SMatthew G. Knepley   ierr = ISDestroy(&patch->iterationSet);CHKERRQ(ierr);
23525f824522SMatthew G. Knepley 
23535f824522SMatthew G. Knepley   ierr = PetscViewerDestroy(&patch->viewerSection);CHKERRQ(ierr);
23544bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
23554bbf5ea8SMatthew G. Knepley }
23564bbf5ea8SMatthew G. Knepley 
2357dadc69c5SMatthew G. Knepley static PetscErrorCode PCDestroy_PATCH_Linear(PC pc)
23584bbf5ea8SMatthew G. Knepley {
23594bbf5ea8SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
23604bbf5ea8SMatthew G. Knepley   PetscInt       i;
23614bbf5ea8SMatthew G. Knepley   PetscErrorCode ierr;
23624bbf5ea8SMatthew G. Knepley 
23634bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
2364dadc69c5SMatthew G. Knepley   if (patch->solver) {
2365dadc69c5SMatthew G. Knepley     for (i = 0; i < patch->npatch; ++i) {ierr = KSPDestroy((KSP *) &patch->solver[i]);CHKERRQ(ierr);}
2366dadc69c5SMatthew G. Knepley     ierr = PetscFree(patch->solver);CHKERRQ(ierr);
23674bbf5ea8SMatthew G. Knepley   }
2368dadc69c5SMatthew G. Knepley   PetscFunctionReturn(0);
2369dadc69c5SMatthew G. Knepley }
2370dadc69c5SMatthew G. Knepley 
2371dadc69c5SMatthew G. Knepley static PetscErrorCode PCDestroy_PATCH(PC pc)
2372dadc69c5SMatthew G. Knepley {
2373dadc69c5SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
2374dadc69c5SMatthew G. Knepley   PetscErrorCode ierr;
2375dadc69c5SMatthew G. Knepley 
2376dadc69c5SMatthew G. Knepley   PetscFunctionBegin;
2377dadc69c5SMatthew G. Knepley   ierr = PCReset_PATCH(pc);CHKERRQ(ierr);
2378dadc69c5SMatthew G. Knepley   ierr = (*patch->destroysolver)(pc);CHKERRQ(ierr);
23794bbf5ea8SMatthew G. Knepley   ierr = PetscFree(pc->data);CHKERRQ(ierr);
23804bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
23814bbf5ea8SMatthew G. Knepley }
23824bbf5ea8SMatthew G. Knepley 
23834bbf5ea8SMatthew G. Knepley static PetscErrorCode PCSetFromOptions_PATCH(PetscOptionItems *PetscOptionsObject, PC pc)
23844bbf5ea8SMatthew G. Knepley {
23854bbf5ea8SMatthew G. Knepley   PC_PATCH            *patch = (PC_PATCH *) pc->data;
23864bbf5ea8SMatthew G. Knepley   PCPatchConstructType patchConstructionType = PC_PATCH_STAR;
23875f824522SMatthew G. Knepley   char                 sub_mat_type[PETSC_MAX_PATH_LEN];
238810534d48SPatrick Farrell   char                 option[PETSC_MAX_PATH_LEN];
23895f824522SMatthew G. Knepley   const char          *prefix;
23904bbf5ea8SMatthew G. Knepley   PetscBool            flg, dimflg, codimflg;
23915f824522SMatthew G. Knepley   MPI_Comm             comm;
2392a48c39c8SPatrick Farrell   PetscInt            *ifields, nfields, k;
23934bbf5ea8SMatthew G. Knepley   PetscErrorCode       ierr;
239461c4b389SFlorian Wechsung   PCCompositeType loctype = PC_COMPOSITE_ADDITIVE;
23954bbf5ea8SMatthew G. Knepley 
23964bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
23975f824522SMatthew G. Knepley   ierr = PetscObjectGetComm((PetscObject) pc, &comm);CHKERRQ(ierr);
23985f824522SMatthew G. Knepley   ierr = PetscObjectGetOptionsPrefix((PetscObject) pc, &prefix);CHKERRQ(ierr);
239910534d48SPatrick Farrell   ierr = PetscOptionsHead(PetscOptionsObject, "Patch solver options");CHKERRQ(ierr);
240010534d48SPatrick Farrell 
240110534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_save_operators", patch->classname);
240210534d48SPatrick Farrell   ierr = PetscOptionsBool(option,  "Store all patch operators for lifetime of object?", "PCPatchSetSaveOperators", patch->save_operators, &patch->save_operators, &flg);CHKERRQ(ierr);
240310534d48SPatrick Farrell 
240410534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_partition_of_unity", patch->classname);
240510534d48SPatrick Farrell   ierr = PetscOptionsBool(option, "Weight contributions by dof multiplicity?", "PCPatchSetPartitionOfUnity", patch->partition_of_unity, &patch->partition_of_unity, &flg);CHKERRQ(ierr);
240610534d48SPatrick Farrell 
240710534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_local_type", patch->classname);
240810534d48SPatrick Farrell   ierr = PetscOptionsEnum(option,"Type of local solver composition (additive or multiplicative)","PCPatchSetLocalComposition",PCCompositeTypes,(PetscEnum)loctype,(PetscEnum*)&loctype,&flg);CHKERRQ(ierr);
240961c4b389SFlorian Wechsung   if(flg) { ierr = PCPatchSetLocalComposition(pc, loctype);CHKERRQ(ierr);}
241010534d48SPatrick Farrell 
241110534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_construct_dim", patch->classname);
241210534d48SPatrick Farrell   ierr = PetscOptionsInt(option, "What dimension of mesh point to construct patches by? (0 = vertices)", "PCPATCH", patch->dim, &patch->dim, &dimflg);CHKERRQ(ierr);
241310534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_construct_codim", patch->classname);
241410534d48SPatrick Farrell   ierr = PetscOptionsInt(option, "What co-dimension of mesh point to construct patches by? (0 = cells)", "PCPATCH", patch->codim, &patch->codim, &codimflg);CHKERRQ(ierr);
241561c4b389SFlorian Wechsung   if (dimflg && codimflg) {SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Can only set one of dimension or co-dimension");CHKERRQ(ierr);}
241610534d48SPatrick Farrell 
241710534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_construct_type", patch->classname);
241810534d48SPatrick Farrell   ierr = PetscOptionsEnum(option, "How should the patches be constructed?", "PCPatchSetConstructType", PCPatchConstructTypes, (PetscEnum) patchConstructionType, (PetscEnum *) &patchConstructionType, &flg);CHKERRQ(ierr);
24194bbf5ea8SMatthew G. Knepley   if (flg) {ierr = PCPatchSetConstructType(pc, patchConstructionType, NULL, NULL);CHKERRQ(ierr);}
242010534d48SPatrick Farrell 
242110534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_vanka_dim", patch->classname);
242210534d48SPatrick Farrell   ierr = PetscOptionsInt(option, "Topological dimension of entities for Vanka to ignore", "PCPATCH", patch->vankadim, &patch->vankadim, &flg);CHKERRQ(ierr);
242310534d48SPatrick Farrell 
242410534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_ignore_dim", patch->classname);
242510534d48SPatrick Farrell   ierr = PetscOptionsInt(option, "Topological dimension of entities for completion to ignore", "PCPATCH", patch->ignoredim, &patch->ignoredim, &flg);CHKERRQ(ierr);
242610534d48SPatrick Farrell 
242710534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_sub_mat_type", patch->classname);
242810534d48SPatrick Farrell   ierr = PetscOptionsFList(option, "Matrix type for patch solves", "PCPatchSetSubMatType", MatList, NULL, sub_mat_type, PETSC_MAX_PATH_LEN, &flg);CHKERRQ(ierr);
24294bbf5ea8SMatthew G. Knepley   if (flg) {ierr = PCPatchSetSubMatType(pc, sub_mat_type);CHKERRQ(ierr);}
243010534d48SPatrick Farrell 
243110534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_symmetrise_sweep", patch->classname);
243210534d48SPatrick Farrell   ierr = PetscOptionsBool(option, "Go start->end, end->start?", "PCPATCH", patch->symmetrise_sweep, &patch->symmetrise_sweep, &flg);CHKERRQ(ierr);
2433e4c66b91SPatrick Farrell 
2434a48c39c8SPatrick Farrell   /* If the user has set the number of subspaces, use that for the buffer size,
2435a48c39c8SPatrick Farrell      otherwise use a large number */
2436a48c39c8SPatrick Farrell   if (patch->nsubspaces <= 0) {
2437a48c39c8SPatrick Farrell     nfields = 128;
2438a48c39c8SPatrick Farrell   } else {
2439a48c39c8SPatrick Farrell     nfields = patch->nsubspaces;
2440a48c39c8SPatrick Farrell   }
2441a48c39c8SPatrick Farrell   ierr = PetscMalloc1(nfields, &ifields);CHKERRQ(ierr);
244210534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_exclude_subspaces", patch->classname);
244310534d48SPatrick Farrell   ierr = PetscOptionsGetIntArray(((PetscObject)pc)->options,((PetscObject)pc)->prefix,option,ifields,&nfields,&flg);CHKERRQ(ierr);
2444e4c66b91SPatrick 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");
2445e4c66b91SPatrick Farrell   if (flg) {
2446e4c66b91SPatrick Farrell     PetscHSetIClear(patch->subspaces_to_exclude);
244759b66c28SPatrick Farrell     for (k = 0; k < nfields; k++) {
2448e4c66b91SPatrick Farrell       PetscHSetIAdd(patch->subspaces_to_exclude, ifields[k]);
2449e4c66b91SPatrick Farrell     }
2450e4c66b91SPatrick Farrell   }
245159b66c28SPatrick Farrell   ierr = PetscFree(ifields);CHKERRQ(ierr);
24525f824522SMatthew G. Knepley 
245310534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_patches_view", patch->classname);
245410534d48SPatrick Farrell   ierr = PetscOptionsBool(option, "Print out information during patch construction", "PCPATCH", patch->viewPatches, &patch->viewPatches, &flg);CHKERRQ(ierr);
245510534d48SPatrick Farrell 
245610534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_cells_view", patch->classname);
245710534d48SPatrick Farrell   ierr = PetscOptionsGetViewer(comm,((PetscObject) pc)->options,prefix, option,   &patch->viewerCells,   &patch->formatCells,   &patch->viewCells);CHKERRQ(ierr);
245810534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_points_view", patch->classname);
245910534d48SPatrick Farrell   ierr = PetscOptionsGetViewer(comm,((PetscObject) pc)->options,prefix, option,  &patch->viewerPoints,  &patch->formatPoints,  &patch->viewPoints);CHKERRQ(ierr);
246010534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_section_view", patch->classname);
246110534d48SPatrick Farrell   ierr = PetscOptionsGetViewer(comm,((PetscObject) pc)->options,prefix, option, &patch->viewerSection, &patch->formatSection, &patch->viewSection);CHKERRQ(ierr);
246210534d48SPatrick Farrell   ierr = PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_mat_view", patch->classname);
246310534d48SPatrick Farrell   ierr = PetscOptionsGetViewer(comm,((PetscObject) pc)->options,prefix, option,     &patch->viewerMatrix,  &patch->formatMatrix,  &patch->viewMatrix);CHKERRQ(ierr);
24644bbf5ea8SMatthew G. Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
24655f824522SMatthew G. Knepley   patch->optionsSet = PETSC_TRUE;
24664bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
24674bbf5ea8SMatthew G. Knepley }
24684bbf5ea8SMatthew G. Knepley 
24694bbf5ea8SMatthew G. Knepley static PetscErrorCode PCSetUpOnBlocks_PATCH(PC pc)
24704bbf5ea8SMatthew G. Knepley {
24714bbf5ea8SMatthew G. Knepley   PC_PATCH          *patch = (PC_PATCH*) pc->data;
24724bbf5ea8SMatthew G. Knepley   KSPConvergedReason reason;
24734bbf5ea8SMatthew G. Knepley   PetscInt           i;
24744bbf5ea8SMatthew G. Knepley   PetscErrorCode     ierr;
24754bbf5ea8SMatthew G. Knepley 
24764bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
2477a1eac568SLawrence Mitchell   if (!patch->save_operators) {
2478a1eac568SLawrence Mitchell     /* Can't do this here because the sub KSPs don't have an operator attached yet. */
2479a1eac568SLawrence Mitchell     PetscFunctionReturn(0);
2480a1eac568SLawrence Mitchell   }
24814bbf5ea8SMatthew G. Knepley   for (i = 0; i < patch->npatch; ++i) {
2482dadc69c5SMatthew G. Knepley     if (!((KSP) patch->solver[i])->setfromoptionscalled) {
2483dadc69c5SMatthew G. Knepley       ierr = KSPSetFromOptions((KSP) patch->solver[i]);CHKERRQ(ierr);
2484a1eac568SLawrence Mitchell     }
2485dadc69c5SMatthew G. Knepley     ierr = KSPSetUp((KSP) patch->solver[i]);CHKERRQ(ierr);
2486dadc69c5SMatthew G. Knepley     ierr = KSPGetConvergedReason((KSP) patch->solver[i], &reason);CHKERRQ(ierr);
24874bbf5ea8SMatthew G. Knepley     if (reason == KSP_DIVERGED_PCSETUP_FAILED) pc->failedreason = PC_SUBPC_ERROR;
24884bbf5ea8SMatthew G. Knepley   }
24894bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
24904bbf5ea8SMatthew G. Knepley }
24914bbf5ea8SMatthew G. Knepley 
24924bbf5ea8SMatthew G. Knepley static PetscErrorCode PCView_PATCH(PC pc, PetscViewer viewer)
24934bbf5ea8SMatthew G. Knepley {
24944bbf5ea8SMatthew G. Knepley   PC_PATCH      *patch = (PC_PATCH *) pc->data;
24954bbf5ea8SMatthew G. Knepley   PetscViewer    sviewer;
24964bbf5ea8SMatthew G. Knepley   PetscBool      isascii;
24974bbf5ea8SMatthew G. Knepley   PetscMPIInt    rank;
24984bbf5ea8SMatthew G. Knepley   PetscErrorCode ierr;
24994bbf5ea8SMatthew G. Knepley 
25004bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
25014bbf5ea8SMatthew G. Knepley   /* TODO Redo tabbing with set tbas in new style */
25024bbf5ea8SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &isascii);CHKERRQ(ierr);
25034bbf5ea8SMatthew G. Knepley   if (!isascii) PetscFunctionReturn(0);
25044bbf5ea8SMatthew G. Knepley   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) pc), &rank);CHKERRQ(ierr);
25054bbf5ea8SMatthew G. Knepley   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
25064bbf5ea8SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "Subspace Correction preconditioner with %d patches\n", patch->npatch);CHKERRQ(ierr);
250761c4b389SFlorian Wechsung   if(patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) {
2508c2e6f3c0SFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Schwarz type: multiplicative\n");CHKERRQ(ierr);
2509e047a90bSFlorian Wechsung   } else {
251073ec7555SLawrence Mitchell     ierr = PetscViewerASCIIPrintf(viewer, "Schwarz type: additive\n");CHKERRQ(ierr);
2511c2e6f3c0SFlorian Wechsung   }
25124bbf5ea8SMatthew G. Knepley   if (patch->partition_of_unity) {ierr = PetscViewerASCIIPrintf(viewer, "Weighting by partition of unity\n");CHKERRQ(ierr);}
25134bbf5ea8SMatthew G. Knepley   else                           {ierr = PetscViewerASCIIPrintf(viewer, "Not weighting by partition of unity\n");CHKERRQ(ierr);}
25144bbf5ea8SMatthew G. Knepley   if (patch->symmetrise_sweep) {ierr = PetscViewerASCIIPrintf(viewer, "Symmetrising sweep (start->end, then end->start)\n");CHKERRQ(ierr);}
25154bbf5ea8SMatthew G. Knepley   else                         {ierr = PetscViewerASCIIPrintf(viewer, "Not symmetrising sweep\n");CHKERRQ(ierr);}
25164bbf5ea8SMatthew G. Knepley   if (!patch->save_operators) {ierr = PetscViewerASCIIPrintf(viewer, "Not saving patch operators (rebuilt every PCApply)\n");CHKERRQ(ierr);}
25174bbf5ea8SMatthew G. Knepley   else                        {ierr = PetscViewerASCIIPrintf(viewer, "Saving patch operators (rebuilt every PCSetUp)\n");CHKERRQ(ierr);}
25184bbf5ea8SMatthew G. Knepley   if (patch->patchconstructop == PCPatchConstruct_Star)       {ierr = PetscViewerASCIIPrintf(viewer, "Patch construction operator: star\n");CHKERRQ(ierr);}
25194bbf5ea8SMatthew G. Knepley   else if (patch->patchconstructop == PCPatchConstruct_Vanka) {ierr = PetscViewerASCIIPrintf(viewer, "Patch construction operator: Vanka\n");CHKERRQ(ierr);}
25204bbf5ea8SMatthew G. Knepley   else if (patch->patchconstructop == PCPatchConstruct_User)  {ierr = PetscViewerASCIIPrintf(viewer, "Patch construction operator: user-specified\n");CHKERRQ(ierr);}
25214bbf5ea8SMatthew G. Knepley   else                                                        {ierr = PetscViewerASCIIPrintf(viewer, "Patch construction operator: unknown\n");CHKERRQ(ierr);}
2522dadc69c5SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "Solver on patches (all same):\n");CHKERRQ(ierr);
2523dadc69c5SMatthew G. Knepley   if (patch->solver) {
25244bbf5ea8SMatthew G. Knepley     ierr = PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer);CHKERRQ(ierr);
25254bbf5ea8SMatthew G. Knepley     if (!rank) {
25264bbf5ea8SMatthew G. Knepley       ierr = PetscViewerASCIIPushTab(sviewer);CHKERRQ(ierr);
2527dadc69c5SMatthew G. Knepley       ierr = PetscObjectView(patch->solver[0], sviewer);CHKERRQ(ierr);
25284bbf5ea8SMatthew G. Knepley       ierr = PetscViewerASCIIPopTab(sviewer);CHKERRQ(ierr);
25294bbf5ea8SMatthew G. Knepley     }
25304bbf5ea8SMatthew G. Knepley     ierr = PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer);CHKERRQ(ierr);
25314bbf5ea8SMatthew G. Knepley   } else {
25324bbf5ea8SMatthew G. Knepley     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
2533dadc69c5SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(viewer, "Solver not yet set.\n");CHKERRQ(ierr);
25344bbf5ea8SMatthew G. Knepley     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
25354bbf5ea8SMatthew G. Knepley   }
25364bbf5ea8SMatthew G. Knepley   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
25374bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
25384bbf5ea8SMatthew G. Knepley }
25394bbf5ea8SMatthew G. Knepley 
2540e5893cccSMatthew G. Knepley /*MC
254198ed095eSMatthew G. Knepley   PCPATCH - A PC object that encapsulates flexible definition of blocks for overlapping and non-overlapping
254298ed095eSMatthew G. Knepley             small block additive preconditioners. Block definition is based on topology from
2543e5893cccSMatthew G. Knepley             a DM and equation numbering from a PetscSection.
2544e5893cccSMatthew G. Knepley 
2545e5893cccSMatthew G. Knepley   Options Database Keys:
2546e5893cccSMatthew G. Knepley + -pc_patch_cells_view   - Views the process local cell numbers for each patch
2547e5893cccSMatthew G. Knepley . -pc_patch_points_view  - Views the process local mesh point numbers for each patch
2548e5893cccSMatthew G. Knepley . -pc_patch_g2l_view     - Views the map between global dofs and patch local dofs for each patch
2549e5893cccSMatthew G. Knepley . -pc_patch_patches_view - Views the global dofs associated with each patch and its boundary
2550e5893cccSMatthew G. Knepley - -pc_patch_sub_mat_view - Views the matrix associated with each patch
2551e5893cccSMatthew G. Knepley 
2552e5893cccSMatthew G. Knepley   Level: intermediate
2553e5893cccSMatthew G. Knepley 
2554e5893cccSMatthew G. Knepley .seealso: PCType, PCCreate(), PCSetType()
2555e5893cccSMatthew G. Knepley M*/
2556642283e9SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PCCreate_Patch(PC pc)
25574bbf5ea8SMatthew G. Knepley {
25584bbf5ea8SMatthew G. Knepley   PC_PATCH      *patch;
25594bbf5ea8SMatthew G. Knepley   PetscErrorCode ierr;
25604bbf5ea8SMatthew G. Knepley 
25614bbf5ea8SMatthew G. Knepley   PetscFunctionBegin;
25624bbf5ea8SMatthew G. Knepley   ierr = PetscNewLog(pc, &patch);CHKERRQ(ierr);
25634bbf5ea8SMatthew G. Knepley 
2564e4c66b91SPatrick Farrell   if (patch->subspaces_to_exclude) {
2565e4c66b91SPatrick Farrell     PetscHSetIDestroy(&patch->subspaces_to_exclude);
2566e4c66b91SPatrick Farrell   }
2567e4c66b91SPatrick Farrell   PetscHSetICreate(&patch->subspaces_to_exclude);
2568e4c66b91SPatrick Farrell 
256910534d48SPatrick Farrell   patch->classname = "pc";
2570debbdec3SPatrick Farrell   patch->isNonlinear = PETSC_FALSE;
257110534d48SPatrick Farrell 
25724bbf5ea8SMatthew G. Knepley   /* Set some defaults */
25735f824522SMatthew G. Knepley   patch->combined           = PETSC_FALSE;
25744bbf5ea8SMatthew G. Knepley   patch->save_operators     = PETSC_TRUE;
257561c4b389SFlorian Wechsung   patch->local_composition_type = PC_COMPOSITE_ADDITIVE;
25764bbf5ea8SMatthew G. Knepley   patch->partition_of_unity = PETSC_FALSE;
25774bbf5ea8SMatthew G. Knepley   patch->codim              = -1;
25784bbf5ea8SMatthew G. Knepley   patch->dim                = -1;
25794bbf5ea8SMatthew G. Knepley   patch->vankadim           = -1;
25805f824522SMatthew G. Knepley   patch->ignoredim          = -1;
25814bbf5ea8SMatthew G. Knepley   patch->patchconstructop   = PCPatchConstruct_Star;
25824bbf5ea8SMatthew G. Knepley   patch->symmetrise_sweep   = PETSC_FALSE;
25835f824522SMatthew G. Knepley   patch->npatch             = 0;
25844bbf5ea8SMatthew G. Knepley   patch->userIS             = NULL;
25855f824522SMatthew G. Knepley   patch->optionsSet         = PETSC_FALSE;
25864bbf5ea8SMatthew G. Knepley   patch->iterationSet       = NULL;
25874bbf5ea8SMatthew G. Knepley   patch->user_patches       = PETSC_FALSE;
25885f824522SMatthew G. Knepley   ierr = PetscStrallocpy(MATDENSE, (char **) &patch->sub_mat_type);CHKERRQ(ierr);
25895f824522SMatthew G. Knepley   patch->viewPatches        = PETSC_FALSE;
25905f824522SMatthew G. Knepley   patch->viewCells          = PETSC_FALSE;
25915f824522SMatthew G. Knepley   patch->viewPoints         = PETSC_FALSE;
25925f824522SMatthew G. Knepley   patch->viewSection        = PETSC_FALSE;
25935f824522SMatthew G. Knepley   patch->viewMatrix         = PETSC_FALSE;
2594dadc69c5SMatthew G. Knepley   patch->setupsolver        = PCSetUp_PATCH_Linear;
2595dadc69c5SMatthew G. Knepley   patch->applysolver        = PCApply_PATCH_Linear;
2596dadc69c5SMatthew G. Knepley   patch->resetsolver        = PCReset_PATCH_Linear;
2597dadc69c5SMatthew G. Knepley   patch->destroysolver      = PCDestroy_PATCH_Linear;
25986c9c532dSPatrick Farrell   patch->updatemultiplicative = PCUpdateMultiplicative_PATCH_Linear;
25994bbf5ea8SMatthew G. Knepley 
26004bbf5ea8SMatthew G. Knepley   pc->data                 = (void *) patch;
26014bbf5ea8SMatthew G. Knepley   pc->ops->apply           = PCApply_PATCH;
26024bbf5ea8SMatthew G. Knepley   pc->ops->applytranspose  = 0; /* PCApplyTranspose_PATCH; */
26034bbf5ea8SMatthew G. Knepley   pc->ops->setup           = PCSetUp_PATCH;
26044bbf5ea8SMatthew G. Knepley   pc->ops->reset           = PCReset_PATCH;
26054bbf5ea8SMatthew G. Knepley   pc->ops->destroy         = PCDestroy_PATCH;
26064bbf5ea8SMatthew G. Knepley   pc->ops->setfromoptions  = PCSetFromOptions_PATCH;
26074bbf5ea8SMatthew G. Knepley   pc->ops->setuponblocks   = PCSetUpOnBlocks_PATCH;
26084bbf5ea8SMatthew G. Knepley   pc->ops->view            = PCView_PATCH;
26094bbf5ea8SMatthew G. Knepley   pc->ops->applyrichardson = 0;
26104bbf5ea8SMatthew G. Knepley 
26114bbf5ea8SMatthew G. Knepley   PetscFunctionReturn(0);
26124bbf5ea8SMatthew G. Knepley }
2613