xref: /petsc/src/vec/is/sf/interface/sf.c (revision c02794c0a446ba929ccbfdb96e2d43802d96134a)
1af0996ceSBarry Smith #include <petsc/private/sfimpl.h> /*I "petscsf.h" I*/
2c4e6a40aSLawrence Mitchell #include <petsc/private/hashseti.h>
353dd6d7dSJunchao Zhang #include <petsc/private/viewerimpl.h>
4eec179cfSJacob Faibussowitsch #include <petsc/private/hashmapi.h>
595fce210SBarry Smith 
67fd2d3dbSJunchao Zhang #if defined(PETSC_HAVE_CUDA)
77fd2d3dbSJunchao Zhang   #include <cuda_runtime.h>
8715b587bSJunchao Zhang   #include <petscdevice_cuda.h>
97fd2d3dbSJunchao Zhang #endif
107fd2d3dbSJunchao Zhang 
117fd2d3dbSJunchao Zhang #if defined(PETSC_HAVE_HIP)
127fd2d3dbSJunchao Zhang   #include <hip/hip_runtime.h>
137fd2d3dbSJunchao Zhang #endif
147fd2d3dbSJunchao Zhang 
152abc8c78SJacob Faibussowitsch #if defined(PETSC_CLANG_STATIC_ANALYZER)
164bf303faSJacob Faibussowitsch extern void PetscSFCheckGraphSet(PetscSF, int);
172abc8c78SJacob Faibussowitsch #else
1895fce210SBarry Smith   #if defined(PETSC_USE_DEBUG)
19a8f51744SPierre Jolivet     #define PetscSFCheckGraphSet(sf, arg) PetscCheck((sf)->graphset, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call PetscSFSetGraph() or PetscSFSetGraphWithPattern() on argument %d \"%s\" before %s()", (arg), #sf, PETSC_FUNCTION_NAME)
2095fce210SBarry Smith   #else
219371c9d4SSatish Balay     #define PetscSFCheckGraphSet(sf, arg) \
229371c9d4SSatish Balay       do { \
239371c9d4SSatish Balay       } while (0)
2495fce210SBarry Smith   #endif
252abc8c78SJacob Faibussowitsch #endif
2695fce210SBarry Smith 
274c8fdceaSLisandro Dalcin const char *const PetscSFDuplicateOptions[]     = {"CONFONLY", "RANKS", "GRAPH", "PetscSFDuplicateOption", "PETSCSF_DUPLICATE_", NULL};
281f40158dSVaclav Hapla const char *const PetscSFConcatenateRootModes[] = {"local", "shared", "global", "PetscSFConcatenateRootMode", "PETSCSF_CONCATENATE_ROOTMODE_", NULL};
2995fce210SBarry Smith 
308af6ec1cSBarry Smith /*@
3195fce210SBarry Smith   PetscSFCreate - create a star forest communication context
3295fce210SBarry Smith 
33d083f849SBarry Smith   Collective
3495fce210SBarry Smith 
354165533cSJose E. Roman   Input Parameter:
3695fce210SBarry Smith . comm - communicator on which the star forest will operate
3795fce210SBarry Smith 
384165533cSJose E. Roman   Output Parameter:
3995fce210SBarry Smith . sf - new star forest context
4095fce210SBarry Smith 
4120662ed9SBarry Smith   Options Database Key:
42cab54364SBarry Smith . -sf_type type - value of type may be
43cab54364SBarry Smith .vb
44cab54364SBarry Smith     basic     -Use MPI persistent Isend/Irecv for communication (Default)
45cab54364SBarry Smith     window    -Use MPI-3 one-sided window for communication
46cab54364SBarry Smith     neighbor  -Use MPI-3 neighborhood collectives for communication
47cab54364SBarry Smith .ve
48dd5b3ca6SJunchao Zhang 
4995fce210SBarry Smith   Level: intermediate
5095fce210SBarry Smith 
51cab54364SBarry Smith   Note:
52cab54364SBarry Smith   When one knows the communication graph is one of the predefined graph, such as `MPI_Alltoall()`, `MPI_Allgatherv()`,
53cab54364SBarry Smith   `MPI_Gatherv()`, one can create a `PetscSF` and then set its graph with `PetscSFSetGraphWithPattern()`. These special
5420662ed9SBarry Smith   `SF`s are optimized and they have better performance than the general `SF`s.
55dd5b3ca6SJunchao Zhang 
5638b5cf2dSJacob Faibussowitsch .seealso: `PetscSF`, `PetscSFSetType`, `PetscSFSetGraph()`, `PetscSFSetGraphWithPattern()`, `PetscSFDestroy()`
5795fce210SBarry Smith @*/
58d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFCreate(MPI_Comm comm, PetscSF *sf)
59d71ae5a4SJacob Faibussowitsch {
6095fce210SBarry Smith   PetscSF b;
6195fce210SBarry Smith 
6295fce210SBarry Smith   PetscFunctionBegin;
634f572ea9SToby Isaac   PetscAssertPointer(sf, 2);
649566063dSJacob Faibussowitsch   PetscCall(PetscSFInitializePackage());
6595fce210SBarry Smith 
669566063dSJacob Faibussowitsch   PetscCall(PetscHeaderCreate(b, PETSCSF_CLASSID, "PetscSF", "Star Forest", "PetscSF", comm, PetscSFDestroy, PetscSFView));
6795fce210SBarry Smith 
6895fce210SBarry Smith   b->nroots    = -1;
6995fce210SBarry Smith   b->nleaves   = -1;
7029046d53SLisandro Dalcin   b->minleaf   = PETSC_MAX_INT;
7129046d53SLisandro Dalcin   b->maxleaf   = PETSC_MIN_INT;
7295fce210SBarry Smith   b->nranks    = -1;
7395fce210SBarry Smith   b->rankorder = PETSC_TRUE;
7495fce210SBarry Smith   b->ingroup   = MPI_GROUP_NULL;
7595fce210SBarry Smith   b->outgroup  = MPI_GROUP_NULL;
7695fce210SBarry Smith   b->graphset  = PETSC_FALSE;
7720c24465SJunchao Zhang #if defined(PETSC_HAVE_DEVICE)
7820c24465SJunchao Zhang   b->use_gpu_aware_mpi    = use_gpu_aware_mpi;
7920c24465SJunchao Zhang   b->use_stream_aware_mpi = PETSC_FALSE;
8071438e86SJunchao Zhang   b->unknown_input_stream = PETSC_FALSE;
8127f636e8SJunchao Zhang   #if defined(PETSC_HAVE_KOKKOS) /* Prefer kokkos over cuda*/
8220c24465SJunchao Zhang   b->backend = PETSCSF_BACKEND_KOKKOS;
8327f636e8SJunchao Zhang   #elif defined(PETSC_HAVE_CUDA)
8427f636e8SJunchao Zhang   b->backend = PETSCSF_BACKEND_CUDA;
8559af0bd3SScott Kruger   #elif defined(PETSC_HAVE_HIP)
8659af0bd3SScott Kruger   b->backend = PETSCSF_BACKEND_HIP;
8720c24465SJunchao Zhang   #endif
8871438e86SJunchao Zhang 
8971438e86SJunchao Zhang   #if defined(PETSC_HAVE_NVSHMEM)
9071438e86SJunchao Zhang   b->use_nvshmem     = PETSC_FALSE; /* Default is not to try NVSHMEM */
9171438e86SJunchao Zhang   b->use_nvshmem_get = PETSC_FALSE; /* Default is to use nvshmem_put based protocol */
929566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-use_nvshmem", &b->use_nvshmem, NULL));
939566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-use_nvshmem_get", &b->use_nvshmem_get, NULL));
9471438e86SJunchao Zhang   #endif
9520c24465SJunchao Zhang #endif
9660c22052SBarry Smith   b->vscat.from_n = -1;
9760c22052SBarry Smith   b->vscat.to_n   = -1;
9860c22052SBarry Smith   b->vscat.unit   = MPIU_SCALAR;
9995fce210SBarry Smith   *sf             = b;
1003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10195fce210SBarry Smith }
10295fce210SBarry Smith 
10329046d53SLisandro Dalcin /*@
10495fce210SBarry Smith   PetscSFReset - Reset a star forest so that different sizes or neighbors can be used
10595fce210SBarry Smith 
10695fce210SBarry Smith   Collective
10795fce210SBarry Smith 
1084165533cSJose E. Roman   Input Parameter:
10995fce210SBarry Smith . sf - star forest
11095fce210SBarry Smith 
11195fce210SBarry Smith   Level: advanced
11295fce210SBarry Smith 
113cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFCreate()`, `PetscSFSetGraph()`, `PetscSFDestroy()`
11495fce210SBarry Smith @*/
115d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFReset(PetscSF sf)
116d71ae5a4SJacob Faibussowitsch {
11795fce210SBarry Smith   PetscFunctionBegin;
11895fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
119dbbe0bcdSBarry Smith   PetscTryTypeMethod(sf, Reset);
12029046d53SLisandro Dalcin   sf->nroots   = -1;
12129046d53SLisandro Dalcin   sf->nleaves  = -1;
12229046d53SLisandro Dalcin   sf->minleaf  = PETSC_MAX_INT;
12329046d53SLisandro Dalcin   sf->maxleaf  = PETSC_MIN_INT;
12495fce210SBarry Smith   sf->mine     = NULL;
12595fce210SBarry Smith   sf->remote   = NULL;
12629046d53SLisandro Dalcin   sf->graphset = PETSC_FALSE;
1279566063dSJacob Faibussowitsch   PetscCall(PetscFree(sf->mine_alloc));
1289566063dSJacob Faibussowitsch   PetscCall(PetscFree(sf->remote_alloc));
12921c688dcSJed Brown   sf->nranks = -1;
1309566063dSJacob Faibussowitsch   PetscCall(PetscFree4(sf->ranks, sf->roffset, sf->rmine, sf->rremote));
13129046d53SLisandro Dalcin   sf->degreeknown = PETSC_FALSE;
1329566063dSJacob Faibussowitsch   PetscCall(PetscFree(sf->degree));
1339566063dSJacob Faibussowitsch   if (sf->ingroup != MPI_GROUP_NULL) PetscCallMPI(MPI_Group_free(&sf->ingroup));
1349566063dSJacob Faibussowitsch   if (sf->outgroup != MPI_GROUP_NULL) PetscCallMPI(MPI_Group_free(&sf->outgroup));
135013b3241SStefano Zampini   if (sf->multi) sf->multi->multi = NULL;
1369566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&sf->multi));
1379566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&sf->map));
13871438e86SJunchao Zhang 
13971438e86SJunchao Zhang #if defined(PETSC_HAVE_DEVICE)
1409566063dSJacob Faibussowitsch   for (PetscInt i = 0; i < 2; i++) PetscCall(PetscSFFree(sf, PETSC_MEMTYPE_DEVICE, sf->rmine_d[i]));
14171438e86SJunchao Zhang #endif
14271438e86SJunchao Zhang 
14395fce210SBarry Smith   sf->setupcalled = PETSC_FALSE;
1443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14595fce210SBarry Smith }
14695fce210SBarry Smith 
14795fce210SBarry Smith /*@C
148cab54364SBarry Smith   PetscSFSetType - Set the `PetscSF` communication implementation
14995fce210SBarry Smith 
150c3339decSBarry Smith   Collective
15195fce210SBarry Smith 
15295fce210SBarry Smith   Input Parameters:
153cab54364SBarry Smith + sf   - the `PetscSF` context
15495fce210SBarry Smith - type - a known method
155cab54364SBarry Smith .vb
156cab54364SBarry Smith     PETSCSFWINDOW - MPI-2/3 one-sided
157cab54364SBarry Smith     PETSCSFBASIC - basic implementation using MPI-1 two-sided
158cab54364SBarry Smith .ve
15995fce210SBarry Smith 
16095fce210SBarry Smith   Options Database Key:
16120662ed9SBarry Smith . -sf_type <type> - Sets the method; for example `basic` or `window` use -help for a list of available methods
162cab54364SBarry Smith 
163cab54364SBarry Smith   Level: intermediate
16495fce210SBarry Smith 
16595fce210SBarry Smith   Notes:
16620662ed9SBarry Smith   See `PetscSFType` for possible values
16795fce210SBarry Smith 
16820662ed9SBarry Smith .seealso: `PetscSF`, `PetscSFType`, `PetscSFCreate()`
16995fce210SBarry Smith @*/
170d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFSetType(PetscSF sf, PetscSFType type)
171d71ae5a4SJacob Faibussowitsch {
17295fce210SBarry Smith   PetscBool match;
1735f80ce2aSJacob Faibussowitsch   PetscErrorCode (*r)(PetscSF);
17495fce210SBarry Smith 
17595fce210SBarry Smith   PetscFunctionBegin;
17695fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
1774f572ea9SToby Isaac   PetscAssertPointer(type, 2);
17895fce210SBarry Smith 
1799566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)sf, type, &match));
1803ba16761SJacob Faibussowitsch   if (match) PetscFunctionReturn(PETSC_SUCCESS);
18195fce210SBarry Smith 
1829566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(PetscSFList, type, &r));
1836adde796SStefano Zampini   PetscCheck(r, PetscObjectComm((PetscObject)sf), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unable to find requested PetscSF type %s", type);
18429046d53SLisandro Dalcin   /* Destroy the previous PetscSF implementation context */
185dbbe0bcdSBarry Smith   PetscTryTypeMethod(sf, Destroy);
1869566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(sf->ops, sizeof(*sf->ops)));
1879566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)sf, type));
1889566063dSJacob Faibussowitsch   PetscCall((*r)(sf));
1893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19095fce210SBarry Smith }
19195fce210SBarry Smith 
19229046d53SLisandro Dalcin /*@C
193cab54364SBarry Smith   PetscSFGetType - Get the `PetscSF` communication implementation
19429046d53SLisandro Dalcin 
19529046d53SLisandro Dalcin   Not Collective
19629046d53SLisandro Dalcin 
19729046d53SLisandro Dalcin   Input Parameter:
198cab54364SBarry Smith . sf - the `PetscSF` context
19929046d53SLisandro Dalcin 
20029046d53SLisandro Dalcin   Output Parameter:
201cab54364SBarry Smith . type - the `PetscSF` type name
20229046d53SLisandro Dalcin 
20329046d53SLisandro Dalcin   Level: intermediate
20429046d53SLisandro Dalcin 
20520662ed9SBarry Smith .seealso: `PetscSF`, `PetscSFType`, `PetscSFSetType()`, `PetscSFCreate()`
20629046d53SLisandro Dalcin @*/
207d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFGetType(PetscSF sf, PetscSFType *type)
208d71ae5a4SJacob Faibussowitsch {
20929046d53SLisandro Dalcin   PetscFunctionBegin;
21029046d53SLisandro Dalcin   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
2114f572ea9SToby Isaac   PetscAssertPointer(type, 2);
21229046d53SLisandro Dalcin   *type = ((PetscObject)sf)->type_name;
2133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21429046d53SLisandro Dalcin }
21529046d53SLisandro Dalcin 
2161fb7b255SJunchao Zhang /*@C
21720662ed9SBarry Smith   PetscSFDestroy - destroy a star forest
21895fce210SBarry Smith 
21995fce210SBarry Smith   Collective
22095fce210SBarry Smith 
2214165533cSJose E. Roman   Input Parameter:
22295fce210SBarry Smith . sf - address of star forest
22395fce210SBarry Smith 
22495fce210SBarry Smith   Level: intermediate
22595fce210SBarry Smith 
22620662ed9SBarry Smith .seealso: `PetscSF`, `PetscSFType`, `PetscSFCreate()`, `PetscSFReset()`
22795fce210SBarry Smith @*/
228d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFDestroy(PetscSF *sf)
229d71ae5a4SJacob Faibussowitsch {
23095fce210SBarry Smith   PetscFunctionBegin;
2313ba16761SJacob Faibussowitsch   if (!*sf) PetscFunctionReturn(PETSC_SUCCESS);
23295fce210SBarry Smith   PetscValidHeaderSpecific((*sf), PETSCSF_CLASSID, 1);
2339371c9d4SSatish Balay   if (--((PetscObject)(*sf))->refct > 0) {
2349371c9d4SSatish Balay     *sf = NULL;
2353ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
2369371c9d4SSatish Balay   }
2379566063dSJacob Faibussowitsch   PetscCall(PetscSFReset(*sf));
238dbbe0bcdSBarry Smith   PetscTryTypeMethod((*sf), Destroy);
2399566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&(*sf)->vscat.lsf));
2409566063dSJacob Faibussowitsch   if ((*sf)->vscat.bs > 1) PetscCallMPI(MPI_Type_free(&(*sf)->vscat.unit));
241*c02794c0SJunchao Zhang #if defined(PETSC_HAVE_CUDA) && defined(PETSC_HAVE_MPIX_STREAM)
242715b587bSJunchao Zhang   if ((*sf)->use_stream_aware_mpi) {
243715b587bSJunchao Zhang     PetscCallMPI(MPIX_Stream_free(&(*sf)->mpi_stream));
244715b587bSJunchao Zhang     PetscCallMPI(MPI_Comm_free(&(*sf)->stream_comm));
245715b587bSJunchao Zhang   }
246715b587bSJunchao Zhang #endif
2479566063dSJacob Faibussowitsch   PetscCall(PetscHeaderDestroy(sf));
2483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24995fce210SBarry Smith }
25095fce210SBarry Smith 
251d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFCheckGraphValid_Private(PetscSF sf)
252d71ae5a4SJacob Faibussowitsch {
253c4e6a40aSLawrence Mitchell   PetscInt           i, nleaves;
254c4e6a40aSLawrence Mitchell   PetscMPIInt        size;
255c4e6a40aSLawrence Mitchell   const PetscInt    *ilocal;
256c4e6a40aSLawrence Mitchell   const PetscSFNode *iremote;
257c4e6a40aSLawrence Mitchell 
258c4e6a40aSLawrence Mitchell   PetscFunctionBegin;
2593ba16761SJacob Faibussowitsch   if (!sf->graphset || !PetscDefined(USE_DEBUG)) PetscFunctionReturn(PETSC_SUCCESS);
2609566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, NULL, &nleaves, &ilocal, &iremote));
2619566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)sf), &size));
262c4e6a40aSLawrence Mitchell   for (i = 0; i < nleaves; i++) {
263c4e6a40aSLawrence Mitchell     const PetscInt rank   = iremote[i].rank;
264c4e6a40aSLawrence Mitchell     const PetscInt remote = iremote[i].index;
265c4e6a40aSLawrence Mitchell     const PetscInt leaf   = ilocal ? ilocal[i] : i;
266c9cc58a2SBarry Smith     PetscCheck(rank >= 0 && rank < size, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Provided rank (%" PetscInt_FMT ") for remote %" PetscInt_FMT " is invalid, should be in [0, %d)", rank, i, size);
26708401ef6SPierre Jolivet     PetscCheck(remote >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Provided index (%" PetscInt_FMT ") for remote %" PetscInt_FMT " is invalid, should be >= 0", remote, i);
26808401ef6SPierre Jolivet     PetscCheck(leaf >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Provided location (%" PetscInt_FMT ") for leaf %" PetscInt_FMT " is invalid, should be >= 0", leaf, i);
269c4e6a40aSLawrence Mitchell   }
2703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
271c4e6a40aSLawrence Mitchell }
272c4e6a40aSLawrence Mitchell 
27395fce210SBarry Smith /*@
27420662ed9SBarry Smith   PetscSFSetUp - set up communication structures for a `PetscSF`, after this is done it may be used to perform communication
27595fce210SBarry Smith 
27695fce210SBarry Smith   Collective
27795fce210SBarry Smith 
2784165533cSJose E. Roman   Input Parameter:
27995fce210SBarry Smith . sf - star forest communication object
28095fce210SBarry Smith 
28195fce210SBarry Smith   Level: beginner
28295fce210SBarry Smith 
28320662ed9SBarry Smith .seealso: `PetscSF`, `PetscSFType`, `PetscSFSetFromOptions()`, `PetscSFSetType()`
28495fce210SBarry Smith @*/
285d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFSetUp(PetscSF sf)
286d71ae5a4SJacob Faibussowitsch {
28795fce210SBarry Smith   PetscFunctionBegin;
28829046d53SLisandro Dalcin   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
28929046d53SLisandro Dalcin   PetscSFCheckGraphSet(sf, 1);
2903ba16761SJacob Faibussowitsch   if (sf->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
2919566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCSF_SetUp, sf, 0, 0, 0));
2929566063dSJacob Faibussowitsch   PetscCall(PetscSFCheckGraphValid_Private(sf));
2939566063dSJacob Faibussowitsch   if (!((PetscObject)sf)->type_name) PetscCall(PetscSFSetType(sf, PETSCSFBASIC)); /* Zero all sf->ops */
294dbbe0bcdSBarry Smith   PetscTryTypeMethod(sf, SetUp);
29520c24465SJunchao Zhang #if defined(PETSC_HAVE_CUDA)
29620c24465SJunchao Zhang   if (sf->backend == PETSCSF_BACKEND_CUDA) {
29771438e86SJunchao Zhang     sf->ops->Malloc = PetscSFMalloc_CUDA;
29871438e86SJunchao Zhang     sf->ops->Free   = PetscSFFree_CUDA;
29920c24465SJunchao Zhang   }
30020c24465SJunchao Zhang #endif
30159af0bd3SScott Kruger #if defined(PETSC_HAVE_HIP)
30259af0bd3SScott Kruger   if (sf->backend == PETSCSF_BACKEND_HIP) {
30359af0bd3SScott Kruger     sf->ops->Malloc = PetscSFMalloc_HIP;
30459af0bd3SScott Kruger     sf->ops->Free   = PetscSFFree_HIP;
30559af0bd3SScott Kruger   }
30659af0bd3SScott Kruger #endif
30720c24465SJunchao Zhang 
30820c24465SJunchao Zhang #if defined(PETSC_HAVE_KOKKOS)
30920c24465SJunchao Zhang   if (sf->backend == PETSCSF_BACKEND_KOKKOS) {
31020c24465SJunchao Zhang     sf->ops->Malloc = PetscSFMalloc_Kokkos;
31120c24465SJunchao Zhang     sf->ops->Free   = PetscSFFree_Kokkos;
31220c24465SJunchao Zhang   }
31320c24465SJunchao Zhang #endif
3149566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCSF_SetUp, sf, 0, 0, 0));
31595fce210SBarry Smith   sf->setupcalled = PETSC_TRUE;
3163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
31795fce210SBarry Smith }
31895fce210SBarry Smith 
3198af6ec1cSBarry Smith /*@
320cab54364SBarry Smith   PetscSFSetFromOptions - set `PetscSF` options using the options database
32195fce210SBarry Smith 
32295fce210SBarry Smith   Logically Collective
32395fce210SBarry Smith 
3244165533cSJose E. Roman   Input Parameter:
32595fce210SBarry Smith . sf - star forest
32695fce210SBarry Smith 
32795fce210SBarry Smith   Options Database Keys:
32820662ed9SBarry Smith + -sf_type                                                                                                         - implementation type, see `PetscSFSetType()`
32951ccb202SJunchao Zhang . -sf_rank_order                                                                                                   - sort composite points for gathers and scatters in rank order, gathers are non-deterministic otherwise
33020662ed9SBarry Smith . -sf_use_default_stream                                                                                           - Assume callers of `PetscSF` computed the input root/leafdata with the default CUDA stream. `PetscSF` will also
33120662ed9SBarry Smith                             use the default stream to process data. Therefore, no stream synchronization is needed between `PetscSF` and its caller (default: true).
33220662ed9SBarry Smith                             If true, this option only works with `-use_gpu_aware_mpi 1`.
33320662ed9SBarry Smith . -sf_use_stream_aware_mpi                                                                                         - Assume the underlying MPI is CUDA-stream aware and `PetscSF` won't sync streams for send/recv buffers passed to MPI (default: false).
33420662ed9SBarry Smith                                If true, this option only works with `-use_gpu_aware_mpi 1`.
33595fce210SBarry Smith 
33638b5cf2dSJacob Faibussowitsch - -sf_backend cuda | hip | kokkos -Select the device backend SF uses. Currently `PetscSF` has these backends: cuda - hip and Kokkos.
33759af0bd3SScott Kruger                               On CUDA (HIP) devices, one can choose cuda (hip) or kokkos with the default being kokkos. On other devices,
33820c24465SJunchao Zhang                               the only available is kokkos.
33920c24465SJunchao Zhang 
34095fce210SBarry Smith   Level: intermediate
341cab54364SBarry Smith 
342cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFCreate()`, `PetscSFSetType()`
34395fce210SBarry Smith @*/
344d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFSetFromOptions(PetscSF sf)
345d71ae5a4SJacob Faibussowitsch {
34695fce210SBarry Smith   PetscSFType deft;
34795fce210SBarry Smith   char        type[256];
34895fce210SBarry Smith   PetscBool   flg;
34995fce210SBarry Smith 
35095fce210SBarry Smith   PetscFunctionBegin;
35195fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
352d0609cedSBarry Smith   PetscObjectOptionsBegin((PetscObject)sf);
35395fce210SBarry Smith   deft = ((PetscObject)sf)->type_name ? ((PetscObject)sf)->type_name : PETSCSFBASIC;
3549566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-sf_type", "PetscSF implementation type", "PetscSFSetType", PetscSFList, deft, type, sizeof(type), &flg));
3559566063dSJacob Faibussowitsch   PetscCall(PetscSFSetType(sf, flg ? type : deft));
3569566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-sf_rank_order", "sort composite points for gathers and scatters in rank order, gathers are non-deterministic otherwise", "PetscSFSetRankOrder", sf->rankorder, &sf->rankorder, NULL));
3577fd2d3dbSJunchao Zhang #if defined(PETSC_HAVE_DEVICE)
35820c24465SJunchao Zhang   {
35920c24465SJunchao Zhang     char      backendstr[32] = {0};
36059af0bd3SScott Kruger     PetscBool isCuda = PETSC_FALSE, isHip = PETSC_FALSE, isKokkos = PETSC_FALSE, set;
36120c24465SJunchao Zhang     /* Change the defaults set in PetscSFCreate() with command line options */
362d5b43468SJose E. Roman     PetscCall(PetscOptionsBool("-sf_unknown_input_stream", "SF root/leafdata is computed on arbitrary streams unknown to SF", "PetscSFSetFromOptions", sf->unknown_input_stream, &sf->unknown_input_stream, NULL));
3639566063dSJacob Faibussowitsch     PetscCall(PetscOptionsBool("-sf_use_stream_aware_mpi", "Assume the underlying MPI is cuda-stream aware", "PetscSFSetFromOptions", sf->use_stream_aware_mpi, &sf->use_stream_aware_mpi, NULL));
3649566063dSJacob Faibussowitsch     PetscCall(PetscOptionsString("-sf_backend", "Select the device backend SF uses", "PetscSFSetFromOptions", NULL, backendstr, sizeof(backendstr), &set));
3659566063dSJacob Faibussowitsch     PetscCall(PetscStrcasecmp("cuda", backendstr, &isCuda));
3669566063dSJacob Faibussowitsch     PetscCall(PetscStrcasecmp("kokkos", backendstr, &isKokkos));
3679566063dSJacob Faibussowitsch     PetscCall(PetscStrcasecmp("hip", backendstr, &isHip));
36859af0bd3SScott Kruger   #if defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
36920c24465SJunchao Zhang     if (isCuda) sf->backend = PETSCSF_BACKEND_CUDA;
37020c24465SJunchao Zhang     else if (isKokkos) sf->backend = PETSCSF_BACKEND_KOKKOS;
37159af0bd3SScott Kruger     else if (isHip) sf->backend = PETSCSF_BACKEND_HIP;
37228b400f6SJacob Faibussowitsch     else PetscCheck(!set, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "-sf_backend %s is not supported. You may choose cuda, hip or kokkos (if installed)", backendstr);
37320c24465SJunchao Zhang   #elif defined(PETSC_HAVE_KOKKOS)
37408401ef6SPierre Jolivet     PetscCheck(!set || isKokkos, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "-sf_backend %s is not supported. You can only choose kokkos", backendstr);
37520c24465SJunchao Zhang   #endif
376715b587bSJunchao Zhang 
377715b587bSJunchao Zhang   #if defined(PETSC_HAVE_CUDA) && defined(PETSC_HAVE_MPIX_STREAM)
378715b587bSJunchao Zhang     if (sf->use_stream_aware_mpi) {
379715b587bSJunchao Zhang       MPI_Info info;
380715b587bSJunchao Zhang 
381715b587bSJunchao Zhang       PetscCallMPI(MPI_Info_create(&info));
382715b587bSJunchao Zhang       PetscCallMPI(MPI_Info_set(info, "type", "cudaStream_t"));
383715b587bSJunchao Zhang       PetscCallMPI(MPIX_Info_set_hex(info, "value", &PetscDefaultCudaStream, sizeof(PetscDefaultCudaStream)));
384715b587bSJunchao Zhang       PetscCallMPI(MPIX_Stream_create(info, &sf->mpi_stream));
385715b587bSJunchao Zhang       PetscCallMPI(MPI_Info_free(&info));
386715b587bSJunchao Zhang       PetscCallMPI(MPIX_Stream_comm_create(PetscObjectComm((PetscObject)sf), sf->mpi_stream, &sf->stream_comm));
387715b587bSJunchao Zhang     }
388715b587bSJunchao Zhang   #endif
38920c24465SJunchao Zhang   }
390c2a741eeSJunchao Zhang #endif
391dbbe0bcdSBarry Smith   PetscTryTypeMethod(sf, SetFromOptions, PetscOptionsObject);
392d0609cedSBarry Smith   PetscOptionsEnd();
3933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
39495fce210SBarry Smith }
39595fce210SBarry Smith 
39629046d53SLisandro Dalcin /*@
39795fce210SBarry Smith   PetscSFSetRankOrder - sort multi-points for gathers and scatters by rank order
39895fce210SBarry Smith 
39995fce210SBarry Smith   Logically Collective
40095fce210SBarry Smith 
4014165533cSJose E. Roman   Input Parameters:
40295fce210SBarry Smith + sf  - star forest
403cab54364SBarry Smith - flg - `PETSC_TRUE` to sort, `PETSC_FALSE` to skip sorting (lower setup cost, but non-deterministic)
40495fce210SBarry Smith 
40595fce210SBarry Smith   Level: advanced
40695fce210SBarry Smith 
40720662ed9SBarry Smith .seealso: `PetscSF`, `PetscSFType`, `PetscSFGatherBegin()`, `PetscSFScatterBegin()`
40895fce210SBarry Smith @*/
409d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFSetRankOrder(PetscSF sf, PetscBool flg)
410d71ae5a4SJacob Faibussowitsch {
41195fce210SBarry Smith   PetscFunctionBegin;
41295fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
41395fce210SBarry Smith   PetscValidLogicalCollectiveBool(sf, flg, 2);
41428b400f6SJacob Faibussowitsch   PetscCheck(!sf->multi, PetscObjectComm((PetscObject)sf), PETSC_ERR_ARG_WRONGSTATE, "Rank ordering must be set before first call to PetscSFGatherBegin() or PetscSFScatterBegin()");
41595fce210SBarry Smith   sf->rankorder = flg;
4163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
41795fce210SBarry Smith }
41895fce210SBarry Smith 
4198dbb0df6SBarry Smith /*@C
42095fce210SBarry Smith   PetscSFSetGraph - Set a parallel star forest
42195fce210SBarry Smith 
42295fce210SBarry Smith   Collective
42395fce210SBarry Smith 
4244165533cSJose E. Roman   Input Parameters:
42595fce210SBarry Smith + sf         - star forest
42695fce210SBarry Smith . nroots     - number of root vertices on the current process (these are possible targets for other process to attach leaves)
42795fce210SBarry Smith . nleaves    - number of leaf vertices on the current process, each of these references a root on any process
42820662ed9SBarry Smith . ilocal     - locations of leaves in leafdata buffers, pass `NULL` for contiguous storage (locations must be >= 0, enforced
429c4e6a40aSLawrence Mitchell during setup in debug mode)
43020662ed9SBarry Smith . localmode  - copy mode for `ilocal`
431c4e6a40aSLawrence Mitchell . iremote    - remote locations of root vertices for each leaf on the current process (locations must be >= 0, enforced
432c4e6a40aSLawrence Mitchell during setup in debug mode)
43320662ed9SBarry Smith - remotemode - copy mode for `iremote`
43495fce210SBarry Smith 
43595fce210SBarry Smith   Level: intermediate
43695fce210SBarry Smith 
43795452b02SPatrick Sanan   Notes:
43820662ed9SBarry Smith   Leaf indices in `ilocal` must be unique, otherwise an error occurs.
43938ab3f8aSBarry Smith 
44020662ed9SBarry Smith   Input arrays `ilocal` and `iremote` follow the `PetscCopyMode` semantics.
44120662ed9SBarry Smith   In particular, if `localmode` or `remotemode` is `PETSC_OWN_POINTER` or `PETSC_USE_POINTER`,
442db2b9530SVaclav Hapla   PETSc might modify the respective array;
44320662ed9SBarry Smith   if `PETSC_USE_POINTER`, the user must delete the array after `PetscSFDestroy()`.
444cab54364SBarry Smith   Only if `PETSC_COPY_VALUES` is used, the respective array is guaranteed to stay intact and a const array can be passed (but a cast to non-const is needed).
445db2b9530SVaclav Hapla 
44638b5cf2dSJacob Faibussowitsch   Fortran Notes:
44720662ed9SBarry Smith   In Fortran you must use `PETSC_COPY_VALUES` for `localmode` and `remotemode`.
448c4e6a40aSLawrence Mitchell 
44938b5cf2dSJacob Faibussowitsch   Developer Notes:
450db2b9530SVaclav Hapla   We sort leaves to check for duplicates and contiguousness and to find minleaf/maxleaf.
45120662ed9SBarry Smith   This also allows to compare leaf sets of two `PetscSF`s easily.
45272bf8598SVaclav Hapla 
45320662ed9SBarry Smith .seealso: `PetscSF`, `PetscSFType`, `PetscSFCreate()`, `PetscSFView()`, `PetscSFGetGraph()`
45495fce210SBarry Smith @*/
455d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFSetGraph(PetscSF sf, PetscInt nroots, PetscInt nleaves, PetscInt *ilocal, PetscCopyMode localmode, PetscSFNode *iremote, PetscCopyMode remotemode)
456d71ae5a4SJacob Faibussowitsch {
457db2b9530SVaclav Hapla   PetscBool unique, contiguous;
45895fce210SBarry Smith 
45995fce210SBarry Smith   PetscFunctionBegin;
46095fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
4614f572ea9SToby Isaac   if (nleaves > 0 && ilocal) PetscAssertPointer(ilocal, 4);
4624f572ea9SToby Isaac   if (nleaves > 0) PetscAssertPointer(iremote, 6);
46308401ef6SPierre Jolivet   PetscCheck(nroots >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nroots %" PetscInt_FMT ", cannot be negative", nroots);
46408401ef6SPierre Jolivet   PetscCheck(nleaves >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nleaves %" PetscInt_FMT ", cannot be negative", nleaves);
4658da24d32SBarry Smith   /* enums may be handled as unsigned by some compilers, NVHPC for example, the int cast
4668da24d32SBarry Smith    * below is to prevent NVHPC from warning about meaningless comparison of unsigned with zero */
4678da24d32SBarry Smith   PetscCheck((int)localmode >= PETSC_COPY_VALUES && localmode <= PETSC_USE_POINTER, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Wrong localmode %d", localmode);
4688da24d32SBarry Smith   PetscCheck((int)remotemode >= PETSC_COPY_VALUES && remotemode <= PETSC_USE_POINTER, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Wrong remotemode %d", remotemode);
46929046d53SLisandro Dalcin 
4702a67d2daSStefano Zampini   if (sf->nroots >= 0) { /* Reset only if graph already set */
4719566063dSJacob Faibussowitsch     PetscCall(PetscSFReset(sf));
4722a67d2daSStefano Zampini   }
4732a67d2daSStefano Zampini 
4749566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCSF_SetGraph, sf, 0, 0, 0));
47529046d53SLisandro Dalcin 
47695fce210SBarry Smith   sf->nroots  = nroots;
47795fce210SBarry Smith   sf->nleaves = nleaves;
47829046d53SLisandro Dalcin 
479db2b9530SVaclav Hapla   if (localmode == PETSC_COPY_VALUES && ilocal) {
480db2b9530SVaclav Hapla     PetscInt *tlocal = NULL;
481db2b9530SVaclav Hapla 
4829566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &tlocal));
4839566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(tlocal, ilocal, nleaves));
484db2b9530SVaclav Hapla     ilocal = tlocal;
485db2b9530SVaclav Hapla   }
486db2b9530SVaclav Hapla   if (remotemode == PETSC_COPY_VALUES) {
487db2b9530SVaclav Hapla     PetscSFNode *tremote = NULL;
488db2b9530SVaclav Hapla 
4899566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &tremote));
4909566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(tremote, iremote, nleaves));
491db2b9530SVaclav Hapla     iremote = tremote;
492db2b9530SVaclav Hapla   }
493db2b9530SVaclav Hapla 
49429046d53SLisandro Dalcin   if (nleaves && ilocal) {
495db2b9530SVaclav Hapla     PetscSFNode work;
496db2b9530SVaclav Hapla 
4979566063dSJacob Faibussowitsch     PetscCall(PetscSortIntWithDataArray(nleaves, ilocal, iremote, sizeof(PetscSFNode), &work));
4989566063dSJacob Faibussowitsch     PetscCall(PetscSortedCheckDupsInt(nleaves, ilocal, &unique));
499db2b9530SVaclav Hapla     unique = PetscNot(unique);
500db2b9530SVaclav Hapla     PetscCheck(sf->allow_multi_leaves || unique, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Input ilocal has duplicate entries which is not allowed for this PetscSF");
501db2b9530SVaclav Hapla     sf->minleaf = ilocal[0];
502db2b9530SVaclav Hapla     sf->maxleaf = ilocal[nleaves - 1];
503db2b9530SVaclav Hapla     contiguous  = (PetscBool)(unique && ilocal[0] == 0 && ilocal[nleaves - 1] == nleaves - 1);
50429046d53SLisandro Dalcin   } else {
50529046d53SLisandro Dalcin     sf->minleaf = 0;
50629046d53SLisandro Dalcin     sf->maxleaf = nleaves - 1;
507db2b9530SVaclav Hapla     unique      = PETSC_TRUE;
508db2b9530SVaclav Hapla     contiguous  = PETSC_TRUE;
50929046d53SLisandro Dalcin   }
51029046d53SLisandro Dalcin 
511db2b9530SVaclav Hapla   if (contiguous) {
512db2b9530SVaclav Hapla     if (localmode == PETSC_USE_POINTER) {
513db2b9530SVaclav Hapla       ilocal = NULL;
514db2b9530SVaclav Hapla     } else {
5159566063dSJacob Faibussowitsch       PetscCall(PetscFree(ilocal));
516db2b9530SVaclav Hapla     }
517db2b9530SVaclav Hapla   }
518db2b9530SVaclav Hapla   sf->mine = ilocal;
519db2b9530SVaclav Hapla   if (localmode == PETSC_USE_POINTER) {
52029046d53SLisandro Dalcin     sf->mine_alloc = NULL;
521db2b9530SVaclav Hapla   } else {
522db2b9530SVaclav Hapla     sf->mine_alloc = ilocal;
52395fce210SBarry Smith   }
524db2b9530SVaclav Hapla   sf->remote = iremote;
525db2b9530SVaclav Hapla   if (remotemode == PETSC_USE_POINTER) {
52629046d53SLisandro Dalcin     sf->remote_alloc = NULL;
527db2b9530SVaclav Hapla   } else {
528db2b9530SVaclav Hapla     sf->remote_alloc = iremote;
52995fce210SBarry Smith   }
5309566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCSF_SetGraph, sf, 0, 0, 0));
53129046d53SLisandro Dalcin   sf->graphset = PETSC_TRUE;
5323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
53395fce210SBarry Smith }
53495fce210SBarry Smith 
53529046d53SLisandro Dalcin /*@
536cab54364SBarry Smith   PetscSFSetGraphWithPattern - Sets the graph of a `PetscSF` with a specific pattern
537dd5b3ca6SJunchao Zhang 
538dd5b3ca6SJunchao Zhang   Collective
539dd5b3ca6SJunchao Zhang 
540dd5b3ca6SJunchao Zhang   Input Parameters:
541cab54364SBarry Smith + sf      - The `PetscSF`
542cab54364SBarry Smith . map     - Layout of roots over all processes (insignificant when pattern is `PETSCSF_PATTERN_ALLTOALL`)
543cab54364SBarry Smith - pattern - One of `PETSCSF_PATTERN_ALLGATHER`, `PETSCSF_PATTERN_GATHER`, `PETSCSF_PATTERN_ALLTOALL`
544cab54364SBarry Smith 
545cab54364SBarry Smith   Level: intermediate
546dd5b3ca6SJunchao Zhang 
547dd5b3ca6SJunchao Zhang   Notes:
54820662ed9SBarry Smith   It is easier to explain `PetscSFPattern` using vectors. Suppose we have an MPI vector `x` and its `PetscLayout` is `map`.
54920662ed9SBarry Smith   `n` and `N` are the local and global sizes of `x` respectively.
550dd5b3ca6SJunchao Zhang 
55120662ed9SBarry Smith   With `PETSCSF_PATTERN_ALLGATHER`, the routine creates a graph that if one does `PetscSFBcastBegin()`/`PetscSFBcastEnd()` on it, it will copy `x` to
55220662ed9SBarry Smith   sequential vectors `y` on all MPI processes.
553dd5b3ca6SJunchao Zhang 
55420662ed9SBarry Smith   With `PETSCSF_PATTERN_GATHER`, the routine creates a graph that if one does `PetscSFBcastBegin()`/`PetscSFBcastEnd()` on it, it will copy `x` to a
55520662ed9SBarry Smith   sequential vector `y` on rank 0.
556dd5b3ca6SJunchao Zhang 
55720662ed9SBarry Smith   In above cases, entries of `x` are roots and entries of `y` are leaves.
558dd5b3ca6SJunchao Zhang 
55920662ed9SBarry Smith   With `PETSCSF_PATTERN_ALLTOALL`, map is insignificant. Suppose NP is size of `sf`'s communicator. The routine
560dd5b3ca6SJunchao Zhang   creates a graph that every rank has NP leaves and NP roots. On rank i, its leaf j is connected to root i
561cab54364SBarry Smith   of rank j. Here 0 <=i,j<NP. It is a kind of `MPI_Alltoall()` with sendcount/recvcount being 1. Note that it does
562dd5b3ca6SJunchao Zhang   not mean one can not send multiple items. One just needs to create a new MPI datatype for the mulptiple data
563cab54364SBarry Smith   items with `MPI_Type_contiguous` and use that as the <unit> argument in SF routines.
564dd5b3ca6SJunchao Zhang 
565dd5b3ca6SJunchao Zhang   In this case, roots and leaves are symmetric.
566dd5b3ca6SJunchao Zhang 
567cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFCreate()`, `PetscSFView()`, `PetscSFGetGraph()`
568dd5b3ca6SJunchao Zhang  @*/
569d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFSetGraphWithPattern(PetscSF sf, PetscLayout map, PetscSFPattern pattern)
570d71ae5a4SJacob Faibussowitsch {
571dd5b3ca6SJunchao Zhang   MPI_Comm    comm;
572dd5b3ca6SJunchao Zhang   PetscInt    n, N, res[2];
573dd5b3ca6SJunchao Zhang   PetscMPIInt rank, size;
574dd5b3ca6SJunchao Zhang   PetscSFType type;
575dd5b3ca6SJunchao Zhang 
576dd5b3ca6SJunchao Zhang   PetscFunctionBegin;
5772abc8c78SJacob Faibussowitsch   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
5784f572ea9SToby Isaac   if (pattern != PETSCSF_PATTERN_ALLTOALL) PetscAssertPointer(map, 2);
5799566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
5802c71b3e2SJacob Faibussowitsch   PetscCheck(pattern >= PETSCSF_PATTERN_ALLGATHER && pattern <= PETSCSF_PATTERN_ALLTOALL, comm, PETSC_ERR_ARG_OUTOFRANGE, "Unsupported PetscSFPattern %d", pattern);
5819566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
5829566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
583dd5b3ca6SJunchao Zhang 
584dd5b3ca6SJunchao Zhang   if (pattern == PETSCSF_PATTERN_ALLTOALL) {
585dd5b3ca6SJunchao Zhang     type = PETSCSFALLTOALL;
5869566063dSJacob Faibussowitsch     PetscCall(PetscLayoutCreate(comm, &sf->map));
5879566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetLocalSize(sf->map, size));
5889566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetSize(sf->map, ((PetscInt)size) * size));
5899566063dSJacob Faibussowitsch     PetscCall(PetscLayoutSetUp(sf->map));
590dd5b3ca6SJunchao Zhang   } else {
5919566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetLocalSize(map, &n));
5929566063dSJacob Faibussowitsch     PetscCall(PetscLayoutGetSize(map, &N));
593dd5b3ca6SJunchao Zhang     res[0] = n;
594dd5b3ca6SJunchao Zhang     res[1] = -n;
595dd5b3ca6SJunchao Zhang     /* Check if n are same over all ranks so that we can optimize it */
5961c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(MPI_IN_PLACE, res, 2, MPIU_INT, MPI_MAX, comm));
597dd5b3ca6SJunchao Zhang     if (res[0] == -res[1]) { /* same n */
598dd5b3ca6SJunchao Zhang       type = (pattern == PETSCSF_PATTERN_ALLGATHER) ? PETSCSFALLGATHER : PETSCSFGATHER;
599dd5b3ca6SJunchao Zhang     } else {
600dd5b3ca6SJunchao Zhang       type = (pattern == PETSCSF_PATTERN_ALLGATHER) ? PETSCSFALLGATHERV : PETSCSFGATHERV;
601dd5b3ca6SJunchao Zhang     }
6029566063dSJacob Faibussowitsch     PetscCall(PetscLayoutReference(map, &sf->map));
603dd5b3ca6SJunchao Zhang   }
6049566063dSJacob Faibussowitsch   PetscCall(PetscSFSetType(sf, type));
605dd5b3ca6SJunchao Zhang 
606dd5b3ca6SJunchao Zhang   sf->pattern = pattern;
607dd5b3ca6SJunchao Zhang   sf->mine    = NULL; /* Contiguous */
608dd5b3ca6SJunchao Zhang 
609dd5b3ca6SJunchao Zhang   /* Set nleaves, nroots here in case user calls PetscSFGetGraph, which is legal to call even before PetscSFSetUp is called.
610dd5b3ca6SJunchao Zhang      Also set other easy stuff.
611dd5b3ca6SJunchao Zhang    */
612dd5b3ca6SJunchao Zhang   if (pattern == PETSCSF_PATTERN_ALLGATHER) {
613dd5b3ca6SJunchao Zhang     sf->nleaves = N;
614dd5b3ca6SJunchao Zhang     sf->nroots  = n;
615dd5b3ca6SJunchao Zhang     sf->nranks  = size;
616dd5b3ca6SJunchao Zhang     sf->minleaf = 0;
617dd5b3ca6SJunchao Zhang     sf->maxleaf = N - 1;
618dd5b3ca6SJunchao Zhang   } else if (pattern == PETSCSF_PATTERN_GATHER) {
619dd5b3ca6SJunchao Zhang     sf->nleaves = rank ? 0 : N;
620dd5b3ca6SJunchao Zhang     sf->nroots  = n;
621dd5b3ca6SJunchao Zhang     sf->nranks  = rank ? 0 : size;
622dd5b3ca6SJunchao Zhang     sf->minleaf = 0;
623dd5b3ca6SJunchao Zhang     sf->maxleaf = rank ? -1 : N - 1;
624dd5b3ca6SJunchao Zhang   } else if (pattern == PETSCSF_PATTERN_ALLTOALL) {
625dd5b3ca6SJunchao Zhang     sf->nleaves = size;
626dd5b3ca6SJunchao Zhang     sf->nroots  = size;
627dd5b3ca6SJunchao Zhang     sf->nranks  = size;
628dd5b3ca6SJunchao Zhang     sf->minleaf = 0;
629dd5b3ca6SJunchao Zhang     sf->maxleaf = size - 1;
630dd5b3ca6SJunchao Zhang   }
631dd5b3ca6SJunchao Zhang   sf->ndranks  = 0; /* We do not need to separate out distinguished ranks for patterned graphs to improve communication performance */
632dd5b3ca6SJunchao Zhang   sf->graphset = PETSC_TRUE;
6333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
634dd5b3ca6SJunchao Zhang }
635dd5b3ca6SJunchao Zhang 
636dd5b3ca6SJunchao Zhang /*@
637cab54364SBarry Smith   PetscSFCreateInverseSF - given a `PetscSF` in which all vertices have degree 1, creates the inverse map
63895fce210SBarry Smith 
63995fce210SBarry Smith   Collective
64095fce210SBarry Smith 
6414165533cSJose E. Roman   Input Parameter:
64295fce210SBarry Smith . sf - star forest to invert
64395fce210SBarry Smith 
6444165533cSJose E. Roman   Output Parameter:
64520662ed9SBarry Smith . isf - inverse of `sf`
6464165533cSJose E. Roman 
64795fce210SBarry Smith   Level: advanced
64895fce210SBarry Smith 
64995fce210SBarry Smith   Notes:
65095fce210SBarry Smith   All roots must have degree 1.
65195fce210SBarry Smith 
65295fce210SBarry Smith   The local space may be a permutation, but cannot be sparse.
65395fce210SBarry Smith 
65420662ed9SBarry Smith .seealso: `PetscSF`, `PetscSFType`, `PetscSFSetGraph()`
65595fce210SBarry Smith @*/
656d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFCreateInverseSF(PetscSF sf, PetscSF *isf)
657d71ae5a4SJacob Faibussowitsch {
65895fce210SBarry Smith   PetscMPIInt     rank;
65995fce210SBarry Smith   PetscInt        i, nroots, nleaves, maxlocal, count, *newilocal;
66095fce210SBarry Smith   const PetscInt *ilocal;
66195fce210SBarry Smith   PetscSFNode    *roots, *leaves;
66295fce210SBarry Smith 
66395fce210SBarry Smith   PetscFunctionBegin;
66429046d53SLisandro Dalcin   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
66529046d53SLisandro Dalcin   PetscSFCheckGraphSet(sf, 1);
6664f572ea9SToby Isaac   PetscAssertPointer(isf, 2);
66729046d53SLisandro Dalcin 
6689566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &nroots, &nleaves, &ilocal, NULL));
66929046d53SLisandro Dalcin   maxlocal = sf->maxleaf + 1; /* TODO: We should use PetscSFGetLeafRange() */
67029046d53SLisandro Dalcin 
6719566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)sf), &rank));
6729566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(nroots, &roots, maxlocal, &leaves));
673ae9aee6dSMatthew G. Knepley   for (i = 0; i < maxlocal; i++) {
67495fce210SBarry Smith     leaves[i].rank  = rank;
67595fce210SBarry Smith     leaves[i].index = i;
67695fce210SBarry Smith   }
67795fce210SBarry Smith   for (i = 0; i < nroots; i++) {
67895fce210SBarry Smith     roots[i].rank  = -1;
67995fce210SBarry Smith     roots[i].index = -1;
68095fce210SBarry Smith   }
6819566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(sf, MPIU_2INT, leaves, roots, MPI_REPLACE));
6829566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(sf, MPIU_2INT, leaves, roots, MPI_REPLACE));
68395fce210SBarry Smith 
68495fce210SBarry Smith   /* Check whether our leaves are sparse */
6859371c9d4SSatish Balay   for (i = 0, count = 0; i < nroots; i++)
6869371c9d4SSatish Balay     if (roots[i].rank >= 0) count++;
68795fce210SBarry Smith   if (count == nroots) newilocal = NULL;
6889371c9d4SSatish Balay   else { /* Index for sparse leaves and compact "roots" array (which is to become our leaves). */ PetscCall(PetscMalloc1(count, &newilocal));
68995fce210SBarry Smith     for (i = 0, count = 0; i < nroots; i++) {
69095fce210SBarry Smith       if (roots[i].rank >= 0) {
69195fce210SBarry Smith         newilocal[count]   = i;
69295fce210SBarry Smith         roots[count].rank  = roots[i].rank;
69395fce210SBarry Smith         roots[count].index = roots[i].index;
69495fce210SBarry Smith         count++;
69595fce210SBarry Smith       }
69695fce210SBarry Smith     }
69795fce210SBarry Smith   }
69895fce210SBarry Smith 
6999566063dSJacob Faibussowitsch   PetscCall(PetscSFDuplicate(sf, PETSCSF_DUPLICATE_CONFONLY, isf));
7009566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(*isf, maxlocal, count, newilocal, PETSC_OWN_POINTER, roots, PETSC_COPY_VALUES));
7019566063dSJacob Faibussowitsch   PetscCall(PetscFree2(roots, leaves));
7023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
70395fce210SBarry Smith }
70495fce210SBarry Smith 
70595fce210SBarry Smith /*@
706cab54364SBarry Smith   PetscSFDuplicate - duplicate a `PetscSF`, optionally preserving rank connectivity and graph
70795fce210SBarry Smith 
70895fce210SBarry Smith   Collective
70995fce210SBarry Smith 
7104165533cSJose E. Roman   Input Parameters:
71195fce210SBarry Smith + sf  - communication object to duplicate
712cab54364SBarry Smith - opt - `PETSCSF_DUPLICATE_CONFONLY`, `PETSCSF_DUPLICATE_RANKS`, or `PETSCSF_DUPLICATE_GRAPH` (see `PetscSFDuplicateOption`)
71395fce210SBarry Smith 
7144165533cSJose E. Roman   Output Parameter:
71595fce210SBarry Smith . newsf - new communication object
71695fce210SBarry Smith 
71795fce210SBarry Smith   Level: beginner
71895fce210SBarry Smith 
71920662ed9SBarry Smith .seealso: `PetscSF`, `PetscSFType`, `PetscSFCreate()`, `PetscSFSetType()`, `PetscSFSetGraph()`
72095fce210SBarry Smith @*/
721d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFDuplicate(PetscSF sf, PetscSFDuplicateOption opt, PetscSF *newsf)
722d71ae5a4SJacob Faibussowitsch {
72329046d53SLisandro Dalcin   PetscSFType  type;
72497929ea7SJunchao Zhang   MPI_Datatype dtype = MPIU_SCALAR;
72595fce210SBarry Smith 
72695fce210SBarry Smith   PetscFunctionBegin;
72729046d53SLisandro Dalcin   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
72829046d53SLisandro Dalcin   PetscValidLogicalCollectiveEnum(sf, opt, 2);
7294f572ea9SToby Isaac   PetscAssertPointer(newsf, 3);
7309566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)sf), newsf));
7319566063dSJacob Faibussowitsch   PetscCall(PetscSFGetType(sf, &type));
7329566063dSJacob Faibussowitsch   if (type) PetscCall(PetscSFSetType(*newsf, type));
73335cb6cd3SPierre Jolivet   (*newsf)->allow_multi_leaves = sf->allow_multi_leaves; /* Dup this flag earlier since PetscSFSetGraph() below checks on this flag */
73495fce210SBarry Smith   if (opt == PETSCSF_DUPLICATE_GRAPH) {
735dd5b3ca6SJunchao Zhang     PetscSFCheckGraphSet(sf, 1);
736dd5b3ca6SJunchao Zhang     if (sf->pattern == PETSCSF_PATTERN_GENERAL) {
73795fce210SBarry Smith       PetscInt           nroots, nleaves;
73895fce210SBarry Smith       const PetscInt    *ilocal;
73995fce210SBarry Smith       const PetscSFNode *iremote;
7409566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGraph(sf, &nroots, &nleaves, &ilocal, &iremote));
7419566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraph(*newsf, nroots, nleaves, (PetscInt *)ilocal, PETSC_COPY_VALUES, (PetscSFNode *)iremote, PETSC_COPY_VALUES));
742dd5b3ca6SJunchao Zhang     } else {
7439566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraphWithPattern(*newsf, sf->map, sf->pattern));
744dd5b3ca6SJunchao Zhang     }
74595fce210SBarry Smith   }
74697929ea7SJunchao Zhang   /* Since oldtype is committed, so is newtype, according to MPI */
7479566063dSJacob Faibussowitsch   if (sf->vscat.bs > 1) PetscCallMPI(MPI_Type_dup(sf->vscat.unit, &dtype));
74897929ea7SJunchao Zhang   (*newsf)->vscat.bs     = sf->vscat.bs;
74997929ea7SJunchao Zhang   (*newsf)->vscat.unit   = dtype;
75097929ea7SJunchao Zhang   (*newsf)->vscat.to_n   = sf->vscat.to_n;
75197929ea7SJunchao Zhang   (*newsf)->vscat.from_n = sf->vscat.from_n;
75297929ea7SJunchao Zhang   /* Do not copy lsf. Build it on demand since it is rarely used */
75397929ea7SJunchao Zhang 
75420c24465SJunchao Zhang #if defined(PETSC_HAVE_DEVICE)
75520c24465SJunchao Zhang   (*newsf)->backend              = sf->backend;
75671438e86SJunchao Zhang   (*newsf)->unknown_input_stream = sf->unknown_input_stream;
75720c24465SJunchao Zhang   (*newsf)->use_gpu_aware_mpi    = sf->use_gpu_aware_mpi;
75820c24465SJunchao Zhang   (*newsf)->use_stream_aware_mpi = sf->use_stream_aware_mpi;
75920c24465SJunchao Zhang #endif
760dbbe0bcdSBarry Smith   PetscTryTypeMethod(sf, Duplicate, opt, *newsf);
76120c24465SJunchao Zhang   /* Don't do PetscSFSetUp() since the new sf's graph might have not been set. */
7623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
76395fce210SBarry Smith }
76495fce210SBarry Smith 
76595fce210SBarry Smith /*@C
76695fce210SBarry Smith   PetscSFGetGraph - Get the graph specifying a parallel star forest
76795fce210SBarry Smith 
76895fce210SBarry Smith   Not Collective
76995fce210SBarry Smith 
7704165533cSJose E. Roman   Input Parameter:
77195fce210SBarry Smith . sf - star forest
77295fce210SBarry Smith 
7734165533cSJose E. Roman   Output Parameters:
77495fce210SBarry Smith + nroots  - number of root vertices on the current process (these are possible targets for other process to attach leaves)
77595fce210SBarry Smith . nleaves - number of leaf vertices on the current process, each of these references a root on any process
77620662ed9SBarry Smith . ilocal  - locations of leaves in leafdata buffers (if returned value is `NULL`, it means leaves are in contiguous storage)
77795fce210SBarry Smith - iremote - remote locations of root vertices for each leaf on the current process
77895fce210SBarry Smith 
779cab54364SBarry Smith   Level: intermediate
780cab54364SBarry Smith 
781373e0d91SLisandro Dalcin   Notes:
78220662ed9SBarry Smith   We are not currently requiring that the graph is set, thus returning `nroots` = -1 if it has not been set yet
783373e0d91SLisandro Dalcin 
78420662ed9SBarry Smith   The returned `ilocal` and `iremote` might contain values in different order than the input ones in `PetscSFSetGraph()`
785db2b9530SVaclav Hapla 
7868dbb0df6SBarry Smith   Fortran Notes:
78720662ed9SBarry Smith   The returned `iremote` array is a copy and must be deallocated after use. Consequently, if you
78820662ed9SBarry Smith   want to update the graph, you must call `PetscSFSetGraph()` after modifying the `iremote` array.
7898dbb0df6SBarry Smith 
79020662ed9SBarry Smith   To check for a `NULL` `ilocal` use
7918dbb0df6SBarry Smith $      if (loc(ilocal) == loc(PETSC_NULL_INTEGER)) then
792ca797d7aSLawrence Mitchell 
79320662ed9SBarry Smith .seealso: `PetscSF`, `PetscSFType`, `PetscSFCreate()`, `PetscSFView()`, `PetscSFSetGraph()`
79495fce210SBarry Smith @*/
795d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFGetGraph(PetscSF sf, PetscInt *nroots, PetscInt *nleaves, const PetscInt **ilocal, const PetscSFNode **iremote)
796d71ae5a4SJacob Faibussowitsch {
79795fce210SBarry Smith   PetscFunctionBegin;
79895fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
799b8dee149SJunchao Zhang   if (sf->ops->GetGraph) {
8009566063dSJacob Faibussowitsch     PetscCall((sf->ops->GetGraph)(sf, nroots, nleaves, ilocal, iremote));
801b8dee149SJunchao Zhang   } else {
80295fce210SBarry Smith     if (nroots) *nroots = sf->nroots;
80395fce210SBarry Smith     if (nleaves) *nleaves = sf->nleaves;
80495fce210SBarry Smith     if (ilocal) *ilocal = sf->mine;
80595fce210SBarry Smith     if (iremote) *iremote = sf->remote;
806b8dee149SJunchao Zhang   }
8073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
80895fce210SBarry Smith }
80995fce210SBarry Smith 
81029046d53SLisandro Dalcin /*@
81195fce210SBarry Smith   PetscSFGetLeafRange - Get the active leaf ranges
81295fce210SBarry Smith 
81395fce210SBarry Smith   Not Collective
81495fce210SBarry Smith 
8154165533cSJose E. Roman   Input Parameter:
81695fce210SBarry Smith . sf - star forest
81795fce210SBarry Smith 
8184165533cSJose E. Roman   Output Parameters:
81920662ed9SBarry Smith + minleaf - minimum active leaf on this process. Returns 0 if there are no leaves.
82020662ed9SBarry Smith - maxleaf - maximum active leaf on this process. Returns -1 if there are no leaves.
82195fce210SBarry Smith 
82295fce210SBarry Smith   Level: developer
82395fce210SBarry Smith 
82420662ed9SBarry Smith .seealso: `PetscSF`, `PetscSFType`, `PetscSFCreate()`, `PetscSFView()`, `PetscSFSetGraph()`, `PetscSFGetGraph()`
82595fce210SBarry Smith @*/
826d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFGetLeafRange(PetscSF sf, PetscInt *minleaf, PetscInt *maxleaf)
827d71ae5a4SJacob Faibussowitsch {
82895fce210SBarry Smith   PetscFunctionBegin;
82995fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
83029046d53SLisandro Dalcin   PetscSFCheckGraphSet(sf, 1);
83195fce210SBarry Smith   if (minleaf) *minleaf = sf->minleaf;
83295fce210SBarry Smith   if (maxleaf) *maxleaf = sf->maxleaf;
8333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
83495fce210SBarry Smith }
83595fce210SBarry Smith 
83695fce210SBarry Smith /*@C
837cab54364SBarry Smith   PetscSFViewFromOptions - View a `PetscSF` based on arguments in the options database
838fe2efc57SMark 
83920f4b53cSBarry Smith   Collective
840fe2efc57SMark 
841fe2efc57SMark   Input Parameters:
842fe2efc57SMark + A    - the star forest
843cab54364SBarry Smith . obj  - Optional object that provides the prefix for the option names
844736c3998SJose E. Roman - name - command line option
845fe2efc57SMark 
846fe2efc57SMark   Level: intermediate
847cab54364SBarry Smith 
84820662ed9SBarry Smith   Note:
84920662ed9SBarry Smith   See `PetscObjectViewFromOptions()` for possible `PetscViewer` and `PetscViewerFormat`
85020662ed9SBarry Smith 
851db781477SPatrick Sanan .seealso: `PetscSF`, `PetscSFView`, `PetscObjectViewFromOptions()`, `PetscSFCreate()`
852fe2efc57SMark @*/
853d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFViewFromOptions(PetscSF A, PetscObject obj, const char name[])
854d71ae5a4SJacob Faibussowitsch {
855fe2efc57SMark   PetscFunctionBegin;
856fe2efc57SMark   PetscValidHeaderSpecific(A, PETSCSF_CLASSID, 1);
8579566063dSJacob Faibussowitsch   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
8583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
859fe2efc57SMark }
860fe2efc57SMark 
861fe2efc57SMark /*@C
86295fce210SBarry Smith   PetscSFView - view a star forest
86395fce210SBarry Smith 
86495fce210SBarry Smith   Collective
86595fce210SBarry Smith 
8664165533cSJose E. Roman   Input Parameters:
86795fce210SBarry Smith + sf     - star forest
868cab54364SBarry Smith - viewer - viewer to display graph, for example `PETSC_VIEWER_STDOUT_WORLD`
86995fce210SBarry Smith 
87095fce210SBarry Smith   Level: beginner
87195fce210SBarry Smith 
872cab54364SBarry Smith .seealso: `PetscSF`, `PetscViewer`, `PetscSFCreate()`, `PetscSFSetGraph()`
87395fce210SBarry Smith @*/
874d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFView(PetscSF sf, PetscViewer viewer)
875d71ae5a4SJacob Faibussowitsch {
87695fce210SBarry Smith   PetscBool         iascii;
87795fce210SBarry Smith   PetscViewerFormat format;
87895fce210SBarry Smith 
87995fce210SBarry Smith   PetscFunctionBegin;
88095fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
8819566063dSJacob Faibussowitsch   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sf), &viewer));
88295fce210SBarry Smith   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
88395fce210SBarry Smith   PetscCheckSameComm(sf, 1, viewer, 2);
8849566063dSJacob Faibussowitsch   if (sf->graphset) PetscCall(PetscSFSetUp(sf));
8859566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
88653dd6d7dSJunchao Zhang   if (iascii && viewer->format != PETSC_VIEWER_ASCII_MATLAB) {
88795fce210SBarry Smith     PetscMPIInt rank;
88881bfa7aaSJed Brown     PetscInt    ii, i, j;
88995fce210SBarry Smith 
8909566063dSJacob Faibussowitsch     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)sf, viewer));
8919566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
892dd5b3ca6SJunchao Zhang     if (sf->pattern == PETSCSF_PATTERN_GENERAL) {
89380153354SVaclav Hapla       if (!sf->graphset) {
8949566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "PetscSFSetGraph() has not been called yet\n"));
8959566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPopTab(viewer));
8963ba16761SJacob Faibussowitsch         PetscFunctionReturn(PETSC_SUCCESS);
89780153354SVaclav Hapla       }
8989566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)sf), &rank));
8999566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
9009566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Number of roots=%" PetscInt_FMT ", leaves=%" PetscInt_FMT ", remote ranks=%" PetscInt_FMT "\n", rank, sf->nroots, sf->nleaves, sf->nranks));
90148a46eb9SPierre Jolivet       for (i = 0; i < sf->nleaves; i++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %" PetscInt_FMT " <- (%" PetscInt_FMT ",%" PetscInt_FMT ")\n", rank, sf->mine ? sf->mine[i] : i, sf->remote[i].rank, sf->remote[i].index));
9029566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
9039566063dSJacob Faibussowitsch       PetscCall(PetscViewerGetFormat(viewer, &format));
90495fce210SBarry Smith       if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
90581bfa7aaSJed Brown         PetscMPIInt *tmpranks, *perm;
9069566063dSJacob Faibussowitsch         PetscCall(PetscMalloc2(sf->nranks, &tmpranks, sf->nranks, &perm));
9079566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(tmpranks, sf->ranks, sf->nranks));
90881bfa7aaSJed Brown         for (i = 0; i < sf->nranks; i++) perm[i] = i;
9099566063dSJacob Faibussowitsch         PetscCall(PetscSortMPIIntWithArray(sf->nranks, tmpranks, perm));
9109566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Roots referenced by my leaves, by rank\n", rank));
91181bfa7aaSJed Brown         for (ii = 0; ii < sf->nranks; ii++) {
91281bfa7aaSJed Brown           i = perm[ii];
9139566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %d: %" PetscInt_FMT " edges\n", rank, sf->ranks[i], sf->roffset[i + 1] - sf->roffset[i]));
91448a46eb9SPierre Jolivet           for (j = sf->roffset[i]; j < sf->roffset[i + 1]; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]    %" PetscInt_FMT " <- %" PetscInt_FMT "\n", rank, sf->rmine[j], sf->rremote[j]));
91595fce210SBarry Smith         }
9169566063dSJacob Faibussowitsch         PetscCall(PetscFree2(tmpranks, perm));
91795fce210SBarry Smith       }
9189566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
9199566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
920dd5b3ca6SJunchao Zhang     }
9219566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
92295fce210SBarry Smith   }
923dbbe0bcdSBarry Smith   PetscTryTypeMethod(sf, View, viewer);
9243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
92595fce210SBarry Smith }
92695fce210SBarry Smith 
92795fce210SBarry Smith /*@C
928dec1416fSJunchao Zhang   PetscSFGetRootRanks - Get root ranks and number of vertices referenced by leaves on this process
92995fce210SBarry Smith 
93095fce210SBarry Smith   Not Collective
93195fce210SBarry Smith 
9324165533cSJose E. Roman   Input Parameter:
93395fce210SBarry Smith . sf - star forest
93495fce210SBarry Smith 
9354165533cSJose E. Roman   Output Parameters:
93695fce210SBarry Smith + nranks  - number of ranks referenced by local part
93720662ed9SBarry Smith . ranks   - [`nranks`] array of ranks
93820662ed9SBarry Smith . roffset - [`nranks`+1] offset in `rmine`/`rremote` for each rank
93920662ed9SBarry Smith . rmine   - [`roffset`[`nranks`]] concatenated array holding local indices referencing each remote rank
94020662ed9SBarry Smith - rremote - [`roffset`[`nranks`]] concatenated array holding remote indices referenced for each remote rank
94195fce210SBarry Smith 
94295fce210SBarry Smith   Level: developer
94395fce210SBarry Smith 
944cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFGetLeafRanks()`
94595fce210SBarry Smith @*/
946d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFGetRootRanks(PetscSF sf, PetscInt *nranks, const PetscMPIInt **ranks, const PetscInt **roffset, const PetscInt **rmine, const PetscInt **rremote)
947d71ae5a4SJacob Faibussowitsch {
94895fce210SBarry Smith   PetscFunctionBegin;
94995fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
95028b400f6SJacob Faibussowitsch   PetscCheck(sf->setupcalled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call PetscSFSetUp() before obtaining ranks");
951dec1416fSJunchao Zhang   if (sf->ops->GetRootRanks) {
9529566063dSJacob Faibussowitsch     PetscCall((sf->ops->GetRootRanks)(sf, nranks, ranks, roffset, rmine, rremote));
953dec1416fSJunchao Zhang   } else {
954dec1416fSJunchao Zhang     /* The generic implementation */
95595fce210SBarry Smith     if (nranks) *nranks = sf->nranks;
95695fce210SBarry Smith     if (ranks) *ranks = sf->ranks;
95795fce210SBarry Smith     if (roffset) *roffset = sf->roffset;
95895fce210SBarry Smith     if (rmine) *rmine = sf->rmine;
95995fce210SBarry Smith     if (rremote) *rremote = sf->rremote;
960dec1416fSJunchao Zhang   }
9613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
96295fce210SBarry Smith }
96395fce210SBarry Smith 
9648750ddebSJunchao Zhang /*@C
9658750ddebSJunchao Zhang   PetscSFGetLeafRanks - Get leaf ranks referencing roots on this process
9668750ddebSJunchao Zhang 
9678750ddebSJunchao Zhang   Not Collective
9688750ddebSJunchao Zhang 
9694165533cSJose E. Roman   Input Parameter:
9708750ddebSJunchao Zhang . sf - star forest
9718750ddebSJunchao Zhang 
9724165533cSJose E. Roman   Output Parameters:
9738750ddebSJunchao Zhang + niranks  - number of leaf ranks referencing roots on this process
97420662ed9SBarry Smith . iranks   - [`niranks`] array of ranks
97520662ed9SBarry Smith . ioffset  - [`niranks`+1] offset in `irootloc` for each rank
97620662ed9SBarry Smith - irootloc - [`ioffset`[`niranks`]] concatenated array holding local indices of roots referenced by each leaf rank
9778750ddebSJunchao Zhang 
9788750ddebSJunchao Zhang   Level: developer
9798750ddebSJunchao Zhang 
980cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFGetRootRanks()`
9818750ddebSJunchao Zhang @*/
982d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFGetLeafRanks(PetscSF sf, PetscInt *niranks, const PetscMPIInt **iranks, const PetscInt **ioffset, const PetscInt **irootloc)
983d71ae5a4SJacob Faibussowitsch {
9848750ddebSJunchao Zhang   PetscFunctionBegin;
9858750ddebSJunchao Zhang   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
98628b400f6SJacob Faibussowitsch   PetscCheck(sf->setupcalled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call PetscSFSetUp() before obtaining ranks");
9878750ddebSJunchao Zhang   if (sf->ops->GetLeafRanks) {
9889566063dSJacob Faibussowitsch     PetscCall((sf->ops->GetLeafRanks)(sf, niranks, iranks, ioffset, irootloc));
9898750ddebSJunchao Zhang   } else {
9908750ddebSJunchao Zhang     PetscSFType type;
9919566063dSJacob Faibussowitsch     PetscCall(PetscSFGetType(sf, &type));
99298921bdaSJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "PetscSFGetLeafRanks() is not supported on this StarForest type: %s", type);
9938750ddebSJunchao Zhang   }
9943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9958750ddebSJunchao Zhang }
9968750ddebSJunchao Zhang 
997d71ae5a4SJacob Faibussowitsch static PetscBool InList(PetscMPIInt needle, PetscMPIInt n, const PetscMPIInt *list)
998d71ae5a4SJacob Faibussowitsch {
999b5a8e515SJed Brown   PetscInt i;
1000b5a8e515SJed Brown   for (i = 0; i < n; i++) {
1001b5a8e515SJed Brown     if (needle == list[i]) return PETSC_TRUE;
1002b5a8e515SJed Brown   }
1003b5a8e515SJed Brown   return PETSC_FALSE;
1004b5a8e515SJed Brown }
1005b5a8e515SJed Brown 
100695fce210SBarry Smith /*@C
1007cab54364SBarry Smith   PetscSFSetUpRanks - Set up data structures associated with ranks; this is for internal use by `PetscSF` implementations.
100821c688dcSJed Brown 
100921c688dcSJed Brown   Collective
101021c688dcSJed Brown 
10114165533cSJose E. Roman   Input Parameters:
1012cab54364SBarry Smith + sf     - `PetscSF` to set up; `PetscSFSetGraph()` must have been called
1013cab54364SBarry Smith - dgroup - `MPI_Group` of ranks to be distinguished (e.g., for self or shared memory exchange)
101421c688dcSJed Brown 
101521c688dcSJed Brown   Level: developer
101621c688dcSJed Brown 
1017cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFGetRootRanks()`
101821c688dcSJed Brown @*/
1019d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFSetUpRanks(PetscSF sf, MPI_Group dgroup)
1020d71ae5a4SJacob Faibussowitsch {
1021eec179cfSJacob Faibussowitsch   PetscHMapI    table;
1022eec179cfSJacob Faibussowitsch   PetscHashIter pos;
1023b5a8e515SJed Brown   PetscMPIInt   size, groupsize, *groupranks;
1024247e8311SStefano Zampini   PetscInt     *rcount, *ranks;
1025247e8311SStefano Zampini   PetscInt      i, irank = -1, orank = -1;
102621c688dcSJed Brown 
102721c688dcSJed Brown   PetscFunctionBegin;
102821c688dcSJed Brown   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
102929046d53SLisandro Dalcin   PetscSFCheckGraphSet(sf, 1);
10309566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)sf), &size));
1031eec179cfSJacob Faibussowitsch   PetscCall(PetscHMapICreateWithSize(10, &table));
103221c688dcSJed Brown   for (i = 0; i < sf->nleaves; i++) {
103321c688dcSJed Brown     /* Log 1-based rank */
1034eec179cfSJacob Faibussowitsch     PetscCall(PetscHMapISetWithMode(table, sf->remote[i].rank + 1, 1, ADD_VALUES));
103521c688dcSJed Brown   }
1036eec179cfSJacob Faibussowitsch   PetscCall(PetscHMapIGetSize(table, &sf->nranks));
10379566063dSJacob Faibussowitsch   PetscCall(PetscMalloc4(sf->nranks, &sf->ranks, sf->nranks + 1, &sf->roffset, sf->nleaves, &sf->rmine, sf->nleaves, &sf->rremote));
10389566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(sf->nranks, &rcount, sf->nranks, &ranks));
1039eec179cfSJacob Faibussowitsch   PetscHashIterBegin(table, pos);
104021c688dcSJed Brown   for (i = 0; i < sf->nranks; i++) {
1041eec179cfSJacob Faibussowitsch     PetscHashIterGetKey(table, pos, ranks[i]);
1042eec179cfSJacob Faibussowitsch     PetscHashIterGetVal(table, pos, rcount[i]);
1043eec179cfSJacob Faibussowitsch     PetscHashIterNext(table, pos);
104421c688dcSJed Brown     ranks[i]--; /* Convert back to 0-based */
104521c688dcSJed Brown   }
1046eec179cfSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&table));
1047b5a8e515SJed Brown 
1048b5a8e515SJed Brown   /* We expect that dgroup is reliably "small" while nranks could be large */
1049b5a8e515SJed Brown   {
10507fb8a5e4SKarl Rupp     MPI_Group    group = MPI_GROUP_NULL;
1051b5a8e515SJed Brown     PetscMPIInt *dgroupranks;
10529566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_group(PetscObjectComm((PetscObject)sf), &group));
10539566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Group_size(dgroup, &groupsize));
10549566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(groupsize, &dgroupranks));
10559566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(groupsize, &groupranks));
1056b5a8e515SJed Brown     for (i = 0; i < groupsize; i++) dgroupranks[i] = i;
10579566063dSJacob Faibussowitsch     if (groupsize) PetscCallMPI(MPI_Group_translate_ranks(dgroup, groupsize, dgroupranks, group, groupranks));
10589566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Group_free(&group));
10599566063dSJacob Faibussowitsch     PetscCall(PetscFree(dgroupranks));
1060b5a8e515SJed Brown   }
1061b5a8e515SJed Brown 
1062b5a8e515SJed Brown   /* Partition ranks[] into distinguished (first sf->ndranks) followed by non-distinguished */
1063b5a8e515SJed Brown   for (sf->ndranks = 0, i = sf->nranks; sf->ndranks < i;) {
1064b5a8e515SJed Brown     for (i--; sf->ndranks < i; i--) { /* Scan i backward looking for distinguished rank */
1065b5a8e515SJed Brown       if (InList(ranks[i], groupsize, groupranks)) break;
1066b5a8e515SJed Brown     }
1067b5a8e515SJed Brown     for (; sf->ndranks <= i; sf->ndranks++) { /* Scan sf->ndranks forward looking for non-distinguished rank */
1068b5a8e515SJed Brown       if (!InList(ranks[sf->ndranks], groupsize, groupranks)) break;
1069b5a8e515SJed Brown     }
1070b5a8e515SJed Brown     if (sf->ndranks < i) { /* Swap ranks[sf->ndranks] with ranks[i] */
1071b5a8e515SJed Brown       PetscInt tmprank, tmpcount;
1072247e8311SStefano Zampini 
1073b5a8e515SJed Brown       tmprank             = ranks[i];
1074b5a8e515SJed Brown       tmpcount            = rcount[i];
1075b5a8e515SJed Brown       ranks[i]            = ranks[sf->ndranks];
1076b5a8e515SJed Brown       rcount[i]           = rcount[sf->ndranks];
1077b5a8e515SJed Brown       ranks[sf->ndranks]  = tmprank;
1078b5a8e515SJed Brown       rcount[sf->ndranks] = tmpcount;
1079b5a8e515SJed Brown       sf->ndranks++;
1080b5a8e515SJed Brown     }
1081b5a8e515SJed Brown   }
10829566063dSJacob Faibussowitsch   PetscCall(PetscFree(groupranks));
10839566063dSJacob Faibussowitsch   PetscCall(PetscSortIntWithArray(sf->ndranks, ranks, rcount));
10845c0db29aSPierre Jolivet   if (rcount) PetscCall(PetscSortIntWithArray(sf->nranks - sf->ndranks, ranks + sf->ndranks, rcount + sf->ndranks));
108521c688dcSJed Brown   sf->roffset[0] = 0;
108621c688dcSJed Brown   for (i = 0; i < sf->nranks; i++) {
10879566063dSJacob Faibussowitsch     PetscCall(PetscMPIIntCast(ranks[i], sf->ranks + i));
108821c688dcSJed Brown     sf->roffset[i + 1] = sf->roffset[i] + rcount[i];
108921c688dcSJed Brown     rcount[i]          = 0;
109021c688dcSJed Brown   }
1091247e8311SStefano Zampini   for (i = 0, irank = -1, orank = -1; i < sf->nleaves; i++) {
1092247e8311SStefano Zampini     /* short circuit */
1093247e8311SStefano Zampini     if (orank != sf->remote[i].rank) {
109421c688dcSJed Brown       /* Search for index of iremote[i].rank in sf->ranks */
10959566063dSJacob Faibussowitsch       PetscCall(PetscFindMPIInt(sf->remote[i].rank, sf->ndranks, sf->ranks, &irank));
1096b5a8e515SJed Brown       if (irank < 0) {
10979566063dSJacob Faibussowitsch         PetscCall(PetscFindMPIInt(sf->remote[i].rank, sf->nranks - sf->ndranks, sf->ranks + sf->ndranks, &irank));
1098b5a8e515SJed Brown         if (irank >= 0) irank += sf->ndranks;
109921c688dcSJed Brown       }
1100247e8311SStefano Zampini       orank = sf->remote[i].rank;
1101247e8311SStefano Zampini     }
110208401ef6SPierre Jolivet     PetscCheck(irank >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find rank %" PetscInt_FMT " in array", sf->remote[i].rank);
110321c688dcSJed Brown     sf->rmine[sf->roffset[irank] + rcount[irank]]   = sf->mine ? sf->mine[i] : i;
110421c688dcSJed Brown     sf->rremote[sf->roffset[irank] + rcount[irank]] = sf->remote[i].index;
110521c688dcSJed Brown     rcount[irank]++;
110621c688dcSJed Brown   }
11079566063dSJacob Faibussowitsch   PetscCall(PetscFree2(rcount, ranks));
11083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
110921c688dcSJed Brown }
111021c688dcSJed Brown 
111121c688dcSJed Brown /*@C
111295fce210SBarry Smith   PetscSFGetGroups - gets incoming and outgoing process groups
111395fce210SBarry Smith 
111495fce210SBarry Smith   Collective
111595fce210SBarry Smith 
11164165533cSJose E. Roman   Input Parameter:
111795fce210SBarry Smith . sf - star forest
111895fce210SBarry Smith 
11194165533cSJose E. Roman   Output Parameters:
112095fce210SBarry Smith + incoming - group of origin processes for incoming edges (leaves that reference my roots)
112195fce210SBarry Smith - outgoing - group of destination processes for outgoing edges (roots that I reference)
112295fce210SBarry Smith 
112395fce210SBarry Smith   Level: developer
112495fce210SBarry Smith 
1125cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFGetWindow()`, `PetscSFRestoreWindow()`
112695fce210SBarry Smith @*/
1127d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFGetGroups(PetscSF sf, MPI_Group *incoming, MPI_Group *outgoing)
1128d71ae5a4SJacob Faibussowitsch {
11297fb8a5e4SKarl Rupp   MPI_Group group = MPI_GROUP_NULL;
113095fce210SBarry Smith 
113195fce210SBarry Smith   PetscFunctionBegin;
113208401ef6SPierre Jolivet   PetscCheck(sf->nranks >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call PetscSFSetUpRanks() before obtaining groups");
113395fce210SBarry Smith   if (sf->ingroup == MPI_GROUP_NULL) {
113495fce210SBarry Smith     PetscInt        i;
113595fce210SBarry Smith     const PetscInt *indegree;
113695fce210SBarry Smith     PetscMPIInt     rank, *outranks, *inranks;
113795fce210SBarry Smith     PetscSFNode    *remote;
113895fce210SBarry Smith     PetscSF         bgcount;
113995fce210SBarry Smith 
114095fce210SBarry Smith     /* Compute the number of incoming ranks */
11419566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(sf->nranks, &remote));
114295fce210SBarry Smith     for (i = 0; i < sf->nranks; i++) {
114395fce210SBarry Smith       remote[i].rank  = sf->ranks[i];
114495fce210SBarry Smith       remote[i].index = 0;
114595fce210SBarry Smith     }
11469566063dSJacob Faibussowitsch     PetscCall(PetscSFDuplicate(sf, PETSCSF_DUPLICATE_CONFONLY, &bgcount));
11479566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(bgcount, 1, sf->nranks, NULL, PETSC_COPY_VALUES, remote, PETSC_OWN_POINTER));
11489566063dSJacob Faibussowitsch     PetscCall(PetscSFComputeDegreeBegin(bgcount, &indegree));
11499566063dSJacob Faibussowitsch     PetscCall(PetscSFComputeDegreeEnd(bgcount, &indegree));
115095fce210SBarry Smith     /* Enumerate the incoming ranks */
11519566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(indegree[0], &inranks, sf->nranks, &outranks));
11529566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)sf), &rank));
115395fce210SBarry Smith     for (i = 0; i < sf->nranks; i++) outranks[i] = rank;
11549566063dSJacob Faibussowitsch     PetscCall(PetscSFGatherBegin(bgcount, MPI_INT, outranks, inranks));
11559566063dSJacob Faibussowitsch     PetscCall(PetscSFGatherEnd(bgcount, MPI_INT, outranks, inranks));
11569566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_group(PetscObjectComm((PetscObject)sf), &group));
11579566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Group_incl(group, indegree[0], inranks, &sf->ingroup));
11589566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Group_free(&group));
11599566063dSJacob Faibussowitsch     PetscCall(PetscFree2(inranks, outranks));
11609566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&bgcount));
116195fce210SBarry Smith   }
116295fce210SBarry Smith   *incoming = sf->ingroup;
116395fce210SBarry Smith 
116495fce210SBarry Smith   if (sf->outgroup == MPI_GROUP_NULL) {
11659566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_group(PetscObjectComm((PetscObject)sf), &group));
11669566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Group_incl(group, sf->nranks, sf->ranks, &sf->outgroup));
11679566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Group_free(&group));
116895fce210SBarry Smith   }
116995fce210SBarry Smith   *outgoing = sf->outgroup;
11703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
117195fce210SBarry Smith }
117295fce210SBarry Smith 
117329046d53SLisandro Dalcin /*@
1174cab54364SBarry Smith   PetscSFGetMultiSF - gets the inner `PetscSF` implementing gathers and scatters
117595fce210SBarry Smith 
117695fce210SBarry Smith   Collective
117795fce210SBarry Smith 
11784165533cSJose E. Roman   Input Parameter:
117995fce210SBarry Smith . sf - star forest that may contain roots with 0 or with more than 1 vertex
118095fce210SBarry Smith 
11814165533cSJose E. Roman   Output Parameter:
118295fce210SBarry Smith . multi - star forest with split roots, such that each root has degree exactly 1
118395fce210SBarry Smith 
118495fce210SBarry Smith   Level: developer
118595fce210SBarry Smith 
1186cab54364SBarry Smith   Note:
1187cab54364SBarry Smith   In most cases, users should use `PetscSFGatherBegin()` and `PetscSFScatterBegin()` instead of manipulating multi
118895fce210SBarry Smith   directly. Since multi satisfies the stronger condition that each entry in the global space has exactly one incoming
118995fce210SBarry Smith   edge, it is a candidate for future optimization that might involve its removal.
119095fce210SBarry Smith 
1191cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFSetGraph()`, `PetscSFGatherBegin()`, `PetscSFScatterBegin()`, `PetscSFComputeMultiRootOriginalNumbering()`
119295fce210SBarry Smith @*/
1193d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFGetMultiSF(PetscSF sf, PetscSF *multi)
1194d71ae5a4SJacob Faibussowitsch {
119595fce210SBarry Smith   PetscFunctionBegin;
119695fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
11974f572ea9SToby Isaac   PetscAssertPointer(multi, 2);
119895fce210SBarry Smith   if (sf->nroots < 0) { /* Graph has not been set yet; why do we need this? */
11999566063dSJacob Faibussowitsch     PetscCall(PetscSFDuplicate(sf, PETSCSF_DUPLICATE_RANKS, &sf->multi));
120095fce210SBarry Smith     *multi           = sf->multi;
1201013b3241SStefano Zampini     sf->multi->multi = sf->multi;
12023ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
120395fce210SBarry Smith   }
120495fce210SBarry Smith   if (!sf->multi) {
120595fce210SBarry Smith     const PetscInt *indegree;
12069837ea96SMatthew G. Knepley     PetscInt        i, *inoffset, *outones, *outoffset, maxlocal;
120795fce210SBarry Smith     PetscSFNode    *remote;
120829046d53SLisandro Dalcin     maxlocal = sf->maxleaf + 1; /* TODO: We should use PetscSFGetLeafRange() */
12099566063dSJacob Faibussowitsch     PetscCall(PetscSFComputeDegreeBegin(sf, &indegree));
12109566063dSJacob Faibussowitsch     PetscCall(PetscSFComputeDegreeEnd(sf, &indegree));
12119566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(sf->nroots + 1, &inoffset, maxlocal, &outones, maxlocal, &outoffset));
121295fce210SBarry Smith     inoffset[0] = 0;
121395fce210SBarry Smith     for (i = 0; i < sf->nroots; i++) inoffset[i + 1] = inoffset[i] + indegree[i];
12149837ea96SMatthew G. Knepley     for (i = 0; i < maxlocal; i++) outones[i] = 1;
12159566063dSJacob Faibussowitsch     PetscCall(PetscSFFetchAndOpBegin(sf, MPIU_INT, inoffset, outones, outoffset, MPI_SUM));
12169566063dSJacob Faibussowitsch     PetscCall(PetscSFFetchAndOpEnd(sf, MPIU_INT, inoffset, outones, outoffset, MPI_SUM));
121795fce210SBarry Smith     for (i = 0; i < sf->nroots; i++) inoffset[i] -= indegree[i]; /* Undo the increment */
121876bd3646SJed Brown     if (PetscDefined(USE_DEBUG)) {                               /* Check that the expected number of increments occurred */
1219ad540459SPierre Jolivet       for (i = 0; i < sf->nroots; i++) PetscCheck(inoffset[i] + indegree[i] == inoffset[i + 1], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Incorrect result after PetscSFFetchAndOp");
122076bd3646SJed Brown     }
12219566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(sf->nleaves, &remote));
122295fce210SBarry Smith     for (i = 0; i < sf->nleaves; i++) {
122395fce210SBarry Smith       remote[i].rank  = sf->remote[i].rank;
122438e7336fSToby Isaac       remote[i].index = outoffset[sf->mine ? sf->mine[i] : i];
122595fce210SBarry Smith     }
12269566063dSJacob Faibussowitsch     PetscCall(PetscSFDuplicate(sf, PETSCSF_DUPLICATE_RANKS, &sf->multi));
1227013b3241SStefano Zampini     sf->multi->multi = sf->multi;
12289566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(sf->multi, inoffset[sf->nroots], sf->nleaves, sf->mine, PETSC_COPY_VALUES, remote, PETSC_OWN_POINTER));
122995fce210SBarry Smith     if (sf->rankorder) { /* Sort the ranks */
123095fce210SBarry Smith       PetscMPIInt  rank;
123195fce210SBarry Smith       PetscInt    *inranks, *newoffset, *outranks, *newoutoffset, *tmpoffset, maxdegree;
123295fce210SBarry Smith       PetscSFNode *newremote;
12339566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)sf), &rank));
123495fce210SBarry Smith       for (i = 0, maxdegree = 0; i < sf->nroots; i++) maxdegree = PetscMax(maxdegree, indegree[i]);
12359566063dSJacob Faibussowitsch       PetscCall(PetscMalloc5(sf->multi->nroots, &inranks, sf->multi->nroots, &newoffset, maxlocal, &outranks, maxlocal, &newoutoffset, maxdegree, &tmpoffset));
12369837ea96SMatthew G. Knepley       for (i = 0; i < maxlocal; i++) outranks[i] = rank;
12379566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(sf->multi, MPIU_INT, outranks, inranks, MPI_REPLACE));
12389566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(sf->multi, MPIU_INT, outranks, inranks, MPI_REPLACE));
123995fce210SBarry Smith       /* Sort the incoming ranks at each vertex, build the inverse map */
124095fce210SBarry Smith       for (i = 0; i < sf->nroots; i++) {
124195fce210SBarry Smith         PetscInt j;
124295fce210SBarry Smith         for (j = 0; j < indegree[i]; j++) tmpoffset[j] = j;
12435c0db29aSPierre Jolivet         if (inranks) PetscCall(PetscSortIntWithArray(indegree[i], inranks + inoffset[i], tmpoffset));
124495fce210SBarry Smith         for (j = 0; j < indegree[i]; j++) newoffset[inoffset[i] + tmpoffset[j]] = inoffset[i] + j;
124595fce210SBarry Smith       }
12469566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(sf->multi, MPIU_INT, newoffset, newoutoffset, MPI_REPLACE));
12479566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(sf->multi, MPIU_INT, newoffset, newoutoffset, MPI_REPLACE));
12489566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(sf->nleaves, &newremote));
124995fce210SBarry Smith       for (i = 0; i < sf->nleaves; i++) {
125095fce210SBarry Smith         newremote[i].rank  = sf->remote[i].rank;
125101365b40SToby Isaac         newremote[i].index = newoutoffset[sf->mine ? sf->mine[i] : i];
125295fce210SBarry Smith       }
12539566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraph(sf->multi, inoffset[sf->nroots], sf->nleaves, sf->mine, PETSC_COPY_VALUES, newremote, PETSC_OWN_POINTER));
12549566063dSJacob Faibussowitsch       PetscCall(PetscFree5(inranks, newoffset, outranks, newoutoffset, tmpoffset));
125595fce210SBarry Smith     }
12569566063dSJacob Faibussowitsch     PetscCall(PetscFree3(inoffset, outones, outoffset));
125795fce210SBarry Smith   }
125895fce210SBarry Smith   *multi = sf->multi;
12593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
126095fce210SBarry Smith }
126195fce210SBarry Smith 
126295fce210SBarry Smith /*@C
126320662ed9SBarry Smith   PetscSFCreateEmbeddedRootSF - removes edges from all but the selected roots of a `PetscSF`, does not remap indices
126495fce210SBarry Smith 
126595fce210SBarry Smith   Collective
126695fce210SBarry Smith 
12674165533cSJose E. Roman   Input Parameters:
126895fce210SBarry Smith + sf        - original star forest
1269ba2a7774SJunchao Zhang . nselected - number of selected roots on this process
1270ba2a7774SJunchao Zhang - selected  - indices of the selected roots on this process
127195fce210SBarry Smith 
12724165533cSJose E. Roman   Output Parameter:
1273cd620004SJunchao Zhang . esf - new star forest
127495fce210SBarry Smith 
127595fce210SBarry Smith   Level: advanced
127695fce210SBarry Smith 
127795fce210SBarry Smith   Note:
1278cab54364SBarry Smith   To use the new `PetscSF`, it may be necessary to know the indices of the leaves that are still participating. This can
127995fce210SBarry Smith   be done by calling PetscSFGetGraph().
128095fce210SBarry Smith 
1281cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFSetGraph()`, `PetscSFGetGraph()`
128295fce210SBarry Smith @*/
1283d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFCreateEmbeddedRootSF(PetscSF sf, PetscInt nselected, const PetscInt *selected, PetscSF *esf)
1284d71ae5a4SJacob Faibussowitsch {
1285cd620004SJunchao Zhang   PetscInt           i, j, n, nroots, nleaves, esf_nleaves, *new_ilocal, minleaf, maxleaf, maxlocal;
1286cd620004SJunchao Zhang   const PetscInt    *ilocal;
1287cd620004SJunchao Zhang   signed char       *rootdata, *leafdata, *leafmem;
1288ba2a7774SJunchao Zhang   const PetscSFNode *iremote;
1289f659e5c7SJunchao Zhang   PetscSFNode       *new_iremote;
1290f659e5c7SJunchao Zhang   MPI_Comm           comm;
129195fce210SBarry Smith 
129295fce210SBarry Smith   PetscFunctionBegin;
129395fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
129429046d53SLisandro Dalcin   PetscSFCheckGraphSet(sf, 1);
12954f572ea9SToby Isaac   if (nselected) PetscAssertPointer(selected, 3);
12964f572ea9SToby Isaac   PetscAssertPointer(esf, 4);
12970511a646SMatthew G. Knepley 
12989566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUp(sf));
12999566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCSF_EmbedSF, sf, 0, 0, 0));
13009566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
13019566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &nroots, &nleaves, &ilocal, &iremote));
1302cd620004SJunchao Zhang 
130376bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) { /* Error out if selected[] has dups or  out of range indices */
1304cd620004SJunchao Zhang     PetscBool dups;
13059566063dSJacob Faibussowitsch     PetscCall(PetscCheckDupsInt(nselected, selected, &dups));
130628b400f6SJacob Faibussowitsch     PetscCheck(!dups, comm, PETSC_ERR_ARG_WRONG, "selected[] has dups");
13079371c9d4SSatish Balay     for (i = 0; i < nselected; i++) PetscCheck(selected[i] >= 0 && selected[i] < nroots, comm, PETSC_ERR_ARG_OUTOFRANGE, "selected root indice %" PetscInt_FMT " is out of [0,%" PetscInt_FMT ")", selected[i], nroots);
1308cd620004SJunchao Zhang   }
1309f659e5c7SJunchao Zhang 
1310dbbe0bcdSBarry Smith   if (sf->ops->CreateEmbeddedRootSF) PetscUseTypeMethod(sf, CreateEmbeddedRootSF, nselected, selected, esf);
1311dbbe0bcdSBarry Smith   else {
1312cd620004SJunchao Zhang     /* A generic version of creating embedded sf */
13139566063dSJacob Faibussowitsch     PetscCall(PetscSFGetLeafRange(sf, &minleaf, &maxleaf));
1314cd620004SJunchao Zhang     maxlocal = maxleaf - minleaf + 1;
13159566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(nroots, &rootdata, maxlocal, &leafmem));
1316cd620004SJunchao Zhang     leafdata = leafmem - minleaf;
1317cd620004SJunchao Zhang     /* Tag selected roots and bcast to leaves */
1318cd620004SJunchao Zhang     for (i = 0; i < nselected; i++) rootdata[selected[i]] = 1;
13199566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(sf, MPI_SIGNED_CHAR, rootdata, leafdata, MPI_REPLACE));
13209566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(sf, MPI_SIGNED_CHAR, rootdata, leafdata, MPI_REPLACE));
1321ba2a7774SJunchao Zhang 
1322cd620004SJunchao Zhang     /* Build esf with leaves that are still connected */
1323cd620004SJunchao Zhang     esf_nleaves = 0;
1324cd620004SJunchao Zhang     for (i = 0; i < nleaves; i++) {
1325cd620004SJunchao Zhang       j = ilocal ? ilocal[i] : i;
1326cd620004SJunchao Zhang       /* esf_nleaves += leafdata[j] should work in theory, but failed with SFWindow bugs
1327cd620004SJunchao Zhang          with PetscSFBcast. See https://gitlab.com/petsc/petsc/issues/555
1328cd620004SJunchao Zhang       */
1329cd620004SJunchao Zhang       esf_nleaves += (leafdata[j] ? 1 : 0);
1330cd620004SJunchao Zhang     }
13319566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(esf_nleaves, &new_ilocal));
13329566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(esf_nleaves, &new_iremote));
1333cd620004SJunchao Zhang     for (i = n = 0; i < nleaves; i++) {
1334cd620004SJunchao Zhang       j = ilocal ? ilocal[i] : i;
1335cd620004SJunchao Zhang       if (leafdata[j]) {
1336cd620004SJunchao Zhang         new_ilocal[n]        = j;
1337cd620004SJunchao Zhang         new_iremote[n].rank  = iremote[i].rank;
1338cd620004SJunchao Zhang         new_iremote[n].index = iremote[i].index;
1339fc1ede2bSMatthew G. Knepley         ++n;
134095fce210SBarry Smith       }
134195fce210SBarry Smith     }
13429566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(comm, esf));
13439566063dSJacob Faibussowitsch     PetscCall(PetscSFSetFromOptions(*esf));
13449566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(*esf, nroots, esf_nleaves, new_ilocal, PETSC_OWN_POINTER, new_iremote, PETSC_OWN_POINTER));
13459566063dSJacob Faibussowitsch     PetscCall(PetscFree2(rootdata, leafmem));
1346f659e5c7SJunchao Zhang   }
13479566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCSF_EmbedSF, sf, 0, 0, 0));
13483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
134995fce210SBarry Smith }
135095fce210SBarry Smith 
13512f5fb4c2SMatthew G. Knepley /*@C
135220662ed9SBarry Smith   PetscSFCreateEmbeddedLeafSF - removes edges from all but the selected leaves of a `PetscSF`, does not remap indices
13532f5fb4c2SMatthew G. Knepley 
13542f5fb4c2SMatthew G. Knepley   Collective
13552f5fb4c2SMatthew G. Knepley 
13564165533cSJose E. Roman   Input Parameters:
13572f5fb4c2SMatthew G. Knepley + sf        - original star forest
1358f659e5c7SJunchao Zhang . nselected - number of selected leaves on this process
1359f659e5c7SJunchao Zhang - selected  - indices of the selected leaves on this process
13602f5fb4c2SMatthew G. Knepley 
13614165533cSJose E. Roman   Output Parameter:
13622f5fb4c2SMatthew G. Knepley . newsf - new star forest
13632f5fb4c2SMatthew G. Knepley 
13642f5fb4c2SMatthew G. Knepley   Level: advanced
13652f5fb4c2SMatthew G. Knepley 
1366cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFCreateEmbeddedRootSF()`, `PetscSFSetGraph()`, `PetscSFGetGraph()`
13672f5fb4c2SMatthew G. Knepley @*/
1368d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFCreateEmbeddedLeafSF(PetscSF sf, PetscInt nselected, const PetscInt *selected, PetscSF *newsf)
1369d71ae5a4SJacob Faibussowitsch {
1370f659e5c7SJunchao Zhang   const PetscSFNode *iremote;
1371f659e5c7SJunchao Zhang   PetscSFNode       *new_iremote;
1372f659e5c7SJunchao Zhang   const PetscInt    *ilocal;
1373f659e5c7SJunchao Zhang   PetscInt           i, nroots, *leaves, *new_ilocal;
1374f659e5c7SJunchao Zhang   MPI_Comm           comm;
13752f5fb4c2SMatthew G. Knepley 
13762f5fb4c2SMatthew G. Knepley   PetscFunctionBegin;
13772f5fb4c2SMatthew G. Knepley   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
137829046d53SLisandro Dalcin   PetscSFCheckGraphSet(sf, 1);
13794f572ea9SToby Isaac   if (nselected) PetscAssertPointer(selected, 3);
13804f572ea9SToby Isaac   PetscAssertPointer(newsf, 4);
13812f5fb4c2SMatthew G. Knepley 
1382f659e5c7SJunchao Zhang   /* Uniq selected[] and put results in leaves[] */
13839566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
13849566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nselected, &leaves));
13859566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(leaves, selected, nselected));
13869566063dSJacob Faibussowitsch   PetscCall(PetscSortedRemoveDupsInt(&nselected, leaves));
138708401ef6SPierre Jolivet   PetscCheck(!nselected || !(leaves[0] < 0 || leaves[nselected - 1] >= sf->nleaves), comm, PETSC_ERR_ARG_OUTOFRANGE, "Min/Max leaf indices %" PetscInt_FMT "/%" PetscInt_FMT " are not in [0,%" PetscInt_FMT ")", leaves[0], leaves[nselected - 1], sf->nleaves);
1388f659e5c7SJunchao Zhang 
1389f659e5c7SJunchao Zhang   /* Optimize the routine only when sf is setup and hence we can reuse sf's communication pattern */
1390dbbe0bcdSBarry Smith   if (sf->setupcalled && sf->ops->CreateEmbeddedLeafSF) PetscUseTypeMethod(sf, CreateEmbeddedLeafSF, nselected, leaves, newsf);
1391dbbe0bcdSBarry Smith   else {
13929566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(sf, &nroots, NULL, &ilocal, &iremote));
13939566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nselected, &new_ilocal));
13949566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nselected, &new_iremote));
1395f659e5c7SJunchao Zhang     for (i = 0; i < nselected; ++i) {
1396f659e5c7SJunchao Zhang       const PetscInt l     = leaves[i];
1397f659e5c7SJunchao Zhang       new_ilocal[i]        = ilocal ? ilocal[l] : l;
1398f659e5c7SJunchao Zhang       new_iremote[i].rank  = iremote[l].rank;
1399f659e5c7SJunchao Zhang       new_iremote[i].index = iremote[l].index;
14002f5fb4c2SMatthew G. Knepley     }
14019566063dSJacob Faibussowitsch     PetscCall(PetscSFDuplicate(sf, PETSCSF_DUPLICATE_CONFONLY, newsf));
14029566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(*newsf, nroots, nselected, new_ilocal, PETSC_OWN_POINTER, new_iremote, PETSC_OWN_POINTER));
1403f659e5c7SJunchao Zhang   }
14049566063dSJacob Faibussowitsch   PetscCall(PetscFree(leaves));
14053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14062f5fb4c2SMatthew G. Knepley }
14072f5fb4c2SMatthew G. Knepley 
140895fce210SBarry Smith /*@C
1409cab54364SBarry Smith   PetscSFBcastBegin - begin pointwise broadcast with root value being reduced to leaf value, to be concluded with call to `PetscSFBcastEnd()`
14103482bfa8SJunchao Zhang 
1411c3339decSBarry Smith   Collective
14123482bfa8SJunchao Zhang 
14134165533cSJose E. Roman   Input Parameters:
14143482bfa8SJunchao Zhang + sf       - star forest on which to communicate
14153482bfa8SJunchao Zhang . unit     - data type associated with each node
14163482bfa8SJunchao Zhang . rootdata - buffer to broadcast
14173482bfa8SJunchao Zhang - op       - operation to use for reduction
14183482bfa8SJunchao Zhang 
14194165533cSJose E. Roman   Output Parameter:
14203482bfa8SJunchao Zhang . leafdata - buffer to be reduced with values from each leaf's respective root
14213482bfa8SJunchao Zhang 
14223482bfa8SJunchao Zhang   Level: intermediate
14233482bfa8SJunchao Zhang 
142420662ed9SBarry Smith   Note:
142520662ed9SBarry Smith   When PETSc is configured with device support, it will use its own mechanism to figure out whether the given data pointers
1426da81f932SPierre Jolivet   are host pointers or device pointers, which may incur a noticeable cost. If you already knew the info, you should
1427cab54364SBarry Smith   use `PetscSFBcastWithMemTypeBegin()` instead.
1428cab54364SBarry Smith 
1429cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFBcastEnd()`, `PetscSFBcastWithMemTypeBegin()`
14303482bfa8SJunchao Zhang @*/
1431d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFBcastBegin(PetscSF sf, MPI_Datatype unit, const void *rootdata, void *leafdata, MPI_Op op)
1432d71ae5a4SJacob Faibussowitsch {
1433eb02082bSJunchao Zhang   PetscMemType rootmtype, leafmtype;
14343482bfa8SJunchao Zhang 
14353482bfa8SJunchao Zhang   PetscFunctionBegin;
14363482bfa8SJunchao Zhang   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
14379566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUp(sf));
14389566063dSJacob Faibussowitsch   if (!sf->vscat.logging) PetscCall(PetscLogEventBegin(PETSCSF_BcastBegin, sf, 0, 0, 0));
14399566063dSJacob Faibussowitsch   PetscCall(PetscGetMemType(rootdata, &rootmtype));
14409566063dSJacob Faibussowitsch   PetscCall(PetscGetMemType(leafdata, &leafmtype));
1441dbbe0bcdSBarry Smith   PetscUseTypeMethod(sf, BcastBegin, unit, rootmtype, rootdata, leafmtype, leafdata, op);
14429566063dSJacob Faibussowitsch   if (!sf->vscat.logging) PetscCall(PetscLogEventEnd(PETSCSF_BcastBegin, sf, 0, 0, 0));
14433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14443482bfa8SJunchao Zhang }
14453482bfa8SJunchao Zhang 
14463482bfa8SJunchao Zhang /*@C
144720662ed9SBarry Smith   PetscSFBcastWithMemTypeBegin - begin pointwise broadcast with root value being reduced to leaf value with explicit memory types, to be concluded with call
144820662ed9SBarry Smith   to `PetscSFBcastEnd()`
1449d0295fc0SJunchao Zhang 
1450c3339decSBarry Smith   Collective
1451d0295fc0SJunchao Zhang 
14524165533cSJose E. Roman   Input Parameters:
1453d0295fc0SJunchao Zhang + sf        - star forest on which to communicate
1454d0295fc0SJunchao Zhang . unit      - data type associated with each node
1455d0295fc0SJunchao Zhang . rootmtype - memory type of rootdata
1456d0295fc0SJunchao Zhang . rootdata  - buffer to broadcast
1457d0295fc0SJunchao Zhang . leafmtype - memory type of leafdata
1458d0295fc0SJunchao Zhang - op        - operation to use for reduction
1459d0295fc0SJunchao Zhang 
14604165533cSJose E. Roman   Output Parameter:
1461d0295fc0SJunchao Zhang . leafdata - buffer to be reduced with values from each leaf's respective root
1462d0295fc0SJunchao Zhang 
1463d0295fc0SJunchao Zhang   Level: intermediate
1464d0295fc0SJunchao Zhang 
1465cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFBcastEnd()`, `PetscSFBcastBegin()`
1466d0295fc0SJunchao Zhang @*/
1467d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFBcastWithMemTypeBegin(PetscSF sf, MPI_Datatype unit, PetscMemType rootmtype, const void *rootdata, PetscMemType leafmtype, void *leafdata, MPI_Op op)
1468d71ae5a4SJacob Faibussowitsch {
1469d0295fc0SJunchao Zhang   PetscFunctionBegin;
1470d0295fc0SJunchao Zhang   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
14719566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUp(sf));
14729566063dSJacob Faibussowitsch   if (!sf->vscat.logging) PetscCall(PetscLogEventBegin(PETSCSF_BcastBegin, sf, 0, 0, 0));
1473dbbe0bcdSBarry Smith   PetscUseTypeMethod(sf, BcastBegin, unit, rootmtype, rootdata, leafmtype, leafdata, op);
14749566063dSJacob Faibussowitsch   if (!sf->vscat.logging) PetscCall(PetscLogEventEnd(PETSCSF_BcastBegin, sf, 0, 0, 0));
14753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1476d0295fc0SJunchao Zhang }
1477d0295fc0SJunchao Zhang 
1478d0295fc0SJunchao Zhang /*@C
147920662ed9SBarry Smith   PetscSFBcastEnd - end a broadcast and reduce operation started with `PetscSFBcastBegin()` or `PetscSFBcastWithMemTypeBegin()`
14803482bfa8SJunchao Zhang 
14813482bfa8SJunchao Zhang   Collective
14823482bfa8SJunchao Zhang 
14834165533cSJose E. Roman   Input Parameters:
14843482bfa8SJunchao Zhang + sf       - star forest
14853482bfa8SJunchao Zhang . unit     - data type
14863482bfa8SJunchao Zhang . rootdata - buffer to broadcast
14873482bfa8SJunchao Zhang - op       - operation to use for reduction
14883482bfa8SJunchao Zhang 
14894165533cSJose E. Roman   Output Parameter:
14903482bfa8SJunchao Zhang . leafdata - buffer to be reduced with values from each leaf's respective root
14913482bfa8SJunchao Zhang 
14923482bfa8SJunchao Zhang   Level: intermediate
14933482bfa8SJunchao Zhang 
1494cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFSetGraph()`, `PetscSFReduceEnd()`
14953482bfa8SJunchao Zhang @*/
1496d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFBcastEnd(PetscSF sf, MPI_Datatype unit, const void *rootdata, void *leafdata, MPI_Op op)
1497d71ae5a4SJacob Faibussowitsch {
14983482bfa8SJunchao Zhang   PetscFunctionBegin;
14993482bfa8SJunchao Zhang   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
15009566063dSJacob Faibussowitsch   if (!sf->vscat.logging) PetscCall(PetscLogEventBegin(PETSCSF_BcastEnd, sf, 0, 0, 0));
1501dbbe0bcdSBarry Smith   PetscUseTypeMethod(sf, BcastEnd, unit, rootdata, leafdata, op);
15029566063dSJacob Faibussowitsch   if (!sf->vscat.logging) PetscCall(PetscLogEventEnd(PETSCSF_BcastEnd, sf, 0, 0, 0));
15033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15043482bfa8SJunchao Zhang }
15053482bfa8SJunchao Zhang 
15063482bfa8SJunchao Zhang /*@C
1507cab54364SBarry Smith   PetscSFReduceBegin - begin reduction of leafdata into rootdata, to be completed with call to `PetscSFReduceEnd()`
150895fce210SBarry Smith 
150995fce210SBarry Smith   Collective
151095fce210SBarry Smith 
15114165533cSJose E. Roman   Input Parameters:
151295fce210SBarry Smith + sf       - star forest
151395fce210SBarry Smith . unit     - data type
151495fce210SBarry Smith . leafdata - values to reduce
151595fce210SBarry Smith - op       - reduction operation
151695fce210SBarry Smith 
15174165533cSJose E. Roman   Output Parameter:
151895fce210SBarry Smith . rootdata - result of reduction of values from all leaves of each root
151995fce210SBarry Smith 
152095fce210SBarry Smith   Level: intermediate
152195fce210SBarry Smith 
152220662ed9SBarry Smith   Note:
152320662ed9SBarry Smith   When PETSc is configured with device support, it will use its own mechanism to figure out whether the given data pointers
1524da81f932SPierre Jolivet   are host pointers or device pointers, which may incur a noticeable cost. If you already knew the info, you should
1525cab54364SBarry Smith   use `PetscSFReduceWithMemTypeBegin()` instead.
1526d0295fc0SJunchao Zhang 
152720662ed9SBarry Smith .seealso: `PetscSF`, `PetscSFBcastBegin()`, `PetscSFReduceWithMemTypeBegin()`, `PetscSFReduceEnd()`
152895fce210SBarry Smith @*/
1529d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFReduceBegin(PetscSF sf, MPI_Datatype unit, const void *leafdata, void *rootdata, MPI_Op op)
1530d71ae5a4SJacob Faibussowitsch {
1531eb02082bSJunchao Zhang   PetscMemType rootmtype, leafmtype;
153295fce210SBarry Smith 
153395fce210SBarry Smith   PetscFunctionBegin;
153495fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
15359566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUp(sf));
15369566063dSJacob Faibussowitsch   if (!sf->vscat.logging) PetscCall(PetscLogEventBegin(PETSCSF_ReduceBegin, sf, 0, 0, 0));
15379566063dSJacob Faibussowitsch   PetscCall(PetscGetMemType(rootdata, &rootmtype));
15389566063dSJacob Faibussowitsch   PetscCall(PetscGetMemType(leafdata, &leafmtype));
15399566063dSJacob Faibussowitsch   PetscCall((sf->ops->ReduceBegin)(sf, unit, leafmtype, leafdata, rootmtype, rootdata, op));
15409566063dSJacob Faibussowitsch   if (!sf->vscat.logging) PetscCall(PetscLogEventEnd(PETSCSF_ReduceBegin, sf, 0, 0, 0));
15413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
154295fce210SBarry Smith }
154395fce210SBarry Smith 
154495fce210SBarry Smith /*@C
1545cab54364SBarry Smith   PetscSFReduceWithMemTypeBegin - begin reduction of leafdata into rootdata with explicit memory types, to be completed with call to `PetscSFReduceEnd()`
1546d0295fc0SJunchao Zhang 
1547d0295fc0SJunchao Zhang   Collective
1548d0295fc0SJunchao Zhang 
15494165533cSJose E. Roman   Input Parameters:
1550d0295fc0SJunchao Zhang + sf        - star forest
1551d0295fc0SJunchao Zhang . unit      - data type
1552d0295fc0SJunchao Zhang . leafmtype - memory type of leafdata
1553d0295fc0SJunchao Zhang . leafdata  - values to reduce
1554d0295fc0SJunchao Zhang . rootmtype - memory type of rootdata
1555d0295fc0SJunchao Zhang - op        - reduction operation
1556d0295fc0SJunchao Zhang 
15574165533cSJose E. Roman   Output Parameter:
1558d0295fc0SJunchao Zhang . rootdata - result of reduction of values from all leaves of each root
1559d0295fc0SJunchao Zhang 
1560d0295fc0SJunchao Zhang   Level: intermediate
1561d0295fc0SJunchao Zhang 
156220662ed9SBarry Smith .seealso: `PetscSF`, `PetscSFBcastBegin()`, `PetscSFReduceBegin()`, `PetscSFReduceEnd()`
1563d0295fc0SJunchao Zhang @*/
1564d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFReduceWithMemTypeBegin(PetscSF sf, MPI_Datatype unit, PetscMemType leafmtype, const void *leafdata, PetscMemType rootmtype, void *rootdata, MPI_Op op)
1565d71ae5a4SJacob Faibussowitsch {
1566d0295fc0SJunchao Zhang   PetscFunctionBegin;
1567d0295fc0SJunchao Zhang   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
15689566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUp(sf));
15699566063dSJacob Faibussowitsch   if (!sf->vscat.logging) PetscCall(PetscLogEventBegin(PETSCSF_ReduceBegin, sf, 0, 0, 0));
15709566063dSJacob Faibussowitsch   PetscCall((sf->ops->ReduceBegin)(sf, unit, leafmtype, leafdata, rootmtype, rootdata, op));
15719566063dSJacob Faibussowitsch   if (!sf->vscat.logging) PetscCall(PetscLogEventEnd(PETSCSF_ReduceBegin, sf, 0, 0, 0));
15723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1573d0295fc0SJunchao Zhang }
1574d0295fc0SJunchao Zhang 
1575d0295fc0SJunchao Zhang /*@C
157620662ed9SBarry Smith   PetscSFReduceEnd - end a reduction operation started with `PetscSFReduceBegin()` or `PetscSFReduceWithMemTypeBegin()`
157795fce210SBarry Smith 
157895fce210SBarry Smith   Collective
157995fce210SBarry Smith 
15804165533cSJose E. Roman   Input Parameters:
158195fce210SBarry Smith + sf       - star forest
158295fce210SBarry Smith . unit     - data type
158395fce210SBarry Smith . leafdata - values to reduce
158495fce210SBarry Smith - op       - reduction operation
158595fce210SBarry Smith 
15864165533cSJose E. Roman   Output Parameter:
158795fce210SBarry Smith . rootdata - result of reduction of values from all leaves of each root
158895fce210SBarry Smith 
158995fce210SBarry Smith   Level: intermediate
159095fce210SBarry Smith 
159120662ed9SBarry Smith .seealso: `PetscSF`, `PetscSFSetGraph()`, `PetscSFBcastEnd()`, `PetscSFReduceBegin()`, `PetscSFReduceWithMemTypeBegin()`
159295fce210SBarry Smith @*/
1593d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFReduceEnd(PetscSF sf, MPI_Datatype unit, const void *leafdata, void *rootdata, MPI_Op op)
1594d71ae5a4SJacob Faibussowitsch {
159595fce210SBarry Smith   PetscFunctionBegin;
159695fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
15979566063dSJacob Faibussowitsch   if (!sf->vscat.logging) PetscCall(PetscLogEventBegin(PETSCSF_ReduceEnd, sf, 0, 0, 0));
1598dbbe0bcdSBarry Smith   PetscUseTypeMethod(sf, ReduceEnd, unit, leafdata, rootdata, op);
15999566063dSJacob Faibussowitsch   if (!sf->vscat.logging) PetscCall(PetscLogEventEnd(PETSCSF_ReduceEnd, sf, 0, 0, 0));
16003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
160195fce210SBarry Smith }
160295fce210SBarry Smith 
160395fce210SBarry Smith /*@C
1604cab54364SBarry Smith   PetscSFFetchAndOpBegin - begin operation that fetches values from root and updates atomically by applying operation using my leaf value,
1605cab54364SBarry Smith   to be completed with `PetscSFFetchAndOpEnd()`
1606a1729e3fSJunchao Zhang 
1607a1729e3fSJunchao Zhang   Collective
1608a1729e3fSJunchao Zhang 
16094165533cSJose E. Roman   Input Parameters:
1610a1729e3fSJunchao Zhang + sf       - star forest
1611a1729e3fSJunchao Zhang . unit     - data type
1612a1729e3fSJunchao Zhang . leafdata - leaf values to use in reduction
1613a1729e3fSJunchao Zhang - op       - operation to use for reduction
1614a1729e3fSJunchao Zhang 
16154165533cSJose E. Roman   Output Parameters:
1616a1729e3fSJunchao Zhang + rootdata   - root values to be updated, input state is seen by first process to perform an update
1617a1729e3fSJunchao Zhang - leafupdate - state at each leaf's respective root immediately prior to my atomic update
1618a1729e3fSJunchao Zhang 
1619a1729e3fSJunchao Zhang   Level: advanced
1620a1729e3fSJunchao Zhang 
1621a1729e3fSJunchao Zhang   Note:
1622a1729e3fSJunchao Zhang   The update is only atomic at the granularity provided by the hardware. Different roots referenced by the same process
1623a1729e3fSJunchao Zhang   might be updated in a different order. Furthermore, if a composite type is used for the unit datatype, atomicity is
1624a1729e3fSJunchao Zhang   not guaranteed across the whole vertex. Therefore, this function is mostly only used with primitive types such as
1625a1729e3fSJunchao Zhang   integers.
1626a1729e3fSJunchao Zhang 
1627cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFComputeDegreeBegin()`, `PetscSFReduceBegin()`, `PetscSFSetGraph()`
1628a1729e3fSJunchao Zhang @*/
1629d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFFetchAndOpBegin(PetscSF sf, MPI_Datatype unit, void *rootdata, const void *leafdata, void *leafupdate, MPI_Op op)
1630d71ae5a4SJacob Faibussowitsch {
1631eb02082bSJunchao Zhang   PetscMemType rootmtype, leafmtype, leafupdatemtype;
1632a1729e3fSJunchao Zhang 
1633a1729e3fSJunchao Zhang   PetscFunctionBegin;
1634a1729e3fSJunchao Zhang   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
16359566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUp(sf));
16369566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCSF_FetchAndOpBegin, sf, 0, 0, 0));
16379566063dSJacob Faibussowitsch   PetscCall(PetscGetMemType(rootdata, &rootmtype));
16389566063dSJacob Faibussowitsch   PetscCall(PetscGetMemType(leafdata, &leafmtype));
16399566063dSJacob Faibussowitsch   PetscCall(PetscGetMemType(leafupdate, &leafupdatemtype));
164008401ef6SPierre Jolivet   PetscCheck(leafmtype == leafupdatemtype, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for leafdata and leafupdate in different memory types");
1641dbbe0bcdSBarry Smith   PetscUseTypeMethod(sf, FetchAndOpBegin, unit, rootmtype, rootdata, leafmtype, leafdata, leafupdate, op);
16429566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCSF_FetchAndOpBegin, sf, 0, 0, 0));
16433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1644a1729e3fSJunchao Zhang }
1645a1729e3fSJunchao Zhang 
1646a1729e3fSJunchao Zhang /*@C
1647cab54364SBarry Smith   PetscSFFetchAndOpWithMemTypeBegin - begin operation with explicit memory types that fetches values from root and updates atomically by
1648cab54364SBarry Smith   applying operation using my leaf value, to be completed with `PetscSFFetchAndOpEnd()`
1649d3b3e55cSJunchao Zhang 
1650d3b3e55cSJunchao Zhang   Collective
1651d3b3e55cSJunchao Zhang 
1652d3b3e55cSJunchao Zhang   Input Parameters:
1653d3b3e55cSJunchao Zhang + sf              - star forest
1654d3b3e55cSJunchao Zhang . unit            - data type
1655d3b3e55cSJunchao Zhang . rootmtype       - memory type of rootdata
1656d3b3e55cSJunchao Zhang . leafmtype       - memory type of leafdata
1657d3b3e55cSJunchao Zhang . leafdata        - leaf values to use in reduction
1658d3b3e55cSJunchao Zhang . leafupdatemtype - memory type of leafupdate
1659d3b3e55cSJunchao Zhang - op              - operation to use for reduction
1660d3b3e55cSJunchao Zhang 
1661d3b3e55cSJunchao Zhang   Output Parameters:
1662d3b3e55cSJunchao Zhang + rootdata   - root values to be updated, input state is seen by first process to perform an update
1663d3b3e55cSJunchao Zhang - leafupdate - state at each leaf's respective root immediately prior to my atomic update
1664d3b3e55cSJunchao Zhang 
1665d3b3e55cSJunchao Zhang   Level: advanced
1666d3b3e55cSJunchao Zhang 
1667cab54364SBarry Smith   Note:
1668cab54364SBarry Smith   See `PetscSFFetchAndOpBegin()` for more details.
1669d3b3e55cSJunchao Zhang 
167020662ed9SBarry Smith .seealso: `PetscSF`, `PetscSFFetchAndOpBegin()`, `PetscSFComputeDegreeBegin()`, `PetscSFReduceBegin()`, `PetscSFSetGraph()`, `PetscSFFetchAndOpEnd()`
1671d3b3e55cSJunchao Zhang @*/
1672d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFFetchAndOpWithMemTypeBegin(PetscSF sf, MPI_Datatype unit, PetscMemType rootmtype, void *rootdata, PetscMemType leafmtype, const void *leafdata, PetscMemType leafupdatemtype, void *leafupdate, MPI_Op op)
1673d71ae5a4SJacob Faibussowitsch {
1674d3b3e55cSJunchao Zhang   PetscFunctionBegin;
1675d3b3e55cSJunchao Zhang   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
16769566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUp(sf));
16779566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCSF_FetchAndOpBegin, sf, 0, 0, 0));
167808401ef6SPierre Jolivet   PetscCheck(leafmtype == leafupdatemtype, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for leafdata and leafupdate in different memory types");
1679dbbe0bcdSBarry Smith   PetscUseTypeMethod(sf, FetchAndOpBegin, unit, rootmtype, rootdata, leafmtype, leafdata, leafupdate, op);
16809566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCSF_FetchAndOpBegin, sf, 0, 0, 0));
16813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1682d3b3e55cSJunchao Zhang }
1683d3b3e55cSJunchao Zhang 
1684d3b3e55cSJunchao Zhang /*@C
168520662ed9SBarry Smith   PetscSFFetchAndOpEnd - end operation started in matching call to `PetscSFFetchAndOpBegin()` or `PetscSFFetchAndOpWithMemTypeBegin()`
168620662ed9SBarry Smith   to fetch values from roots and update atomically by applying operation using my leaf value
1687a1729e3fSJunchao Zhang 
1688a1729e3fSJunchao Zhang   Collective
1689a1729e3fSJunchao Zhang 
16904165533cSJose E. Roman   Input Parameters:
1691a1729e3fSJunchao Zhang + sf       - star forest
1692a1729e3fSJunchao Zhang . unit     - data type
1693a1729e3fSJunchao Zhang . leafdata - leaf values to use in reduction
1694a1729e3fSJunchao Zhang - op       - operation to use for reduction
1695a1729e3fSJunchao Zhang 
16964165533cSJose E. Roman   Output Parameters:
1697a1729e3fSJunchao Zhang + rootdata   - root values to be updated, input state is seen by first process to perform an update
1698a1729e3fSJunchao Zhang - leafupdate - state at each leaf's respective root immediately prior to my atomic update
1699a1729e3fSJunchao Zhang 
1700a1729e3fSJunchao Zhang   Level: advanced
1701a1729e3fSJunchao Zhang 
170220662ed9SBarry Smith .seealso: `PetscSF`, `PetscSFComputeDegreeEnd()`, `PetscSFReduceEnd()`, `PetscSFSetGraph()`, `PetscSFFetchAndOpBegin()`, `PetscSFFetchAndOpWithMemTypeBegin()`
1703a1729e3fSJunchao Zhang @*/
1704d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFFetchAndOpEnd(PetscSF sf, MPI_Datatype unit, void *rootdata, const void *leafdata, void *leafupdate, MPI_Op op)
1705d71ae5a4SJacob Faibussowitsch {
1706a1729e3fSJunchao Zhang   PetscFunctionBegin;
1707a1729e3fSJunchao Zhang   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
17089566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCSF_FetchAndOpEnd, sf, 0, 0, 0));
1709dbbe0bcdSBarry Smith   PetscUseTypeMethod(sf, FetchAndOpEnd, unit, rootdata, leafdata, leafupdate, op);
17109566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCSF_FetchAndOpEnd, sf, 0, 0, 0));
17113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1712a1729e3fSJunchao Zhang }
1713a1729e3fSJunchao Zhang 
1714a1729e3fSJunchao Zhang /*@C
1715cab54364SBarry Smith   PetscSFComputeDegreeBegin - begin computation of degree for each root vertex, to be completed with `PetscSFComputeDegreeEnd()`
171695fce210SBarry Smith 
171795fce210SBarry Smith   Collective
171895fce210SBarry Smith 
17194165533cSJose E. Roman   Input Parameter:
172095fce210SBarry Smith . sf - star forest
172195fce210SBarry Smith 
17224165533cSJose E. Roman   Output Parameter:
172395fce210SBarry Smith . degree - degree of each root vertex
172495fce210SBarry Smith 
172595fce210SBarry Smith   Level: advanced
172695fce210SBarry Smith 
1727cab54364SBarry Smith   Note:
172820662ed9SBarry Smith   The returned array is owned by `PetscSF` and automatically freed by `PetscSFDestroy()`. Hence there is no need to call `PetscFree()` on it.
1729ffe67aa5SVáclav Hapla 
1730cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFGatherBegin()`, `PetscSFComputeDegreeEnd()`
173195fce210SBarry Smith @*/
1732d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFComputeDegreeBegin(PetscSF sf, const PetscInt **degree)
1733d71ae5a4SJacob Faibussowitsch {
173495fce210SBarry Smith   PetscFunctionBegin;
173595fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
173695fce210SBarry Smith   PetscSFCheckGraphSet(sf, 1);
17374f572ea9SToby Isaac   PetscAssertPointer(degree, 2);
1738803bd9e8SMatthew G. Knepley   if (!sf->degreeknown) {
17395b0d146aSStefano Zampini     PetscInt i, nroots = sf->nroots, maxlocal;
174028b400f6SJacob Faibussowitsch     PetscCheck(!sf->degree, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Calls to PetscSFComputeDegreeBegin() cannot be nested.");
17415b0d146aSStefano Zampini     maxlocal = sf->maxleaf - sf->minleaf + 1;
17429566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nroots, &sf->degree));
17439566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(PetscMax(maxlocal, 1), &sf->degreetmp)); /* allocate at least one entry, see check in PetscSFComputeDegreeEnd() */
174429046d53SLisandro Dalcin     for (i = 0; i < nroots; i++) sf->degree[i] = 0;
17459837ea96SMatthew G. Knepley     for (i = 0; i < maxlocal; i++) sf->degreetmp[i] = 1;
17469566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(sf, MPIU_INT, sf->degreetmp - sf->minleaf, sf->degree, MPI_SUM));
174795fce210SBarry Smith   }
174895fce210SBarry Smith   *degree = NULL;
17493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
175095fce210SBarry Smith }
175195fce210SBarry Smith 
175295fce210SBarry Smith /*@C
1753cab54364SBarry Smith   PetscSFComputeDegreeEnd - complete computation of degree for each root vertex, started with `PetscSFComputeDegreeBegin()`
175495fce210SBarry Smith 
175595fce210SBarry Smith   Collective
175695fce210SBarry Smith 
17574165533cSJose E. Roman   Input Parameter:
175895fce210SBarry Smith . sf - star forest
175995fce210SBarry Smith 
17604165533cSJose E. Roman   Output Parameter:
176195fce210SBarry Smith . degree - degree of each root vertex
176295fce210SBarry Smith 
176395fce210SBarry Smith   Level: developer
176495fce210SBarry Smith 
1765cab54364SBarry Smith   Note:
176620662ed9SBarry Smith   The returned array is owned by `PetscSF` and automatically freed by `PetscSFDestroy()`. Hence there is no need to call `PetscFree()` on it.
1767ffe67aa5SVáclav Hapla 
1768cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFGatherBegin()`, `PetscSFComputeDegreeBegin()`
176995fce210SBarry Smith @*/
1770d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFComputeDegreeEnd(PetscSF sf, const PetscInt **degree)
1771d71ae5a4SJacob Faibussowitsch {
177295fce210SBarry Smith   PetscFunctionBegin;
177395fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
177495fce210SBarry Smith   PetscSFCheckGraphSet(sf, 1);
17754f572ea9SToby Isaac   PetscAssertPointer(degree, 2);
177695fce210SBarry Smith   if (!sf->degreeknown) {
177728b400f6SJacob Faibussowitsch     PetscCheck(sf->degreetmp, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call PetscSFComputeDegreeBegin() before PetscSFComputeDegreeEnd()");
17789566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(sf, MPIU_INT, sf->degreetmp - sf->minleaf, sf->degree, MPI_SUM));
17799566063dSJacob Faibussowitsch     PetscCall(PetscFree(sf->degreetmp));
178095fce210SBarry Smith     sf->degreeknown = PETSC_TRUE;
178195fce210SBarry Smith   }
178295fce210SBarry Smith   *degree = sf->degree;
17833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
178495fce210SBarry Smith }
178595fce210SBarry Smith 
1786673100f5SVaclav Hapla /*@C
178720662ed9SBarry Smith   PetscSFComputeMultiRootOriginalNumbering - Returns original numbering of multi-roots (roots of multi-`PetscSF` returned by `PetscSFGetMultiSF()`).
178866dfcd1aSVaclav Hapla   Each multi-root is assigned index of the corresponding original root.
1789673100f5SVaclav Hapla 
1790673100f5SVaclav Hapla   Collective
1791673100f5SVaclav Hapla 
17924165533cSJose E. Roman   Input Parameters:
1793673100f5SVaclav Hapla + sf     - star forest
1794cab54364SBarry Smith - degree - degree of each root vertex, computed with `PetscSFComputeDegreeBegin()`/`PetscSFComputeDegreeEnd()`
1795673100f5SVaclav Hapla 
17964165533cSJose E. Roman   Output Parameters:
179720662ed9SBarry Smith + nMultiRoots             - (optional) number of multi-roots (roots of multi-`PetscSF`)
179820662ed9SBarry Smith - multiRootsOrigNumbering - original indices of multi-roots; length of this array is `nMultiRoots`
1799673100f5SVaclav Hapla 
1800673100f5SVaclav Hapla   Level: developer
1801673100f5SVaclav Hapla 
1802cab54364SBarry Smith   Note:
180320662ed9SBarry Smith   The returned array `multiRootsOrigNumbering` is newly allocated and should be destroyed with `PetscFree()` when no longer needed.
1804ffe67aa5SVáclav Hapla 
1805cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFComputeDegreeBegin()`, `PetscSFComputeDegreeEnd()`, `PetscSFGetMultiSF()`
1806673100f5SVaclav Hapla @*/
1807d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFComputeMultiRootOriginalNumbering(PetscSF sf, const PetscInt degree[], PetscInt *nMultiRoots, PetscInt *multiRootsOrigNumbering[])
1808d71ae5a4SJacob Faibussowitsch {
1809673100f5SVaclav Hapla   PetscSF  msf;
1810673100f5SVaclav Hapla   PetscInt i, j, k, nroots, nmroots;
1811673100f5SVaclav Hapla 
1812673100f5SVaclav Hapla   PetscFunctionBegin;
1813673100f5SVaclav Hapla   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
18149566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL));
18154f572ea9SToby Isaac   if (nroots) PetscAssertPointer(degree, 2);
18164f572ea9SToby Isaac   if (nMultiRoots) PetscAssertPointer(nMultiRoots, 3);
18174f572ea9SToby Isaac   PetscAssertPointer(multiRootsOrigNumbering, 4);
18189566063dSJacob Faibussowitsch   PetscCall(PetscSFGetMultiSF(sf, &msf));
18199566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(msf, &nmroots, NULL, NULL, NULL));
18209566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nmroots, multiRootsOrigNumbering));
1821673100f5SVaclav Hapla   for (i = 0, j = 0, k = 0; i < nroots; i++) {
1822673100f5SVaclav Hapla     if (!degree[i]) continue;
1823ad540459SPierre Jolivet     for (j = 0; j < degree[i]; j++, k++) (*multiRootsOrigNumbering)[k] = i;
1824673100f5SVaclav Hapla   }
182508401ef6SPierre Jolivet   PetscCheck(k == nmroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "sanity check fail");
182666dfcd1aSVaclav Hapla   if (nMultiRoots) *nMultiRoots = nmroots;
18273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1828673100f5SVaclav Hapla }
1829673100f5SVaclav Hapla 
183095fce210SBarry Smith /*@C
1831cab54364SBarry Smith   PetscSFGatherBegin - begin pointwise gather of all leaves into multi-roots, to be completed with `PetscSFGatherEnd()`
183295fce210SBarry Smith 
183395fce210SBarry Smith   Collective
183495fce210SBarry Smith 
18354165533cSJose E. Roman   Input Parameters:
183695fce210SBarry Smith + sf       - star forest
183795fce210SBarry Smith . unit     - data type
183895fce210SBarry Smith - leafdata - leaf data to gather to roots
183995fce210SBarry Smith 
18404165533cSJose E. Roman   Output Parameter:
184195fce210SBarry Smith . multirootdata - root buffer to gather into, amount of space per root is equal to its degree
184295fce210SBarry Smith 
184395fce210SBarry Smith   Level: intermediate
184495fce210SBarry Smith 
1845cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFComputeDegreeBegin()`, `PetscSFScatterBegin()`
184695fce210SBarry Smith @*/
1847d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFGatherBegin(PetscSF sf, MPI_Datatype unit, const void *leafdata, void *multirootdata)
1848d71ae5a4SJacob Faibussowitsch {
1849a5526d50SJunchao Zhang   PetscSF multi = NULL;
185095fce210SBarry Smith 
185195fce210SBarry Smith   PetscFunctionBegin;
185295fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
18539566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUp(sf));
18549566063dSJacob Faibussowitsch   PetscCall(PetscSFGetMultiSF(sf, &multi));
18559566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(multi, unit, leafdata, multirootdata, MPI_REPLACE));
18563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
185795fce210SBarry Smith }
185895fce210SBarry Smith 
185995fce210SBarry Smith /*@C
1860cab54364SBarry Smith   PetscSFGatherEnd - ends pointwise gather operation that was started with `PetscSFGatherBegin()`
186195fce210SBarry Smith 
186295fce210SBarry Smith   Collective
186395fce210SBarry Smith 
18644165533cSJose E. Roman   Input Parameters:
186595fce210SBarry Smith + sf       - star forest
186695fce210SBarry Smith . unit     - data type
186795fce210SBarry Smith - leafdata - leaf data to gather to roots
186895fce210SBarry Smith 
18694165533cSJose E. Roman   Output Parameter:
187095fce210SBarry Smith . multirootdata - root buffer to gather into, amount of space per root is equal to its degree
187195fce210SBarry Smith 
187295fce210SBarry Smith   Level: intermediate
187395fce210SBarry Smith 
1874cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFComputeDegreeEnd()`, `PetscSFScatterEnd()`
187595fce210SBarry Smith @*/
1876d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFGatherEnd(PetscSF sf, MPI_Datatype unit, const void *leafdata, void *multirootdata)
1877d71ae5a4SJacob Faibussowitsch {
1878a5526d50SJunchao Zhang   PetscSF multi = NULL;
187995fce210SBarry Smith 
188095fce210SBarry Smith   PetscFunctionBegin;
188195fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
18829566063dSJacob Faibussowitsch   PetscCall(PetscSFGetMultiSF(sf, &multi));
18839566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(multi, unit, leafdata, multirootdata, MPI_REPLACE));
18843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
188595fce210SBarry Smith }
188695fce210SBarry Smith 
188795fce210SBarry Smith /*@C
1888cab54364SBarry Smith   PetscSFScatterBegin - begin pointwise scatter operation from multi-roots to leaves, to be completed with `PetscSFScatterEnd()`
188995fce210SBarry Smith 
189095fce210SBarry Smith   Collective
189195fce210SBarry Smith 
18924165533cSJose E. Roman   Input Parameters:
189395fce210SBarry Smith + sf            - star forest
189495fce210SBarry Smith . unit          - data type
189595fce210SBarry Smith - multirootdata - root buffer to send to each leaf, one unit of data per leaf
189695fce210SBarry Smith 
18974165533cSJose E. Roman   Output Parameter:
189895fce210SBarry Smith . leafdata - leaf data to be update with personal data from each respective root
189995fce210SBarry Smith 
190095fce210SBarry Smith   Level: intermediate
190195fce210SBarry Smith 
190220662ed9SBarry Smith .seealso: `PetscSF`, `PetscSFComputeDegreeBegin()`, `PetscSFScatterEnd()`
190395fce210SBarry Smith @*/
1904d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFScatterBegin(PetscSF sf, MPI_Datatype unit, const void *multirootdata, void *leafdata)
1905d71ae5a4SJacob Faibussowitsch {
1906a5526d50SJunchao Zhang   PetscSF multi = NULL;
190795fce210SBarry Smith 
190895fce210SBarry Smith   PetscFunctionBegin;
190995fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
19109566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUp(sf));
19119566063dSJacob Faibussowitsch   PetscCall(PetscSFGetMultiSF(sf, &multi));
19129566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(multi, unit, multirootdata, leafdata, MPI_REPLACE));
19133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
191495fce210SBarry Smith }
191595fce210SBarry Smith 
191695fce210SBarry Smith /*@C
1917cab54364SBarry Smith   PetscSFScatterEnd - ends pointwise scatter operation that was started with `PetscSFScatterBegin()`
191895fce210SBarry Smith 
191995fce210SBarry Smith   Collective
192095fce210SBarry Smith 
19214165533cSJose E. Roman   Input Parameters:
192295fce210SBarry Smith + sf            - star forest
192395fce210SBarry Smith . unit          - data type
192495fce210SBarry Smith - multirootdata - root buffer to send to each leaf, one unit of data per leaf
192595fce210SBarry Smith 
19264165533cSJose E. Roman   Output Parameter:
192795fce210SBarry Smith . leafdata - leaf data to be update with personal data from each respective root
192895fce210SBarry Smith 
192995fce210SBarry Smith   Level: intermediate
193095fce210SBarry Smith 
193120662ed9SBarry Smith .seealso: `PetscSF`, `PetscSFComputeDegreeEnd()`, `PetscSFScatterBegin()`
193295fce210SBarry Smith @*/
1933d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFScatterEnd(PetscSF sf, MPI_Datatype unit, const void *multirootdata, void *leafdata)
1934d71ae5a4SJacob Faibussowitsch {
1935a5526d50SJunchao Zhang   PetscSF multi = NULL;
193695fce210SBarry Smith 
193795fce210SBarry Smith   PetscFunctionBegin;
193895fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
19399566063dSJacob Faibussowitsch   PetscCall(PetscSFGetMultiSF(sf, &multi));
19409566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(multi, unit, multirootdata, leafdata, MPI_REPLACE));
19413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
194295fce210SBarry Smith }
1943a7b3aa13SAta Mesgarnejad 
1944d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFCheckLeavesUnique_Private(PetscSF sf)
1945d71ae5a4SJacob Faibussowitsch {
1946a072220fSLawrence Mitchell   PetscInt        i, n, nleaves;
1947a072220fSLawrence Mitchell   const PetscInt *ilocal = NULL;
1948a072220fSLawrence Mitchell   PetscHSetI      seen;
1949a072220fSLawrence Mitchell 
1950a072220fSLawrence Mitchell   PetscFunctionBegin;
1951b458e8f1SJose E. Roman   if (PetscDefined(USE_DEBUG)) {
19529566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(sf, NULL, &nleaves, &ilocal, NULL));
19539566063dSJacob Faibussowitsch     PetscCall(PetscHSetICreate(&seen));
1954a072220fSLawrence Mitchell     for (i = 0; i < nleaves; i++) {
1955a072220fSLawrence Mitchell       const PetscInt leaf = ilocal ? ilocal[i] : i;
19569566063dSJacob Faibussowitsch       PetscCall(PetscHSetIAdd(seen, leaf));
1957a072220fSLawrence Mitchell     }
19589566063dSJacob Faibussowitsch     PetscCall(PetscHSetIGetSize(seen, &n));
195908401ef6SPierre Jolivet     PetscCheck(n == nleaves, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Provided leaves have repeated values: all leaves must be unique");
19609566063dSJacob Faibussowitsch     PetscCall(PetscHSetIDestroy(&seen));
1961b458e8f1SJose E. Roman   }
19623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1963a072220fSLawrence Mitchell }
196454729392SStefano Zampini 
1965a7b3aa13SAta Mesgarnejad /*@
1966cab54364SBarry Smith   PetscSFCompose - Compose a new `PetscSF` by putting the second `PetscSF` under the first one in a top (roots) down (leaves) view
1967a7b3aa13SAta Mesgarnejad 
1968a7b3aa13SAta Mesgarnejad   Input Parameters:
1969cab54364SBarry Smith + sfA - The first `PetscSF`
1970cab54364SBarry Smith - sfB - The second `PetscSF`
1971a7b3aa13SAta Mesgarnejad 
19722fe279fdSBarry Smith   Output Parameter:
1973cab54364SBarry Smith . sfBA - The composite `PetscSF`
1974a7b3aa13SAta Mesgarnejad 
1975a7b3aa13SAta Mesgarnejad   Level: developer
1976a7b3aa13SAta Mesgarnejad 
1977a072220fSLawrence Mitchell   Notes:
1978cab54364SBarry Smith   Currently, the two `PetscSF`s must be defined on congruent communicators and they must be true star
197954729392SStefano Zampini   forests, i.e. the same leaf is not connected with different roots.
198054729392SStefano Zampini 
198120662ed9SBarry Smith   `sfA`'s leaf space and `sfB`'s root space might be partially overlapped. The composition builds
198220662ed9SBarry Smith   a graph with `sfA`'s roots and `sfB`'s leaves only when there is a path between them. Unconnected
198320662ed9SBarry Smith   nodes (roots or leaves) are not in `sfBA`. Doing a `PetscSFBcastBegin()`/`PetscSFBcastEnd()` on the new `PetscSF` is equivalent to doing a
198420662ed9SBarry Smith   `PetscSFBcastBegin()`/`PetscSFBcastEnd()` on `sfA`, then a `PetscSFBcastBegin()`/`PetscSFBcastEnd()` on `sfB`, on connected nodes.
1985a072220fSLawrence Mitchell 
1986db781477SPatrick Sanan .seealso: `PetscSF`, `PetscSFComposeInverse()`, `PetscSFGetGraph()`, `PetscSFSetGraph()`
1987a7b3aa13SAta Mesgarnejad @*/
1988d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFCompose(PetscSF sfA, PetscSF sfB, PetscSF *sfBA)
1989d71ae5a4SJacob Faibussowitsch {
1990a7b3aa13SAta Mesgarnejad   const PetscSFNode *remotePointsA, *remotePointsB;
1991d41018fbSJunchao Zhang   PetscSFNode       *remotePointsBA = NULL, *reorderedRemotePointsA = NULL, *leafdataB;
199254729392SStefano Zampini   const PetscInt    *localPointsA, *localPointsB;
199354729392SStefano Zampini   PetscInt          *localPointsBA;
199454729392SStefano Zampini   PetscInt           i, numRootsA, numLeavesA, numRootsB, numLeavesB, minleaf, maxleaf, numLeavesBA;
199554729392SStefano Zampini   PetscBool          denseB;
1996a7b3aa13SAta Mesgarnejad 
1997a7b3aa13SAta Mesgarnejad   PetscFunctionBegin;
1998a7b3aa13SAta Mesgarnejad   PetscValidHeaderSpecific(sfA, PETSCSF_CLASSID, 1);
199929046d53SLisandro Dalcin   PetscSFCheckGraphSet(sfA, 1);
200029046d53SLisandro Dalcin   PetscValidHeaderSpecific(sfB, PETSCSF_CLASSID, 2);
200129046d53SLisandro Dalcin   PetscSFCheckGraphSet(sfB, 2);
200254729392SStefano Zampini   PetscCheckSameComm(sfA, 1, sfB, 2);
20034f572ea9SToby Isaac   PetscAssertPointer(sfBA, 3);
20049566063dSJacob Faibussowitsch   PetscCall(PetscSFCheckLeavesUnique_Private(sfA));
20059566063dSJacob Faibussowitsch   PetscCall(PetscSFCheckLeavesUnique_Private(sfB));
200654729392SStefano Zampini 
20079566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sfA, &numRootsA, &numLeavesA, &localPointsA, &remotePointsA));
20089566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sfB, &numRootsB, &numLeavesB, &localPointsB, &remotePointsB));
200920662ed9SBarry Smith   /* Make sure that PetscSFBcast{Begin, End}(sfB, ...) works with root data of size
201020662ed9SBarry Smith      numRootsB; otherwise, garbage will be broadcasted.
201120662ed9SBarry Smith      Example (comm size = 1):
201220662ed9SBarry Smith      sfA: 0 <- (0, 0)
201320662ed9SBarry Smith      sfB: 100 <- (0, 0)
201420662ed9SBarry Smith           101 <- (0, 1)
201520662ed9SBarry Smith      Here, we have remotePointsA = [(0, 0)], but for remotePointsA to be a valid tartget
201620662ed9SBarry Smith      of sfB, it has to be recasted as [(0, 0), (-1, -1)] so that points 100 and 101 would
201720662ed9SBarry Smith      receive (0, 0) and (-1, -1), respectively, when PetscSFBcast(sfB, ...) is called on
201820662ed9SBarry Smith      remotePointsA; if not recasted, point 101 would receive a garbage value.             */
20199566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numRootsB, &reorderedRemotePointsA));
202054729392SStefano Zampini   for (i = 0; i < numRootsB; i++) {
202154729392SStefano Zampini     reorderedRemotePointsA[i].rank  = -1;
202254729392SStefano Zampini     reorderedRemotePointsA[i].index = -1;
202354729392SStefano Zampini   }
202454729392SStefano Zampini   for (i = 0; i < numLeavesA; i++) {
20250ea77edaSksagiyam     PetscInt localp = localPointsA ? localPointsA[i] : i;
20260ea77edaSksagiyam 
20270ea77edaSksagiyam     if (localp >= numRootsB) continue;
20280ea77edaSksagiyam     reorderedRemotePointsA[localp] = remotePointsA[i];
202954729392SStefano Zampini   }
2030d41018fbSJunchao Zhang   remotePointsA = reorderedRemotePointsA;
20319566063dSJacob Faibussowitsch   PetscCall(PetscSFGetLeafRange(sfB, &minleaf, &maxleaf));
20329566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxleaf - minleaf + 1, &leafdataB));
20330ea77edaSksagiyam   for (i = 0; i < maxleaf - minleaf + 1; i++) {
20340ea77edaSksagiyam     leafdataB[i].rank  = -1;
20350ea77edaSksagiyam     leafdataB[i].index = -1;
20360ea77edaSksagiyam   }
20379566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sfB, MPIU_2INT, remotePointsA, leafdataB - minleaf, MPI_REPLACE));
20389566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sfB, MPIU_2INT, remotePointsA, leafdataB - minleaf, MPI_REPLACE));
20399566063dSJacob Faibussowitsch   PetscCall(PetscFree(reorderedRemotePointsA));
2040d41018fbSJunchao Zhang 
204154729392SStefano Zampini   denseB = (PetscBool)!localPointsB;
204254729392SStefano Zampini   for (i = 0, numLeavesBA = 0; i < numLeavesB; i++) {
204354729392SStefano Zampini     if (leafdataB[localPointsB ? localPointsB[i] - minleaf : i].rank == -1) denseB = PETSC_FALSE;
204454729392SStefano Zampini     else numLeavesBA++;
204554729392SStefano Zampini   }
204654729392SStefano Zampini   if (denseB) {
2047d41018fbSJunchao Zhang     localPointsBA  = NULL;
2048d41018fbSJunchao Zhang     remotePointsBA = leafdataB;
2049d41018fbSJunchao Zhang   } else {
20509566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeavesBA, &localPointsBA));
20519566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeavesBA, &remotePointsBA));
205254729392SStefano Zampini     for (i = 0, numLeavesBA = 0; i < numLeavesB; i++) {
205354729392SStefano Zampini       const PetscInt l = localPointsB ? localPointsB[i] : i;
205454729392SStefano Zampini 
205554729392SStefano Zampini       if (leafdataB[l - minleaf].rank == -1) continue;
205654729392SStefano Zampini       remotePointsBA[numLeavesBA] = leafdataB[l - minleaf];
205754729392SStefano Zampini       localPointsBA[numLeavesBA]  = l;
205854729392SStefano Zampini       numLeavesBA++;
205954729392SStefano Zampini     }
20609566063dSJacob Faibussowitsch     PetscCall(PetscFree(leafdataB));
2061d41018fbSJunchao Zhang   }
20629566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)sfA), sfBA));
20639566063dSJacob Faibussowitsch   PetscCall(PetscSFSetFromOptions(*sfBA));
20649566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(*sfBA, numRootsA, numLeavesBA, localPointsBA, PETSC_OWN_POINTER, remotePointsBA, PETSC_OWN_POINTER));
20653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2066a7b3aa13SAta Mesgarnejad }
20671c6ba672SJunchao Zhang 
206804c0ada0SJunchao Zhang /*@
2069cab54364SBarry Smith   PetscSFComposeInverse - Compose a new `PetscSF` by putting the inverse of the second `PetscSF` under the first one
207004c0ada0SJunchao Zhang 
207104c0ada0SJunchao Zhang   Input Parameters:
2072cab54364SBarry Smith + sfA - The first `PetscSF`
2073cab54364SBarry Smith - sfB - The second `PetscSF`
207404c0ada0SJunchao Zhang 
20752fe279fdSBarry Smith   Output Parameter:
2076cab54364SBarry Smith . sfBA - The composite `PetscSF`.
207704c0ada0SJunchao Zhang 
207804c0ada0SJunchao Zhang   Level: developer
207904c0ada0SJunchao Zhang 
208054729392SStefano Zampini   Notes:
208120662ed9SBarry Smith   Currently, the two `PetscSF`s must be defined on congruent communicators and they must be true star
208254729392SStefano Zampini   forests, i.e. the same leaf is not connected with different roots. Even more, all roots of the
208320662ed9SBarry Smith   second `PetscSF` must have a degree of 1, i.e., no roots have more than one leaf connected.
208454729392SStefano Zampini 
208520662ed9SBarry Smith   `sfA`'s leaf space and `sfB`'s leaf space might be partially overlapped. The composition builds
208620662ed9SBarry Smith   a graph with `sfA`'s roots and `sfB`'s roots only when there is a path between them. Unconnected
208720662ed9SBarry Smith   roots are not in `sfBA`. Doing a `PetscSFBcastBegin()`/`PetscSFBcastEnd()` on the new `PetscSF` is equivalent to doing a `PetscSFBcastBegin()`/`PetscSFBcastEnd()`
208820662ed9SBarry Smith   on `sfA`, then
208920662ed9SBarry Smith   a `PetscSFReduceBegin()`/`PetscSFReduceEnd()` on `sfB`, on connected roots.
209054729392SStefano Zampini 
2091db781477SPatrick Sanan .seealso: `PetscSF`, `PetscSFCompose()`, `PetscSFGetGraph()`, `PetscSFSetGraph()`, `PetscSFCreateInverseSF()`
209204c0ada0SJunchao Zhang @*/
2093d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFComposeInverse(PetscSF sfA, PetscSF sfB, PetscSF *sfBA)
2094d71ae5a4SJacob Faibussowitsch {
209504c0ada0SJunchao Zhang   const PetscSFNode *remotePointsA, *remotePointsB;
209604c0ada0SJunchao Zhang   PetscSFNode       *remotePointsBA;
209704c0ada0SJunchao Zhang   const PetscInt    *localPointsA, *localPointsB;
209854729392SStefano Zampini   PetscSFNode       *reorderedRemotePointsA = NULL;
209954729392SStefano Zampini   PetscInt           i, numRootsA, numLeavesA, numLeavesBA, numRootsB, numLeavesB, minleaf, maxleaf, *localPointsBA;
21005b0d146aSStefano Zampini   MPI_Op             op;
21015b0d146aSStefano Zampini #if defined(PETSC_USE_64BIT_INDICES)
21025b0d146aSStefano Zampini   PetscBool iswin;
21035b0d146aSStefano Zampini #endif
210404c0ada0SJunchao Zhang 
210504c0ada0SJunchao Zhang   PetscFunctionBegin;
210604c0ada0SJunchao Zhang   PetscValidHeaderSpecific(sfA, PETSCSF_CLASSID, 1);
210704c0ada0SJunchao Zhang   PetscSFCheckGraphSet(sfA, 1);
210804c0ada0SJunchao Zhang   PetscValidHeaderSpecific(sfB, PETSCSF_CLASSID, 2);
210904c0ada0SJunchao Zhang   PetscSFCheckGraphSet(sfB, 2);
211054729392SStefano Zampini   PetscCheckSameComm(sfA, 1, sfB, 2);
21114f572ea9SToby Isaac   PetscAssertPointer(sfBA, 3);
21129566063dSJacob Faibussowitsch   PetscCall(PetscSFCheckLeavesUnique_Private(sfA));
21139566063dSJacob Faibussowitsch   PetscCall(PetscSFCheckLeavesUnique_Private(sfB));
211454729392SStefano Zampini 
21159566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sfA, &numRootsA, &numLeavesA, &localPointsA, &remotePointsA));
21169566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sfB, &numRootsB, &numLeavesB, &localPointsB, &remotePointsB));
21175b0d146aSStefano Zampini 
21185b0d146aSStefano Zampini   /* TODO: Check roots of sfB have degree of 1 */
21195b0d146aSStefano Zampini   /* Once we implement it, we can replace the MPI_MAXLOC
212083df288dSJunchao Zhang      with MPI_REPLACE. In that case, MPI_MAXLOC and MPI_REPLACE have the same effect.
21215b0d146aSStefano Zampini      We use MPI_MAXLOC only to have a deterministic output from this routine if
21225b0d146aSStefano Zampini      the root condition is not meet.
21235b0d146aSStefano Zampini    */
21245b0d146aSStefano Zampini   op = MPI_MAXLOC;
21255b0d146aSStefano Zampini #if defined(PETSC_USE_64BIT_INDICES)
21265b0d146aSStefano Zampini   /* we accept a non-deterministic output (if any) with PETSCSFWINDOW, since MPI_MAXLOC cannot operate on MPIU_2INT with MPI_Accumulate */
21279566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)sfB, PETSCSFWINDOW, &iswin));
212883df288dSJunchao Zhang   if (iswin) op = MPI_REPLACE;
21295b0d146aSStefano Zampini #endif
21305b0d146aSStefano Zampini 
21319566063dSJacob Faibussowitsch   PetscCall(PetscSFGetLeafRange(sfB, &minleaf, &maxleaf));
21329566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxleaf - minleaf + 1, &reorderedRemotePointsA));
213354729392SStefano Zampini   for (i = 0; i < maxleaf - minleaf + 1; i++) {
213454729392SStefano Zampini     reorderedRemotePointsA[i].rank  = -1;
213554729392SStefano Zampini     reorderedRemotePointsA[i].index = -1;
213654729392SStefano Zampini   }
213754729392SStefano Zampini   if (localPointsA) {
213854729392SStefano Zampini     for (i = 0; i < numLeavesA; i++) {
213954729392SStefano Zampini       if (localPointsA[i] > maxleaf || localPointsA[i] < minleaf) continue;
214054729392SStefano Zampini       reorderedRemotePointsA[localPointsA[i] - minleaf] = remotePointsA[i];
214154729392SStefano Zampini     }
214254729392SStefano Zampini   } else {
214354729392SStefano Zampini     for (i = 0; i < numLeavesA; i++) {
214454729392SStefano Zampini       if (i > maxleaf || i < minleaf) continue;
214554729392SStefano Zampini       reorderedRemotePointsA[i - minleaf] = remotePointsA[i];
214654729392SStefano Zampini     }
214754729392SStefano Zampini   }
214854729392SStefano Zampini 
21499566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numRootsB, &localPointsBA));
21509566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numRootsB, &remotePointsBA));
215154729392SStefano Zampini   for (i = 0; i < numRootsB; i++) {
215254729392SStefano Zampini     remotePointsBA[i].rank  = -1;
215354729392SStefano Zampini     remotePointsBA[i].index = -1;
215454729392SStefano Zampini   }
215554729392SStefano Zampini 
21569566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(sfB, MPIU_2INT, reorderedRemotePointsA - minleaf, remotePointsBA, op));
21579566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(sfB, MPIU_2INT, reorderedRemotePointsA - minleaf, remotePointsBA, op));
21589566063dSJacob Faibussowitsch   PetscCall(PetscFree(reorderedRemotePointsA));
215954729392SStefano Zampini   for (i = 0, numLeavesBA = 0; i < numRootsB; i++) {
216054729392SStefano Zampini     if (remotePointsBA[i].rank == -1) continue;
216154729392SStefano Zampini     remotePointsBA[numLeavesBA].rank  = remotePointsBA[i].rank;
216254729392SStefano Zampini     remotePointsBA[numLeavesBA].index = remotePointsBA[i].index;
216354729392SStefano Zampini     localPointsBA[numLeavesBA]        = i;
216454729392SStefano Zampini     numLeavesBA++;
216554729392SStefano Zampini   }
21669566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)sfA), sfBA));
21679566063dSJacob Faibussowitsch   PetscCall(PetscSFSetFromOptions(*sfBA));
21689566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(*sfBA, numRootsA, numLeavesBA, localPointsBA, PETSC_OWN_POINTER, remotePointsBA, PETSC_OWN_POINTER));
21693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
217004c0ada0SJunchao Zhang }
217104c0ada0SJunchao Zhang 
21721c6ba672SJunchao Zhang /*
2173cab54364SBarry Smith   PetscSFCreateLocalSF_Private - Creates a local `PetscSF` that only has intra-process edges of the global `PetscSF`
21741c6ba672SJunchao Zhang 
21752fe279fdSBarry Smith   Input Parameter:
2176cab54364SBarry Smith . sf - The global `PetscSF`
21771c6ba672SJunchao Zhang 
21782fe279fdSBarry Smith   Output Parameter:
2179cab54364SBarry Smith . out - The local `PetscSF`
2180cab54364SBarry Smith 
2181cab54364SBarry Smith .seealso: `PetscSF`, `PetscSFCreate()`
21821c6ba672SJunchao Zhang  */
2183d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFCreateLocalSF_Private(PetscSF sf, PetscSF *out)
2184d71ae5a4SJacob Faibussowitsch {
21851c6ba672SJunchao Zhang   MPI_Comm           comm;
21861c6ba672SJunchao Zhang   PetscMPIInt        myrank;
21871c6ba672SJunchao Zhang   const PetscInt    *ilocal;
21881c6ba672SJunchao Zhang   const PetscSFNode *iremote;
21891c6ba672SJunchao Zhang   PetscInt           i, j, nroots, nleaves, lnleaves, *lilocal;
21901c6ba672SJunchao Zhang   PetscSFNode       *liremote;
21911c6ba672SJunchao Zhang   PetscSF            lsf;
21921c6ba672SJunchao Zhang 
21931c6ba672SJunchao Zhang   PetscFunctionBegin;
21941c6ba672SJunchao Zhang   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
2195dbbe0bcdSBarry Smith   if (sf->ops->CreateLocalSF) PetscUseTypeMethod(sf, CreateLocalSF, out);
2196dbbe0bcdSBarry Smith   else {
21971c6ba672SJunchao Zhang     /* Could use PetscSFCreateEmbeddedLeafSF, but since we know the comm is PETSC_COMM_SELF, we can make it fast */
21989566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
21999566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm, &myrank));
22001c6ba672SJunchao Zhang 
22011c6ba672SJunchao Zhang     /* Find out local edges and build a local SF */
22029566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(sf, &nroots, &nleaves, &ilocal, &iremote));
22039371c9d4SSatish Balay     for (i = lnleaves = 0; i < nleaves; i++) {
22049371c9d4SSatish Balay       if (iremote[i].rank == (PetscInt)myrank) lnleaves++;
22059371c9d4SSatish Balay     }
22069566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(lnleaves, &lilocal));
22079566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(lnleaves, &liremote));
22081c6ba672SJunchao Zhang 
22091c6ba672SJunchao Zhang     for (i = j = 0; i < nleaves; i++) {
22101c6ba672SJunchao Zhang       if (iremote[i].rank == (PetscInt)myrank) {
22111c6ba672SJunchao Zhang         lilocal[j]        = ilocal ? ilocal[i] : i; /* ilocal=NULL for contiguous storage */
22121c6ba672SJunchao Zhang         liremote[j].rank  = 0;                      /* rank in PETSC_COMM_SELF */
22131c6ba672SJunchao Zhang         liremote[j].index = iremote[i].index;
22141c6ba672SJunchao Zhang         j++;
22151c6ba672SJunchao Zhang       }
22161c6ba672SJunchao Zhang     }
22179566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PETSC_COMM_SELF, &lsf));
22189566063dSJacob Faibussowitsch     PetscCall(PetscSFSetFromOptions(lsf));
22199566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(lsf, nroots, lnleaves, lilocal, PETSC_OWN_POINTER, liremote, PETSC_OWN_POINTER));
22209566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(lsf));
22211c6ba672SJunchao Zhang     *out = lsf;
22221c6ba672SJunchao Zhang   }
22233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22241c6ba672SJunchao Zhang }
2225dd5b3ca6SJunchao Zhang 
2226dd5b3ca6SJunchao Zhang /* Similar to PetscSFBcast, but only Bcast to leaves on rank 0 */
2227d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFBcastToZero_Private(PetscSF sf, MPI_Datatype unit, const void *rootdata, void *leafdata)
2228d71ae5a4SJacob Faibussowitsch {
2229eb02082bSJunchao Zhang   PetscMemType rootmtype, leafmtype;
2230dd5b3ca6SJunchao Zhang 
2231dd5b3ca6SJunchao Zhang   PetscFunctionBegin;
2232dd5b3ca6SJunchao Zhang   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
22339566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUp(sf));
22349566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCSF_BcastBegin, sf, 0, 0, 0));
22359566063dSJacob Faibussowitsch   PetscCall(PetscGetMemType(rootdata, &rootmtype));
22369566063dSJacob Faibussowitsch   PetscCall(PetscGetMemType(leafdata, &leafmtype));
2237dbbe0bcdSBarry Smith   PetscUseTypeMethod(sf, BcastToZero, unit, rootmtype, rootdata, leafmtype, leafdata);
22389566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCSF_BcastBegin, sf, 0, 0, 0));
22393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2240dd5b3ca6SJunchao Zhang }
2241dd5b3ca6SJunchao Zhang 
2242157edd7aSVaclav Hapla /*@
2243cab54364SBarry Smith   PetscSFConcatenate - concatenate multiple `PetscSF` into one
2244157edd7aSVaclav Hapla 
2245157edd7aSVaclav Hapla   Input Parameters:
2246157edd7aSVaclav Hapla + comm        - the communicator
2247cab54364SBarry Smith . nsfs        - the number of input `PetscSF`
2248cab54364SBarry Smith . sfs         - the array of input `PetscSF`
22491f40158dSVaclav Hapla . rootMode    - the root mode specifying how roots are handled
225020662ed9SBarry Smith - leafOffsets - the array of local leaf offsets, one for each input `PetscSF`, or `NULL` for contiguous storage
2251157edd7aSVaclav Hapla 
22522fe279fdSBarry Smith   Output Parameter:
2253cab54364SBarry Smith . newsf - The resulting `PetscSF`
2254157edd7aSVaclav Hapla 
22551f40158dSVaclav Hapla   Level: advanced
2256157edd7aSVaclav Hapla 
2257157edd7aSVaclav Hapla   Notes:
225820662ed9SBarry Smith   The communicator of all `PetscSF`s in `sfs` must be comm.
2259157edd7aSVaclav Hapla 
226020662ed9SBarry Smith   Leaves are always concatenated locally, keeping them ordered by the input `PetscSF` index and original local order.
226120662ed9SBarry Smith 
226220662ed9SBarry Smith   The offsets in `leafOffsets` are added to the original leaf indices.
226320662ed9SBarry Smith 
226420662ed9SBarry Smith   If all input SFs use contiguous leaf storage (`ilocal` = `NULL`), `leafOffsets` can be passed as `NULL` as well.
226520662ed9SBarry Smith   In this case, `NULL` is also passed as `ilocal` to the resulting `PetscSF`.
226620662ed9SBarry Smith 
226720662ed9SBarry Smith   If any input `PetscSF` has non-null `ilocal`, `leafOffsets` is needed to distinguish leaves from different input `PetscSF`s.
2268157edd7aSVaclav Hapla   In this case, user is responsible to provide correct offsets so that the resulting leaves are unique (otherwise an error occurs).
2269157edd7aSVaclav Hapla 
227020662ed9SBarry Smith   All root modes retain the essential connectivity condition.
227120662ed9SBarry Smith   If two leaves of the same input `PetscSF` are connected (sharing the same root), they are also connected in the output `PetscSF`.
227220662ed9SBarry Smith   Parameter `rootMode` controls how the input root spaces are combined.
227320662ed9SBarry Smith   For `PETSCSF_CONCATENATE_ROOTMODE_SHARED`, the root space is considered the same for each input `PetscSF` (checked in debug mode)
227420662ed9SBarry Smith   and is also the same in the output `PetscSF`.
22751f40158dSVaclav Hapla   For `PETSCSF_CONCATENATE_ROOTMODE_LOCAL` and `PETSCSF_CONCATENATE_ROOTMODE_GLOBAL`, the input root spaces are taken as separate and joined.
22761f40158dSVaclav Hapla   `PETSCSF_CONCATENATE_ROOTMODE_LOCAL` joins the root spaces locally;
227720662ed9SBarry Smith   roots of sfs[0], sfs[1], sfs[2], ... are joined on each rank separately, ordered by input `PetscSF` and original local index, and renumbered contiguously.
22781f40158dSVaclav Hapla   `PETSCSF_CONCATENATE_ROOTMODE_GLOBAL` joins the root spaces globally;
22791593df67SStefano Zampini   roots of sfs[0], sfs[1], sfs[2], ... are joined globally, ordered by input `PetscSF` index and original global index, and renumbered contiguously;
22801f40158dSVaclav Hapla   the original root ranks are ignored.
22811f40158dSVaclav Hapla   For both `PETSCSF_CONCATENATE_ROOTMODE_LOCAL` and `PETSCSF_CONCATENATE_ROOTMODE_GLOBAL`,
228220662ed9SBarry Smith   the output `PetscSF`'s root layout is such that the local number of roots is a sum of the input `PetscSF`'s local numbers of roots on each rank
228320662ed9SBarry Smith   to keep the load balancing.
228420662ed9SBarry Smith   However, for `PETSCSF_CONCATENATE_ROOTMODE_GLOBAL`, roots can move to different ranks.
22851f40158dSVaclav Hapla 
22861f40158dSVaclav Hapla   Example:
22871f40158dSVaclav Hapla   We can use src/vec/is/sf/tests/ex18.c to compare the root modes. By running
228820662ed9SBarry Smith .vb
228920662ed9SBarry Smith   make -C $PETSC_DIR/src/vec/is/sf/tests ex18
229020662ed9SBarry Smith   for m in {local,global,shared}; do
229120662ed9SBarry Smith     mpirun -n 2 $PETSC_DIR/src/vec/is/sf/tests/ex18 -nsfs 2 -n 2 -root_mode $m -sf_view
229220662ed9SBarry Smith   done
229320662ed9SBarry Smith .ve
229420662ed9SBarry Smith   we generate two identical `PetscSF`s sf_0 and sf_1,
229520662ed9SBarry Smith .vb
229620662ed9SBarry Smith   PetscSF Object: sf_0 2 MPI processes
229720662ed9SBarry Smith     type: basic
229820662ed9SBarry Smith     rank #leaves #roots
229920662ed9SBarry Smith     [ 0]       4      2
230020662ed9SBarry Smith     [ 1]       4      2
230120662ed9SBarry Smith     leaves      roots       roots in global numbering
230220662ed9SBarry Smith     ( 0,  0) <- ( 0,  0)  =   0
230320662ed9SBarry Smith     ( 0,  1) <- ( 0,  1)  =   1
230420662ed9SBarry Smith     ( 0,  2) <- ( 1,  0)  =   2
230520662ed9SBarry Smith     ( 0,  3) <- ( 1,  1)  =   3
230620662ed9SBarry Smith     ( 1,  0) <- ( 0,  0)  =   0
230720662ed9SBarry Smith     ( 1,  1) <- ( 0,  1)  =   1
230820662ed9SBarry Smith     ( 1,  2) <- ( 1,  0)  =   2
230920662ed9SBarry Smith     ( 1,  3) <- ( 1,  1)  =   3
231020662ed9SBarry Smith .ve
2311e33f79d8SJacob Faibussowitsch   and pass them to `PetscSFConcatenate()` along with different choices of `rootMode`, yielding different result_sf\:
231220662ed9SBarry Smith .vb
231320662ed9SBarry Smith   rootMode = local:
231420662ed9SBarry Smith   PetscSF Object: result_sf 2 MPI processes
231520662ed9SBarry Smith     type: basic
231620662ed9SBarry Smith     rank #leaves #roots
231720662ed9SBarry Smith     [ 0]       8      4
231820662ed9SBarry Smith     [ 1]       8      4
231920662ed9SBarry Smith     leaves      roots       roots in global numbering
232020662ed9SBarry Smith     ( 0,  0) <- ( 0,  0)  =   0
232120662ed9SBarry Smith     ( 0,  1) <- ( 0,  1)  =   1
232220662ed9SBarry Smith     ( 0,  2) <- ( 1,  0)  =   4
232320662ed9SBarry Smith     ( 0,  3) <- ( 1,  1)  =   5
232420662ed9SBarry Smith     ( 0,  4) <- ( 0,  2)  =   2
232520662ed9SBarry Smith     ( 0,  5) <- ( 0,  3)  =   3
232620662ed9SBarry Smith     ( 0,  6) <- ( 1,  2)  =   6
232720662ed9SBarry Smith     ( 0,  7) <- ( 1,  3)  =   7
232820662ed9SBarry Smith     ( 1,  0) <- ( 0,  0)  =   0
232920662ed9SBarry Smith     ( 1,  1) <- ( 0,  1)  =   1
233020662ed9SBarry Smith     ( 1,  2) <- ( 1,  0)  =   4
233120662ed9SBarry Smith     ( 1,  3) <- ( 1,  1)  =   5
233220662ed9SBarry Smith     ( 1,  4) <- ( 0,  2)  =   2
233320662ed9SBarry Smith     ( 1,  5) <- ( 0,  3)  =   3
233420662ed9SBarry Smith     ( 1,  6) <- ( 1,  2)  =   6
233520662ed9SBarry Smith     ( 1,  7) <- ( 1,  3)  =   7
233620662ed9SBarry Smith 
233720662ed9SBarry Smith   rootMode = global:
233820662ed9SBarry Smith   PetscSF Object: result_sf 2 MPI processes
233920662ed9SBarry Smith     type: basic
234020662ed9SBarry Smith     rank #leaves #roots
234120662ed9SBarry Smith     [ 0]       8      4
234220662ed9SBarry Smith     [ 1]       8      4
234320662ed9SBarry Smith     leaves      roots       roots in global numbering
234420662ed9SBarry Smith     ( 0,  0) <- ( 0,  0)  =   0
234520662ed9SBarry Smith     ( 0,  1) <- ( 0,  1)  =   1
234620662ed9SBarry Smith     ( 0,  2) <- ( 0,  2)  =   2
234720662ed9SBarry Smith     ( 0,  3) <- ( 0,  3)  =   3
234820662ed9SBarry Smith     ( 0,  4) <- ( 1,  0)  =   4
234920662ed9SBarry Smith     ( 0,  5) <- ( 1,  1)  =   5
235020662ed9SBarry Smith     ( 0,  6) <- ( 1,  2)  =   6
235120662ed9SBarry Smith     ( 0,  7) <- ( 1,  3)  =   7
235220662ed9SBarry Smith     ( 1,  0) <- ( 0,  0)  =   0
235320662ed9SBarry Smith     ( 1,  1) <- ( 0,  1)  =   1
235420662ed9SBarry Smith     ( 1,  2) <- ( 0,  2)  =   2
235520662ed9SBarry Smith     ( 1,  3) <- ( 0,  3)  =   3
235620662ed9SBarry Smith     ( 1,  4) <- ( 1,  0)  =   4
235720662ed9SBarry Smith     ( 1,  5) <- ( 1,  1)  =   5
235820662ed9SBarry Smith     ( 1,  6) <- ( 1,  2)  =   6
235920662ed9SBarry Smith     ( 1,  7) <- ( 1,  3)  =   7
236020662ed9SBarry Smith 
236120662ed9SBarry Smith   rootMode = shared:
236220662ed9SBarry Smith   PetscSF Object: result_sf 2 MPI processes
236320662ed9SBarry Smith     type: basic
236420662ed9SBarry Smith     rank #leaves #roots
236520662ed9SBarry Smith     [ 0]       8      2
236620662ed9SBarry Smith     [ 1]       8      2
236720662ed9SBarry Smith     leaves      roots       roots in global numbering
236820662ed9SBarry Smith     ( 0,  0) <- ( 0,  0)  =   0
236920662ed9SBarry Smith     ( 0,  1) <- ( 0,  1)  =   1
237020662ed9SBarry Smith     ( 0,  2) <- ( 1,  0)  =   2
237120662ed9SBarry Smith     ( 0,  3) <- ( 1,  1)  =   3
237220662ed9SBarry Smith     ( 0,  4) <- ( 0,  0)  =   0
237320662ed9SBarry Smith     ( 0,  5) <- ( 0,  1)  =   1
237420662ed9SBarry Smith     ( 0,  6) <- ( 1,  0)  =   2
237520662ed9SBarry Smith     ( 0,  7) <- ( 1,  1)  =   3
237620662ed9SBarry Smith     ( 1,  0) <- ( 0,  0)  =   0
237720662ed9SBarry Smith     ( 1,  1) <- ( 0,  1)  =   1
237820662ed9SBarry Smith     ( 1,  2) <- ( 1,  0)  =   2
237920662ed9SBarry Smith     ( 1,  3) <- ( 1,  1)  =   3
238020662ed9SBarry Smith     ( 1,  4) <- ( 0,  0)  =   0
238120662ed9SBarry Smith     ( 1,  5) <- ( 0,  1)  =   1
238220662ed9SBarry Smith     ( 1,  6) <- ( 1,  0)  =   2
238320662ed9SBarry Smith     ( 1,  7) <- ( 1,  1)  =   3
238420662ed9SBarry Smith .ve
23851f40158dSVaclav Hapla 
23861f40158dSVaclav Hapla .seealso: `PetscSF`, `PetscSFCompose()`, `PetscSFGetGraph()`, `PetscSFSetGraph()`, `PetscSFConcatenateRootMode`
2387157edd7aSVaclav Hapla @*/
23881f40158dSVaclav Hapla PetscErrorCode PetscSFConcatenate(MPI_Comm comm, PetscInt nsfs, PetscSF sfs[], PetscSFConcatenateRootMode rootMode, PetscInt leafOffsets[], PetscSF *newsf)
2389d71ae5a4SJacob Faibussowitsch {
2390157edd7aSVaclav Hapla   PetscInt     i, s, nLeaves, nRoots;
2391157edd7aSVaclav Hapla   PetscInt    *leafArrayOffsets;
2392157edd7aSVaclav Hapla   PetscInt    *ilocal_new;
2393157edd7aSVaclav Hapla   PetscSFNode *iremote_new;
2394157edd7aSVaclav Hapla   PetscBool    all_ilocal_null = PETSC_FALSE;
23951f40158dSVaclav Hapla   PetscLayout  glayout         = NULL;
23961f40158dSVaclav Hapla   PetscInt    *gremote         = NULL;
23971f40158dSVaclav Hapla   PetscMPIInt  rank, size;
2398157edd7aSVaclav Hapla 
2399157edd7aSVaclav Hapla   PetscFunctionBegin;
240012f479c1SVaclav Hapla   if (PetscDefined(USE_DEBUG)) {
2401157edd7aSVaclav Hapla     PetscSF dummy; /* just to have a PetscObject on comm for input validation */
2402157edd7aSVaclav Hapla 
24039566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(comm, &dummy));
2404157edd7aSVaclav Hapla     PetscValidLogicalCollectiveInt(dummy, nsfs, 2);
24054f572ea9SToby Isaac     PetscAssertPointer(sfs, 3);
2406157edd7aSVaclav Hapla     for (i = 0; i < nsfs; i++) {
2407157edd7aSVaclav Hapla       PetscValidHeaderSpecific(sfs[i], PETSCSF_CLASSID, 3);
2408157edd7aSVaclav Hapla       PetscCheckSameComm(dummy, 1, sfs[i], 3);
2409157edd7aSVaclav Hapla     }
24101f40158dSVaclav Hapla     PetscValidLogicalCollectiveEnum(dummy, rootMode, 4);
24114f572ea9SToby Isaac     if (leafOffsets) PetscAssertPointer(leafOffsets, 5);
24124f572ea9SToby Isaac     PetscAssertPointer(newsf, 6);
24139566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&dummy));
2414157edd7aSVaclav Hapla   }
2415157edd7aSVaclav Hapla   if (!nsfs) {
24169566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(comm, newsf));
24179566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(*newsf, 0, 0, NULL, PETSC_OWN_POINTER, NULL, PETSC_OWN_POINTER));
24183ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
2419157edd7aSVaclav Hapla   }
24209566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
24211f40158dSVaclav Hapla   PetscCallMPI(MPI_Comm_size(comm, &size));
2422157edd7aSVaclav Hapla 
24231f40158dSVaclav Hapla   /* Calculate leaf array offsets */
24249566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nsfs + 1, &leafArrayOffsets));
2425157edd7aSVaclav Hapla   leafArrayOffsets[0] = 0;
2426157edd7aSVaclav Hapla   for (s = 0; s < nsfs; s++) {
2427157edd7aSVaclav Hapla     PetscInt nl;
2428157edd7aSVaclav Hapla 
24299566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(sfs[s], NULL, &nl, NULL, NULL));
2430157edd7aSVaclav Hapla     leafArrayOffsets[s + 1] = leafArrayOffsets[s] + nl;
2431157edd7aSVaclav Hapla   }
2432157edd7aSVaclav Hapla   nLeaves = leafArrayOffsets[nsfs];
2433157edd7aSVaclav Hapla 
24341f40158dSVaclav Hapla   /* Calculate number of roots */
24351f40158dSVaclav Hapla   switch (rootMode) {
24361f40158dSVaclav Hapla   case PETSCSF_CONCATENATE_ROOTMODE_SHARED: {
24371f40158dSVaclav Hapla     PetscCall(PetscSFGetGraph(sfs[0], &nRoots, NULL, NULL, NULL));
24381f40158dSVaclav Hapla     if (PetscDefined(USE_DEBUG)) {
24391f40158dSVaclav Hapla       for (s = 1; s < nsfs; s++) {
24401f40158dSVaclav Hapla         PetscInt nr;
24411f40158dSVaclav Hapla 
24421f40158dSVaclav Hapla         PetscCall(PetscSFGetGraph(sfs[s], &nr, NULL, NULL, NULL));
24431f40158dSVaclav Hapla         PetscCheck(nr == nRoots, comm, PETSC_ERR_ARG_SIZ, "rootMode = %s but sfs[%" PetscInt_FMT "] has a different number of roots (%" PetscInt_FMT ") than sfs[0] (%" PetscInt_FMT ")", PetscSFConcatenateRootModes[rootMode], s, nr, nRoots);
24441f40158dSVaclav Hapla       }
24451f40158dSVaclav Hapla     }
24461f40158dSVaclav Hapla   } break;
24471f40158dSVaclav Hapla   case PETSCSF_CONCATENATE_ROOTMODE_GLOBAL: {
24481f40158dSVaclav Hapla     /* Calculate also global layout in this case */
24491f40158dSVaclav Hapla     PetscInt    *nls;
24501f40158dSVaclav Hapla     PetscLayout *lts;
24511f40158dSVaclav Hapla     PetscInt   **inds;
24521f40158dSVaclav Hapla     PetscInt     j;
24531f40158dSVaclav Hapla     PetscInt     rootOffset = 0;
24541f40158dSVaclav Hapla 
24551f40158dSVaclav Hapla     PetscCall(PetscCalloc3(nsfs, &lts, nsfs, &nls, nsfs, &inds));
24561f40158dSVaclav Hapla     PetscCall(PetscLayoutCreate(comm, &glayout));
24571f40158dSVaclav Hapla     glayout->bs = 1;
24581f40158dSVaclav Hapla     glayout->n  = 0;
24591f40158dSVaclav Hapla     glayout->N  = 0;
24601f40158dSVaclav Hapla     for (s = 0; s < nsfs; s++) {
24611f40158dSVaclav Hapla       PetscCall(PetscSFGetGraphLayout(sfs[s], &lts[s], &nls[s], NULL, &inds[s]));
24621f40158dSVaclav Hapla       glayout->n += lts[s]->n;
24631f40158dSVaclav Hapla       glayout->N += lts[s]->N;
24641f40158dSVaclav Hapla     }
24651f40158dSVaclav Hapla     PetscCall(PetscLayoutSetUp(glayout));
24661f40158dSVaclav Hapla     PetscCall(PetscMalloc1(nLeaves, &gremote));
24671f40158dSVaclav Hapla     for (s = 0, j = 0; s < nsfs; s++) {
24681f40158dSVaclav Hapla       for (i = 0; i < nls[s]; i++, j++) gremote[j] = inds[s][i] + rootOffset;
24691f40158dSVaclav Hapla       rootOffset += lts[s]->N;
24701f40158dSVaclav Hapla       PetscCall(PetscLayoutDestroy(&lts[s]));
24711f40158dSVaclav Hapla       PetscCall(PetscFree(inds[s]));
24721f40158dSVaclav Hapla     }
24731f40158dSVaclav Hapla     PetscCall(PetscFree3(lts, nls, inds));
24741f40158dSVaclav Hapla     nRoots = glayout->N;
24751f40158dSVaclav Hapla   } break;
24761f40158dSVaclav Hapla   case PETSCSF_CONCATENATE_ROOTMODE_LOCAL:
24771f40158dSVaclav Hapla     /* nRoots calculated later in this case */
24781f40158dSVaclav Hapla     break;
24791f40158dSVaclav Hapla   default:
24801f40158dSVaclav Hapla     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid PetscSFConcatenateRootMode %d", rootMode);
24811f40158dSVaclav Hapla   }
24821f40158dSVaclav Hapla 
2483157edd7aSVaclav Hapla   if (!leafOffsets) {
2484157edd7aSVaclav Hapla     all_ilocal_null = PETSC_TRUE;
2485157edd7aSVaclav Hapla     for (s = 0; s < nsfs; s++) {
2486157edd7aSVaclav Hapla       const PetscInt *ilocal;
2487157edd7aSVaclav Hapla 
24889566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGraph(sfs[s], NULL, NULL, &ilocal, NULL));
2489157edd7aSVaclav Hapla       if (ilocal) {
2490157edd7aSVaclav Hapla         all_ilocal_null = PETSC_FALSE;
2491157edd7aSVaclav Hapla         break;
2492157edd7aSVaclav Hapla       }
2493157edd7aSVaclav Hapla     }
2494157edd7aSVaclav Hapla     PetscCheck(all_ilocal_null, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "leafOffsets can be passed as NULL only if all SFs have ilocal = NULL");
2495157edd7aSVaclav Hapla   }
2496157edd7aSVaclav Hapla 
2497157edd7aSVaclav Hapla   /* Renumber and concatenate local leaves */
2498157edd7aSVaclav Hapla   ilocal_new = NULL;
2499157edd7aSVaclav Hapla   if (!all_ilocal_null) {
25009566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nLeaves, &ilocal_new));
2501157edd7aSVaclav Hapla     for (i = 0; i < nLeaves; i++) ilocal_new[i] = -1;
2502157edd7aSVaclav Hapla     for (s = 0; s < nsfs; s++) {
2503157edd7aSVaclav Hapla       const PetscInt *ilocal;
2504157edd7aSVaclav Hapla       PetscInt       *ilocal_l = &ilocal_new[leafArrayOffsets[s]];
2505157edd7aSVaclav Hapla       PetscInt        i, nleaves_l;
2506157edd7aSVaclav Hapla 
25079566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGraph(sfs[s], NULL, &nleaves_l, &ilocal, NULL));
2508157edd7aSVaclav Hapla       for (i = 0; i < nleaves_l; i++) ilocal_l[i] = (ilocal ? ilocal[i] : i) + leafOffsets[s];
2509157edd7aSVaclav Hapla     }
2510157edd7aSVaclav Hapla   }
2511157edd7aSVaclav Hapla 
2512157edd7aSVaclav Hapla   /* Renumber and concatenate remote roots */
25131f40158dSVaclav Hapla   if (rootMode == PETSCSF_CONCATENATE_ROOTMODE_LOCAL || rootMode == PETSCSF_CONCATENATE_ROOTMODE_SHARED) {
25141f40158dSVaclav Hapla     PetscInt rootOffset = 0;
25151f40158dSVaclav Hapla 
25169566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nLeaves, &iremote_new));
2517157edd7aSVaclav Hapla     for (i = 0; i < nLeaves; i++) {
2518157edd7aSVaclav Hapla       iremote_new[i].rank  = -1;
2519157edd7aSVaclav Hapla       iremote_new[i].index = -1;
2520157edd7aSVaclav Hapla     }
2521157edd7aSVaclav Hapla     for (s = 0; s < nsfs; s++) {
2522157edd7aSVaclav Hapla       PetscInt           i, nl, nr;
2523157edd7aSVaclav Hapla       PetscSF            tmp_sf;
2524157edd7aSVaclav Hapla       const PetscSFNode *iremote;
2525157edd7aSVaclav Hapla       PetscSFNode       *tmp_rootdata;
2526157edd7aSVaclav Hapla       PetscSFNode       *tmp_leafdata = &iremote_new[leafArrayOffsets[s]];
2527157edd7aSVaclav Hapla 
25289566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGraph(sfs[s], &nr, &nl, NULL, &iremote));
25299566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(comm, &tmp_sf));
2530157edd7aSVaclav Hapla       /* create helper SF with contiguous leaves */
25319566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraph(tmp_sf, nr, nl, NULL, PETSC_USE_POINTER, (PetscSFNode *)iremote, PETSC_COPY_VALUES));
25329566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(tmp_sf));
25339566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nr, &tmp_rootdata));
25341f40158dSVaclav Hapla       if (rootMode == PETSCSF_CONCATENATE_ROOTMODE_LOCAL) {
2535157edd7aSVaclav Hapla         for (i = 0; i < nr; i++) {
25361f40158dSVaclav Hapla           tmp_rootdata[i].index = i + rootOffset;
2537157edd7aSVaclav Hapla           tmp_rootdata[i].rank  = (PetscInt)rank;
2538157edd7aSVaclav Hapla         }
25391f40158dSVaclav Hapla         rootOffset += nr;
25401f40158dSVaclav Hapla       } else {
25411f40158dSVaclav Hapla         for (i = 0; i < nr; i++) {
25421f40158dSVaclav Hapla           tmp_rootdata[i].index = i;
25431f40158dSVaclav Hapla           tmp_rootdata[i].rank  = (PetscInt)rank;
25441f40158dSVaclav Hapla         }
25451f40158dSVaclav Hapla       }
25469566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(tmp_sf, MPIU_2INT, tmp_rootdata, tmp_leafdata, MPI_REPLACE));
25479566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(tmp_sf, MPIU_2INT, tmp_rootdata, tmp_leafdata, MPI_REPLACE));
25489566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&tmp_sf));
25499566063dSJacob Faibussowitsch       PetscCall(PetscFree(tmp_rootdata));
2550157edd7aSVaclav Hapla     }
2551aa624791SPierre Jolivet     if (rootMode == PETSCSF_CONCATENATE_ROOTMODE_LOCAL) nRoots = rootOffset; // else nRoots already calculated above
2552157edd7aSVaclav Hapla 
2553157edd7aSVaclav Hapla     /* Build the new SF */
25549566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(comm, newsf));
25559566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(*newsf, nRoots, nLeaves, ilocal_new, PETSC_OWN_POINTER, iremote_new, PETSC_OWN_POINTER));
25561f40158dSVaclav Hapla   } else {
25571f40158dSVaclav Hapla     /* Build the new SF */
25581f40158dSVaclav Hapla     PetscCall(PetscSFCreate(comm, newsf));
25591f40158dSVaclav Hapla     PetscCall(PetscSFSetGraphLayout(*newsf, glayout, nLeaves, ilocal_new, PETSC_OWN_POINTER, gremote));
25601f40158dSVaclav Hapla   }
25619566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUp(*newsf));
25621f40158dSVaclav Hapla   PetscCall(PetscSFViewFromOptions(*newsf, NULL, "-sf_concat_view"));
25631f40158dSVaclav Hapla   PetscCall(PetscLayoutDestroy(&glayout));
25641f40158dSVaclav Hapla   PetscCall(PetscFree(gremote));
25659566063dSJacob Faibussowitsch   PetscCall(PetscFree(leafArrayOffsets));
25663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2567157edd7aSVaclav Hapla }
2568