Thanks, sounds like something DMPLEX should be automatically optionally doing directly.
> On Oct 28, 2021, at 10:58 AM, Lawrence Mitchell <we...@gmx.li> wrote: > > Hi Barry et al., > >> On 28 Oct 2021, at 15:37, Barry Smith <bsm...@petsc.dev> wrote: >> >> >> >>> On Oct 28, 2021, at 10:31 AM, Matthew Knepley <knep...@gmail.com> wrote: >>> >>> On Thu, Oct 28, 2021 at 9:37 AM Barry Smith <bsm...@petsc.dev> wrote: >>> >>> Matt, >>> >>> How difficult would it be to rework DMPLEX to allow the use of VecGhost? >>> We have performance problems with GPUs with simple DMNETWORK models because >>> the code spends more time uselessly copying the local part of the vector to >>> another vector in global to local and local to global; more than 1/2 the >>> time of the total simulation. >>> >>> Firedrake already does this because they "vec ghost" their vectors by >>> default. Here is what you need: >>> >>> When you create the PetscSection, by default it orders the unknowns >>> according to the default point numbering. This >>> is what causes the ghost unknowns to be mixed in with the local unknowns. >>> However, PetscSection allows you to set >>> a point permutation >>> >>> >>> https://petsc.org/main/docs/manualpages/PetscSection/PetscSectionSetPermutation.html >>> >>> This determines the order of dogs by iterating through points in this >>> permutation, and you can put all shared points at the end. >> >> How do I know what are shared points to put at the end? Couldn't DMPLEX do >> this automatically with an option? Where is the Firedrake code that does >> this with DMPLEX so I can see it? > > The DM's "point sf" indicates shared points. To label them, do something like: > > DMCreateLabel(dm, "ghost_points"); > DMGetPointSF(dm, &pointsf); > PetscSFGetGraph(pointsf, NULL, &nleaves, &ilocal, NULL); > for (PetscInt p = 0; p < nleaves; p++) { > DMSetLabelValue(dm, "ghost_points", p, 1); > } > > Then you do something like (this is more pseudo-codey): > > PetscInt *permutation; > DMPlexGetChart(dm, &pStart, &pEnd); > PetscMalloc1(pEnd - pStart, &permutation); > PetscInt offsets[2] = {0, pEnd - pStart - nleaves}; > DMGetLabel(dm, &ghosts); > DMLabelCreateIndex(ghosts, pStart, pEnd); > for (PetscInt p = pStart, p < pEnd; p++) { > DMLabelHasPoint(ghosts, p, &has); > if (has) { > // this point is ghost point > permutation[offsets[1]++] = p; > } else { > permutation[offsets[0]++] = p; > } > } > DMLabelDestroyIndex(ghosts, pStart, pEnd); > ISCreateGeneral(..., permutation, &isperm); > > // Now whenever your do PetscSectionCreate, do > PetscSectionSetPermutation(..., isperm); > > And now ghost point dofs will appear after local ones. > > Note that this is probably more complicated for multi-field setups, depending > whether you are point major or field major. > > You can see what we actually do (if you like reading Cython) here: > https://github.com/firedrakeproject/firedrake/blob/master/firedrake/cython/dmcommon.pyx#L1734 > > It's more complicated because here we are doing some additional things: > > 1. We compute an RCM-order traversal for cells with DMPlexGetOrdering; > 2. Rather than ordering all plex points in the permutation, we walk the cells > in the RCM order and then greedily number points in the transitive closure > (so that in a section cell and vertex dofs from the same cell will be "close" > to each other in the final Vec). > > Thanks, > > Lawrence