xref: /petsc/src/vec/is/sf/utils/sfutils.c (revision 7c0883d534795ebc7b69f947707473b1809c98bb)
1b0c7db22SLisandro Dalcin #include <petsc/private/sfimpl.h>       /*I  "petscsf.h"   I*/
2b0c7db22SLisandro Dalcin #include <petsc/private/sectionimpl.h>
3b0c7db22SLisandro Dalcin 
4b0c7db22SLisandro Dalcin /*@C
5b0c7db22SLisandro Dalcin    PetscSFSetGraphLayout - Set a parallel star forest via global indices and a PetscLayout
6b0c7db22SLisandro Dalcin 
7b0c7db22SLisandro Dalcin    Collective
8b0c7db22SLisandro Dalcin 
94165533cSJose E. Roman    Input Parameters:
10b0c7db22SLisandro Dalcin +  sf - star forest
11ddea5d60SJunchao Zhang .  layout - PetscLayout defining the global space for roots
12b0c7db22SLisandro Dalcin .  nleaves - number of leaf vertices on the current process, each of these references a root on any process
13b0c7db22SLisandro Dalcin .  ilocal - locations of leaves in leafdata buffers, pass NULL for contiguous storage
14b0c7db22SLisandro Dalcin .  localmode - copy mode for ilocal
1586c56f52SVaclav Hapla -  iremote - root vertices in global numbering corresponding to leaves in ilocal
16b0c7db22SLisandro Dalcin 
17b0c7db22SLisandro Dalcin    Level: intermediate
18b0c7db22SLisandro Dalcin 
1986c56f52SVaclav Hapla    Notes:
2086c56f52SVaclav Hapla    Global indices must lie in [0, N) where N is the global size of layout.
21db2b9530SVaclav Hapla    Leaf indices in ilocal get sorted; this means the user-provided array gets sorted if localmode is PETSC_OWN_POINTER.
2286c56f52SVaclav Hapla 
23db2b9530SVaclav Hapla    Developer Notes:
2486c56f52SVaclav Hapla    Local indices which are the identity permutation in the range [0,nleaves) are discarded as they
25b0c7db22SLisandro Dalcin    encode contiguous storage. In such case, if localmode is PETSC_OWN_POINTER, the memory is deallocated as it is not
26b0c7db22SLisandro Dalcin    needed
27b0c7db22SLisandro Dalcin 
28b0c7db22SLisandro Dalcin .seealso: PetscSFCreate(), PetscSFView(), PetscSFSetGraph(), PetscSFGetGraph()
29b0c7db22SLisandro Dalcin @*/
30db2b9530SVaclav Hapla PetscErrorCode PetscSFSetGraphLayout(PetscSF sf,PetscLayout layout,PetscInt nleaves,PetscInt *ilocal,PetscCopyMode localmode,const PetscInt *iremote)
31b0c7db22SLisandro Dalcin {
3238a25198SStefano Zampini   const PetscInt *range;
3338a25198SStefano Zampini   PetscInt       i, nroots, ls = -1, ln = -1;
3438a25198SStefano Zampini   PetscMPIInt    lr = -1;
35b0c7db22SLisandro Dalcin   PetscSFNode    *remote;
36b0c7db22SLisandro Dalcin 
37b0c7db22SLisandro Dalcin   PetscFunctionBegin;
389566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetLocalSize(layout,&nroots));
399566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRanges(layout,&range));
409566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nleaves,&remote));
4138a25198SStefano Zampini   if (nleaves) { ls = iremote[0] + 1; }
42b0c7db22SLisandro Dalcin   for (i=0; i<nleaves; i++) {
4338a25198SStefano Zampini     const PetscInt idx = iremote[i] - ls;
4438a25198SStefano Zampini     if (idx < 0 || idx >= ln) { /* short-circuit the search */
459566063dSJacob Faibussowitsch       PetscCall(PetscLayoutFindOwnerIndex(layout,iremote[i],&lr,&remote[i].index));
4638a25198SStefano Zampini       remote[i].rank = lr;
4738a25198SStefano Zampini       ls = range[lr];
4838a25198SStefano Zampini       ln = range[lr+1] - ls;
4938a25198SStefano Zampini     } else {
5038a25198SStefano Zampini       remote[i].rank  = lr;
5138a25198SStefano Zampini       remote[i].index = idx;
5238a25198SStefano Zampini     }
53b0c7db22SLisandro Dalcin   }
549566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf,nroots,nleaves,ilocal,localmode,remote,PETSC_OWN_POINTER));
55b0c7db22SLisandro Dalcin   PetscFunctionReturn(0);
56b0c7db22SLisandro Dalcin }
57b0c7db22SLisandro Dalcin 
58b0c7db22SLisandro Dalcin /*@
59b0c7db22SLisandro Dalcin   PetscSFSetGraphSection - Sets the PetscSF graph encoding the parallel dof overlap based upon the PetscSections
60b0c7db22SLisandro Dalcin   describing the data layout.
61b0c7db22SLisandro Dalcin 
62b0c7db22SLisandro Dalcin   Input Parameters:
63b0c7db22SLisandro Dalcin + sf - The SF
64b0c7db22SLisandro Dalcin . localSection - PetscSection describing the local data layout
65b0c7db22SLisandro Dalcin - globalSection - PetscSection describing the global data layout
66b0c7db22SLisandro Dalcin 
67b0c7db22SLisandro Dalcin   Level: developer
68b0c7db22SLisandro Dalcin 
69b0c7db22SLisandro Dalcin .seealso: PetscSFSetGraph(), PetscSFSetGraphLayout()
70b0c7db22SLisandro Dalcin @*/
71b0c7db22SLisandro Dalcin PetscErrorCode PetscSFSetGraphSection(PetscSF sf, PetscSection localSection, PetscSection globalSection)
72b0c7db22SLisandro Dalcin {
73b0c7db22SLisandro Dalcin   MPI_Comm       comm;
74b0c7db22SLisandro Dalcin   PetscLayout    layout;
75b0c7db22SLisandro Dalcin   const PetscInt *ranges;
76b0c7db22SLisandro Dalcin   PetscInt       *local;
77b0c7db22SLisandro Dalcin   PetscSFNode    *remote;
78b0c7db22SLisandro Dalcin   PetscInt       pStart, pEnd, p, nroots, nleaves = 0, l;
79b0c7db22SLisandro Dalcin   PetscMPIInt    size, rank;
80b0c7db22SLisandro Dalcin 
81b0c7db22SLisandro Dalcin   PetscFunctionBegin;
82b0c7db22SLisandro Dalcin   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
83b0c7db22SLisandro Dalcin   PetscValidHeaderSpecific(localSection, PETSC_SECTION_CLASSID, 2);
84b0c7db22SLisandro Dalcin   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
85b0c7db22SLisandro Dalcin 
869566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)sf,&comm));
879566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
889566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
899566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(globalSection, &pStart, &pEnd));
909566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &nroots));
919566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(comm, &layout));
929566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(layout, 1));
939566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(layout, nroots));
949566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(layout));
959566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRanges(layout, &ranges));
96b0c7db22SLisandro Dalcin   for (p = pStart; p < pEnd; ++p) {
97b0c7db22SLisandro Dalcin     PetscInt gdof, gcdof;
98b0c7db22SLisandro Dalcin 
999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalSection, p, &gdof));
1009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalSection, p, &gcdof));
1012c71b3e2SJacob Faibussowitsch     PetscCheckFalse(gcdof > (gdof < 0 ? -(gdof+1) : gdof),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " has %" PetscInt_FMT " constraints > %" PetscInt_FMT " dof", p, gcdof, (gdof < 0 ? -(gdof+1) : gdof));
102b0c7db22SLisandro Dalcin     nleaves += gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
103b0c7db22SLisandro Dalcin   }
1049566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nleaves, &local));
1059566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nleaves, &remote));
106b0c7db22SLisandro Dalcin   for (p = pStart, l = 0; p < pEnd; ++p) {
107b0c7db22SLisandro Dalcin     const PetscInt *cind;
108b0c7db22SLisandro Dalcin     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d, c;
109b0c7db22SLisandro Dalcin 
1109566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(localSection, p, &dof));
1119566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(localSection, p, &off));
1129566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(localSection, p, &cdof));
1139566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintIndices(localSection, p, &cind));
1149566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(globalSection, p, &gdof));
1159566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(globalSection, p, &gcdof));
1169566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(globalSection, p, &goff));
117b0c7db22SLisandro Dalcin     if (!gdof) continue; /* Censored point */
118b0c7db22SLisandro Dalcin     gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
119b0c7db22SLisandro Dalcin     if (gsize != dof-cdof) {
1202c71b3e2SJacob Faibussowitsch       PetscCheckFalse(gsize != dof,comm, PETSC_ERR_ARG_WRONG, "Global dof %" PetscInt_FMT " for point %" PetscInt_FMT " is neither the constrained size %" PetscInt_FMT ", nor the unconstrained %" PetscInt_FMT, gsize, p, dof-cdof, dof);
121b0c7db22SLisandro Dalcin       cdof = 0; /* Ignore constraints */
122b0c7db22SLisandro Dalcin     }
123b0c7db22SLisandro Dalcin     for (d = 0, c = 0; d < dof; ++d) {
124b0c7db22SLisandro Dalcin       if ((c < cdof) && (cind[c] == d)) {++c; continue;}
125b0c7db22SLisandro Dalcin       local[l+d-c] = off+d;
126b0c7db22SLisandro Dalcin     }
1272c71b3e2SJacob Faibussowitsch     PetscCheckFalse(d-c != gsize,comm, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT ": Global dof %" PetscInt_FMT " != %" PetscInt_FMT " size - number of constraints", p, gsize, d-c);
128b0c7db22SLisandro Dalcin     if (gdof < 0) {
129b0c7db22SLisandro Dalcin       for (d = 0; d < gsize; ++d, ++l) {
130b0c7db22SLisandro Dalcin         PetscInt offset = -(goff+1) + d, r;
131b0c7db22SLisandro Dalcin 
1329566063dSJacob Faibussowitsch         PetscCall(PetscFindInt(offset,size+1,ranges,&r));
133b0c7db22SLisandro Dalcin         if (r < 0) r = -(r+2);
1342c71b3e2SJacob Faibussowitsch         PetscCheckFalse((r < 0) || (r >= size),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " mapped to invalid process %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ")", p, r, gdof, goff);
135b0c7db22SLisandro Dalcin         remote[l].rank  = r;
136b0c7db22SLisandro Dalcin         remote[l].index = offset - ranges[r];
137b0c7db22SLisandro Dalcin       }
138b0c7db22SLisandro Dalcin     } else {
139b0c7db22SLisandro Dalcin       for (d = 0; d < gsize; ++d, ++l) {
140b0c7db22SLisandro Dalcin         remote[l].rank  = rank;
141b0c7db22SLisandro Dalcin         remote[l].index = goff+d - ranges[rank];
142b0c7db22SLisandro Dalcin       }
143b0c7db22SLisandro Dalcin     }
144b0c7db22SLisandro Dalcin   }
1452c71b3e2SJacob Faibussowitsch   PetscCheckFalse(l != nleaves,comm, PETSC_ERR_PLIB, "Iteration error, l %" PetscInt_FMT " != nleaves %" PetscInt_FMT, l, nleaves);
1469566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&layout));
1479566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER));
148b0c7db22SLisandro Dalcin   PetscFunctionReturn(0);
149b0c7db22SLisandro Dalcin }
150b0c7db22SLisandro Dalcin 
151b0c7db22SLisandro Dalcin /*@C
152b0c7db22SLisandro Dalcin   PetscSFDistributeSection - Create a new PetscSection reorganized, moving from the root to the leaves of the SF
153b0c7db22SLisandro Dalcin 
154b0c7db22SLisandro Dalcin   Collective on sf
155b0c7db22SLisandro Dalcin 
156b0c7db22SLisandro Dalcin   Input Parameters:
157b0c7db22SLisandro Dalcin + sf - The SF
158b0c7db22SLisandro Dalcin - rootSection - Section defined on root space
159b0c7db22SLisandro Dalcin 
160b0c7db22SLisandro Dalcin   Output Parameters:
161b0c7db22SLisandro Dalcin + remoteOffsets - root offsets in leaf storage, or NULL
162b0c7db22SLisandro Dalcin - leafSection - Section defined on the leaf space
163b0c7db22SLisandro Dalcin 
164b0c7db22SLisandro Dalcin   Level: advanced
165b0c7db22SLisandro Dalcin 
166b0c7db22SLisandro Dalcin .seealso: PetscSFCreate()
167b0c7db22SLisandro Dalcin @*/
168b0c7db22SLisandro Dalcin PetscErrorCode PetscSFDistributeSection(PetscSF sf, PetscSection rootSection, PetscInt **remoteOffsets, PetscSection leafSection)
169b0c7db22SLisandro Dalcin {
170b0c7db22SLisandro Dalcin   PetscSF        embedSF;
171b0c7db22SLisandro Dalcin   const PetscInt *indices;
172b0c7db22SLisandro Dalcin   IS             selected;
173b0c7db22SLisandro Dalcin   PetscInt       numFields, nroots, rpStart, rpEnd, lpStart = PETSC_MAX_INT, lpEnd = -1, f, c;
174b0c7db22SLisandro Dalcin   PetscBool      *sub, hasc;
175b0c7db22SLisandro Dalcin 
176b0c7db22SLisandro Dalcin   PetscFunctionBegin;
1779566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCSF_DistSect,sf,0,0,0));
1789566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(rootSection, &numFields));
179029e8818Sksagiyam   if (numFields) {
180029e8818Sksagiyam     IS perm;
181029e8818Sksagiyam 
182029e8818Sksagiyam     /* PetscSectionSetNumFields() calls PetscSectionReset(), which destroys
183029e8818Sksagiyam        leafSection->perm. To keep this permutation set by the user, we grab
184029e8818Sksagiyam        the reference before calling PetscSectionSetNumFields() and set it
185029e8818Sksagiyam        back after. */
1869566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetPermutation(leafSection, &perm));
1879566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)perm));
1889566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetNumFields(leafSection, numFields));
1899566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetPermutation(leafSection, perm));
1909566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&perm));
191029e8818Sksagiyam   }
1929566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numFields+2, &sub));
193b0c7db22SLisandro Dalcin   sub[1] = rootSection->bc ? PETSC_TRUE : PETSC_FALSE;
194b0c7db22SLisandro Dalcin   for (f = 0; f < numFields; ++f) {
1952ee82556SMatthew G. Knepley     PetscSectionSym sym, dsym = NULL;
196b0c7db22SLisandro Dalcin     const char      *name   = NULL;
197b0c7db22SLisandro Dalcin     PetscInt        numComp = 0;
198b0c7db22SLisandro Dalcin 
199b0c7db22SLisandro Dalcin     sub[2 + f] = rootSection->field[f]->bc ? PETSC_TRUE : PETSC_FALSE;
2009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldComponents(rootSection, f, &numComp));
2019566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldName(rootSection, f, &name));
2029566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetFieldSym(rootSection, f, &sym));
2039566063dSJacob Faibussowitsch     if (sym) PetscCall(PetscSectionSymDistribute(sym, sf, &dsym));
2049566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldComponents(leafSection, f, numComp));
2059566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldName(leafSection, f, name));
2069566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldSym(leafSection, f, dsym));
2079566063dSJacob Faibussowitsch     PetscCall(PetscSectionSymDestroy(&dsym));
208b0c7db22SLisandro Dalcin     for (c = 0; c < rootSection->numFieldComponents[f]; ++c) {
2099566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetComponentName(rootSection, f, c, &name));
2109566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetComponentName(leafSection, f, c, name));
211b0c7db22SLisandro Dalcin     }
212b0c7db22SLisandro Dalcin   }
2139566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(rootSection, &rpStart, &rpEnd));
2149566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf,&nroots,NULL,NULL,NULL));
215b0c7db22SLisandro Dalcin   rpEnd = PetscMin(rpEnd,nroots);
216b0c7db22SLisandro Dalcin   rpEnd = PetscMax(rpStart,rpEnd);
217b0c7db22SLisandro Dalcin   /* see if we can avoid creating the embedded SF, since it can cost more than an allreduce */
218b0c7db22SLisandro Dalcin   sub[0] = (PetscBool)(nroots != rpEnd - rpStart);
2199566063dSJacob Faibussowitsch   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, sub, 2+numFields, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)sf)));
220b0c7db22SLisandro Dalcin   if (sub[0]) {
2219566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, rpEnd - rpStart, rpStart, 1, &selected));
2229566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(selected, &indices));
2239566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateEmbeddedRootSF(sf, rpEnd - rpStart, indices, &embedSF));
2249566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(selected, &indices));
2259566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&selected));
226b0c7db22SLisandro Dalcin   } else {
2279566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)sf));
228b0c7db22SLisandro Dalcin     embedSF = sf;
229b0c7db22SLisandro Dalcin   }
2309566063dSJacob Faibussowitsch   PetscCall(PetscSFGetLeafRange(embedSF, &lpStart, &lpEnd));
231b0c7db22SLisandro Dalcin   lpEnd++;
232b0c7db22SLisandro Dalcin 
2339566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(leafSection, lpStart, lpEnd));
234b0c7db22SLisandro Dalcin 
235b0c7db22SLisandro Dalcin   /* Constrained dof section */
236b0c7db22SLisandro Dalcin   hasc = sub[1];
237b0c7db22SLisandro Dalcin   for (f = 0; f < numFields; ++f) hasc = (PetscBool)(hasc || sub[2+f]);
238b0c7db22SLisandro Dalcin 
239b0c7db22SLisandro Dalcin   /* Could fuse these at the cost of copies and extra allocation */
2409566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->atlasDof[-rpStart], &leafSection->atlasDof[-lpStart],MPI_REPLACE));
2419566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->atlasDof[-rpStart], &leafSection->atlasDof[-lpStart],MPI_REPLACE));
242b0c7db22SLisandro Dalcin   if (sub[1]) {
243*7c0883d5SVaclav Hapla     PetscCall(PetscSectionCheckConstraints_Private(rootSection));
244*7c0883d5SVaclav Hapla     PetscCall(PetscSectionCheckConstraints_Private(leafSection));
2459566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->bc->atlasDof[-rpStart], &leafSection->bc->atlasDof[-lpStart],MPI_REPLACE));
2469566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->bc->atlasDof[-rpStart], &leafSection->bc->atlasDof[-lpStart],MPI_REPLACE));
247b0c7db22SLisandro Dalcin   }
248b0c7db22SLisandro Dalcin   for (f = 0; f < numFields; ++f) {
2499566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->field[f]->atlasDof[-rpStart], &leafSection->field[f]->atlasDof[-lpStart],MPI_REPLACE));
2509566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->field[f]->atlasDof[-rpStart], &leafSection->field[f]->atlasDof[-lpStart],MPI_REPLACE));
251b0c7db22SLisandro Dalcin     if (sub[2+f]) {
252*7c0883d5SVaclav Hapla       PetscCall(PetscSectionCheckConstraints_Private(rootSection->field[f]));
253*7c0883d5SVaclav Hapla       PetscCall(PetscSectionCheckConstraints_Private(leafSection->field[f]));
2549566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasDof[-rpStart], &leafSection->field[f]->bc->atlasDof[-lpStart],MPI_REPLACE));
2559566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasDof[-rpStart], &leafSection->field[f]->bc->atlasDof[-lpStart],MPI_REPLACE));
256b0c7db22SLisandro Dalcin     }
257b0c7db22SLisandro Dalcin   }
258b0c7db22SLisandro Dalcin   if (remoteOffsets) {
2599566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(lpEnd - lpStart, remoteOffsets));
2609566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->atlasOff[-rpStart], &(*remoteOffsets)[-lpStart],MPI_REPLACE));
2619566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->atlasOff[-rpStart], &(*remoteOffsets)[-lpStart],MPI_REPLACE));
262b0c7db22SLisandro Dalcin   }
2639566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(leafSection));
264b0c7db22SLisandro Dalcin   if (hasc) { /* need to communicate bcIndices */
265b0c7db22SLisandro Dalcin     PetscSF  bcSF;
266b0c7db22SLisandro Dalcin     PetscInt *rOffBc;
267b0c7db22SLisandro Dalcin 
2689566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(lpEnd - lpStart, &rOffBc));
269b0c7db22SLisandro Dalcin     if (sub[1]) {
2709566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->bc->atlasOff[-rpStart], &rOffBc[-lpStart],MPI_REPLACE));
2719566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->bc->atlasOff[-rpStart], &rOffBc[-lpStart],MPI_REPLACE));
2729566063dSJacob Faibussowitsch       PetscCall(PetscSFCreateSectionSF(embedSF, rootSection->bc, rOffBc, leafSection->bc, &bcSF));
2739566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(bcSF, MPIU_INT, rootSection->bcIndices, leafSection->bcIndices,MPI_REPLACE));
2749566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(bcSF, MPIU_INT, rootSection->bcIndices, leafSection->bcIndices,MPI_REPLACE));
2759566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&bcSF));
276b0c7db22SLisandro Dalcin     }
277b0c7db22SLisandro Dalcin     for (f = 0; f < numFields; ++f) {
278b0c7db22SLisandro Dalcin       if (sub[2+f]) {
2799566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasOff[-rpStart], &rOffBc[-lpStart],MPI_REPLACE));
2809566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasOff[-rpStart], &rOffBc[-lpStart],MPI_REPLACE));
2819566063dSJacob Faibussowitsch         PetscCall(PetscSFCreateSectionSF(embedSF, rootSection->field[f]->bc, rOffBc, leafSection->field[f]->bc, &bcSF));
2829566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(bcSF, MPIU_INT, rootSection->field[f]->bcIndices, leafSection->field[f]->bcIndices,MPI_REPLACE));
2839566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(bcSF, MPIU_INT, rootSection->field[f]->bcIndices, leafSection->field[f]->bcIndices,MPI_REPLACE));
2849566063dSJacob Faibussowitsch         PetscCall(PetscSFDestroy(&bcSF));
285b0c7db22SLisandro Dalcin       }
286b0c7db22SLisandro Dalcin     }
2879566063dSJacob Faibussowitsch     PetscCall(PetscFree(rOffBc));
288b0c7db22SLisandro Dalcin   }
2899566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&embedSF));
2909566063dSJacob Faibussowitsch   PetscCall(PetscFree(sub));
2919566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCSF_DistSect,sf,0,0,0));
292b0c7db22SLisandro Dalcin   PetscFunctionReturn(0);
293b0c7db22SLisandro Dalcin }
294b0c7db22SLisandro Dalcin 
295b0c7db22SLisandro Dalcin /*@C
296b0c7db22SLisandro Dalcin   PetscSFCreateRemoteOffsets - Create offsets for point data on remote processes
297b0c7db22SLisandro Dalcin 
298b0c7db22SLisandro Dalcin   Collective on sf
299b0c7db22SLisandro Dalcin 
300b0c7db22SLisandro Dalcin   Input Parameters:
301b0c7db22SLisandro Dalcin + sf          - The SF
302b0c7db22SLisandro Dalcin . rootSection - Data layout of remote points for outgoing data (this is layout for SF roots)
303b0c7db22SLisandro Dalcin - leafSection - Data layout of local points for incoming data  (this is layout for SF leaves)
304b0c7db22SLisandro Dalcin 
305b0c7db22SLisandro Dalcin   Output Parameter:
306b0c7db22SLisandro Dalcin . remoteOffsets - Offsets for point data on remote processes (these are offsets from the root section), or NULL
307b0c7db22SLisandro Dalcin 
308b0c7db22SLisandro Dalcin   Level: developer
309b0c7db22SLisandro Dalcin 
310b0c7db22SLisandro Dalcin .seealso: PetscSFCreate()
311b0c7db22SLisandro Dalcin @*/
312b0c7db22SLisandro Dalcin PetscErrorCode PetscSFCreateRemoteOffsets(PetscSF sf, PetscSection rootSection, PetscSection leafSection, PetscInt **remoteOffsets)
313b0c7db22SLisandro Dalcin {
314b0c7db22SLisandro Dalcin   PetscSF         embedSF;
315b0c7db22SLisandro Dalcin   const PetscInt *indices;
316b0c7db22SLisandro Dalcin   IS              selected;
317b0c7db22SLisandro Dalcin   PetscInt        numRoots, rpStart = 0, rpEnd = 0, lpStart = 0, lpEnd = 0;
318b0c7db22SLisandro Dalcin 
319b0c7db22SLisandro Dalcin   PetscFunctionBegin;
320b0c7db22SLisandro Dalcin   *remoteOffsets = NULL;
3219566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &numRoots, NULL, NULL, NULL));
322b0c7db22SLisandro Dalcin   if (numRoots < 0) PetscFunctionReturn(0);
3239566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCSF_RemoteOff,sf,0,0,0));
3249566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(rootSection, &rpStart, &rpEnd));
3259566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(leafSection, &lpStart, &lpEnd));
3269566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, rpEnd - rpStart, rpStart, 1, &selected));
3279566063dSJacob Faibussowitsch   PetscCall(ISGetIndices(selected, &indices));
3289566063dSJacob Faibussowitsch   PetscCall(PetscSFCreateEmbeddedRootSF(sf, rpEnd - rpStart, indices, &embedSF));
3299566063dSJacob Faibussowitsch   PetscCall(ISRestoreIndices(selected, &indices));
3309566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&selected));
3319566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(lpEnd - lpStart, remoteOffsets));
3329566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->atlasOff[-rpStart], &(*remoteOffsets)[-lpStart],MPI_REPLACE));
3339566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->atlasOff[-rpStart], &(*remoteOffsets)[-lpStart],MPI_REPLACE));
3349566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&embedSF));
3359566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCSF_RemoteOff,sf,0,0,0));
336b0c7db22SLisandro Dalcin   PetscFunctionReturn(0);
337b0c7db22SLisandro Dalcin }
338b0c7db22SLisandro Dalcin 
339b0c7db22SLisandro Dalcin /*@C
340b0c7db22SLisandro Dalcin   PetscSFCreateSectionSF - Create an expanded SF of dofs, assuming the input SF relates points
341b0c7db22SLisandro Dalcin 
342b0c7db22SLisandro Dalcin   Collective on sf
343b0c7db22SLisandro Dalcin 
344b0c7db22SLisandro Dalcin   Input Parameters:
345b0c7db22SLisandro Dalcin + sf - The SF
346b0c7db22SLisandro Dalcin . rootSection - Data layout of remote points for outgoing data (this is usually the serial section)
347b0c7db22SLisandro Dalcin . remoteOffsets - Offsets for point data on remote processes (these are offsets from the root section), or NULL
348b0c7db22SLisandro Dalcin - leafSection - Data layout of local points for incoming data  (this is the distributed section)
349b0c7db22SLisandro Dalcin 
350b0c7db22SLisandro Dalcin   Output Parameters:
351b0c7db22SLisandro Dalcin - sectionSF - The new SF
352b0c7db22SLisandro Dalcin 
353b0c7db22SLisandro Dalcin   Note: Either rootSection or remoteOffsets can be specified
354b0c7db22SLisandro Dalcin 
355b0c7db22SLisandro Dalcin   Level: advanced
356b0c7db22SLisandro Dalcin 
357b0c7db22SLisandro Dalcin .seealso: PetscSFCreate()
358b0c7db22SLisandro Dalcin @*/
359b0c7db22SLisandro Dalcin PetscErrorCode PetscSFCreateSectionSF(PetscSF sf, PetscSection rootSection, PetscInt remoteOffsets[], PetscSection leafSection, PetscSF *sectionSF)
360b0c7db22SLisandro Dalcin {
361b0c7db22SLisandro Dalcin   MPI_Comm          comm;
362b0c7db22SLisandro Dalcin   const PetscInt    *localPoints;
363b0c7db22SLisandro Dalcin   const PetscSFNode *remotePoints;
364b0c7db22SLisandro Dalcin   PetscInt          lpStart, lpEnd;
365b0c7db22SLisandro Dalcin   PetscInt          numRoots, numSectionRoots, numPoints, numIndices = 0;
366b0c7db22SLisandro Dalcin   PetscInt          *localIndices;
367b0c7db22SLisandro Dalcin   PetscSFNode       *remoteIndices;
368b0c7db22SLisandro Dalcin   PetscInt          i, ind;
369b0c7db22SLisandro Dalcin 
370b0c7db22SLisandro Dalcin   PetscFunctionBegin;
371b0c7db22SLisandro Dalcin   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
372b0c7db22SLisandro Dalcin   PetscValidPointer(rootSection,2);
373b0c7db22SLisandro Dalcin   /* Cannot check PetscValidIntPointer(remoteOffsets,3) because it can be NULL if sf does not reference any points in leafSection */
374b0c7db22SLisandro Dalcin   PetscValidPointer(leafSection,4);
375b0c7db22SLisandro Dalcin   PetscValidPointer(sectionSF,5);
3769566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)sf,&comm));
3779566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, sectionSF));
3789566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(leafSection, &lpStart, &lpEnd));
3799566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(rootSection, &numSectionRoots));
3809566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &numRoots, &numPoints, &localPoints, &remotePoints));
381b0c7db22SLisandro Dalcin   if (numRoots < 0) PetscFunctionReturn(0);
3829566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCSF_SectSF,sf,0,0,0));
383b0c7db22SLisandro Dalcin   for (i = 0; i < numPoints; ++i) {
384b0c7db22SLisandro Dalcin     PetscInt localPoint = localPoints ? localPoints[i] : i;
385b0c7db22SLisandro Dalcin     PetscInt dof;
386b0c7db22SLisandro Dalcin 
387b0c7db22SLisandro Dalcin     if ((localPoint >= lpStart) && (localPoint < lpEnd)) {
3889566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafSection, localPoint, &dof));
389b0c7db22SLisandro Dalcin       numIndices += dof;
390b0c7db22SLisandro Dalcin     }
391b0c7db22SLisandro Dalcin   }
3929566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numIndices, &localIndices));
3939566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numIndices, &remoteIndices));
394b0c7db22SLisandro Dalcin   /* Create new index graph */
395b0c7db22SLisandro Dalcin   for (i = 0, ind = 0; i < numPoints; ++i) {
396b0c7db22SLisandro Dalcin     PetscInt localPoint = localPoints ? localPoints[i] : i;
397b0c7db22SLisandro Dalcin     PetscInt rank       = remotePoints[i].rank;
398b0c7db22SLisandro Dalcin 
399b0c7db22SLisandro Dalcin     if ((localPoint >= lpStart) && (localPoint < lpEnd)) {
400b0c7db22SLisandro Dalcin       PetscInt remoteOffset = remoteOffsets[localPoint-lpStart];
401b0c7db22SLisandro Dalcin       PetscInt loff, dof, d;
402b0c7db22SLisandro Dalcin 
4039566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(leafSection, localPoint, &loff));
4049566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(leafSection, localPoint, &dof));
405b0c7db22SLisandro Dalcin       for (d = 0; d < dof; ++d, ++ind) {
406b0c7db22SLisandro Dalcin         localIndices[ind]        = loff+d;
407b0c7db22SLisandro Dalcin         remoteIndices[ind].rank  = rank;
408b0c7db22SLisandro Dalcin         remoteIndices[ind].index = remoteOffset+d;
409b0c7db22SLisandro Dalcin       }
410b0c7db22SLisandro Dalcin     }
411b0c7db22SLisandro Dalcin   }
4122c71b3e2SJacob Faibussowitsch   PetscCheckFalse(numIndices != ind,comm, PETSC_ERR_PLIB, "Inconsistency in indices, %" PetscInt_FMT " should be %" PetscInt_FMT, ind, numIndices);
4139566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(*sectionSF, numSectionRoots, numIndices, localIndices, PETSC_OWN_POINTER, remoteIndices, PETSC_OWN_POINTER));
4149566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUp(*sectionSF));
4159566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCSF_SectSF,sf,0,0,0));
416b0c7db22SLisandro Dalcin   PetscFunctionReturn(0);
417b0c7db22SLisandro Dalcin }
4188fa9e22eSVaclav Hapla 
4198fa9e22eSVaclav Hapla /*@C
4208fa9e22eSVaclav Hapla    PetscSFCreateFromLayouts - Creates a parallel star forest mapping two PetscLayout objects
4218fa9e22eSVaclav Hapla 
4228fa9e22eSVaclav Hapla    Collective
4238fa9e22eSVaclav Hapla 
4244165533cSJose E. Roman    Input Parameters:
4258fa9e22eSVaclav Hapla +  rmap - PetscLayout defining the global root space
4268fa9e22eSVaclav Hapla -  lmap - PetscLayout defining the global leaf space
4278fa9e22eSVaclav Hapla 
4284165533cSJose E. Roman    Output Parameter:
4298fa9e22eSVaclav Hapla .  sf - The parallel star forest
4308fa9e22eSVaclav Hapla 
4318fa9e22eSVaclav Hapla    Level: intermediate
4328fa9e22eSVaclav Hapla 
4338fa9e22eSVaclav Hapla .seealso: PetscSFCreate(), PetscLayoutCreate(), PetscSFSetGraphLayout()
4348fa9e22eSVaclav Hapla @*/
4358fa9e22eSVaclav Hapla PetscErrorCode PetscSFCreateFromLayouts(PetscLayout rmap, PetscLayout lmap, PetscSF* sf)
4368fa9e22eSVaclav Hapla {
4378fa9e22eSVaclav Hapla   PetscInt       i,nroots,nleaves = 0;
4388fa9e22eSVaclav Hapla   PetscInt       rN, lst, len;
4398fa9e22eSVaclav Hapla   PetscMPIInt    owner = -1;
4408fa9e22eSVaclav Hapla   PetscSFNode    *remote;
4418fa9e22eSVaclav Hapla   MPI_Comm       rcomm = rmap->comm;
4428fa9e22eSVaclav Hapla   MPI_Comm       lcomm = lmap->comm;
4438fa9e22eSVaclav Hapla   PetscMPIInt    flg;
4448fa9e22eSVaclav Hapla 
4458fa9e22eSVaclav Hapla   PetscFunctionBegin;
4468fa9e22eSVaclav Hapla   PetscValidPointer(sf,3);
44728b400f6SJacob Faibussowitsch   PetscCheck(rmap->setupcalled,rcomm,PETSC_ERR_ARG_WRONGSTATE,"Root layout not setup");
44828b400f6SJacob Faibussowitsch   PetscCheck(lmap->setupcalled,lcomm,PETSC_ERR_ARG_WRONGSTATE,"Leaf layout not setup");
4499566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_compare(rcomm,lcomm,&flg));
4502c71b3e2SJacob Faibussowitsch   PetscCheckFalse(flg != MPI_CONGRUENT && flg != MPI_IDENT,rcomm,PETSC_ERR_SUP,"cannot map two layouts with non-matching communicators");
4519566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(rcomm,sf));
4529566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetLocalSize(rmap,&nroots));
4539566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetSize(rmap,&rN));
4549566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(lmap,&lst,&len));
4559566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(len-lst,&remote));
4568fa9e22eSVaclav Hapla   for (i = lst; i < len && i < rN; i++) {
4578fa9e22eSVaclav Hapla     if (owner < -1 || i >= rmap->range[owner+1]) {
4589566063dSJacob Faibussowitsch       PetscCall(PetscLayoutFindOwner(rmap,i,&owner));
4598fa9e22eSVaclav Hapla     }
4608fa9e22eSVaclav Hapla     remote[nleaves].rank  = owner;
4618fa9e22eSVaclav Hapla     remote[nleaves].index = i - rmap->range[owner];
4628fa9e22eSVaclav Hapla     nleaves++;
4638fa9e22eSVaclav Hapla   }
4649566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(*sf,nroots,nleaves,NULL,PETSC_OWN_POINTER,remote,PETSC_COPY_VALUES));
4659566063dSJacob Faibussowitsch   PetscCall(PetscFree(remote));
4668fa9e22eSVaclav Hapla   PetscFunctionReturn(0);
4678fa9e22eSVaclav Hapla }
4688fa9e22eSVaclav Hapla 
4698fa9e22eSVaclav Hapla /* TODO: handle nooffprocentries like MatZeroRowsMapLocal_Private, since this code is the same */
4708fa9e22eSVaclav Hapla PetscErrorCode PetscLayoutMapLocal(PetscLayout map,PetscInt N,const PetscInt idxs[], PetscInt *on,PetscInt **oidxs,PetscInt **ogidxs)
4718fa9e22eSVaclav Hapla {
4728fa9e22eSVaclav Hapla   PetscInt      *owners = map->range;
4738fa9e22eSVaclav Hapla   PetscInt       n      = map->n;
4748fa9e22eSVaclav Hapla   PetscSF        sf;
4758fa9e22eSVaclav Hapla   PetscInt      *lidxs,*work = NULL;
4768fa9e22eSVaclav Hapla   PetscSFNode   *ridxs;
4778fa9e22eSVaclav Hapla   PetscMPIInt    rank, p = 0;
4788fa9e22eSVaclav Hapla   PetscInt       r, len = 0;
4798fa9e22eSVaclav Hapla 
4808fa9e22eSVaclav Hapla   PetscFunctionBegin;
4818fa9e22eSVaclav Hapla   if (on) *on = 0;              /* squelch -Wmaybe-uninitialized */
4828fa9e22eSVaclav Hapla   /* Create SF where leaves are input idxs and roots are owned idxs */
4839566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(map->comm,&rank));
4849566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n,&lidxs));
4858fa9e22eSVaclav Hapla   for (r = 0; r < n; ++r) lidxs[r] = -1;
4869566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(N,&ridxs));
4878fa9e22eSVaclav Hapla   for (r = 0; r < N; ++r) {
4888fa9e22eSVaclav Hapla     const PetscInt idx = idxs[r];
4892c71b3e2SJacob Faibussowitsch     PetscCheckFalse(idx < 0 || map->N <= idx,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Index %" PetscInt_FMT " out of range [0,%" PetscInt_FMT ")",idx,map->N);
4908fa9e22eSVaclav Hapla     if (idx < owners[p] || owners[p+1] <= idx) { /* short-circuit the search if the last p owns this idx too */
4919566063dSJacob Faibussowitsch       PetscCall(PetscLayoutFindOwner(map,idx,&p));
4928fa9e22eSVaclav Hapla     }
4938fa9e22eSVaclav Hapla     ridxs[r].rank = p;
4948fa9e22eSVaclav Hapla     ridxs[r].index = idxs[r] - owners[p];
4958fa9e22eSVaclav Hapla   }
4969566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(map->comm,&sf));
4979566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf,n,N,NULL,PETSC_OWN_POINTER,ridxs,PETSC_OWN_POINTER));
4989566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(sf,MPIU_INT,(PetscInt*)idxs,lidxs,MPI_LOR));
4999566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(sf,MPIU_INT,(PetscInt*)idxs,lidxs,MPI_LOR));
5008fa9e22eSVaclav Hapla   if (ogidxs) { /* communicate global idxs */
5018fa9e22eSVaclav Hapla     PetscInt cum = 0,start,*work2;
5028fa9e22eSVaclav Hapla 
5039566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n,&work));
5049566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(N,&work2));
5058fa9e22eSVaclav Hapla     for (r = 0; r < N; ++r) if (idxs[r] >=0) cum++;
5069566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&cum,&start,1,MPIU_INT,MPI_SUM,map->comm));
5078fa9e22eSVaclav Hapla     start -= cum;
5088fa9e22eSVaclav Hapla     cum = 0;
5098fa9e22eSVaclav Hapla     for (r = 0; r < N; ++r) if (idxs[r] >=0) work2[r] = start+cum++;
5109566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceBegin(sf,MPIU_INT,work2,work,MPI_REPLACE));
5119566063dSJacob Faibussowitsch     PetscCall(PetscSFReduceEnd(sf,MPIU_INT,work2,work,MPI_REPLACE));
5129566063dSJacob Faibussowitsch     PetscCall(PetscFree(work2));
5138fa9e22eSVaclav Hapla   }
5149566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&sf));
5158fa9e22eSVaclav Hapla   /* Compress and put in indices */
5168fa9e22eSVaclav Hapla   for (r = 0; r < n; ++r)
5178fa9e22eSVaclav Hapla     if (lidxs[r] >= 0) {
5188fa9e22eSVaclav Hapla       if (work) work[len] = work[r];
5198fa9e22eSVaclav Hapla       lidxs[len++] = r;
5208fa9e22eSVaclav Hapla     }
5218fa9e22eSVaclav Hapla   if (on) *on = len;
5228fa9e22eSVaclav Hapla   if (oidxs) *oidxs = lidxs;
5238fa9e22eSVaclav Hapla   if (ogidxs) *ogidxs = work;
5248fa9e22eSVaclav Hapla   PetscFunctionReturn(0);
5258fa9e22eSVaclav Hapla }
526deffd5ebSksagiyam 
527deffd5ebSksagiyam /*@
528deffd5ebSksagiyam   PetscSFCreateByMatchingIndices - Create SF by matching root and leaf indices
529deffd5ebSksagiyam 
530deffd5ebSksagiyam   Collective
531deffd5ebSksagiyam 
532deffd5ebSksagiyam   Input Parameters:
533deffd5ebSksagiyam + layout - PetscLayout defining the global index space and the rank that brokers each index
534deffd5ebSksagiyam . numRootIndices - size of rootIndices
535deffd5ebSksagiyam . rootIndices - PetscInt array of global indices of which this process requests ownership
536deffd5ebSksagiyam . rootLocalIndices - root local index permutation (NULL if no permutation)
537deffd5ebSksagiyam . rootLocalOffset - offset to be added to root local indices
538deffd5ebSksagiyam . numLeafIndices - size of leafIndices
539deffd5ebSksagiyam . leafIndices - PetscInt array of global indices with which this process requires data associated
540deffd5ebSksagiyam . leafLocalIndices - leaf local index permutation (NULL if no permutation)
541deffd5ebSksagiyam - leafLocalOffset - offset to be added to leaf local indices
542deffd5ebSksagiyam 
543d8d19677SJose E. Roman   Output Parameters:
544deffd5ebSksagiyam + sfA - star forest representing the communication pattern from the layout space to the leaf space (NULL if not needed)
545deffd5ebSksagiyam - sf - star forest representing the communication pattern from the root space to the leaf space
546deffd5ebSksagiyam 
547deffd5ebSksagiyam   Example 1:
548deffd5ebSksagiyam $
549deffd5ebSksagiyam $  rank             : 0            1            2
550deffd5ebSksagiyam $  rootIndices      : [1 0 2]      [3]          [3]
551deffd5ebSksagiyam $  rootLocalOffset  : 100          200          300
552deffd5ebSksagiyam $  layout           : [0 1]        [2]          [3]
553deffd5ebSksagiyam $  leafIndices      : [0]          [2]          [0 3]
554deffd5ebSksagiyam $  leafLocalOffset  : 400          500          600
555deffd5ebSksagiyam $
5567ef5781fSVaclav Hapla would build the following SF
557deffd5ebSksagiyam $
558deffd5ebSksagiyam $  [0] 400 <- (0,101)
559deffd5ebSksagiyam $  [1] 500 <- (0,102)
560deffd5ebSksagiyam $  [2] 600 <- (0,101)
561deffd5ebSksagiyam $  [2] 601 <- (2,300)
562deffd5ebSksagiyam $
563deffd5ebSksagiyam   Example 2:
564deffd5ebSksagiyam $
565deffd5ebSksagiyam $  rank             : 0               1               2
566deffd5ebSksagiyam $  rootIndices      : [1 0 2]         [3]             [3]
567deffd5ebSksagiyam $  rootLocalOffset  : 100             200             300
568deffd5ebSksagiyam $  layout           : [0 1]           [2]             [3]
569deffd5ebSksagiyam $  leafIndices      : rootIndices     rootIndices     rootIndices
570deffd5ebSksagiyam $  leafLocalOffset  : rootLocalOffset rootLocalOffset rootLocalOffset
571deffd5ebSksagiyam $
5727ef5781fSVaclav Hapla would build the following SF
573deffd5ebSksagiyam $
574deffd5ebSksagiyam $  [1] 200 <- (2,300)
575deffd5ebSksagiyam $
576deffd5ebSksagiyam   Example 3:
577deffd5ebSksagiyam $
578deffd5ebSksagiyam $  No process requests ownership of global index 1, but no process needs it.
579deffd5ebSksagiyam $
580deffd5ebSksagiyam $  rank             : 0            1            2
581deffd5ebSksagiyam $  numRootIndices   : 2            1            1
582deffd5ebSksagiyam $  rootIndices      : [0 2]        [3]          [3]
583deffd5ebSksagiyam $  rootLocalOffset  : 100          200          300
584deffd5ebSksagiyam $  layout           : [0 1]        [2]          [3]
585deffd5ebSksagiyam $  numLeafIndices   : 1            1            2
586deffd5ebSksagiyam $  leafIndices      : [0]          [2]          [0 3]
587deffd5ebSksagiyam $  leafLocalOffset  : 400          500          600
588deffd5ebSksagiyam $
5897ef5781fSVaclav Hapla would build the following SF
590deffd5ebSksagiyam $
591deffd5ebSksagiyam $  [0] 400 <- (0,100)
592deffd5ebSksagiyam $  [1] 500 <- (0,101)
593deffd5ebSksagiyam $  [2] 600 <- (0,100)
594deffd5ebSksagiyam $  [2] 601 <- (2,300)
595deffd5ebSksagiyam $
596deffd5ebSksagiyam 
597deffd5ebSksagiyam   Notes:
598deffd5ebSksagiyam   The layout parameter represents any partitioning of [0, N), where N is the total number of global indices, and its
599deffd5ebSksagiyam   local size can be set to PETSC_DECIDE.
600deffd5ebSksagiyam   If a global index x lies in the partition owned by process i, each process whose rootIndices contains x requests
601deffd5ebSksagiyam   ownership of x and sends its own rank and the local index of x to process i.
602deffd5ebSksagiyam   If multiple processes request ownership of x, the one with the highest rank is to own x.
603deffd5ebSksagiyam   Process i then broadcasts the ownership information, so that each process whose leafIndices contains x knows the
604deffd5ebSksagiyam   ownership information of x.
605deffd5ebSksagiyam   The output sf is constructed by associating each leaf point to a root point in this way.
606deffd5ebSksagiyam 
607deffd5ebSksagiyam   Suppose there is point data ordered according to the global indices and partitioned according to the given layout.
608deffd5ebSksagiyam   The optional output PetscSF object sfA can be used to push such data to leaf points.
609deffd5ebSksagiyam 
610deffd5ebSksagiyam   All indices in rootIndices and leafIndices must lie in the layout range. The union (over all processes) of rootIndices
611deffd5ebSksagiyam   must cover that of leafIndices, but need not cover the entire layout.
612deffd5ebSksagiyam 
613deffd5ebSksagiyam   If (leafIndices, leafLocalIndices, leafLocalOffset) == (rootIndices, rootLocalIndices, rootLocalOffset), the output
614deffd5ebSksagiyam   star forest is almost identity, so will only include non-trivial part of the map.
615deffd5ebSksagiyam 
616deffd5ebSksagiyam   Developer Notes:
617deffd5ebSksagiyam   Current approach of a process of the highest rank gaining the ownership may cause load imbalance; consider using
618deffd5ebSksagiyam   hash(rank, root_local_index) as the bid for the ownership determination.
619deffd5ebSksagiyam 
620deffd5ebSksagiyam   Level: advanced
621deffd5ebSksagiyam 
622deffd5ebSksagiyam .seealso: PetscSFCreate()
623deffd5ebSksagiyam @*/
624deffd5ebSksagiyam PetscErrorCode PetscSFCreateByMatchingIndices(PetscLayout layout, PetscInt numRootIndices, const PetscInt *rootIndices, const PetscInt *rootLocalIndices, PetscInt rootLocalOffset, PetscInt numLeafIndices, const PetscInt *leafIndices, const PetscInt *leafLocalIndices, PetscInt leafLocalOffset, PetscSF *sfA, PetscSF *sf)
625deffd5ebSksagiyam {
626deffd5ebSksagiyam   MPI_Comm        comm = layout->comm;
627deffd5ebSksagiyam   PetscMPIInt     size, rank;
628deffd5ebSksagiyam   PetscSF         sf1;
629deffd5ebSksagiyam   PetscSFNode    *owners, *buffer, *iremote;
630deffd5ebSksagiyam   PetscInt       *ilocal, nleaves, N, n, i;
631deffd5ebSksagiyam #if defined(PETSC_USE_DEBUG)
632deffd5ebSksagiyam   PetscInt        N1;
633deffd5ebSksagiyam #endif
634deffd5ebSksagiyam   PetscBool       flag;
635deffd5ebSksagiyam 
636deffd5ebSksagiyam   PetscFunctionBegin;
637deffd5ebSksagiyam   if (rootIndices)      PetscValidIntPointer(rootIndices,3);
638deffd5ebSksagiyam   if (rootLocalIndices) PetscValidIntPointer(rootLocalIndices,4);
639deffd5ebSksagiyam   if (leafIndices)      PetscValidIntPointer(leafIndices,7);
640deffd5ebSksagiyam   if (leafLocalIndices) PetscValidIntPointer(leafLocalIndices,8);
641deffd5ebSksagiyam   if (sfA)              PetscValidPointer(sfA,10);
642deffd5ebSksagiyam   PetscValidPointer(sf,11);
6432c71b3e2SJacob Faibussowitsch   PetscCheckFalse(numRootIndices < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "numRootIndices (%" PetscInt_FMT ") must be non-negative", numRootIndices);
6442c71b3e2SJacob Faibussowitsch   PetscCheckFalse(numLeafIndices < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "numLeafIndices (%" PetscInt_FMT ") must be non-negative", numLeafIndices);
6459566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
6469566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
6479566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(layout));
6489566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetSize(layout, &N));
6499566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetLocalSize(layout, &n));
650deffd5ebSksagiyam   flag = (PetscBool)(leafIndices == rootIndices);
6519566063dSJacob Faibussowitsch   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &flag, 1, MPIU_BOOL, MPI_LAND, comm));
6522c71b3e2SJacob Faibussowitsch   PetscCheckFalse(flag && numLeafIndices != numRootIndices,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "leafIndices == rootIndices, but numLeafIndices (%" PetscInt_FMT ") != numRootIndices(%" PetscInt_FMT ")", numLeafIndices, numRootIndices);
653deffd5ebSksagiyam #if defined(PETSC_USE_DEBUG)
654deffd5ebSksagiyam   N1 = PETSC_MIN_INT;
655deffd5ebSksagiyam   for (i = 0; i < numRootIndices; i++) if (rootIndices[i] > N1) N1 = rootIndices[i];
6569566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &N1, 1, MPIU_INT, MPI_MAX, comm));
6572c71b3e2SJacob Faibussowitsch   PetscCheckFalse(N1 >= N,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Max. root index (%" PetscInt_FMT ") out of layout range [0,%" PetscInt_FMT ")", N1, N);
658deffd5ebSksagiyam   if (!flag) {
659deffd5ebSksagiyam     N1 = PETSC_MIN_INT;
660deffd5ebSksagiyam     for (i = 0; i < numLeafIndices; i++) if (leafIndices[i] > N1) N1 = leafIndices[i];
6619566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &N1, 1, MPIU_INT, MPI_MAX, comm));
6622c71b3e2SJacob Faibussowitsch     PetscCheckFalse(N1 >= N,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Max. leaf index (%" PetscInt_FMT ") out of layout range [0,%" PetscInt_FMT ")", N1, N);
663deffd5ebSksagiyam   }
664deffd5ebSksagiyam #endif
665deffd5ebSksagiyam   /* Reduce: owners -> buffer */
6669566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &buffer));
6679566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, &sf1));
6689566063dSJacob Faibussowitsch   PetscCall(PetscSFSetFromOptions(sf1));
6699566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraphLayout(sf1, layout, numRootIndices, NULL, PETSC_OWN_POINTER, rootIndices));
6709566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numRootIndices, &owners));
671deffd5ebSksagiyam   for (i = 0; i < numRootIndices; ++i) {
672deffd5ebSksagiyam     owners[i].rank = rank;
673deffd5ebSksagiyam     owners[i].index = rootLocalOffset + (rootLocalIndices ? rootLocalIndices[i] : i);
674deffd5ebSksagiyam   }
675deffd5ebSksagiyam   for (i = 0; i < n; ++i) {
676deffd5ebSksagiyam     buffer[i].index = -1;
677deffd5ebSksagiyam     buffer[i].rank = -1;
678deffd5ebSksagiyam   }
6799566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceBegin(sf1, MPIU_2INT, owners, buffer, MPI_MAXLOC));
6809566063dSJacob Faibussowitsch   PetscCall(PetscSFReduceEnd(sf1, MPIU_2INT, owners, buffer, MPI_MAXLOC));
681deffd5ebSksagiyam   /* Bcast: buffer -> owners */
682deffd5ebSksagiyam   if (!flag) {
683deffd5ebSksagiyam     /* leafIndices is different from rootIndices */
6849566063dSJacob Faibussowitsch     PetscCall(PetscFree(owners));
6859566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraphLayout(sf1, layout, numLeafIndices, NULL, PETSC_OWN_POINTER, leafIndices));
6869566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeafIndices, &owners));
687deffd5ebSksagiyam   }
6889566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sf1, MPIU_2INT, buffer, owners, MPI_REPLACE));
6899566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sf1, MPIU_2INT, buffer, owners, MPI_REPLACE));
6902c71b3e2SJacob Faibussowitsch   for (i = 0; i < numLeafIndices; ++i) PetscCheckFalse(owners[i].rank < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Global point %" PetscInt_FMT " was unclaimed", leafIndices[i]);
6919566063dSJacob Faibussowitsch   PetscCall(PetscFree(buffer));
692deffd5ebSksagiyam   if (sfA) {*sfA = sf1;}
6939566063dSJacob Faibussowitsch   else     PetscCall(PetscSFDestroy(&sf1));
694deffd5ebSksagiyam   /* Create sf */
695deffd5ebSksagiyam   if (flag && rootLocalIndices == leafLocalIndices && leafLocalOffset == rootLocalOffset) {
696deffd5ebSksagiyam     /* leaf space == root space */
697deffd5ebSksagiyam     for (i = 0, nleaves = 0; i < numLeafIndices; ++i) if (owners[i].rank != rank) ++nleaves;
6989566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &ilocal));
6999566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &iremote));
700deffd5ebSksagiyam     for (i = 0, nleaves = 0; i < numLeafIndices; ++i) {
701deffd5ebSksagiyam       if (owners[i].rank != rank) {
702deffd5ebSksagiyam         ilocal[nleaves]        = leafLocalOffset + i;
703deffd5ebSksagiyam         iremote[nleaves].rank  = owners[i].rank;
704deffd5ebSksagiyam         iremote[nleaves].index = owners[i].index;
705deffd5ebSksagiyam         ++nleaves;
706deffd5ebSksagiyam       }
707deffd5ebSksagiyam     }
7089566063dSJacob Faibussowitsch     PetscCall(PetscFree(owners));
709deffd5ebSksagiyam   } else {
710deffd5ebSksagiyam     nleaves = numLeafIndices;
7119566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &ilocal));
712deffd5ebSksagiyam     for (i = 0; i < nleaves; ++i) {ilocal[i] = leafLocalOffset + (leafLocalIndices ? leafLocalIndices[i] : i);}
713deffd5ebSksagiyam     iremote = owners;
714deffd5ebSksagiyam   }
7159566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, sf));
7169566063dSJacob Faibussowitsch   PetscCall(PetscSFSetFromOptions(*sf));
7179566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(*sf, rootLocalOffset + numRootIndices, nleaves, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
718deffd5ebSksagiyam   PetscFunctionReturn(0);
719deffd5ebSksagiyam }
720