Hi Barry et al.,

> On 28 Oct 2021, at 15:37, Barry Smith <[email protected]> wrote:
> 
> 
> 
>> On Oct 28, 2021, at 10:31 AM, Matthew Knepley <[email protected]> wrote:
>> 
>> On Thu, Oct 28, 2021 at 9:37 AM Barry Smith <[email protected]> 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

Reply via email to