xref: /petsc/src/vec/is/section/interface/section.c (revision 884d422fa8a734f01f4cddac68ca9e4d00f53602)
1 /*
2    This file contains routines for basic section object implementation.
3 */
4 
5 #include <petsc/private/sectionimpl.h> /*I  "petscsection.h"   I*/
6 #include <petscsf.h>
7 
8 PetscClassId PETSC_SECTION_CLASSID;
9 
10 /*@
11   PetscSectionCreate - Allocates a `PetscSection` and sets the map contents to the default.
12 
13   Collective
14 
15   Input Parameters:
16 + comm - the MPI communicator
17 - s    - pointer to the section
18 
19   Level: beginner
20 
21   Notes:
22   Typical calling sequence
23 .vb
24        PetscSectionCreate(MPI_Comm,PetscSection *);!
25        PetscSectionSetNumFields(PetscSection, numFields);
26        PetscSectionSetChart(PetscSection,low,high);
27        PetscSectionSetDof(PetscSection,point,numdof);
28        PetscSectionSetUp(PetscSection);
29        PetscSectionGetOffset(PetscSection,point,PetscInt *);
30        PetscSectionDestroy(PetscSection);
31 .ve
32 
33   The `PetscSection` object and methods are intended to be used in the PETSc `Vec` and `Mat` implementations. The indices returned by the `PetscSection` are appropriate for the kind of `Vec` it is associated with. For example, if the vector being indexed is a local vector, we call the section a local section. If the section indexes a global vector, we call it a global section. For parallel vectors, like global vectors, we use negative indices to indicate dofs owned by other processes.
34 
35 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetChart()`, `PetscSectionDestroy()`, `PetscSectionCreateGlobalSection()`
36 @*/
37 PetscErrorCode PetscSectionCreate(MPI_Comm comm, PetscSection *s)
38 {
39   PetscFunctionBegin;
40   PetscAssertPointer(s, 2);
41   PetscCall(ISInitializePackage());
42 
43   PetscCall(PetscHeaderCreate(*s, PETSC_SECTION_CLASSID, "PetscSection", "Section", "IS", comm, PetscSectionDestroy, PetscSectionView));
44 
45   (*s)->pStart              = -1;
46   (*s)->pEnd                = -1;
47   (*s)->perm                = NULL;
48   (*s)->pointMajor          = PETSC_TRUE;
49   (*s)->includesConstraints = PETSC_TRUE;
50   (*s)->atlasDof            = NULL;
51   (*s)->atlasOff            = NULL;
52   (*s)->bc                  = NULL;
53   (*s)->bcIndices           = NULL;
54   (*s)->setup               = PETSC_FALSE;
55   (*s)->numFields           = 0;
56   (*s)->fieldNames          = NULL;
57   (*s)->field               = NULL;
58   (*s)->useFieldOff         = PETSC_FALSE;
59   (*s)->compNames           = NULL;
60   (*s)->clObj               = NULL;
61   (*s)->clHash              = NULL;
62   (*s)->clSection           = NULL;
63   (*s)->clPoints            = NULL;
64   PetscCall(PetscSectionInvalidateMaxDof_Internal(*s));
65   PetscFunctionReturn(PETSC_SUCCESS);
66 }
67 
68 /*@
69   PetscSectionCopy - Creates a shallow (if possible) copy of the `PetscSection`
70 
71   Collective
72 
73   Input Parameter:
74 . section - the `PetscSection`
75 
76   Output Parameter:
77 . newSection - the copy
78 
79   Level: intermediate
80 
81   Developer Notes:
82   What exactly does shallow mean in this context?
83 
84 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()`
85 @*/
86 PetscErrorCode PetscSectionCopy(PetscSection section, PetscSection newSection)
87 {
88   PetscFunctionBegin;
89   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
90   PetscValidHeaderSpecific(newSection, PETSC_SECTION_CLASSID, 2);
91   PetscCall(PetscSectionCopy_Internal(section, newSection, NULL));
92   PetscFunctionReturn(PETSC_SUCCESS);
93 }
94 
95 PetscErrorCode PetscSectionCopy_Internal(PetscSection section, PetscSection newSection, PetscBT constrained_dofs)
96 {
97   PetscSectionSym sym;
98   IS              perm;
99   PetscInt        numFields, f, c, pStart, pEnd, p;
100 
101   PetscFunctionBegin;
102   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
103   PetscValidHeaderSpecific(newSection, PETSC_SECTION_CLASSID, 2);
104   PetscCall(PetscSectionReset(newSection));
105   PetscCall(PetscSectionGetNumFields(section, &numFields));
106   if (numFields) PetscCall(PetscSectionSetNumFields(newSection, numFields));
107   for (f = 0; f < numFields; ++f) {
108     const char *fieldName = NULL, *compName = NULL;
109     PetscInt    numComp = 0;
110 
111     PetscCall(PetscSectionGetFieldName(section, f, &fieldName));
112     PetscCall(PetscSectionSetFieldName(newSection, f, fieldName));
113     PetscCall(PetscSectionGetFieldComponents(section, f, &numComp));
114     PetscCall(PetscSectionSetFieldComponents(newSection, f, numComp));
115     for (c = 0; c < numComp; ++c) {
116       PetscCall(PetscSectionGetComponentName(section, f, c, &compName));
117       PetscCall(PetscSectionSetComponentName(newSection, f, c, compName));
118     }
119     PetscCall(PetscSectionGetFieldSym(section, f, &sym));
120     PetscCall(PetscSectionSetFieldSym(newSection, f, sym));
121   }
122   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
123   PetscCall(PetscSectionSetChart(newSection, pStart, pEnd));
124   PetscCall(PetscSectionGetPermutation(section, &perm));
125   PetscCall(PetscSectionSetPermutation(newSection, perm));
126   PetscCall(PetscSectionGetSym(section, &sym));
127   PetscCall(PetscSectionSetSym(newSection, sym));
128   for (p = pStart; p < pEnd; ++p) {
129     PetscInt  dof, cdof, fcdof = 0;
130     PetscBool force_constrained = (PetscBool)(constrained_dofs && PetscBTLookup(constrained_dofs, p - pStart));
131 
132     PetscCall(PetscSectionGetDof(section, p, &dof));
133     PetscCall(PetscSectionSetDof(newSection, p, dof));
134     if (force_constrained) cdof = dof;
135     else PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
136     if (cdof) PetscCall(PetscSectionSetConstraintDof(newSection, p, cdof));
137     for (f = 0; f < numFields; ++f) {
138       PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
139       PetscCall(PetscSectionSetFieldDof(newSection, p, f, dof));
140       if (cdof) {
141         if (force_constrained) fcdof = dof;
142         else PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof));
143         if (fcdof) PetscCall(PetscSectionSetFieldConstraintDof(newSection, p, f, fcdof));
144       }
145     }
146   }
147   PetscCall(PetscSectionSetUp(newSection));
148   for (p = pStart; p < pEnd; ++p) {
149     PetscInt        off, cdof, fcdof = 0;
150     const PetscInt *cInd;
151     PetscBool       force_constrained = (PetscBool)(constrained_dofs && PetscBTLookup(constrained_dofs, p - pStart));
152 
153     /* Must set offsets in case they do not agree with the prefix sums */
154     PetscCall(PetscSectionGetOffset(section, p, &off));
155     PetscCall(PetscSectionSetOffset(newSection, p, off));
156     PetscCall(PetscSectionGetConstraintDof(newSection, p, &cdof));
157     if (cdof) {
158       if (force_constrained) cInd = NULL;
159       else PetscCall(PetscSectionGetConstraintIndices(section, p, &cInd));
160       PetscCall(PetscSectionSetConstraintIndices(newSection, p, cInd));
161       for (f = 0; f < numFields; ++f) {
162         PetscCall(PetscSectionGetFieldOffset(section, p, f, &off));
163         PetscCall(PetscSectionSetFieldOffset(newSection, p, f, off));
164         PetscCall(PetscSectionGetFieldConstraintDof(newSection, p, f, &fcdof));
165         if (fcdof) {
166           if (force_constrained) cInd = NULL;
167           else PetscCall(PetscSectionGetFieldConstraintIndices(section, p, f, &cInd));
168           PetscCall(PetscSectionSetFieldConstraintIndices(newSection, p, f, cInd));
169         }
170       }
171     }
172   }
173   PetscFunctionReturn(PETSC_SUCCESS);
174 }
175 
176 /*@
177   PetscSectionClone - Creates a shallow (if possible) copy of the `PetscSection`
178 
179   Collective
180 
181   Input Parameter:
182 . section - the `PetscSection`
183 
184   Output Parameter:
185 . newSection - the copy
186 
187   Level: beginner
188 
189   Developer Notes:
190   With standard PETSc terminology this should be called `PetscSectionDuplicate()`
191 
192 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()`, `PetscSectionCopy()`
193 @*/
194 PetscErrorCode PetscSectionClone(PetscSection section, PetscSection *newSection)
195 {
196   PetscFunctionBegin;
197   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
198   PetscAssertPointer(newSection, 2);
199   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section), newSection));
200   PetscCall(PetscSectionCopy(section, *newSection));
201   PetscFunctionReturn(PETSC_SUCCESS);
202 }
203 
204 /*@
205   PetscSectionSetFromOptions - sets parameters in a `PetscSection` from the options database
206 
207   Collective
208 
209   Input Parameter:
210 . s - the `PetscSection`
211 
212   Options Database Key:
213 . -petscsection_point_major - `PETSC_TRUE` for point-major order
214 
215   Level: intermediate
216 
217 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()`
218 @*/
219 PetscErrorCode PetscSectionSetFromOptions(PetscSection s)
220 {
221   PetscFunctionBegin;
222   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
223   PetscObjectOptionsBegin((PetscObject)s);
224   PetscCall(PetscOptionsBool("-petscsection_point_major", "The for ordering, either point major or field major", "PetscSectionSetPointMajor", s->pointMajor, &s->pointMajor, NULL));
225   /* process any options handlers added with PetscObjectAddOptionsHandler() */
226   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)s, PetscOptionsObject));
227   PetscOptionsEnd();
228   PetscCall(PetscObjectViewFromOptions((PetscObject)s, NULL, "-petscsection_view"));
229   PetscFunctionReturn(PETSC_SUCCESS);
230 }
231 
232 /*@
233   PetscSectionCompare - Compares two sections
234 
235   Collective
236 
237   Input Parameters:
238 + s1 - the first `PetscSection`
239 - s2 - the second `PetscSection`
240 
241   Output Parameter:
242 . congruent - `PETSC_TRUE` if the two sections are congruent, `PETSC_FALSE` otherwise
243 
244   Level: intermediate
245 
246   Note:
247   Field names are disregarded.
248 
249 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionCopy()`, `PetscSectionClone()`
250 @*/
251 PetscErrorCode PetscSectionCompare(PetscSection s1, PetscSection s2, PetscBool *congruent)
252 {
253   PetscInt        pStart, pEnd, nfields, ncdof, nfcdof, p, f, n1, n2;
254   const PetscInt *idx1, *idx2;
255   IS              perm1, perm2;
256   PetscBool       flg;
257   PetscMPIInt     mflg;
258 
259   PetscFunctionBegin;
260   PetscValidHeaderSpecific(s1, PETSC_SECTION_CLASSID, 1);
261   PetscValidHeaderSpecific(s2, PETSC_SECTION_CLASSID, 2);
262   PetscAssertPointer(congruent, 3);
263   flg = PETSC_FALSE;
264 
265   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)s1), PetscObjectComm((PetscObject)s2), &mflg));
266   if (mflg != MPI_CONGRUENT && mflg != MPI_IDENT) {
267     *congruent = PETSC_FALSE;
268     PetscFunctionReturn(PETSC_SUCCESS);
269   }
270 
271   PetscCall(PetscSectionGetChart(s1, &pStart, &pEnd));
272   PetscCall(PetscSectionGetChart(s2, &n1, &n2));
273   if (pStart != n1 || pEnd != n2) goto not_congruent;
274 
275   PetscCall(PetscSectionGetPermutation(s1, &perm1));
276   PetscCall(PetscSectionGetPermutation(s2, &perm2));
277   if (perm1 && perm2) {
278     PetscCall(ISEqual(perm1, perm2, congruent));
279     if (!(*congruent)) goto not_congruent;
280   } else if (perm1 != perm2) goto not_congruent;
281 
282   for (p = pStart; p < pEnd; ++p) {
283     PetscCall(PetscSectionGetOffset(s1, p, &n1));
284     PetscCall(PetscSectionGetOffset(s2, p, &n2));
285     if (n1 != n2) goto not_congruent;
286 
287     PetscCall(PetscSectionGetDof(s1, p, &n1));
288     PetscCall(PetscSectionGetDof(s2, p, &n2));
289     if (n1 != n2) goto not_congruent;
290 
291     PetscCall(PetscSectionGetConstraintDof(s1, p, &ncdof));
292     PetscCall(PetscSectionGetConstraintDof(s2, p, &n2));
293     if (ncdof != n2) goto not_congruent;
294 
295     PetscCall(PetscSectionGetConstraintIndices(s1, p, &idx1));
296     PetscCall(PetscSectionGetConstraintIndices(s2, p, &idx2));
297     PetscCall(PetscArraycmp(idx1, idx2, ncdof, congruent));
298     if (!(*congruent)) goto not_congruent;
299   }
300 
301   PetscCall(PetscSectionGetNumFields(s1, &nfields));
302   PetscCall(PetscSectionGetNumFields(s2, &n2));
303   if (nfields != n2) goto not_congruent;
304 
305   for (f = 0; f < nfields; ++f) {
306     PetscCall(PetscSectionGetFieldComponents(s1, f, &n1));
307     PetscCall(PetscSectionGetFieldComponents(s2, f, &n2));
308     if (n1 != n2) goto not_congruent;
309 
310     for (p = pStart; p < pEnd; ++p) {
311       PetscCall(PetscSectionGetFieldOffset(s1, p, f, &n1));
312       PetscCall(PetscSectionGetFieldOffset(s2, p, f, &n2));
313       if (n1 != n2) goto not_congruent;
314 
315       PetscCall(PetscSectionGetFieldDof(s1, p, f, &n1));
316       PetscCall(PetscSectionGetFieldDof(s2, p, f, &n2));
317       if (n1 != n2) goto not_congruent;
318 
319       PetscCall(PetscSectionGetFieldConstraintDof(s1, p, f, &nfcdof));
320       PetscCall(PetscSectionGetFieldConstraintDof(s2, p, f, &n2));
321       if (nfcdof != n2) goto not_congruent;
322 
323       PetscCall(PetscSectionGetFieldConstraintIndices(s1, p, f, &idx1));
324       PetscCall(PetscSectionGetFieldConstraintIndices(s2, p, f, &idx2));
325       PetscCall(PetscArraycmp(idx1, idx2, nfcdof, congruent));
326       if (!(*congruent)) goto not_congruent;
327     }
328   }
329 
330   flg = PETSC_TRUE;
331 not_congruent:
332   PetscCall(MPIU_Allreduce(&flg, congruent, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)s1)));
333   PetscFunctionReturn(PETSC_SUCCESS);
334 }
335 
336 /*@
337   PetscSectionGetNumFields - Returns the number of fields in a `PetscSection`, or 0 if no fields were defined.
338 
339   Not Collective
340 
341   Input Parameter:
342 . s - the `PetscSection`
343 
344   Output Parameter:
345 . numFields - the number of fields defined, or 0 if none were defined
346 
347   Level: intermediate
348 
349 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetNumFields()`
350 @*/
351 PetscErrorCode PetscSectionGetNumFields(PetscSection s, PetscInt *numFields)
352 {
353   PetscFunctionBegin;
354   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
355   PetscAssertPointer(numFields, 2);
356   *numFields = s->numFields;
357   PetscFunctionReturn(PETSC_SUCCESS);
358 }
359 
360 /*@
361   PetscSectionSetNumFields - Sets the number of fields in a `PetscSection`
362 
363   Not Collective
364 
365   Input Parameters:
366 + s         - the `PetscSection`
367 - numFields - the number of fields
368 
369   Level: intermediate
370 
371   Notes:
372   Calling this destroys all the information in the `PetscSection` including the chart.
373 
374   You must call `PetscSectionSetChart()` after calling this.
375 
376 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetNumFields()`, `PetscSectionSetChart()`, `PetscSectionReset()`
377 @*/
378 PetscErrorCode PetscSectionSetNumFields(PetscSection s, PetscInt numFields)
379 {
380   PetscInt f;
381 
382   PetscFunctionBegin;
383   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
384   PetscCheck(numFields > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "The number of fields %" PetscInt_FMT " must be positive", numFields);
385   PetscCall(PetscSectionReset(s));
386 
387   s->numFields = numFields;
388   PetscCall(PetscMalloc1(s->numFields, &s->numFieldComponents));
389   PetscCall(PetscMalloc1(s->numFields, &s->fieldNames));
390   PetscCall(PetscMalloc1(s->numFields, &s->compNames));
391   PetscCall(PetscMalloc1(s->numFields, &s->field));
392   for (f = 0; f < s->numFields; ++f) {
393     char name[64];
394 
395     s->numFieldComponents[f] = 1;
396 
397     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), &s->field[f]));
398     PetscCall(PetscSNPrintf(name, 64, "Field_%" PetscInt_FMT, f));
399     PetscCall(PetscStrallocpy(name, (char **)&s->fieldNames[f]));
400     PetscCall(PetscSNPrintf(name, 64, "Component_0"));
401     PetscCall(PetscMalloc1(s->numFieldComponents[f], &s->compNames[f]));
402     PetscCall(PetscStrallocpy(name, (char **)&s->compNames[f][0]));
403   }
404   PetscFunctionReturn(PETSC_SUCCESS);
405 }
406 
407 /*@C
408   PetscSectionGetFieldName - Returns the name of a field in the `PetscSection`
409 
410   Not Collective
411 
412   Input Parameters:
413 + s     - the `PetscSection`
414 - field - the field number
415 
416   Output Parameter:
417 . fieldName - the field name
418 
419   Level: intermediate
420 
421   Note:
422   Will error if the field number is out of range
423 
424 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetFieldName()`, `PetscSectionSetNumFields()`, `PetscSectionGetNumFields()`
425 @*/
426 PetscErrorCode PetscSectionGetFieldName(PetscSection s, PetscInt field, const char *fieldName[])
427 {
428   PetscFunctionBegin;
429   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
430   PetscAssertPointer(fieldName, 3);
431   PetscSectionCheckValidField(field, s->numFields);
432   *fieldName = s->fieldNames[field];
433   PetscFunctionReturn(PETSC_SUCCESS);
434 }
435 
436 /*@C
437   PetscSectionSetFieldName - Sets the name of a field in the `PetscSection`
438 
439   Not Collective
440 
441   Input Parameters:
442 + s         - the `PetscSection`
443 . field     - the field number
444 - fieldName - the field name
445 
446   Level: intermediate
447 
448   Note:
449   Will error if the field number is out of range
450 
451 .seealso: [PetscSection](sec_petscsection), `PetscSectionGetFieldName()`, `PetscSectionSetNumFields()`, `PetscSectionGetNumFields()`
452 @*/
453 PetscErrorCode PetscSectionSetFieldName(PetscSection s, PetscInt field, const char fieldName[])
454 {
455   PetscFunctionBegin;
456   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
457   if (fieldName) PetscAssertPointer(fieldName, 3);
458   PetscSectionCheckValidField(field, s->numFields);
459   PetscCall(PetscFree(s->fieldNames[field]));
460   PetscCall(PetscStrallocpy(fieldName, (char **)&s->fieldNames[field]));
461   PetscFunctionReturn(PETSC_SUCCESS);
462 }
463 
464 /*@C
465   PetscSectionGetComponentName - Gets the name of a field component in the `PetscSection`
466 
467   Not Collective
468 
469   Input Parameters:
470 + s     - the `PetscSection`
471 . field - the field number
472 - comp  - the component number
473 
474   Output Parameter:
475 . compName - the component name
476 
477   Level: intermediate
478 
479   Note:
480   Will error if the field or component number do not exist
481 
482   Developer Notes:
483   The function name should have Field in it since they are field components.
484 
485 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetFieldName()`, `PetscSectionSetNumFields()`, `PetscSectionGetNumFields()`,
486           `PetscSectionSetComponentName()`, `PetscSectionSetFieldName()`, `PetscSectionGetFieldComponents()`, `PetscSectionSetFieldComponents()`
487 @*/
488 PetscErrorCode PetscSectionGetComponentName(PetscSection s, PetscInt field, PetscInt comp, const char *compName[])
489 {
490   PetscFunctionBegin;
491   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
492   PetscAssertPointer(compName, 4);
493   PetscSectionCheckValidField(field, s->numFields);
494   PetscSectionCheckValidFieldComponent(comp, s->numFieldComponents[field]);
495   *compName = s->compNames[field][comp];
496   PetscFunctionReturn(PETSC_SUCCESS);
497 }
498 
499 /*@C
500   PetscSectionSetComponentName - Sets the name of a field component in the `PetscSection`
501 
502   Not Collective
503 
504   Input Parameters:
505 + s        - the `PetscSection`
506 . field    - the field number
507 . comp     - the component number
508 - compName - the component name
509 
510   Level: advanced
511 
512   Note:
513   Will error if the field or component number do not exist
514 
515   Developer Notes:
516   The function name should have Field in it since they are field components.
517 
518 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetComponentName()`, `PetscSectionSetNumFields()`, `PetscSectionGetNumFields()`,
519           `PetscSectionSetFieldName()`, `PetscSectionGetFieldComponents()`, `PetscSectionSetFieldComponents()`
520 @*/
521 PetscErrorCode PetscSectionSetComponentName(PetscSection s, PetscInt field, PetscInt comp, const char compName[])
522 {
523   PetscFunctionBegin;
524   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
525   if (compName) PetscAssertPointer(compName, 4);
526   PetscSectionCheckValidField(field, s->numFields);
527   PetscSectionCheckValidFieldComponent(comp, s->numFieldComponents[field]);
528   PetscCall(PetscFree(s->compNames[field][comp]));
529   PetscCall(PetscStrallocpy(compName, (char **)&s->compNames[field][comp]));
530   PetscFunctionReturn(PETSC_SUCCESS);
531 }
532 
533 /*@
534   PetscSectionGetFieldComponents - Returns the number of field components for the given field.
535 
536   Not Collective
537 
538   Input Parameters:
539 + s     - the `PetscSection`
540 - field - the field number
541 
542   Output Parameter:
543 . numComp - the number of field components
544 
545   Level: advanced
546 
547   Developer Notes:
548   This function is misnamed. There is a Num in `PetscSectionGetNumFields()` but not in this name
549 
550 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetFieldComponents()`, `PetscSectionGetNumFields()`,
551           `PetscSectionSetComponentName()`, `PetscSectionGetComponentName()`
552 @*/
553 PetscErrorCode PetscSectionGetFieldComponents(PetscSection s, PetscInt field, PetscInt *numComp)
554 {
555   PetscFunctionBegin;
556   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
557   PetscAssertPointer(numComp, 3);
558   PetscSectionCheckValidField(field, s->numFields);
559   *numComp = s->numFieldComponents[field];
560   PetscFunctionReturn(PETSC_SUCCESS);
561 }
562 
563 /*@
564   PetscSectionSetFieldComponents - Sets the number of field components for the given field.
565 
566   Not Collective
567 
568   Input Parameters:
569 + s       - the `PetscSection`
570 . field   - the field number
571 - numComp - the number of field components
572 
573   Level: advanced
574 
575   Note:
576   This number can be different than the values set with `PetscSectionSetFieldDof()`. It can be used to indicate the number of
577   components in the field of the underlying physical model which may be different than the number of degrees of freedom needed
578   at a point in a discretization. For example, if in three dimensions the field is velocity, it will have 3 components, u, v, and w but
579   an face based model for velocity (where the velocity normal to the face is stored) there is only 1 dof for each face point.
580 
581   The value set with this function are not needed or used in `PetscSectionSetUp()`.
582 
583   Developer Notes:
584   This function is misnamed. There is a Num in `PetscSectionSetNumFields()` but not in this name
585 
586 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetFieldComponents()`, `PetscSectionSetComponentName()`,
587           `PetscSectionGetComponentName()`, `PetscSectionGetNumFields()`
588 @*/
589 PetscErrorCode PetscSectionSetFieldComponents(PetscSection s, PetscInt field, PetscInt numComp)
590 {
591   PetscInt c;
592 
593   PetscFunctionBegin;
594   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
595   PetscSectionCheckValidField(field, s->numFields);
596   if (s->compNames) {
597     for (c = 0; c < s->numFieldComponents[field]; ++c) PetscCall(PetscFree(s->compNames[field][c]));
598     PetscCall(PetscFree(s->compNames[field]));
599   }
600 
601   s->numFieldComponents[field] = numComp;
602   if (numComp) {
603     PetscCall(PetscMalloc1(numComp, (char ***)&s->compNames[field]));
604     for (c = 0; c < numComp; ++c) {
605       char name[64];
606 
607       PetscCall(PetscSNPrintf(name, 64, "%" PetscInt_FMT, c));
608       PetscCall(PetscStrallocpy(name, (char **)&s->compNames[field][c]));
609     }
610   }
611   PetscFunctionReturn(PETSC_SUCCESS);
612 }
613 
614 /*@
615   PetscSectionGetChart - Returns the range [`pStart`, `pEnd`) in which points (indices) lie for this `PetscSection` on this MPI process
616 
617   Not Collective
618 
619   Input Parameter:
620 . s - the `PetscSection`
621 
622   Output Parameters:
623 + pStart - the first point
624 - pEnd   - one past the last point
625 
626   Level: intermediate
627 
628 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetChart()`, `PetscSectionCreate()`
629 @*/
630 PetscErrorCode PetscSectionGetChart(PetscSection s, PetscInt *pStart, PetscInt *pEnd)
631 {
632   PetscFunctionBegin;
633   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
634   if (pStart) *pStart = s->pStart;
635   if (pEnd) *pEnd = s->pEnd;
636   PetscFunctionReturn(PETSC_SUCCESS);
637 }
638 
639 /*@
640   PetscSectionSetChart - Sets the range [`pStart`, `pEnd`) in which points (indices) lie for this `PetscSection` on this MPI process
641 
642   Not Collective
643 
644   Input Parameters:
645 + s      - the `PetscSection`
646 . pStart - the first point
647 - pEnd   - one past the last point, `pStart` $ \le $ `pEnd`
648 
649   Level: intermediate
650 
651   Notes:
652   The charts on different MPI processes may (and often do) overlap
653 
654   If you intend to use `PetscSectionSetNumFields()` it must be called before this call.
655 
656   The chart for all fields created with `PetscSectionSetNumFields()` is the same as this chart.
657 
658 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetChart()`, `PetscSectionCreate()`, `PetscSectionSetNumFields()`
659 @*/
660 PetscErrorCode PetscSectionSetChart(PetscSection s, PetscInt pStart, PetscInt pEnd)
661 {
662   PetscInt f;
663 
664   PetscFunctionBegin;
665   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
666   PetscCheck(pEnd >= pStart, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Chart pEnd %" PetscInt_FMT " cannot be smaller than chart pStart %" PetscInt_FMT, pEnd, pStart);
667   if (pStart == s->pStart && pEnd == s->pEnd) PetscFunctionReturn(PETSC_SUCCESS);
668   /* Cannot Reset() because it destroys field information */
669   s->setup = PETSC_FALSE;
670   PetscCall(PetscSectionDestroy(&s->bc));
671   PetscCall(PetscFree(s->bcIndices));
672   PetscCall(PetscFree2(s->atlasDof, s->atlasOff));
673 
674   s->pStart = pStart;
675   s->pEnd   = pEnd;
676   PetscCall(PetscMalloc2((pEnd - pStart), &s->atlasDof, (pEnd - pStart), &s->atlasOff));
677   PetscCall(PetscArrayzero(s->atlasDof, pEnd - pStart));
678   for (f = 0; f < s->numFields; ++f) PetscCall(PetscSectionSetChart(s->field[f], pStart, pEnd));
679   PetscFunctionReturn(PETSC_SUCCESS);
680 }
681 
682 /*@
683   PetscSectionGetPermutation - Returns the permutation of [0, `pEnd` - `pStart`) or `NULL` that was set with `PetscSectionSetPermutation()`
684 
685   Not Collective
686 
687   Input Parameter:
688 . s - the `PetscSection`
689 
690   Output Parameter:
691 . perm - The permutation as an `IS`
692 
693   Level: intermediate
694 
695 .seealso: [](sec_scatter), `IS`, `PetscSection`, `PetscSectionSetPermutation()`, `PetscSectionCreate()`
696 @*/
697 PetscErrorCode PetscSectionGetPermutation(PetscSection s, IS *perm)
698 {
699   PetscFunctionBegin;
700   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
701   if (perm) {
702     PetscAssertPointer(perm, 2);
703     *perm = s->perm;
704   }
705   PetscFunctionReturn(PETSC_SUCCESS);
706 }
707 
708 /*@
709   PetscSectionSetPermutation - Sets a permutation of the chart for this section, [0, `pEnd` - `pStart`), which determines the order to store the `PetscSection` information
710 
711   Not Collective
712 
713   Input Parameters:
714 + s    - the `PetscSection`
715 - perm - the permutation of points
716 
717   Level: intermediate
718 
719   Notes:
720   The permutation must be provided before `PetscSectionSetUp()`.
721 
722   The data in the `PetscSection` are permuted but the access via `PetscSectionGetFieldOffset()` and `PetscSectionGetOffset()` is not changed
723 
724   Compart to `PetscSectionPermute()`
725 
726 .seealso: [](sec_scatter), `IS`, `PetscSection`, `PetscSectionSetUp()`, `PetscSectionGetPermutation()`, `PetscSectionPermute()`, `PetscSectionCreate()`
727 @*/
728 PetscErrorCode PetscSectionSetPermutation(PetscSection s, IS perm)
729 {
730   PetscFunctionBegin;
731   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
732   if (perm) PetscValidHeaderSpecific(perm, IS_CLASSID, 2);
733   PetscCheck(!s->setup, PetscObjectComm((PetscObject)s), PETSC_ERR_ARG_WRONGSTATE, "Cannot set a permutation after the section is setup");
734   if (s->perm != perm) {
735     PetscCall(ISDestroy(&s->perm));
736     if (perm) {
737       s->perm = perm;
738       PetscCall(PetscObjectReference((PetscObject)s->perm));
739     }
740   }
741   PetscFunctionReturn(PETSC_SUCCESS);
742 }
743 
744 /*@
745   PetscSectionGetPointMajor - Returns the flag for dof ordering, `PETSC_TRUE` if it is point major, `PETSC_FALSE` if it is field major
746 
747   Not Collective
748 
749   Input Parameter:
750 . s - the `PetscSection`
751 
752   Output Parameter:
753 . pm - the flag for point major ordering
754 
755   Level: intermediate
756 
757 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetPointMajor()`
758 @*/
759 PetscErrorCode PetscSectionGetPointMajor(PetscSection s, PetscBool *pm)
760 {
761   PetscFunctionBegin;
762   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
763   PetscAssertPointer(pm, 2);
764   *pm = s->pointMajor;
765   PetscFunctionReturn(PETSC_SUCCESS);
766 }
767 
768 /*@
769   PetscSectionSetPointMajor - Sets the flag for dof ordering, `PETSC_TRUE` for point major, otherwise it will be field major
770 
771   Not Collective
772 
773   Input Parameters:
774 + s  - the `PetscSection`
775 - pm - the flag for point major ordering
776 
777   Level: intermediate
778 
779   Note:
780   Field-major order is not recommended unless you are managing the entire problem yourself, since many higher-level functions in PETSc depend on point-major order.
781 
782   Point major order means the degrees of freedom are stored as follows
783 .vb
784     all the degrees of freedom for each point are stored contiguously, one point after another (respecting a permutation set with `PetscSectionSetPermutation()`)
785     for each point
786        the degrees of freedom for each field (starting with the unnamed default field) are listed in order by field
787 .ve
788 
789   Field major order means the degrees of freedom are stored as follows
790 .vb
791     all degrees of freedom for each field (including the unnamed default field) are stored contiguously, one field after another
792     for each field (started with unnamed default field)
793       the degrees of freedom for each point are listed in order by point (respecting a permutation set with `PetscSectionSetPermutation()`)
794 .ve
795 
796 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetPointMajor()`, `PetscSectionSetPermutation()`
797 @*/
798 PetscErrorCode PetscSectionSetPointMajor(PetscSection s, PetscBool pm)
799 {
800   PetscFunctionBegin;
801   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
802   PetscCheck(!s->setup, PetscObjectComm((PetscObject)s), PETSC_ERR_ARG_WRONGSTATE, "Cannot set the dof ordering after the section is setup");
803   s->pointMajor = pm;
804   PetscFunctionReturn(PETSC_SUCCESS);
805 }
806 
807 /*@
808   PetscSectionGetIncludesConstraints - Returns the flag indicating if constrained dofs were included when computing offsets in the `PetscSection`.
809   The value is set with `PetscSectionSetIncludesConstraints()`
810 
811   Not Collective
812 
813   Input Parameter:
814 . s - the `PetscSection`
815 
816   Output Parameter:
817 . includesConstraints - the flag indicating if constrained dofs were included when computing offsets
818 
819   Level: intermediate
820 
821 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetIncludesConstraints()`
822 @*/
823 PetscErrorCode PetscSectionGetIncludesConstraints(PetscSection s, PetscBool *includesConstraints)
824 {
825   PetscFunctionBegin;
826   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
827   PetscAssertPointer(includesConstraints, 2);
828   *includesConstraints = s->includesConstraints;
829   PetscFunctionReturn(PETSC_SUCCESS);
830 }
831 
832 /*@
833   PetscSectionSetIncludesConstraints - Sets the flag indicating if constrained dofs are to be included when computing offsets
834 
835   Not Collective
836 
837   Input Parameters:
838 + s                   - the `PetscSection`
839 - includesConstraints - the flag indicating if constrained dofs are to be included when computing offsets
840 
841   Level: intermediate
842 
843 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetIncludesConstraints()`
844 @*/
845 PetscErrorCode PetscSectionSetIncludesConstraints(PetscSection s, PetscBool includesConstraints)
846 {
847   PetscFunctionBegin;
848   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
849   PetscCheck(!s->setup, PetscObjectComm((PetscObject)s), PETSC_ERR_ARG_WRONGSTATE, "Cannot set includesConstraints after the section is set up");
850   s->includesConstraints = includesConstraints;
851   PetscFunctionReturn(PETSC_SUCCESS);
852 }
853 
854 /*@
855   PetscSectionGetDof - Return the total number of degrees of freedom associated with a given point.
856 
857   Not Collective
858 
859   Input Parameters:
860 + s     - the `PetscSection`
861 - point - the point
862 
863   Output Parameter:
864 . numDof - the number of dof
865 
866   Level: intermediate
867 
868   Notes:
869   In a global section, this size will be negative for points not owned by this process.
870 
871   This number is for the unnamed default field at the given point plus all degrees of freedom associated with all fields at that point
872 
873 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetDof()`, `PetscSectionCreate()`
874 @*/
875 PetscErrorCode PetscSectionGetDof(PetscSection s, PetscInt point, PetscInt *numDof)
876 {
877   PetscFunctionBeginHot;
878   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
879   PetscAssertPointer(numDof, 3);
880   PetscAssert(point >= s->pStart && point < s->pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section point %" PetscInt_FMT " should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, s->pStart, s->pEnd);
881   *numDof = s->atlasDof[point - s->pStart];
882   PetscFunctionReturn(PETSC_SUCCESS);
883 }
884 
885 /*@
886   PetscSectionSetDof - Sets the total number of degrees of freedom associated with a given point.
887 
888   Not Collective
889 
890   Input Parameters:
891 + s      - the `PetscSection`
892 . point  - the point
893 - numDof - the number of dof, these values may be negative -(dof+1) to indicate they are off process
894 
895   Level: intermediate
896 
897   Note:
898   This number is for the unnamed default field at the given point plus all degrees of freedom associated with all fields at that point
899 
900 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionAddDof()`, `PetscSectionCreate()`
901 @*/
902 PetscErrorCode PetscSectionSetDof(PetscSection s, PetscInt point, PetscInt numDof)
903 {
904   PetscFunctionBegin;
905   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
906   PetscAssert(point >= s->pStart && point < s->pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section point %" PetscInt_FMT " should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, s->pStart, s->pEnd);
907   s->atlasDof[point - s->pStart] = numDof;
908   PetscCall(PetscSectionInvalidateMaxDof_Internal(s));
909   PetscFunctionReturn(PETSC_SUCCESS);
910 }
911 
912 /*@
913   PetscSectionAddDof - Adds to the total number of degrees of freedom associated with a given point.
914 
915   Not Collective
916 
917   Input Parameters:
918 + s      - the `PetscSection`
919 . point  - the point
920 - numDof - the number of additional dof
921 
922   Level: intermediate
923 
924   Note:
925   This number is for the unnamed default field at the given point plus all degrees of freedom associated with all fields at that point
926 
927 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionSetDof()`, `PetscSectionCreate()`
928 @*/
929 PetscErrorCode PetscSectionAddDof(PetscSection s, PetscInt point, PetscInt numDof)
930 {
931   PetscFunctionBeginHot;
932   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
933   PetscAssert(point >= s->pStart && point < s->pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section point %" PetscInt_FMT " should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, s->pStart, s->pEnd);
934   PetscCheck(numDof >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "numDof %" PetscInt_FMT " should not be negative", numDof);
935   s->atlasDof[point - s->pStart] += numDof;
936   PetscCall(PetscSectionInvalidateMaxDof_Internal(s));
937   PetscFunctionReturn(PETSC_SUCCESS);
938 }
939 
940 /*@
941   PetscSectionGetFieldDof - Return the number of degrees of freedom associated with a field on a given point.
942 
943   Not Collective
944 
945   Input Parameters:
946 + s     - the `PetscSection`
947 . point - the point
948 - field - the field
949 
950   Output Parameter:
951 . numDof - the number of dof
952 
953   Level: intermediate
954 
955 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetFieldDof()`, `PetscSectionCreate()`
956 @*/
957 PetscErrorCode PetscSectionGetFieldDof(PetscSection s, PetscInt point, PetscInt field, PetscInt *numDof)
958 {
959   PetscFunctionBegin;
960   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
961   PetscAssertPointer(numDof, 4);
962   PetscSectionCheckValidField(field, s->numFields);
963   PetscCall(PetscSectionGetDof(s->field[field], point, numDof));
964   PetscFunctionReturn(PETSC_SUCCESS);
965 }
966 
967 /*@
968   PetscSectionSetFieldDof - Sets the number of degrees of freedom associated with a field on a given point.
969 
970   Not Collective
971 
972   Input Parameters:
973 + s      - the `PetscSection`
974 . point  - the point
975 . field  - the field
976 - numDof - the number of dof, these values may be negative -(dof+1) to indicate they are off process
977 
978   Level: intermediate
979 
980   Note:
981   When setting the number of dof for a field at a point one must also ensure the count of the total number of dof at the point (summed over
982   the fields and the unnamed default field) is correct by also calling `PetscSectionAddDof()` or `PetscSectionSetDof()`
983 
984   This is equivalent to
985 .vb
986      PetscSection fs;
987      PetscSectionGetField(s,field,&fs)
988      PetscSectionSetDof(fs,numDof)
989 .ve
990 
991 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetFieldDof()`, `PetscSectionCreate()`, `PetscSectionAddDof()`, `PetscSectionSetDof()`
992 @*/
993 PetscErrorCode PetscSectionSetFieldDof(PetscSection s, PetscInt point, PetscInt field, PetscInt numDof)
994 {
995   PetscFunctionBegin;
996   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
997   PetscSectionCheckValidField(field, s->numFields);
998   PetscCall(PetscSectionSetDof(s->field[field], point, numDof));
999   PetscFunctionReturn(PETSC_SUCCESS);
1000 }
1001 
1002 /*@
1003   PetscSectionAddFieldDof - Adds a number of degrees of freedom associated with a field on a given point.
1004 
1005   Not Collective
1006 
1007   Input Parameters:
1008 + s      - the `PetscSection`
1009 . point  - the point
1010 . field  - the field
1011 - numDof - the number of dof
1012 
1013   Level: intermediate
1014 
1015   Notes:
1016   When adding to the number of dof for a field at a point one must also ensure the count of the total number of dof at the point (summed over
1017   the fields and the unnamed default field) is correct by also calling `PetscSectionAddDof()` or `PetscSectionSetDof()`
1018 
1019   This is equivalent to
1020 .vb
1021      PetscSection fs;
1022      PetscSectionGetField(s,field,&fs)
1023      PetscSectionAddDof(fs,numDof)
1024 .ve
1025 
1026 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetFieldDof()`, `PetscSectionGetFieldDof()`, `PetscSectionCreate()`
1027 @*/
1028 PetscErrorCode PetscSectionAddFieldDof(PetscSection s, PetscInt point, PetscInt field, PetscInt numDof)
1029 {
1030   PetscFunctionBegin;
1031   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1032   PetscSectionCheckValidField(field, s->numFields);
1033   PetscCall(PetscSectionAddDof(s->field[field], point, numDof));
1034   PetscFunctionReturn(PETSC_SUCCESS);
1035 }
1036 
1037 /*@
1038   PetscSectionGetConstraintDof - Return the number of constrained degrees of freedom associated with a given point.
1039 
1040   Not Collective
1041 
1042   Input Parameters:
1043 + s     - the `PetscSection`
1044 - point - the point
1045 
1046   Output Parameter:
1047 . numDof - the number of dof which are fixed by constraints
1048 
1049   Level: intermediate
1050 
1051 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionSetConstraintDof()`, `PetscSectionCreate()`
1052 @*/
1053 PetscErrorCode PetscSectionGetConstraintDof(PetscSection s, PetscInt point, PetscInt *numDof)
1054 {
1055   PetscFunctionBegin;
1056   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1057   PetscAssertPointer(numDof, 3);
1058   if (s->bc) {
1059     PetscCall(PetscSectionGetDof(s->bc, point, numDof));
1060   } else *numDof = 0;
1061   PetscFunctionReturn(PETSC_SUCCESS);
1062 }
1063 
1064 /*@
1065   PetscSectionSetConstraintDof - Set the number of constrained degrees of freedom associated with a given point.
1066 
1067   Not Collective
1068 
1069   Input Parameters:
1070 + s      - the `PetscSection`
1071 . point  - the point
1072 - numDof - the number of dof which are fixed by constraints
1073 
1074   Level: intermediate
1075 
1076 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetDof()`, `PetscSectionGetConstraintDof()`, `PetscSectionCreate()`
1077 @*/
1078 PetscErrorCode PetscSectionSetConstraintDof(PetscSection s, PetscInt point, PetscInt numDof)
1079 {
1080   PetscFunctionBegin;
1081   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1082   if (numDof) {
1083     PetscCall(PetscSectionCheckConstraints_Private(s));
1084     PetscCall(PetscSectionSetDof(s->bc, point, numDof));
1085   }
1086   PetscFunctionReturn(PETSC_SUCCESS);
1087 }
1088 
1089 /*@
1090   PetscSectionAddConstraintDof - Increment the number of constrained degrees of freedom associated with a given point.
1091 
1092   Not Collective
1093 
1094   Input Parameters:
1095 + s      - the `PetscSection`
1096 . point  - the point
1097 - numDof - the number of additional dof which are fixed by constraints
1098 
1099   Level: intermediate
1100 
1101 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionAddDof()`, `PetscSectionGetConstraintDof()`, `PetscSectionCreate()`
1102 @*/
1103 PetscErrorCode PetscSectionAddConstraintDof(PetscSection s, PetscInt point, PetscInt numDof)
1104 {
1105   PetscFunctionBegin;
1106   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1107   if (numDof) {
1108     PetscCall(PetscSectionCheckConstraints_Private(s));
1109     PetscCall(PetscSectionAddDof(s->bc, point, numDof));
1110   }
1111   PetscFunctionReturn(PETSC_SUCCESS);
1112 }
1113 
1114 /*@
1115   PetscSectionGetFieldConstraintDof - Return the number of constrained degrees of freedom associated with a given field on a point.
1116 
1117   Not Collective
1118 
1119   Input Parameters:
1120 + s     - the `PetscSection`
1121 . point - the point
1122 - field - the field
1123 
1124   Output Parameter:
1125 . numDof - the number of dof which are fixed by constraints
1126 
1127   Level: intermediate
1128 
1129 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionSetFieldConstraintDof()`, `PetscSectionCreate()`
1130 @*/
1131 PetscErrorCode PetscSectionGetFieldConstraintDof(PetscSection s, PetscInt point, PetscInt field, PetscInt *numDof)
1132 {
1133   PetscFunctionBegin;
1134   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1135   PetscAssertPointer(numDof, 4);
1136   PetscSectionCheckValidField(field, s->numFields);
1137   PetscCall(PetscSectionGetConstraintDof(s->field[field], point, numDof));
1138   PetscFunctionReturn(PETSC_SUCCESS);
1139 }
1140 
1141 /*@
1142   PetscSectionSetFieldConstraintDof - Set the number of constrained degrees of freedom associated with a given field on a point.
1143 
1144   Not Collective
1145 
1146   Input Parameters:
1147 + s      - the `PetscSection`
1148 . point  - the point
1149 . field  - the field
1150 - numDof - the number of dof which are fixed by constraints
1151 
1152   Level: intermediate
1153 
1154 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetDof()`, `PetscSectionGetFieldConstraintDof()`, `PetscSectionCreate()`
1155 @*/
1156 PetscErrorCode PetscSectionSetFieldConstraintDof(PetscSection s, PetscInt point, PetscInt field, PetscInt numDof)
1157 {
1158   PetscFunctionBegin;
1159   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1160   PetscSectionCheckValidField(field, s->numFields);
1161   PetscCall(PetscSectionSetConstraintDof(s->field[field], point, numDof));
1162   PetscFunctionReturn(PETSC_SUCCESS);
1163 }
1164 
1165 /*@
1166   PetscSectionAddFieldConstraintDof - Increment the number of constrained degrees of freedom associated with a given field on a point.
1167 
1168   Not Collective
1169 
1170   Input Parameters:
1171 + s      - the `PetscSection`
1172 . point  - the point
1173 . field  - the field
1174 - numDof - the number of additional dof which are fixed by constraints
1175 
1176   Level: intermediate
1177 
1178 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionAddDof()`, `PetscSectionGetFieldConstraintDof()`, `PetscSectionCreate()`
1179 @*/
1180 PetscErrorCode PetscSectionAddFieldConstraintDof(PetscSection s, PetscInt point, PetscInt field, PetscInt numDof)
1181 {
1182   PetscFunctionBegin;
1183   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1184   PetscSectionCheckValidField(field, s->numFields);
1185   PetscCall(PetscSectionAddConstraintDof(s->field[field], point, numDof));
1186   PetscFunctionReturn(PETSC_SUCCESS);
1187 }
1188 
1189 /*@
1190   PetscSectionSetUpBC - Setup the subsections describing boundary conditions.
1191 
1192   Not Collective
1193 
1194   Input Parameter:
1195 . s - the `PetscSection`
1196 
1197   Level: advanced
1198 
1199 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetUp()`, `PetscSectionCreate()`
1200 @*/
1201 PetscErrorCode PetscSectionSetUpBC(PetscSection s)
1202 {
1203   PetscFunctionBegin;
1204   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1205   if (s->bc) {
1206     const PetscInt last = (s->bc->pEnd - s->bc->pStart) - 1;
1207 
1208     PetscCall(PetscSectionSetUp(s->bc));
1209     PetscCall(PetscMalloc1((last >= 0 ? s->bc->atlasOff[last] + s->bc->atlasDof[last] : 0), &s->bcIndices));
1210   }
1211   PetscFunctionReturn(PETSC_SUCCESS);
1212 }
1213 
1214 /*@
1215   PetscSectionSetUp - Calculate offsets based upon the number of degrees of freedom for each point in preparation for use of the `PetscSection`
1216 
1217   Not Collective
1218 
1219   Input Parameter:
1220 . s - the `PetscSection`
1221 
1222   Level: intermediate
1223 
1224   Notes:
1225   If used, `PetscSectionSetPermutation()` must be called before this routine.
1226 
1227   `PetscSectionSetPointMajor()`, cannot be called after this routine.
1228 
1229 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionSetPermutation()`
1230 @*/
1231 PetscErrorCode PetscSectionSetUp(PetscSection s)
1232 {
1233   const PetscInt *pind   = NULL;
1234   PetscInt        offset = 0, foff, p, f;
1235 
1236   PetscFunctionBegin;
1237   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1238   if (s->setup) PetscFunctionReturn(PETSC_SUCCESS);
1239   s->setup = PETSC_TRUE;
1240   /* Set offsets and field offsets for all points */
1241   /*   Assume that all fields have the same chart */
1242   PetscCheck(s->includesConstraints, PETSC_COMM_SELF, PETSC_ERR_SUP, "PetscSectionSetUp is currently unsupported for includesConstraints = PETSC_TRUE");
1243   if (s->perm) PetscCall(ISGetIndices(s->perm, &pind));
1244   if (s->pointMajor) {
1245     for (p = 0; p < s->pEnd - s->pStart; ++p) {
1246       const PetscInt q = pind ? pind[p] : p;
1247 
1248       /* Set point offset */
1249       s->atlasOff[q] = offset;
1250       offset += s->atlasDof[q];
1251       /* Set field offset */
1252       for (f = 0, foff = s->atlasOff[q]; f < s->numFields; ++f) {
1253         PetscSection sf = s->field[f];
1254 
1255         sf->atlasOff[q] = foff;
1256         foff += sf->atlasDof[q];
1257       }
1258     }
1259   } else {
1260     /* Set field offsets for all points */
1261     for (f = 0; f < s->numFields; ++f) {
1262       PetscSection sf = s->field[f];
1263 
1264       for (p = 0; p < s->pEnd - s->pStart; ++p) {
1265         const PetscInt q = pind ? pind[p] : p;
1266 
1267         sf->atlasOff[q] = offset;
1268         offset += sf->atlasDof[q];
1269       }
1270     }
1271     /* Disable point offsets since these are unused */
1272     for (p = 0; p < s->pEnd - s->pStart; ++p) s->atlasOff[p] = -1;
1273   }
1274   if (s->perm) PetscCall(ISRestoreIndices(s->perm, &pind));
1275   /* Setup BC sections */
1276   PetscCall(PetscSectionSetUpBC(s));
1277   for (f = 0; f < s->numFields; ++f) PetscCall(PetscSectionSetUpBC(s->field[f]));
1278   PetscFunctionReturn(PETSC_SUCCESS);
1279 }
1280 
1281 /*@
1282   PetscSectionGetMaxDof - Return the maximum number of degrees of freedom on any point in the `PetscSection`
1283 
1284   Not Collective
1285 
1286   Input Parameter:
1287 . s - the `PetscSection`
1288 
1289   Output Parameter:
1290 . maxDof - the maximum dof
1291 
1292   Level: intermediate
1293 
1294   Notes:
1295   The returned number is up-to-date without need for `PetscSectionSetUp()`.
1296 
1297   This is the maximum over all points of the sum of the number of dof in the unnamed default field plus all named fields. This is equivalent to
1298   the maximum over all points of the value returned by `PetscSectionGetDof()` on this MPI process
1299 
1300   Developer Notes:
1301   The returned number is calculated lazily and stashed.
1302 
1303   A call to `PetscSectionInvalidateMaxDof_Internal()` invalidates the stashed value.
1304 
1305   `PetscSectionInvalidateMaxDof_Internal()` is called in `PetscSectionSetDof()`, `PetscSectionAddDof()` and `PetscSectionReset()`
1306 
1307   It should also be called every time `atlasDof` is modified directly.
1308 
1309 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionSetDof()`, `PetscSectionAddDof()`, `PetscSectionCreate()`
1310 @*/
1311 PetscErrorCode PetscSectionGetMaxDof(PetscSection s, PetscInt *maxDof)
1312 {
1313   PetscInt p;
1314 
1315   PetscFunctionBegin;
1316   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1317   PetscAssertPointer(maxDof, 2);
1318   if (s->maxDof == PETSC_MIN_INT) {
1319     s->maxDof = 0;
1320     for (p = 0; p < s->pEnd - s->pStart; ++p) s->maxDof = PetscMax(s->maxDof, s->atlasDof[p]);
1321   }
1322   *maxDof = s->maxDof;
1323   PetscFunctionReturn(PETSC_SUCCESS);
1324 }
1325 
1326 /*@
1327   PetscSectionGetStorageSize - Return the size of an array or local `Vec` capable of holding all the degrees of freedom defined in a `PetscSection`
1328 
1329   Not Collective
1330 
1331   Input Parameter:
1332 . s - the `PetscSection`
1333 
1334   Output Parameter:
1335 . size - the size of an array which can hold all the dofs
1336 
1337   Level: intermediate
1338 
1339 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionGetConstrainedStorageSize()`, `PetscSectionCreate()`
1340 @*/
1341 PetscErrorCode PetscSectionGetStorageSize(PetscSection s, PetscInt *size)
1342 {
1343   PetscInt p, n = 0;
1344 
1345   PetscFunctionBegin;
1346   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1347   PetscAssertPointer(size, 2);
1348   for (p = 0; p < s->pEnd - s->pStart; ++p) n += s->atlasDof[p] > 0 ? s->atlasDof[p] : 0;
1349   *size = n;
1350   PetscFunctionReturn(PETSC_SUCCESS);
1351 }
1352 
1353 /*@
1354   PetscSectionGetConstrainedStorageSize - Return the size of an array or local `Vec` capable of holding all unconstrained degrees of freedom in a `PetscSection`
1355 
1356   Not Collective
1357 
1358   Input Parameter:
1359 . s - the `PetscSection`
1360 
1361   Output Parameter:
1362 . size - the size of an array which can hold all unconstrained dofs
1363 
1364   Level: intermediate
1365 
1366 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetStorageSize()`, `PetscSectionGetOffset()`, `PetscSectionCreate()`
1367 @*/
1368 PetscErrorCode PetscSectionGetConstrainedStorageSize(PetscSection s, PetscInt *size)
1369 {
1370   PetscInt p, n = 0;
1371 
1372   PetscFunctionBegin;
1373   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1374   PetscAssertPointer(size, 2);
1375   for (p = 0; p < s->pEnd - s->pStart; ++p) {
1376     const PetscInt cdof = s->bc ? s->bc->atlasDof[p] : 0;
1377     n += s->atlasDof[p] > 0 ? s->atlasDof[p] - cdof : 0;
1378   }
1379   *size = n;
1380   PetscFunctionReturn(PETSC_SUCCESS);
1381 }
1382 
1383 /*@
1384   PetscSectionCreateGlobalSection - Create a parallel section describing the global layout using
1385   a local (sequential) `PetscSection` on each MPI process and a `PetscSF` describing the section point overlap.
1386 
1387   Input Parameters:
1388 + s                  - The `PetscSection` for the local field layout
1389 . sf                 - The `PetscSF` describing parallel layout of the section points (leaves are unowned local points)
1390 . includeConstraints - By default this is `PETSC_FALSE`, meaning that the global field vector will not possess constrained dofs
1391 - localOffsets       - If `PETSC_TRUE`, use local rather than global offsets for the points
1392 
1393   Output Parameter:
1394 . gsection - The `PetscSection` for the global field layout
1395 
1396   Level: intermediate
1397 
1398   Notes:
1399   On each MPI process `gsection` inherits the chart of the `s` on that process.
1400 
1401   This sets negative sizes and offsets to points not owned by this process as defined by `sf` but that are within the local value of the chart of `gsection`.
1402   In those locations the value of size is -(size+1) and the value of the offset on the remote process is -(off+1).
1403 
1404 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionCreateGlobalSectionCensored()`
1405 @*/
1406 PetscErrorCode PetscSectionCreateGlobalSection(PetscSection s, PetscSF sf, PetscBool includeConstraints, PetscBool localOffsets, PetscSection *gsection)
1407 {
1408   PetscSection    gs;
1409   const PetscInt *pind = NULL;
1410   PetscInt       *recv = NULL, *neg = NULL;
1411   PetscInt        pStart, pEnd, p, dof, cdof, off, foff, globalOff = 0, nroots, nlocal, maxleaf;
1412   PetscInt        numFields, f, numComponents;
1413 
1414   PetscFunctionBegin;
1415   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1416   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
1417   PetscValidLogicalCollectiveBool(s, includeConstraints, 3);
1418   PetscValidLogicalCollectiveBool(s, localOffsets, 4);
1419   PetscAssertPointer(gsection, 5);
1420   PetscCheck(s->pointMajor, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for field major ordering");
1421   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), &gs));
1422   PetscCall(PetscSectionGetNumFields(s, &numFields));
1423   if (numFields > 0) PetscCall(PetscSectionSetNumFields(gs, numFields));
1424   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
1425   PetscCall(PetscSectionSetChart(gs, pStart, pEnd));
1426   gs->includesConstraints = includeConstraints;
1427   PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL));
1428   nlocal = nroots; /* The local/leaf space matches global/root space */
1429   /* Must allocate for all points visible to SF, which may be more than this section */
1430   if (nroots >= 0) { /* nroots < 0 means that the graph has not been set, only happens in serial */
1431     PetscCall(PetscSFGetLeafRange(sf, NULL, &maxleaf));
1432     PetscCheck(nroots >= pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "SF roots %" PetscInt_FMT " < pEnd %" PetscInt_FMT, nroots, pEnd);
1433     PetscCheck(maxleaf < nroots, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Max local leaf %" PetscInt_FMT " >= nroots %" PetscInt_FMT, maxleaf, nroots);
1434     PetscCall(PetscMalloc2(nroots, &neg, nlocal, &recv));
1435     PetscCall(PetscArrayzero(neg, nroots));
1436   }
1437   /* Mark all local points with negative dof */
1438   for (p = pStart; p < pEnd; ++p) {
1439     PetscCall(PetscSectionGetDof(s, p, &dof));
1440     PetscCall(PetscSectionSetDof(gs, p, dof));
1441     PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
1442     if (!includeConstraints && cdof > 0) PetscCall(PetscSectionSetConstraintDof(gs, p, cdof));
1443     if (neg) neg[p] = -(dof + 1);
1444   }
1445   PetscCall(PetscSectionSetUpBC(gs));
1446   if (gs->bcIndices) PetscCall(PetscArraycpy(gs->bcIndices, s->bcIndices, gs->bc->atlasOff[gs->bc->pEnd - gs->bc->pStart - 1] + gs->bc->atlasDof[gs->bc->pEnd - gs->bc->pStart - 1]));
1447   if (nroots >= 0) {
1448     PetscCall(PetscArrayzero(recv, nlocal));
1449     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, recv, MPI_REPLACE));
1450     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, recv, MPI_REPLACE));
1451     for (p = pStart; p < pEnd; ++p) {
1452       if (recv[p] < 0) {
1453         gs->atlasDof[p - pStart] = recv[p];
1454         PetscCall(PetscSectionGetDof(s, p, &dof));
1455         PetscCheck(-(recv[p] + 1) == dof, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Global dof %" PetscInt_FMT " for point %" PetscInt_FMT " is not the unconstrained %" PetscInt_FMT, -(recv[p] + 1), p, dof);
1456       }
1457     }
1458   }
1459   /* Calculate new sizes, get process offset, and calculate point offsets */
1460   if (s->perm) PetscCall(ISGetIndices(s->perm, &pind));
1461   for (p = 0, off = 0; p < pEnd - pStart; ++p) {
1462     const PetscInt q = pind ? pind[p] : p;
1463 
1464     cdof            = (!includeConstraints && s->bc) ? s->bc->atlasDof[q] : 0;
1465     gs->atlasOff[q] = off;
1466     off += gs->atlasDof[q] > 0 ? gs->atlasDof[q] - cdof : 0;
1467   }
1468   if (!localOffsets) {
1469     PetscCallMPI(MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)s)));
1470     globalOff -= off;
1471   }
1472   for (p = pStart, off = 0; p < pEnd; ++p) {
1473     gs->atlasOff[p - pStart] += globalOff;
1474     if (neg) neg[p] = -(gs->atlasOff[p - pStart] + 1);
1475   }
1476   if (s->perm) PetscCall(ISRestoreIndices(s->perm, &pind));
1477   /* Put in negative offsets for ghost points */
1478   if (nroots >= 0) {
1479     PetscCall(PetscArrayzero(recv, nlocal));
1480     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, recv, MPI_REPLACE));
1481     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, recv, MPI_REPLACE));
1482     for (p = pStart; p < pEnd; ++p) {
1483       if (recv[p] < 0) gs->atlasOff[p - pStart] = recv[p];
1484     }
1485   }
1486   PetscCall(PetscFree2(neg, recv));
1487   /* Set field dofs/offsets/constraints */
1488   for (f = 0; f < numFields; ++f) {
1489     gs->field[f]->includesConstraints = includeConstraints;
1490     PetscCall(PetscSectionGetFieldComponents(s, f, &numComponents));
1491     PetscCall(PetscSectionSetFieldComponents(gs, f, numComponents));
1492   }
1493   for (p = pStart; p < pEnd; ++p) {
1494     PetscCall(PetscSectionGetOffset(gs, p, &off));
1495     for (f = 0, foff = off; f < numFields; ++f) {
1496       PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cdof));
1497       if (!includeConstraints && cdof > 0) PetscCall(PetscSectionSetFieldConstraintDof(gs, p, f, cdof));
1498       PetscCall(PetscSectionGetFieldDof(s, p, f, &dof));
1499       PetscCall(PetscSectionSetFieldDof(gs, p, f, off < 0 ? -(dof + 1) : dof));
1500       PetscCall(PetscSectionSetFieldOffset(gs, p, f, foff));
1501       PetscCall(PetscSectionGetFieldConstraintDof(gs, p, f, &cdof));
1502       foff = off < 0 ? foff - (dof - cdof) : foff + (dof - cdof);
1503     }
1504   }
1505   for (f = 0; f < numFields; ++f) {
1506     PetscSection gfs = gs->field[f];
1507 
1508     PetscCall(PetscSectionSetUpBC(gfs));
1509     if (gfs->bcIndices) PetscCall(PetscArraycpy(gfs->bcIndices, s->field[f]->bcIndices, gfs->bc->atlasOff[gfs->bc->pEnd - gfs->bc->pStart - 1] + gfs->bc->atlasDof[gfs->bc->pEnd - gfs->bc->pStart - 1]));
1510   }
1511   gs->setup = PETSC_TRUE;
1512   PetscCall(PetscSectionViewFromOptions(gs, NULL, "-global_section_view"));
1513   *gsection = gs;
1514   PetscFunctionReturn(PETSC_SUCCESS);
1515 }
1516 
1517 /*@
1518   PetscSectionCreateGlobalSectionCensored - Create a `PetscSection` describing the globallayout using
1519   a local (sequential) `PetscSection` on each MPI process and an `PetscSF` describing the section point overlap.
1520 
1521   Input Parameters:
1522 + s                  - The `PetscSection` for the local field layout
1523 . sf                 - The `PetscSF` describing parallel layout of the section points
1524 . includeConstraints - By default this is `PETSC_FALSE`, meaning that the global vector will not possess constrained dofs
1525 . numExcludes        - The number of exclusion ranges, this must have the same value on all MPI processes
1526 - excludes           - An array [start_0, end_0, start_1, end_1, ...] where there are `numExcludes` pairs and must have the same values on all MPI processes
1527 
1528   Output Parameter:
1529 . gsection - The `PetscSection` for the global field layout
1530 
1531   Level: advanced
1532 
1533   Notes:
1534   On each MPI process `gsection` inherits the chart of the `s` on that process.
1535 
1536   This sets negative sizes and offsets to points not owned by this process as defined by `sf` but that are within the local value of the chart of `gsection`.
1537   In those locations the value of size is -(size+1) and the value of the offset on the remote process is -(off+1).
1538 
1539   This routine augments `PetscSectionCreateGlobalSection()` by allowing one to exclude certain ranges in the chart of the `PetscSection`
1540 
1541   Developer Notes:
1542   This is a terrible function name
1543 
1544 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`
1545 @*/
1546 PetscErrorCode PetscSectionCreateGlobalSectionCensored(PetscSection s, PetscSF sf, PetscBool includeConstraints, PetscInt numExcludes, const PetscInt excludes[], PetscSection *gsection)
1547 {
1548   const PetscInt *pind = NULL;
1549   PetscInt       *neg = NULL, *tmpOff = NULL;
1550   PetscInt        pStart, pEnd, p, e, dof, cdof, off, globalOff = 0, nroots;
1551 
1552   PetscFunctionBegin;
1553   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1554   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
1555   PetscAssertPointer(gsection, 6);
1556   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), gsection));
1557   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
1558   PetscCall(PetscSectionSetChart(*gsection, pStart, pEnd));
1559   PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL));
1560   if (nroots >= 0) {
1561     PetscCheck(nroots >= pEnd - pStart, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %" PetscInt_FMT " < %" PetscInt_FMT " section size", nroots, pEnd - pStart);
1562     PetscCall(PetscCalloc1(nroots, &neg));
1563     if (nroots > pEnd - pStart) {
1564       PetscCall(PetscCalloc1(nroots, &tmpOff));
1565     } else {
1566       tmpOff = &(*gsection)->atlasDof[-pStart];
1567     }
1568   }
1569   /* Mark ghost points with negative dof */
1570   for (p = pStart; p < pEnd; ++p) {
1571     for (e = 0; e < numExcludes; ++e) {
1572       if ((p >= excludes[e * 2 + 0]) && (p < excludes[e * 2 + 1])) {
1573         PetscCall(PetscSectionSetDof(*gsection, p, 0));
1574         break;
1575       }
1576     }
1577     if (e < numExcludes) continue;
1578     PetscCall(PetscSectionGetDof(s, p, &dof));
1579     PetscCall(PetscSectionSetDof(*gsection, p, dof));
1580     PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
1581     if (!includeConstraints && cdof > 0) PetscCall(PetscSectionSetConstraintDof(*gsection, p, cdof));
1582     if (neg) neg[p] = -(dof + 1);
1583   }
1584   PetscCall(PetscSectionSetUpBC(*gsection));
1585   if (nroots >= 0) {
1586     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
1587     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
1588     if (nroots > pEnd - pStart) {
1589       for (p = pStart; p < pEnd; ++p) {
1590         if (tmpOff[p] < 0) (*gsection)->atlasDof[p - pStart] = tmpOff[p];
1591       }
1592     }
1593   }
1594   /* Calculate new sizes, get process offset, and calculate point offsets */
1595   if (s->perm) PetscCall(ISGetIndices(s->perm, &pind));
1596   for (p = 0, off = 0; p < pEnd - pStart; ++p) {
1597     const PetscInt q = pind ? pind[p] : p;
1598 
1599     cdof                     = (!includeConstraints && s->bc) ? s->bc->atlasDof[q] : 0;
1600     (*gsection)->atlasOff[q] = off;
1601     off += (*gsection)->atlasDof[q] > 0 ? (*gsection)->atlasDof[q] - cdof : 0;
1602   }
1603   PetscCallMPI(MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)s)));
1604   globalOff -= off;
1605   for (p = 0, off = 0; p < pEnd - pStart; ++p) {
1606     (*gsection)->atlasOff[p] += globalOff;
1607     if (neg) neg[p + pStart] = -((*gsection)->atlasOff[p] + 1);
1608   }
1609   if (s->perm) PetscCall(ISRestoreIndices(s->perm, &pind));
1610   /* Put in negative offsets for ghost points */
1611   if (nroots >= 0) {
1612     if (nroots == pEnd - pStart) tmpOff = &(*gsection)->atlasOff[-pStart];
1613     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
1614     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
1615     if (nroots > pEnd - pStart) {
1616       for (p = pStart; p < pEnd; ++p) {
1617         if (tmpOff[p] < 0) (*gsection)->atlasOff[p - pStart] = tmpOff[p];
1618       }
1619     }
1620   }
1621   if (nroots >= 0 && nroots > pEnd - pStart) PetscCall(PetscFree(tmpOff));
1622   PetscCall(PetscFree(neg));
1623   PetscFunctionReturn(PETSC_SUCCESS);
1624 }
1625 
1626 /*@
1627   PetscSectionGetPointLayout - Get a `PetscLayout` for the points with nonzero dof counts of the unnamed default field within this `PetscSection`s local chart
1628 
1629   Collective
1630 
1631   Input Parameters:
1632 + comm - The `MPI_Comm`
1633 - s    - The `PetscSection`
1634 
1635   Output Parameter:
1636 . layout - The point layout for the data that defines the section
1637 
1638   Level: advanced
1639 
1640   Notes:
1641   `PetscSectionGetValueLayout()` provides similar information but counting the total number of degrees of freedom on the MPI process (excluding constrained
1642   degrees of freedom).
1643 
1644   This count includes constrained degrees of freedom
1645 
1646   This is usually called on the default global section.
1647 
1648   Example:
1649 .vb
1650      The chart is [2,5), point 2 has 2 dof, point 3 has 0 dof, point 4 has 1 dof
1651      The local size of the `PetscLayout` is 2 since 2 points have a non-zero number of dof
1652 .ve
1653 
1654   Developer Notes:
1655   I find the names of these two functions extremely non-informative
1656 
1657 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetValueLayout()`, `PetscSectionCreate()`
1658 @*/
1659 PetscErrorCode PetscSectionGetPointLayout(MPI_Comm comm, PetscSection s, PetscLayout *layout)
1660 {
1661   PetscInt pStart, pEnd, p, localSize = 0;
1662 
1663   PetscFunctionBegin;
1664   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
1665   for (p = pStart; p < pEnd; ++p) {
1666     PetscInt dof;
1667 
1668     PetscCall(PetscSectionGetDof(s, p, &dof));
1669     if (dof >= 0) ++localSize;
1670   }
1671   PetscCall(PetscLayoutCreate(comm, layout));
1672   PetscCall(PetscLayoutSetLocalSize(*layout, localSize));
1673   PetscCall(PetscLayoutSetBlockSize(*layout, 1));
1674   PetscCall(PetscLayoutSetUp(*layout));
1675   PetscFunctionReturn(PETSC_SUCCESS);
1676 }
1677 
1678 /*@
1679   PetscSectionGetValueLayout - Get the `PetscLayout` associated with the section dofs of a `PetscSection`
1680 
1681   Collective
1682 
1683   Input Parameters:
1684 + comm - The `MPI_Comm`
1685 - s    - The `PetscSection`
1686 
1687   Output Parameter:
1688 . layout - The dof layout for the section
1689 
1690   Level: advanced
1691 
1692   Notes:
1693   `PetscSectionGetPointLayout()` provides similar information but only counting the number of points with nonzero degrees of freedom and
1694   including the constrained degrees of freedom
1695 
1696   This is usually called for the default global section.
1697 
1698   Example:
1699 .vb
1700      The chart is [2,5), point 2 has 4 dof (2 constrained), point 3 has 0 dof, point 4 has 1 dof (not constrained)
1701      The local size of the `PetscLayout` is 3 since there are 3 unconstrained degrees of freedom on this MPI process
1702 .ve
1703 
1704 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetPointLayout()`, `PetscSectionCreate()`
1705 @*/
1706 PetscErrorCode PetscSectionGetValueLayout(MPI_Comm comm, PetscSection s, PetscLayout *layout)
1707 {
1708   PetscInt pStart, pEnd, p, localSize = 0;
1709 
1710   PetscFunctionBegin;
1711   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 2);
1712   PetscAssertPointer(layout, 3);
1713   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
1714   for (p = pStart; p < pEnd; ++p) {
1715     PetscInt dof, cdof;
1716 
1717     PetscCall(PetscSectionGetDof(s, p, &dof));
1718     PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
1719     if (dof - cdof > 0) localSize += dof - cdof;
1720   }
1721   PetscCall(PetscLayoutCreate(comm, layout));
1722   PetscCall(PetscLayoutSetLocalSize(*layout, localSize));
1723   PetscCall(PetscLayoutSetBlockSize(*layout, 1));
1724   PetscCall(PetscLayoutSetUp(*layout));
1725   PetscFunctionReturn(PETSC_SUCCESS);
1726 }
1727 
1728 /*@
1729   PetscSectionGetOffset - Return the offset into an array or `Vec` for the dof associated with the given point.
1730 
1731   Not Collective
1732 
1733   Input Parameters:
1734 + s     - the `PetscSection`
1735 - point - the point
1736 
1737   Output Parameter:
1738 . offset - the offset
1739 
1740   Level: intermediate
1741 
1742   Notes:
1743   In a global section, `offset` will be negative for points not owned by this process.
1744 
1745   This is for the unnamed default field in the `PetscSection` not the named fields
1746 
1747   The `offset` values are different depending on a value set with `PetscSectionSetPointMajor()`
1748 
1749 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetFieldOffset()`, `PetscSectionCreate()`, `PetscSectionSetPointMajor()`
1750 @*/
1751 PetscErrorCode PetscSectionGetOffset(PetscSection s, PetscInt point, PetscInt *offset)
1752 {
1753   PetscFunctionBegin;
1754   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1755   PetscAssertPointer(offset, 3);
1756   PetscAssert(!(point < s->pStart) && !(point >= s->pEnd), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section point %" PetscInt_FMT " should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, s->pStart, s->pEnd);
1757   *offset = s->atlasOff[point - s->pStart];
1758   PetscFunctionReturn(PETSC_SUCCESS);
1759 }
1760 
1761 /*@
1762   PetscSectionSetOffset - Set the offset into an array or `Vec` for the dof associated with the given point.
1763 
1764   Not Collective
1765 
1766   Input Parameters:
1767 + s      - the `PetscSection`
1768 . point  - the point
1769 - offset - the offset, these values may be negative indicating the values are off process
1770 
1771   Level: developer
1772 
1773   Note:
1774   The user usually does not call this function, but uses `PetscSectionSetUp()`
1775 
1776 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetFieldOffset()`, `PetscSectionCreate()`, `PetscSectionSetUp()`
1777 @*/
1778 PetscErrorCode PetscSectionSetOffset(PetscSection s, PetscInt point, PetscInt offset)
1779 {
1780   PetscFunctionBegin;
1781   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1782   PetscCheck(!(point < s->pStart) && !(point >= s->pEnd), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section point %" PetscInt_FMT " should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, s->pStart, s->pEnd);
1783   s->atlasOff[point - s->pStart] = offset;
1784   PetscFunctionReturn(PETSC_SUCCESS);
1785 }
1786 
1787 /*@
1788   PetscSectionGetFieldOffset - Return the offset into an array or `Vec` for the field dof associated with the given point.
1789 
1790   Not Collective
1791 
1792   Input Parameters:
1793 + s     - the `PetscSection`
1794 . point - the point
1795 - field - the field
1796 
1797   Output Parameter:
1798 . offset - the offset
1799 
1800   Level: intermediate
1801 
1802   Notes:
1803   In a global section, `offset` will be negative for points not owned by this process.
1804 
1805   The `offset` values are different depending on a value set with `PetscSectionSetPointMajor()`
1806 
1807 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionCreate()`, `PetscSectionGetFieldPointOffset()`
1808 @*/
1809 PetscErrorCode PetscSectionGetFieldOffset(PetscSection s, PetscInt point, PetscInt field, PetscInt *offset)
1810 {
1811   PetscFunctionBegin;
1812   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1813   PetscAssertPointer(offset, 4);
1814   PetscSectionCheckValidField(field, s->numFields);
1815   PetscCall(PetscSectionGetOffset(s->field[field], point, offset));
1816   PetscFunctionReturn(PETSC_SUCCESS);
1817 }
1818 
1819 /*@
1820   PetscSectionSetFieldOffset - Set the offset into an array or `Vec` for the dof associated with the given field at a point.
1821 
1822   Not Collective
1823 
1824   Input Parameters:
1825 + s      - the `PetscSection`
1826 . point  - the point
1827 . field  - the field
1828 - offset - the offset, these values may be negative indicating the values are off process
1829 
1830   Level: developer
1831 
1832   Note:
1833   The user usually does not call this function, but uses `PetscSectionSetUp()`
1834 
1835 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetFieldOffset()`, `PetscSectionSetOffset()`, `PetscSectionCreate()`, `PetscSectionSetUp()`
1836 @*/
1837 PetscErrorCode PetscSectionSetFieldOffset(PetscSection s, PetscInt point, PetscInt field, PetscInt offset)
1838 {
1839   PetscFunctionBegin;
1840   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1841   PetscSectionCheckValidField(field, s->numFields);
1842   PetscCall(PetscSectionSetOffset(s->field[field], point, offset));
1843   PetscFunctionReturn(PETSC_SUCCESS);
1844 }
1845 
1846 /*@
1847   PetscSectionGetFieldPointOffset - Return the offset for the first field dof associated with the given point relative to the offset for that point for the
1848   unnamed default field's first dof
1849 
1850   Not Collective
1851 
1852   Input Parameters:
1853 + s     - the `PetscSection`
1854 . point - the point
1855 - field - the field
1856 
1857   Output Parameter:
1858 . offset - the offset
1859 
1860   Level: advanced
1861 
1862   Note:
1863   This ignores constraints
1864 
1865   Example:
1866 .vb
1867   if PetscSectionSetPointMajor(s,PETSC_TRUE)
1868   The unnamed default field has 3 dof at `point`
1869   Field 0 has 2 dof at `point`
1870   Then PetscSectionGetFieldPointOffset(s,point,1,&offset) returns and offset of 5
1871 .ve
1872 
1873 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionCreate()`, `PetscSectionGetFieldOffset()`
1874 @*/
1875 PetscErrorCode PetscSectionGetFieldPointOffset(PetscSection s, PetscInt point, PetscInt field, PetscInt *offset)
1876 {
1877   PetscInt off, foff;
1878 
1879   PetscFunctionBegin;
1880   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1881   PetscAssertPointer(offset, 4);
1882   PetscSectionCheckValidField(field, s->numFields);
1883   PetscCall(PetscSectionGetOffset(s, point, &off));
1884   PetscCall(PetscSectionGetOffset(s->field[field], point, &foff));
1885   *offset = foff - off;
1886   PetscFunctionReturn(PETSC_SUCCESS);
1887 }
1888 
1889 /*@
1890   PetscSectionGetOffsetRange - Return the full range of offsets [`start`, `end`) for a `PetscSection`
1891 
1892   Not Collective
1893 
1894   Input Parameter:
1895 . s - the `PetscSection`
1896 
1897   Output Parameters:
1898 + start - the minimum offset
1899 - end   - one more than the maximum offset
1900 
1901   Level: intermediate
1902 
1903 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionCreate()`
1904 @*/
1905 PetscErrorCode PetscSectionGetOffsetRange(PetscSection s, PetscInt *start, PetscInt *end)
1906 {
1907   PetscInt os = 0, oe = 0, pStart, pEnd, p;
1908 
1909   PetscFunctionBegin;
1910   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1911   if (s->atlasOff) {
1912     os = s->atlasOff[0];
1913     oe = s->atlasOff[0];
1914   }
1915   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
1916   for (p = 0; p < pEnd - pStart; ++p) {
1917     PetscInt dof = s->atlasDof[p], off = s->atlasOff[p];
1918 
1919     if (off >= 0) {
1920       os = PetscMin(os, off);
1921       oe = PetscMax(oe, off + dof);
1922     }
1923   }
1924   if (start) *start = os;
1925   if (end) *end = oe;
1926   PetscFunctionReturn(PETSC_SUCCESS);
1927 }
1928 
1929 /*@
1930   PetscSectionCreateSubsection - Create a new, smaller `PetscSection` composed of only selected fields
1931 
1932   Collective
1933 
1934   Input Parameters:
1935 + s      - the `PetscSection`
1936 . len    - the number of subfields
1937 - fields - the subfield numbers
1938 
1939   Output Parameter:
1940 . subs - the subsection
1941 
1942   Level: advanced
1943 
1944   Notes:
1945   The chart of `subs` is the same as the chart of `s`
1946 
1947   This will error if a fieldnumber is out of range
1948 
1949 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreateSupersection()`, `PetscSectionCreate()`
1950 @*/
1951 PetscErrorCode PetscSectionCreateSubsection(PetscSection s, PetscInt len, const PetscInt fields[], PetscSection *subs)
1952 {
1953   PetscInt nF, f, c, pStart, pEnd, p, maxCdof = 0;
1954 
1955   PetscFunctionBegin;
1956   if (!len) PetscFunctionReturn(PETSC_SUCCESS);
1957   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1958   PetscAssertPointer(fields, 3);
1959   PetscAssertPointer(subs, 4);
1960   PetscCall(PetscSectionGetNumFields(s, &nF));
1961   PetscCheck(len <= nF, PetscObjectComm((PetscObject)s), PETSC_ERR_ARG_WRONG, "Number of requested fields %" PetscInt_FMT " greater than number of fields %" PetscInt_FMT, len, nF);
1962   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), subs));
1963   PetscCall(PetscSectionSetNumFields(*subs, len));
1964   for (f = 0; f < len; ++f) {
1965     const char     *name    = NULL;
1966     PetscInt        numComp = 0;
1967     PetscSectionSym sym;
1968 
1969     PetscCall(PetscSectionGetFieldName(s, fields[f], &name));
1970     PetscCall(PetscSectionSetFieldName(*subs, f, name));
1971     PetscCall(PetscSectionGetFieldComponents(s, fields[f], &numComp));
1972     PetscCall(PetscSectionSetFieldComponents(*subs, f, numComp));
1973     for (c = 0; c < s->numFieldComponents[fields[f]]; ++c) {
1974       PetscCall(PetscSectionGetComponentName(s, fields[f], c, &name));
1975       PetscCall(PetscSectionSetComponentName(*subs, f, c, name));
1976     }
1977     PetscCall(PetscSectionGetFieldSym(s, fields[f], &sym));
1978     PetscCall(PetscSectionSetFieldSym(*subs, f, sym));
1979   }
1980   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
1981   PetscCall(PetscSectionSetChart(*subs, pStart, pEnd));
1982   for (p = pStart; p < pEnd; ++p) {
1983     PetscInt dof = 0, cdof = 0, fdof = 0, cfdof = 0;
1984 
1985     for (f = 0; f < len; ++f) {
1986       PetscCall(PetscSectionGetFieldDof(s, p, fields[f], &fdof));
1987       PetscCall(PetscSectionSetFieldDof(*subs, p, f, fdof));
1988       PetscCall(PetscSectionGetFieldConstraintDof(s, p, fields[f], &cfdof));
1989       if (cfdof) PetscCall(PetscSectionSetFieldConstraintDof(*subs, p, f, cfdof));
1990       dof += fdof;
1991       cdof += cfdof;
1992     }
1993     PetscCall(PetscSectionSetDof(*subs, p, dof));
1994     if (cdof) PetscCall(PetscSectionSetConstraintDof(*subs, p, cdof));
1995     maxCdof = PetscMax(cdof, maxCdof);
1996   }
1997   PetscCall(PetscSectionSetUp(*subs));
1998   if (maxCdof) {
1999     PetscInt *indices;
2000 
2001     PetscCall(PetscMalloc1(maxCdof, &indices));
2002     for (p = pStart; p < pEnd; ++p) {
2003       PetscInt cdof;
2004 
2005       PetscCall(PetscSectionGetConstraintDof(*subs, p, &cdof));
2006       if (cdof) {
2007         const PetscInt *oldIndices = NULL;
2008         PetscInt        fdof = 0, cfdof = 0, fc, numConst = 0, fOff = 0;
2009 
2010         for (f = 0; f < len; ++f) {
2011           PetscCall(PetscSectionGetFieldDof(s, p, fields[f], &fdof));
2012           PetscCall(PetscSectionGetFieldConstraintDof(s, p, fields[f], &cfdof));
2013           PetscCall(PetscSectionGetFieldConstraintIndices(s, p, fields[f], &oldIndices));
2014           PetscCall(PetscSectionSetFieldConstraintIndices(*subs, p, f, oldIndices));
2015           for (fc = 0; fc < cfdof; ++fc) indices[numConst + fc] = oldIndices[fc] + fOff;
2016           numConst += cfdof;
2017           fOff += fdof;
2018         }
2019         PetscCall(PetscSectionSetConstraintIndices(*subs, p, indices));
2020       }
2021     }
2022     PetscCall(PetscFree(indices));
2023   }
2024   PetscFunctionReturn(PETSC_SUCCESS);
2025 }
2026 
2027 /*@
2028   PetscSectionCreateSupersection - Create a new, larger section composed of multiple `PetscSection`s
2029 
2030   Collective
2031 
2032   Input Parameters:
2033 + s   - the input sections
2034 - len - the number of input sections
2035 
2036   Output Parameter:
2037 . supers - the supersection
2038 
2039   Level: advanced
2040 
2041   Notes:
2042   The section offsets now refer to a new, larger vector.
2043 
2044   Developer Notes:
2045   Needs to explain how the sections are composed
2046 
2047 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreateSubsection()`, `PetscSectionCreate()`
2048 @*/
2049 PetscErrorCode PetscSectionCreateSupersection(PetscSection s[], PetscInt len, PetscSection *supers)
2050 {
2051   PetscInt Nf = 0, f, pStart = PETSC_MAX_INT, pEnd = 0, p, maxCdof = 0, i;
2052 
2053   PetscFunctionBegin;
2054   if (!len) PetscFunctionReturn(PETSC_SUCCESS);
2055   for (i = 0; i < len; ++i) {
2056     PetscInt nf, pStarti, pEndi;
2057 
2058     PetscCall(PetscSectionGetNumFields(s[i], &nf));
2059     PetscCall(PetscSectionGetChart(s[i], &pStarti, &pEndi));
2060     pStart = PetscMin(pStart, pStarti);
2061     pEnd   = PetscMax(pEnd, pEndi);
2062     Nf += nf;
2063   }
2064   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s[0]), supers));
2065   PetscCall(PetscSectionSetNumFields(*supers, Nf));
2066   for (i = 0, f = 0; i < len; ++i) {
2067     PetscInt nf, fi, ci;
2068 
2069     PetscCall(PetscSectionGetNumFields(s[i], &nf));
2070     for (fi = 0; fi < nf; ++fi, ++f) {
2071       const char *name    = NULL;
2072       PetscInt    numComp = 0;
2073 
2074       PetscCall(PetscSectionGetFieldName(s[i], fi, &name));
2075       PetscCall(PetscSectionSetFieldName(*supers, f, name));
2076       PetscCall(PetscSectionGetFieldComponents(s[i], fi, &numComp));
2077       PetscCall(PetscSectionSetFieldComponents(*supers, f, numComp));
2078       for (ci = 0; ci < s[i]->numFieldComponents[fi]; ++ci) {
2079         PetscCall(PetscSectionGetComponentName(s[i], fi, ci, &name));
2080         PetscCall(PetscSectionSetComponentName(*supers, f, ci, name));
2081       }
2082     }
2083   }
2084   PetscCall(PetscSectionSetChart(*supers, pStart, pEnd));
2085   for (p = pStart; p < pEnd; ++p) {
2086     PetscInt dof = 0, cdof = 0;
2087 
2088     for (i = 0, f = 0; i < len; ++i) {
2089       PetscInt nf, fi, pStarti, pEndi;
2090       PetscInt fdof = 0, cfdof = 0;
2091 
2092       PetscCall(PetscSectionGetNumFields(s[i], &nf));
2093       PetscCall(PetscSectionGetChart(s[i], &pStarti, &pEndi));
2094       if ((p < pStarti) || (p >= pEndi)) continue;
2095       for (fi = 0; fi < nf; ++fi, ++f) {
2096         PetscCall(PetscSectionGetFieldDof(s[i], p, fi, &fdof));
2097         PetscCall(PetscSectionAddFieldDof(*supers, p, f, fdof));
2098         PetscCall(PetscSectionGetFieldConstraintDof(s[i], p, fi, &cfdof));
2099         if (cfdof) PetscCall(PetscSectionAddFieldConstraintDof(*supers, p, f, cfdof));
2100         dof += fdof;
2101         cdof += cfdof;
2102       }
2103     }
2104     PetscCall(PetscSectionSetDof(*supers, p, dof));
2105     if (cdof) PetscCall(PetscSectionSetConstraintDof(*supers, p, cdof));
2106     maxCdof = PetscMax(cdof, maxCdof);
2107   }
2108   PetscCall(PetscSectionSetUp(*supers));
2109   if (maxCdof) {
2110     PetscInt *indices;
2111 
2112     PetscCall(PetscMalloc1(maxCdof, &indices));
2113     for (p = pStart; p < pEnd; ++p) {
2114       PetscInt cdof;
2115 
2116       PetscCall(PetscSectionGetConstraintDof(*supers, p, &cdof));
2117       if (cdof) {
2118         PetscInt dof, numConst = 0, fOff = 0;
2119 
2120         for (i = 0, f = 0; i < len; ++i) {
2121           const PetscInt *oldIndices = NULL;
2122           PetscInt        nf, fi, pStarti, pEndi, fdof, cfdof, fc;
2123 
2124           PetscCall(PetscSectionGetNumFields(s[i], &nf));
2125           PetscCall(PetscSectionGetChart(s[i], &pStarti, &pEndi));
2126           if ((p < pStarti) || (p >= pEndi)) continue;
2127           for (fi = 0; fi < nf; ++fi, ++f) {
2128             PetscCall(PetscSectionGetFieldDof(s[i], p, fi, &fdof));
2129             PetscCall(PetscSectionGetFieldConstraintDof(s[i], p, fi, &cfdof));
2130             PetscCall(PetscSectionGetFieldConstraintIndices(s[i], p, fi, &oldIndices));
2131             for (fc = 0; fc < cfdof; ++fc) indices[numConst + fc] = oldIndices[fc];
2132             PetscCall(PetscSectionSetFieldConstraintIndices(*supers, p, f, &indices[numConst]));
2133             for (fc = 0; fc < cfdof; ++fc) indices[numConst + fc] += fOff;
2134             numConst += cfdof;
2135           }
2136           PetscCall(PetscSectionGetDof(s[i], p, &dof));
2137           fOff += dof;
2138         }
2139         PetscCall(PetscSectionSetConstraintIndices(*supers, p, indices));
2140       }
2141     }
2142     PetscCall(PetscFree(indices));
2143   }
2144   PetscFunctionReturn(PETSC_SUCCESS);
2145 }
2146 
2147 static PetscErrorCode PetscSectionCreateSubplexSection_Private(PetscSection s, IS subpointMap, PetscBool renumberPoints, PetscSection *subs)
2148 {
2149   const PetscInt *points = NULL, *indices = NULL;
2150   PetscInt        numFields, f, c, numSubpoints = 0, pStart, pEnd, p, spStart, spEnd, subp;
2151 
2152   PetscFunctionBegin;
2153   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2154   PetscValidHeaderSpecific(subpointMap, IS_CLASSID, 2);
2155   PetscAssertPointer(subs, 4);
2156   PetscCall(PetscSectionGetNumFields(s, &numFields));
2157   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), subs));
2158   if (numFields) PetscCall(PetscSectionSetNumFields(*subs, numFields));
2159   for (f = 0; f < numFields; ++f) {
2160     const char *name    = NULL;
2161     PetscInt    numComp = 0;
2162 
2163     PetscCall(PetscSectionGetFieldName(s, f, &name));
2164     PetscCall(PetscSectionSetFieldName(*subs, f, name));
2165     PetscCall(PetscSectionGetFieldComponents(s, f, &numComp));
2166     PetscCall(PetscSectionSetFieldComponents(*subs, f, numComp));
2167     for (c = 0; c < s->numFieldComponents[f]; ++c) {
2168       PetscCall(PetscSectionGetComponentName(s, f, c, &name));
2169       PetscCall(PetscSectionSetComponentName(*subs, f, c, name));
2170     }
2171   }
2172   /* For right now, we do not try to squeeze the subchart */
2173   if (subpointMap) {
2174     PetscCall(ISGetSize(subpointMap, &numSubpoints));
2175     PetscCall(ISGetIndices(subpointMap, &points));
2176   }
2177   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
2178   if (renumberPoints) {
2179     spStart = 0;
2180     spEnd   = numSubpoints;
2181   } else {
2182     PetscCall(ISGetMinMax(subpointMap, &spStart, &spEnd));
2183     ++spEnd;
2184   }
2185   PetscCall(PetscSectionSetChart(*subs, spStart, spEnd));
2186   for (p = pStart; p < pEnd; ++p) {
2187     PetscInt dof, cdof, fdof = 0, cfdof = 0;
2188 
2189     PetscCall(PetscFindInt(p, numSubpoints, points, &subp));
2190     if (subp < 0) continue;
2191     if (!renumberPoints) subp = p;
2192     for (f = 0; f < numFields; ++f) {
2193       PetscCall(PetscSectionGetFieldDof(s, p, f, &fdof));
2194       PetscCall(PetscSectionSetFieldDof(*subs, subp, f, fdof));
2195       PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cfdof));
2196       if (cfdof) PetscCall(PetscSectionSetFieldConstraintDof(*subs, subp, f, cfdof));
2197     }
2198     PetscCall(PetscSectionGetDof(s, p, &dof));
2199     PetscCall(PetscSectionSetDof(*subs, subp, dof));
2200     PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
2201     if (cdof) PetscCall(PetscSectionSetConstraintDof(*subs, subp, cdof));
2202   }
2203   PetscCall(PetscSectionSetUp(*subs));
2204   /* Change offsets to original offsets */
2205   for (p = pStart; p < pEnd; ++p) {
2206     PetscInt off, foff = 0;
2207 
2208     PetscCall(PetscFindInt(p, numSubpoints, points, &subp));
2209     if (subp < 0) continue;
2210     if (!renumberPoints) subp = p;
2211     for (f = 0; f < numFields; ++f) {
2212       PetscCall(PetscSectionGetFieldOffset(s, p, f, &foff));
2213       PetscCall(PetscSectionSetFieldOffset(*subs, subp, f, foff));
2214     }
2215     PetscCall(PetscSectionGetOffset(s, p, &off));
2216     PetscCall(PetscSectionSetOffset(*subs, subp, off));
2217   }
2218   /* Copy constraint indices */
2219   for (subp = spStart; subp < spEnd; ++subp) {
2220     PetscInt cdof;
2221 
2222     PetscCall(PetscSectionGetConstraintDof(*subs, subp, &cdof));
2223     if (cdof) {
2224       for (f = 0; f < numFields; ++f) {
2225         PetscCall(PetscSectionGetFieldConstraintIndices(s, points[subp - spStart], f, &indices));
2226         PetscCall(PetscSectionSetFieldConstraintIndices(*subs, subp, f, indices));
2227       }
2228       PetscCall(PetscSectionGetConstraintIndices(s, points[subp - spStart], &indices));
2229       PetscCall(PetscSectionSetConstraintIndices(*subs, subp, indices));
2230     }
2231   }
2232   if (subpointMap) PetscCall(ISRestoreIndices(subpointMap, &points));
2233   PetscFunctionReturn(PETSC_SUCCESS);
2234 }
2235 
2236 /*@
2237   PetscSectionCreateSubmeshSection - Create a new, smaller section with support on the submesh
2238 
2239   Collective
2240 
2241   Input Parameters:
2242 + s           - the `PetscSection`
2243 - subpointMap - a sorted list of points in the original mesh which are in the submesh
2244 
2245   Output Parameter:
2246 . subs - the subsection
2247 
2248   Level: advanced
2249 
2250   Notes:
2251   The points are renumbered from 0, and the section offsets now refer to a new, smaller vector. That is the chart of `subs` is `[0,sizeof(subpointmap))`
2252 
2253   Compare this with `PetscSectionCreateSubdomainSection()` that does not map the points numbers to start at zero but leaves them as before
2254 
2255   Developer Notes:
2256   The use of the term Submesh is confusing and needs clarification, it is not specific to meshes. It appears to be just a subset of the chart of the original `PetscSection`
2257 
2258 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreateSubdomainSection()`, `PetscSectionCreateSubsection()`, `DMPlexGetSubpointMap()`, `PetscSectionCreate()`
2259 @*/
2260 PetscErrorCode PetscSectionCreateSubmeshSection(PetscSection s, IS subpointMap, PetscSection *subs)
2261 {
2262   PetscFunctionBegin;
2263   PetscCall(PetscSectionCreateSubplexSection_Private(s, subpointMap, PETSC_TRUE, subs));
2264   PetscFunctionReturn(PETSC_SUCCESS);
2265 }
2266 
2267 /*@
2268   PetscSectionCreateSubdomainSection - Create a new, smaller section with support on a subdomain of the mesh
2269 
2270   Collective
2271 
2272   Input Parameters:
2273 + s           - the `PetscSection`
2274 - subpointMap - a sorted list of points in the original mesh which are in the subdomain
2275 
2276   Output Parameter:
2277 . subs - the subsection
2278 
2279   Level: advanced
2280 
2281   Notes:
2282   The point numbers remain the same as in the larger `PetscSection`, but the section offsets now refer to a new, smaller vector. The chart of `subs`
2283   is `[min(subpointMap),max(subpointMap)+1)`
2284 
2285   Compare this with `PetscSectionCreateSubmeshSection()` that maps the point numbers to start at zero
2286 
2287   Developer Notes:
2288   The use of the term Subdomain is unneeded and needs clarification, it is not specific to meshes. It appears to be just a subset of the chart of the original `PetscSection`
2289 
2290 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreateSubmeshSection()`, `PetscSectionCreateSubsection()`, `DMPlexGetSubpointMap()`, `PetscSectionCreate()`
2291 @*/
2292 PetscErrorCode PetscSectionCreateSubdomainSection(PetscSection s, IS subpointMap, PetscSection *subs)
2293 {
2294   PetscFunctionBegin;
2295   PetscCall(PetscSectionCreateSubplexSection_Private(s, subpointMap, PETSC_FALSE, subs));
2296   PetscFunctionReturn(PETSC_SUCCESS);
2297 }
2298 
2299 static PetscErrorCode PetscSectionView_ASCII(PetscSection s, PetscViewer viewer)
2300 {
2301   PetscInt    p;
2302   PetscMPIInt rank;
2303 
2304   PetscFunctionBegin;
2305   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
2306   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
2307   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank));
2308   for (p = 0; p < s->pEnd - s->pStart; ++p) {
2309     if (s->bc && s->bc->atlasDof[p] > 0) {
2310       PetscInt b;
2311       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT " constrained", p + s->pStart, s->atlasDof[p], s->atlasOff[p]));
2312       if (s->bcIndices) {
2313         for (b = 0; b < s->bc->atlasDof[p]; ++b) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, s->bcIndices[s->bc->atlasOff[p] + b]));
2314       }
2315       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
2316     } else {
2317       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT "\n", p + s->pStart, s->atlasDof[p], s->atlasOff[p]));
2318     }
2319   }
2320   PetscCall(PetscViewerFlush(viewer));
2321   PetscCall(PetscViewerASCIIPopSynchronized(viewer));
2322   if (s->sym) {
2323     PetscCall(PetscViewerASCIIPushTab(viewer));
2324     PetscCall(PetscSectionSymView(s->sym, viewer));
2325     PetscCall(PetscViewerASCIIPopTab(viewer));
2326   }
2327   PetscFunctionReturn(PETSC_SUCCESS);
2328 }
2329 
2330 /*@C
2331   PetscSectionViewFromOptions - View the `PetscSection` based on values in the options database
2332 
2333   Collective
2334 
2335   Input Parameters:
2336 + A    - the `PetscSection` object to view
2337 . obj  - Optional object that provides the options prefix used for the options
2338 - name - command line option
2339 
2340   Level: intermediate
2341 
2342   Note:
2343   See `PetscObjectViewFromOptions()` for available values of `PetscViewer` and `PetscViewerFormat`
2344 
2345 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionView`, `PetscObjectViewFromOptions()`, `PetscSectionCreate()`, `PetscSectionView()`
2346 @*/
2347 PetscErrorCode PetscSectionViewFromOptions(PetscSection A, PetscObject obj, const char name[])
2348 {
2349   PetscFunctionBegin;
2350   PetscValidHeaderSpecific(A, PETSC_SECTION_CLASSID, 1);
2351   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
2352   PetscFunctionReturn(PETSC_SUCCESS);
2353 }
2354 
2355 /*@C
2356   PetscSectionView - Views a `PetscSection`
2357 
2358   Collective
2359 
2360   Input Parameters:
2361 + s      - the `PetscSection` object to view
2362 - viewer - the viewer
2363 
2364   Level: beginner
2365 
2366   Note:
2367   `PetscSectionView()`, when viewer is of type `PETSCVIEWERHDF5`, only saves
2368   distribution independent data, such as dofs, offsets, constraint dofs,
2369   and constraint indices. Points that have negative dofs, for instance,
2370   are not saved as they represent points owned by other processes.
2371   Point numbering and rank assignment is currently not stored.
2372   The saved section can be loaded with `PetscSectionLoad()`.
2373 
2374 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()`, `PetscSectionLoad()`, `PetscViewer`
2375 @*/
2376 PetscErrorCode PetscSectionView(PetscSection s, PetscViewer viewer)
2377 {
2378   PetscBool isascii, ishdf5;
2379   PetscInt  f;
2380 
2381   PetscFunctionBegin;
2382   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2383   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)s), &viewer));
2384   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2385   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
2386   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2387   if (isascii) {
2388     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)s, viewer));
2389     if (s->numFields) {
2390       PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " fields\n", s->numFields));
2391       for (f = 0; f < s->numFields; ++f) {
2392         PetscCall(PetscViewerASCIIPrintf(viewer, "  field %" PetscInt_FMT " with %" PetscInt_FMT " components\n", f, s->numFieldComponents[f]));
2393         PetscCall(PetscSectionView_ASCII(s->field[f], viewer));
2394       }
2395     } else {
2396       PetscCall(PetscSectionView_ASCII(s, viewer));
2397     }
2398   } else if (ishdf5) {
2399 #if PetscDefined(HAVE_HDF5)
2400     PetscCall(PetscSectionView_HDF5_Internal(s, viewer));
2401 #else
2402     SETERRQ(PetscObjectComm((PetscObject)s), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2403 #endif
2404   }
2405   PetscFunctionReturn(PETSC_SUCCESS);
2406 }
2407 
2408 /*@C
2409   PetscSectionLoad - Loads a `PetscSection`
2410 
2411   Collective
2412 
2413   Input Parameters:
2414 + s      - the `PetscSection` object to load
2415 - viewer - the viewer
2416 
2417   Level: beginner
2418 
2419   Note:
2420   `PetscSectionLoad()`, when viewer is of type `PETSCVIEWERHDF5`, loads
2421   a section saved with `PetscSectionView()`. The number of processes
2422   used here (N) does not need to be the same as that used when saving.
2423   After calling this function, the chart of s on rank i will be set
2424   to [0, E_i), where \sum_{i=0}^{N-1}E_i equals to the total number of
2425   saved section points.
2426 
2427 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()`, `PetscSectionView()`
2428 @*/
2429 PetscErrorCode PetscSectionLoad(PetscSection s, PetscViewer viewer)
2430 {
2431   PetscBool ishdf5;
2432 
2433   PetscFunctionBegin;
2434   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2435   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2436   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2437   if (ishdf5) {
2438 #if PetscDefined(HAVE_HDF5)
2439     PetscCall(PetscSectionLoad_HDF5_Internal(s, viewer));
2440     PetscFunctionReturn(PETSC_SUCCESS);
2441 #else
2442     SETERRQ(PetscObjectComm((PetscObject)s), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2443 #endif
2444   } else SETERRQ(PetscObjectComm((PetscObject)s), PETSC_ERR_SUP, "Viewer type %s not yet supported for PetscSection loading", ((PetscObject)viewer)->type_name);
2445 }
2446 
2447 /*@
2448   PetscSectionResetClosurePermutation - Remove any existing closure permutation
2449 
2450   Input Parameter:
2451 . section - The `PetscSection`
2452 
2453   Level: intermediate
2454 
2455 .seealso: `PetscSectionSetClosurePermutation()`, `PetscSectionSetClosureIndex()`, `PetscSectionReset()`
2456 @*/
2457 PetscErrorCode PetscSectionResetClosurePermutation(PetscSection section)
2458 {
2459   PetscSectionClosurePermVal clVal;
2460 
2461   PetscFunctionBegin;
2462   if (!section->clHash) PetscFunctionReturn(PETSC_SUCCESS);
2463   kh_foreach_value(section->clHash, clVal, {
2464     PetscCall(PetscFree(clVal.perm));
2465     PetscCall(PetscFree(clVal.invPerm));
2466   });
2467   kh_destroy(ClPerm, section->clHash);
2468   section->clHash = NULL;
2469   PetscFunctionReturn(PETSC_SUCCESS);
2470 }
2471 
2472 /*@
2473   PetscSectionReset - Frees all section data, the section is then as if `PetscSectionCreate()` had just been called.
2474 
2475   Not Collective
2476 
2477   Input Parameter:
2478 . s - the `PetscSection`
2479 
2480   Level: beginner
2481 
2482 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`
2483 @*/
2484 PetscErrorCode PetscSectionReset(PetscSection s)
2485 {
2486   PetscInt f, c;
2487 
2488   PetscFunctionBegin;
2489   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2490   for (f = 0; f < s->numFields; ++f) {
2491     PetscCall(PetscSectionDestroy(&s->field[f]));
2492     PetscCall(PetscFree(s->fieldNames[f]));
2493     for (c = 0; c < s->numFieldComponents[f]; ++c) PetscCall(PetscFree(s->compNames[f][c]));
2494     PetscCall(PetscFree(s->compNames[f]));
2495   }
2496   PetscCall(PetscFree(s->numFieldComponents));
2497   PetscCall(PetscFree(s->fieldNames));
2498   PetscCall(PetscFree(s->compNames));
2499   PetscCall(PetscFree(s->field));
2500   PetscCall(PetscSectionDestroy(&s->bc));
2501   PetscCall(PetscFree(s->bcIndices));
2502   PetscCall(PetscFree2(s->atlasDof, s->atlasOff));
2503   PetscCall(PetscSectionDestroy(&s->clSection));
2504   PetscCall(ISDestroy(&s->clPoints));
2505   PetscCall(ISDestroy(&s->perm));
2506   PetscCall(PetscSectionResetClosurePermutation(s));
2507   PetscCall(PetscSectionSymDestroy(&s->sym));
2508   PetscCall(PetscSectionDestroy(&s->clSection));
2509   PetscCall(ISDestroy(&s->clPoints));
2510   PetscCall(PetscSectionInvalidateMaxDof_Internal(s));
2511   s->pStart    = -1;
2512   s->pEnd      = -1;
2513   s->maxDof    = 0;
2514   s->setup     = PETSC_FALSE;
2515   s->numFields = 0;
2516   s->clObj     = NULL;
2517   PetscFunctionReturn(PETSC_SUCCESS);
2518 }
2519 
2520 /*@
2521   PetscSectionDestroy - Frees a `PetscSection`
2522 
2523   Not Collective
2524 
2525   Input Parameter:
2526 . s - the `PetscSection`
2527 
2528   Level: beginner
2529 
2530 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionReset()`
2531 @*/
2532 PetscErrorCode PetscSectionDestroy(PetscSection *s)
2533 {
2534   PetscFunctionBegin;
2535   if (!*s) PetscFunctionReturn(PETSC_SUCCESS);
2536   PetscValidHeaderSpecific(*s, PETSC_SECTION_CLASSID, 1);
2537   if (--((PetscObject)(*s))->refct > 0) {
2538     *s = NULL;
2539     PetscFunctionReturn(PETSC_SUCCESS);
2540   }
2541   PetscCall(PetscSectionReset(*s));
2542   PetscCall(PetscHeaderDestroy(s));
2543   PetscFunctionReturn(PETSC_SUCCESS);
2544 }
2545 
2546 static PetscErrorCode VecIntGetValuesSection_Private(const PetscInt *baseArray, PetscSection s, PetscInt point, const PetscInt **values)
2547 {
2548   const PetscInt p = point - s->pStart;
2549 
2550   PetscFunctionBegin;
2551   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 2);
2552   *values = &baseArray[s->atlasOff[p]];
2553   PetscFunctionReturn(PETSC_SUCCESS);
2554 }
2555 
2556 static PetscErrorCode VecIntSetValuesSection_Private(PetscInt *baseArray, PetscSection s, PetscInt point, const PetscInt values[], InsertMode mode)
2557 {
2558   PetscInt      *array;
2559   const PetscInt p           = point - s->pStart;
2560   const PetscInt orientation = 0; /* Needs to be included for use in closure operations */
2561   PetscInt       cDim        = 0;
2562 
2563   PetscFunctionBegin;
2564   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 2);
2565   PetscCall(PetscSectionGetConstraintDof(s, p, &cDim));
2566   array = &baseArray[s->atlasOff[p]];
2567   if (!cDim) {
2568     if (orientation >= 0) {
2569       const PetscInt dim = s->atlasDof[p];
2570       PetscInt       i;
2571 
2572       if (mode == INSERT_VALUES) {
2573         for (i = 0; i < dim; ++i) array[i] = values ? values[i] : i;
2574       } else {
2575         for (i = 0; i < dim; ++i) array[i] += values[i];
2576       }
2577     } else {
2578       PetscInt offset = 0;
2579       PetscInt j      = -1, field, i;
2580 
2581       for (field = 0; field < s->numFields; ++field) {
2582         const PetscInt dim = s->field[field]->atlasDof[p];
2583 
2584         for (i = dim - 1; i >= 0; --i) array[++j] = values ? values[i + offset] : i + offset;
2585         offset += dim;
2586       }
2587     }
2588   } else {
2589     if (orientation >= 0) {
2590       const PetscInt  dim  = s->atlasDof[p];
2591       PetscInt        cInd = 0, i;
2592       const PetscInt *cDof;
2593 
2594       PetscCall(PetscSectionGetConstraintIndices(s, point, &cDof));
2595       if (mode == INSERT_VALUES) {
2596         for (i = 0; i < dim; ++i) {
2597           if ((cInd < cDim) && (i == cDof[cInd])) {
2598             ++cInd;
2599             continue;
2600           }
2601           array[i] = values ? values[i] : i;
2602         }
2603       } else {
2604         for (i = 0; i < dim; ++i) {
2605           if ((cInd < cDim) && (i == cDof[cInd])) {
2606             ++cInd;
2607             continue;
2608           }
2609           array[i] += values[i];
2610         }
2611       }
2612     } else {
2613       const PetscInt *cDof;
2614       PetscInt        offset  = 0;
2615       PetscInt        cOffset = 0;
2616       PetscInt        j       = 0, field;
2617 
2618       PetscCall(PetscSectionGetConstraintIndices(s, point, &cDof));
2619       for (field = 0; field < s->numFields; ++field) {
2620         const PetscInt dim  = s->field[field]->atlasDof[p];     /* PetscSectionGetFieldDof() */
2621         const PetscInt tDim = s->field[field]->bc->atlasDof[p]; /* PetscSectionGetFieldConstraintDof() */
2622         const PetscInt sDim = dim - tDim;
2623         PetscInt       cInd = 0, i, k;
2624 
2625         for (i = 0, k = dim + offset - 1; i < dim; ++i, ++j, --k) {
2626           if ((cInd < sDim) && (j == cDof[cInd + cOffset])) {
2627             ++cInd;
2628             continue;
2629           }
2630           array[j] = values ? values[k] : k;
2631         }
2632         offset += dim;
2633         cOffset += dim - tDim;
2634       }
2635     }
2636   }
2637   PetscFunctionReturn(PETSC_SUCCESS);
2638 }
2639 
2640 /*@C
2641   PetscSectionHasConstraints - Determine whether a `PetscSection` has constrained dofs
2642 
2643   Not Collective
2644 
2645   Input Parameter:
2646 . s - The `PetscSection`
2647 
2648   Output Parameter:
2649 . hasConstraints - flag indicating that the section has constrained dofs
2650 
2651   Level: intermediate
2652 
2653 .seealso: [PetscSection](sec_petscsection), `PetscSectionSetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection`
2654 @*/
2655 PetscErrorCode PetscSectionHasConstraints(PetscSection s, PetscBool *hasConstraints)
2656 {
2657   PetscFunctionBegin;
2658   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2659   PetscAssertPointer(hasConstraints, 2);
2660   *hasConstraints = s->bc ? PETSC_TRUE : PETSC_FALSE;
2661   PetscFunctionReturn(PETSC_SUCCESS);
2662 }
2663 
2664 /*@C
2665   PetscSectionGetConstraintIndices - Get the point dof numbers, in [0, dof), which are constrained for a given point
2666 
2667   Not Collective
2668 
2669   Input Parameters:
2670 + s     - The `PetscSection`
2671 - point - The point
2672 
2673   Output Parameter:
2674 . indices - The constrained dofs
2675 
2676   Level: intermediate
2677 
2678   Fortran Notes:
2679   Use `PetscSectionGetConstraintIndicesF90()` and `PetscSectionRestoreConstraintIndicesF90()`
2680 
2681 .seealso: [PetscSection](sec_petscsection), `PetscSectionSetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection`
2682 @*/
2683 PetscErrorCode PetscSectionGetConstraintIndices(PetscSection s, PetscInt point, const PetscInt **indices)
2684 {
2685   PetscFunctionBegin;
2686   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2687   if (s->bc) {
2688     PetscCall(VecIntGetValuesSection_Private(s->bcIndices, s->bc, point, indices));
2689   } else *indices = NULL;
2690   PetscFunctionReturn(PETSC_SUCCESS);
2691 }
2692 
2693 /*@C
2694   PetscSectionSetConstraintIndices - Set the point dof numbers, in [0, dof), which are constrained
2695 
2696   Not Collective
2697 
2698   Input Parameters:
2699 + s       - The `PetscSection`
2700 . point   - The point
2701 - indices - The constrained dofs
2702 
2703   Level: intermediate
2704 
2705   Fortran Notes:
2706   Use `PetscSectionSetConstraintIndicesF90()`
2707 
2708 .seealso: [PetscSection](sec_petscsection), `PetscSectionGetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection`
2709 @*/
2710 PetscErrorCode PetscSectionSetConstraintIndices(PetscSection s, PetscInt point, const PetscInt indices[])
2711 {
2712   PetscFunctionBegin;
2713   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2714   if (s->bc) {
2715     const PetscInt dof  = s->atlasDof[point];
2716     const PetscInt cdof = s->bc->atlasDof[point];
2717     PetscInt       d;
2718 
2719     if (indices)
2720       for (d = 0; d < cdof; ++d) PetscCheck(indices[d] < dof, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " dof %" PetscInt_FMT ", invalid constraint index[%" PetscInt_FMT "]: %" PetscInt_FMT, point, dof, d, indices[d]);
2721     PetscCall(VecIntSetValuesSection_Private(s->bcIndices, s->bc, point, indices, INSERT_VALUES));
2722   }
2723   PetscFunctionReturn(PETSC_SUCCESS);
2724 }
2725 
2726 /*@C
2727   PetscSectionGetFieldConstraintIndices - Get the field dof numbers, in [0, fdof), which are constrained
2728 
2729   Not Collective
2730 
2731   Input Parameters:
2732 + s     - The `PetscSection`
2733 . field - The field number
2734 - point - The point
2735 
2736   Output Parameter:
2737 . indices - The constrained dofs sorted in ascending order
2738 
2739   Level: intermediate
2740 
2741   Note:
2742   The indices array, which is provided by the caller, must have capacity to hold the number of constrained dofs, e.g., as returned by `PetscSectionGetConstraintDof()`.
2743 
2744   Fortran Notes:
2745   Use `PetscSectionGetFieldConstraintIndicesF90()` and `PetscSectionRestoreFieldConstraintIndicesF90()`
2746 
2747 .seealso: [PetscSection](sec_petscsection), `PetscSectionSetFieldConstraintIndices()`, `PetscSectionGetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection`
2748 @*/
2749 PetscErrorCode PetscSectionGetFieldConstraintIndices(PetscSection s, PetscInt point, PetscInt field, const PetscInt **indices)
2750 {
2751   PetscFunctionBegin;
2752   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2753   PetscAssertPointer(indices, 4);
2754   PetscSectionCheckValidField(field, s->numFields);
2755   PetscCall(PetscSectionGetConstraintIndices(s->field[field], point, indices));
2756   PetscFunctionReturn(PETSC_SUCCESS);
2757 }
2758 
2759 /*@C
2760   PetscSectionSetFieldConstraintIndices - Set the field dof numbers, in [0, fdof), which are constrained
2761 
2762   Not Collective
2763 
2764   Input Parameters:
2765 + s       - The `PetscSection`
2766 . point   - The point
2767 . field   - The field number
2768 - indices - The constrained dofs
2769 
2770   Level: intermediate
2771 
2772   Fortran Notes:
2773   Use `PetscSectionSetFieldConstraintIndicesF90()`
2774 
2775 .seealso: [PetscSection](sec_petscsection), `PetscSectionSetConstraintIndices()`, `PetscSectionGetFieldConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection`
2776 @*/
2777 PetscErrorCode PetscSectionSetFieldConstraintIndices(PetscSection s, PetscInt point, PetscInt field, const PetscInt indices[])
2778 {
2779   PetscFunctionBegin;
2780   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2781   PetscSectionCheckValidField(field, s->numFields);
2782   PetscCall(PetscSectionSetConstraintIndices(s->field[field], point, indices));
2783   PetscFunctionReturn(PETSC_SUCCESS);
2784 }
2785 
2786 /*@
2787   PetscSectionPermute - Reorder the section according to the input point permutation
2788 
2789   Collective
2790 
2791   Input Parameters:
2792 + section     - The `PetscSection` object
2793 - permutation - The point permutation, old point p becomes new point perm[p]
2794 
2795   Output Parameter:
2796 . sectionNew - The permuted `PetscSection`
2797 
2798   Level: intermediate
2799 
2800   Note:
2801   The data and the access to the data via `PetscSectionGetFieldOffset()` and `PetscSectionGetOffset()` are both changed in `sectionNew`
2802 
2803   Compare to `PetscSectionSetPermutation()`
2804 
2805 .seealso: [PetscSection](sec_petscsection), `IS`, `PetscSection`, `MatPermute()`, `PetscSectionSetPermutation()`
2806 @*/
2807 PetscErrorCode PetscSectionPermute(PetscSection section, IS permutation, PetscSection *sectionNew)
2808 {
2809   PetscSection    s = section, sNew;
2810   const PetscInt *perm;
2811   PetscInt        numFields, f, c, numPoints, pStart, pEnd, p;
2812 
2813   PetscFunctionBegin;
2814   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
2815   PetscValidHeaderSpecific(permutation, IS_CLASSID, 2);
2816   PetscAssertPointer(sectionNew, 3);
2817   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), &sNew));
2818   PetscCall(PetscSectionGetNumFields(s, &numFields));
2819   if (numFields) PetscCall(PetscSectionSetNumFields(sNew, numFields));
2820   for (f = 0; f < numFields; ++f) {
2821     const char *name;
2822     PetscInt    numComp;
2823 
2824     PetscCall(PetscSectionGetFieldName(s, f, &name));
2825     PetscCall(PetscSectionSetFieldName(sNew, f, name));
2826     PetscCall(PetscSectionGetFieldComponents(s, f, &numComp));
2827     PetscCall(PetscSectionSetFieldComponents(sNew, f, numComp));
2828     for (c = 0; c < s->numFieldComponents[f]; ++c) {
2829       PetscCall(PetscSectionGetComponentName(s, f, c, &name));
2830       PetscCall(PetscSectionSetComponentName(sNew, f, c, name));
2831     }
2832   }
2833   PetscCall(ISGetLocalSize(permutation, &numPoints));
2834   PetscCall(ISGetIndices(permutation, &perm));
2835   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
2836   PetscCall(PetscSectionSetChart(sNew, pStart, pEnd));
2837   PetscCheck(numPoints >= pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Permutation size %" PetscInt_FMT " is less than largest Section point %" PetscInt_FMT, numPoints, pEnd);
2838   for (p = pStart; p < pEnd; ++p) {
2839     PetscInt dof, cdof;
2840 
2841     PetscCall(PetscSectionGetDof(s, p, &dof));
2842     PetscCall(PetscSectionSetDof(sNew, perm[p], dof));
2843     PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
2844     if (cdof) PetscCall(PetscSectionSetConstraintDof(sNew, perm[p], cdof));
2845     for (f = 0; f < numFields; ++f) {
2846       PetscCall(PetscSectionGetFieldDof(s, p, f, &dof));
2847       PetscCall(PetscSectionSetFieldDof(sNew, perm[p], f, dof));
2848       PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cdof));
2849       if (cdof) PetscCall(PetscSectionSetFieldConstraintDof(sNew, perm[p], f, cdof));
2850     }
2851   }
2852   PetscCall(PetscSectionSetUp(sNew));
2853   for (p = pStart; p < pEnd; ++p) {
2854     const PetscInt *cind;
2855     PetscInt        cdof;
2856 
2857     PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
2858     if (cdof) {
2859       PetscCall(PetscSectionGetConstraintIndices(s, p, &cind));
2860       PetscCall(PetscSectionSetConstraintIndices(sNew, perm[p], cind));
2861     }
2862     for (f = 0; f < numFields; ++f) {
2863       PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cdof));
2864       if (cdof) {
2865         PetscCall(PetscSectionGetFieldConstraintIndices(s, p, f, &cind));
2866         PetscCall(PetscSectionSetFieldConstraintIndices(sNew, perm[p], f, cind));
2867       }
2868     }
2869   }
2870   PetscCall(ISRestoreIndices(permutation, &perm));
2871   *sectionNew = sNew;
2872   PetscFunctionReturn(PETSC_SUCCESS);
2873 }
2874 
2875 /*@
2876   PetscSectionSetClosureIndex - Create an internal data structure to speed up closure queries.
2877 
2878   Collective
2879 
2880   Input Parameters:
2881 + section   - The `PetscSection`
2882 . obj       - A `PetscObject` which serves as the key for this index
2883 . clSection - `PetscSection` giving the size of the closure of each point
2884 - clPoints  - `IS` giving the points in each closure
2885 
2886   Level: advanced
2887 
2888   Note:
2889   This function creates an internal map from each point to its closure. We compress out closure points with no dofs in this section.
2890 
2891   Developer Notes:
2892   The information provided here is completely opaque
2893 
2894 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetClosureIndex()`, `DMPlexCreateClosureIndex()`
2895 @*/
2896 PetscErrorCode PetscSectionSetClosureIndex(PetscSection section, PetscObject obj, PetscSection clSection, IS clPoints)
2897 {
2898   PetscFunctionBegin;
2899   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
2900   PetscValidHeaderSpecific(clSection, PETSC_SECTION_CLASSID, 3);
2901   PetscValidHeaderSpecific(clPoints, IS_CLASSID, 4);
2902   if (section->clObj != obj) PetscCall(PetscSectionResetClosurePermutation(section));
2903   section->clObj = obj;
2904   PetscCall(PetscObjectReference((PetscObject)clSection));
2905   PetscCall(PetscObjectReference((PetscObject)clPoints));
2906   PetscCall(PetscSectionDestroy(&section->clSection));
2907   PetscCall(ISDestroy(&section->clPoints));
2908   section->clSection = clSection;
2909   section->clPoints  = clPoints;
2910   PetscFunctionReturn(PETSC_SUCCESS);
2911 }
2912 
2913 /*@
2914   PetscSectionGetClosureIndex - Get the cache of points in the closure of each point in the section set with `PetscSectionSetClosureIndex()`
2915 
2916   Collective
2917 
2918   Input Parameters:
2919 + section - The `PetscSection`
2920 - obj     - A `PetscObject` which serves as the key for this index
2921 
2922   Output Parameters:
2923 + clSection - `PetscSection` giving the size of the closure of each point
2924 - clPoints  - `IS` giving the points in each closure
2925 
2926   Level: advanced
2927 
2928 .seealso: [PetscSection](sec_petscsection), `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()`
2929 @*/
2930 PetscErrorCode PetscSectionGetClosureIndex(PetscSection section, PetscObject obj, PetscSection *clSection, IS *clPoints)
2931 {
2932   PetscFunctionBegin;
2933   if (section->clObj == obj) {
2934     if (clSection) *clSection = section->clSection;
2935     if (clPoints) *clPoints = section->clPoints;
2936   } else {
2937     if (clSection) *clSection = NULL;
2938     if (clPoints) *clPoints = NULL;
2939   }
2940   PetscFunctionReturn(PETSC_SUCCESS);
2941 }
2942 
2943 PetscErrorCode PetscSectionSetClosurePermutation_Internal(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, PetscCopyMode mode, PetscInt *clPerm)
2944 {
2945   PetscInt                    i;
2946   khiter_t                    iter;
2947   int                         new_entry;
2948   PetscSectionClosurePermKey  key = {depth, clSize};
2949   PetscSectionClosurePermVal *val;
2950 
2951   PetscFunctionBegin;
2952   if (section->clObj != obj) {
2953     PetscCall(PetscSectionDestroy(&section->clSection));
2954     PetscCall(ISDestroy(&section->clPoints));
2955   }
2956   section->clObj = obj;
2957   if (!section->clHash) PetscCall(PetscClPermCreate(&section->clHash));
2958   iter = kh_put(ClPerm, section->clHash, key, &new_entry);
2959   val  = &kh_val(section->clHash, iter);
2960   if (!new_entry) {
2961     PetscCall(PetscFree(val->perm));
2962     PetscCall(PetscFree(val->invPerm));
2963   }
2964   if (mode == PETSC_COPY_VALUES) {
2965     PetscCall(PetscMalloc1(clSize, &val->perm));
2966     PetscCall(PetscArraycpy(val->perm, clPerm, clSize));
2967   } else if (mode == PETSC_OWN_POINTER) {
2968     val->perm = clPerm;
2969   } else SETERRQ(PetscObjectComm(obj), PETSC_ERR_SUP, "Do not support borrowed arrays");
2970   PetscCall(PetscMalloc1(clSize, &val->invPerm));
2971   for (i = 0; i < clSize; ++i) val->invPerm[clPerm[i]] = i;
2972   PetscFunctionReturn(PETSC_SUCCESS);
2973 }
2974 
2975 /*@
2976   PetscSectionSetClosurePermutation - Set the dof permutation for the closure of each cell in the section, meaning clPerm[newIndex] = oldIndex.
2977 
2978   Not Collective
2979 
2980   Input Parameters:
2981 + section - The `PetscSection`
2982 . obj     - A `PetscObject` which serves as the key for this index (usually a `DM`)
2983 . depth   - Depth of points on which to apply the given permutation
2984 - perm    - Permutation of the cell dof closure
2985 
2986   Level: intermediate
2987 
2988   Notes:
2989   The specified permutation will only be applied to points at depth whose closure size matches the length of perm.  In a
2990   mixed-topology or variable-degree finite element space, this function can be called multiple times at each depth for
2991   each topology and degree.
2992 
2993   This approach assumes that (depth, len(perm)) uniquely identifies the desired permutation; this might not be true for
2994   exotic/enriched spaces on mixed topology meshes.
2995 
2996 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `IS`, `PetscSectionGetClosurePermutation()`, `PetscSectionGetClosureIndex()`, `DMPlexCreateClosureIndex()`, `PetscCopyMode`
2997 @*/
2998 PetscErrorCode PetscSectionSetClosurePermutation(PetscSection section, PetscObject obj, PetscInt depth, IS perm)
2999 {
3000   const PetscInt *clPerm = NULL;
3001   PetscInt        clSize = 0;
3002 
3003   PetscFunctionBegin;
3004   if (perm) {
3005     PetscCall(ISGetLocalSize(perm, &clSize));
3006     PetscCall(ISGetIndices(perm, &clPerm));
3007   }
3008   PetscCall(PetscSectionSetClosurePermutation_Internal(section, obj, depth, clSize, PETSC_COPY_VALUES, (PetscInt *)clPerm));
3009   if (perm) PetscCall(ISRestoreIndices(perm, &clPerm));
3010   PetscFunctionReturn(PETSC_SUCCESS);
3011 }
3012 
3013 static PetscErrorCode PetscSectionGetClosurePermutation_Private(PetscSection section, PetscObject obj, PetscInt depth, PetscInt size, const PetscInt *perm[])
3014 {
3015   PetscFunctionBegin;
3016   if (section->clObj == obj) {
3017     PetscSectionClosurePermKey k = {depth, size};
3018     PetscSectionClosurePermVal v;
3019 
3020     PetscCall(PetscClPermGet(section->clHash, k, &v));
3021     if (perm) *perm = v.perm;
3022   } else {
3023     if (perm) *perm = NULL;
3024   }
3025   PetscFunctionReturn(PETSC_SUCCESS);
3026 }
3027 
3028 /*@
3029   PetscSectionGetClosurePermutation - Get the dof permutation for the closure of each cell in the section, meaning clPerm[newIndex] = oldIndex.
3030 
3031   Not Collective
3032 
3033   Input Parameters:
3034 + section - The `PetscSection`
3035 . obj     - A `PetscObject` which serves as the key for this index (usually a DM)
3036 . depth   - Depth stratum on which to obtain closure permutation
3037 - clSize  - Closure size to be permuted (e.g., may vary with element topology and degree)
3038 
3039   Output Parameter:
3040 . perm - The dof closure permutation
3041 
3042   Level: intermediate
3043 
3044   Note:
3045   The user must destroy the `IS` that is returned.
3046 
3047 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `IS`, `PetscSectionSetClosurePermutation()`, `PetscSectionGetClosureInversePermutation()`, `PetscSectionGetClosureIndex()`, `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()`
3048 @*/
3049 PetscErrorCode PetscSectionGetClosurePermutation(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, IS *perm)
3050 {
3051   const PetscInt *clPerm = NULL;
3052 
3053   PetscFunctionBegin;
3054   PetscCall(PetscSectionGetClosurePermutation_Private(section, obj, depth, clSize, &clPerm));
3055   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, clSize, clPerm, PETSC_USE_POINTER, perm));
3056   PetscFunctionReturn(PETSC_SUCCESS);
3057 }
3058 
3059 PetscErrorCode PetscSectionGetClosureInversePermutation_Internal(PetscSection section, PetscObject obj, PetscInt depth, PetscInt size, const PetscInt *perm[])
3060 {
3061   PetscFunctionBegin;
3062   if (section->clObj == obj && section->clHash) {
3063     PetscSectionClosurePermKey k = {depth, size};
3064     PetscSectionClosurePermVal v;
3065     PetscCall(PetscClPermGet(section->clHash, k, &v));
3066     if (perm) *perm = v.invPerm;
3067   } else {
3068     if (perm) *perm = NULL;
3069   }
3070   PetscFunctionReturn(PETSC_SUCCESS);
3071 }
3072 
3073 /*@
3074   PetscSectionGetClosureInversePermutation - Get the inverse dof permutation for the closure of each cell in the section, meaning clPerm[oldIndex] = newIndex.
3075 
3076   Not Collective
3077 
3078   Input Parameters:
3079 + section - The `PetscSection`
3080 . obj     - A `PetscObject` which serves as the key for this index (usually a `DM`)
3081 . depth   - Depth stratum on which to obtain closure permutation
3082 - clSize  - Closure size to be permuted (e.g., may vary with element topology and degree)
3083 
3084   Output Parameter:
3085 . perm - The dof closure permutation
3086 
3087   Level: intermediate
3088 
3089   Note:
3090   The user must destroy the `IS` that is returned.
3091 
3092 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `IS`, `PetscSectionSetClosurePermutation()`, `PetscSectionGetClosureIndex()`, `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()`
3093 @*/
3094 PetscErrorCode PetscSectionGetClosureInversePermutation(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, IS *perm)
3095 {
3096   const PetscInt *clPerm = NULL;
3097 
3098   PetscFunctionBegin;
3099   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, obj, depth, clSize, &clPerm));
3100   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, clSize, clPerm, PETSC_USE_POINTER, perm));
3101   PetscFunctionReturn(PETSC_SUCCESS);
3102 }
3103 
3104 /*@
3105   PetscSectionGetField - Get the `PetscSection` associated with a single field
3106 
3107   Input Parameters:
3108 + s     - The `PetscSection`
3109 - field - The field number
3110 
3111   Output Parameter:
3112 . subs - The `PetscSection` for the given field, note the chart of `subs` is not set
3113 
3114   Level: intermediate
3115 
3116   Note:
3117   Does not increase the reference count of the selected sub-section. There is no matching `PetscSectionRestoreField()`
3118 
3119 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `IS`, `PetscSectionSetNumFields()`
3120 @*/
3121 PetscErrorCode PetscSectionGetField(PetscSection s, PetscInt field, PetscSection *subs)
3122 {
3123   PetscFunctionBegin;
3124   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
3125   PetscAssertPointer(subs, 3);
3126   PetscSectionCheckValidField(field, s->numFields);
3127   *subs = s->field[field];
3128   PetscFunctionReturn(PETSC_SUCCESS);
3129 }
3130 
3131 PetscClassId      PETSC_SECTION_SYM_CLASSID;
3132 PetscFunctionList PetscSectionSymList = NULL;
3133 
3134 /*@
3135   PetscSectionSymCreate - Creates an empty `PetscSectionSym` object.
3136 
3137   Collective
3138 
3139   Input Parameter:
3140 . comm - the MPI communicator
3141 
3142   Output Parameter:
3143 . sym - pointer to the new set of symmetries
3144 
3145   Level: developer
3146 
3147 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSym`, `PetscSectionSymDestroy()`
3148 @*/
3149 PetscErrorCode PetscSectionSymCreate(MPI_Comm comm, PetscSectionSym *sym)
3150 {
3151   PetscFunctionBegin;
3152   PetscAssertPointer(sym, 2);
3153   PetscCall(ISInitializePackage());
3154   PetscCall(PetscHeaderCreate(*sym, PETSC_SECTION_SYM_CLASSID, "PetscSectionSym", "Section Symmetry", "IS", comm, PetscSectionSymDestroy, PetscSectionSymView));
3155   PetscFunctionReturn(PETSC_SUCCESS);
3156 }
3157 
3158 /*@C
3159   PetscSectionSymSetType - Builds a `PetscSectionSym`, for a particular implementation.
3160 
3161   Collective
3162 
3163   Input Parameters:
3164 + sym    - The section symmetry object
3165 - method - The name of the section symmetry type
3166 
3167   Level: developer
3168 
3169 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymGetType()`, `PetscSectionSymCreate()`
3170 @*/
3171 PetscErrorCode PetscSectionSymSetType(PetscSectionSym sym, PetscSectionSymType method)
3172 {
3173   PetscErrorCode (*r)(PetscSectionSym);
3174   PetscBool match;
3175 
3176   PetscFunctionBegin;
3177   PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1);
3178   PetscCall(PetscObjectTypeCompare((PetscObject)sym, method, &match));
3179   if (match) PetscFunctionReturn(PETSC_SUCCESS);
3180 
3181   PetscCall(PetscFunctionListFind(PetscSectionSymList, method, &r));
3182   PetscCheck(r, PetscObjectComm((PetscObject)sym), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscSectionSym type: %s", method);
3183   PetscTryTypeMethod(sym, destroy);
3184   sym->ops->destroy = NULL;
3185 
3186   PetscCall((*r)(sym));
3187   PetscCall(PetscObjectChangeTypeName((PetscObject)sym, method));
3188   PetscFunctionReturn(PETSC_SUCCESS);
3189 }
3190 
3191 /*@C
3192   PetscSectionSymGetType - Gets the section symmetry type name (as a string) from the `PetscSectionSym`.
3193 
3194   Not Collective
3195 
3196   Input Parameter:
3197 . sym - The section symmetry
3198 
3199   Output Parameter:
3200 . type - The index set type name
3201 
3202   Level: developer
3203 
3204 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymSetType()`, `PetscSectionSymCreate()`
3205 @*/
3206 PetscErrorCode PetscSectionSymGetType(PetscSectionSym sym, PetscSectionSymType *type)
3207 {
3208   PetscFunctionBegin;
3209   PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1);
3210   PetscAssertPointer(type, 2);
3211   *type = ((PetscObject)sym)->type_name;
3212   PetscFunctionReturn(PETSC_SUCCESS);
3213 }
3214 
3215 /*@C
3216   PetscSectionSymRegister - Registers a new section symmetry implementation
3217 
3218   Not Collective
3219 
3220   Input Parameters:
3221 + sname    - The name of a new user-defined creation routine
3222 - function - The creation routine itself
3223 
3224   Level: developer
3225 
3226   Notes:
3227   `PetscSectionSymRegister()` may be called multiple times to add several user-defined vectors
3228 
3229 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymCreate()`, `PetscSectionSymSetType()`
3230 @*/
3231 PetscErrorCode PetscSectionSymRegister(const char sname[], PetscErrorCode (*function)(PetscSectionSym))
3232 {
3233   PetscFunctionBegin;
3234   PetscCall(ISInitializePackage());
3235   PetscCall(PetscFunctionListAdd(&PetscSectionSymList, sname, function));
3236   PetscFunctionReturn(PETSC_SUCCESS);
3237 }
3238 
3239 /*@
3240   PetscSectionSymDestroy - Destroys a section symmetry.
3241 
3242   Collective
3243 
3244   Input Parameter:
3245 . sym - the section symmetry
3246 
3247   Level: developer
3248 
3249 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()`
3250 @*/
3251 PetscErrorCode PetscSectionSymDestroy(PetscSectionSym *sym)
3252 {
3253   SymWorkLink link, next;
3254 
3255   PetscFunctionBegin;
3256   if (!*sym) PetscFunctionReturn(PETSC_SUCCESS);
3257   PetscValidHeaderSpecific((*sym), PETSC_SECTION_SYM_CLASSID, 1);
3258   if (--((PetscObject)(*sym))->refct > 0) {
3259     *sym = NULL;
3260     PetscFunctionReturn(PETSC_SUCCESS);
3261   }
3262   if ((*sym)->ops->destroy) PetscCall((*(*sym)->ops->destroy)(*sym));
3263   PetscCheck(!(*sym)->workout, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Work array still checked out");
3264   for (link = (*sym)->workin; link; link = next) {
3265     PetscInt    **perms = (PetscInt **)link->perms;
3266     PetscScalar **rots  = (PetscScalar **)link->rots;
3267     PetscCall(PetscFree2(perms, rots));
3268     next = link->next;
3269     PetscCall(PetscFree(link));
3270   }
3271   (*sym)->workin = NULL;
3272   PetscCall(PetscHeaderDestroy(sym));
3273   PetscFunctionReturn(PETSC_SUCCESS);
3274 }
3275 
3276 /*@C
3277   PetscSectionSymView - Displays a section symmetry
3278 
3279   Collective
3280 
3281   Input Parameters:
3282 + sym    - the index set
3283 - viewer - viewer used to display the set, for example `PETSC_VIEWER_STDOUT_SELF`.
3284 
3285   Level: developer
3286 
3287 .seealso: `PetscSectionSym`, `PetscViewer`, `PetscViewerASCIIOpen()`
3288 @*/
3289 PetscErrorCode PetscSectionSymView(PetscSectionSym sym, PetscViewer viewer)
3290 {
3291   PetscFunctionBegin;
3292   PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1);
3293   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sym), &viewer));
3294   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
3295   PetscCheckSameComm(sym, 1, viewer, 2);
3296   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)sym, viewer));
3297   PetscTryTypeMethod(sym, view, viewer);
3298   PetscFunctionReturn(PETSC_SUCCESS);
3299 }
3300 
3301 /*@
3302   PetscSectionSetSym - Set the symmetries for the data referred to by the section
3303 
3304   Collective
3305 
3306   Input Parameters:
3307 + section - the section describing data layout
3308 - sym     - the symmetry describing the affect of orientation on the access of the data
3309 
3310   Level: developer
3311 
3312 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetSym()`, `PetscSectionSymCreate()`
3313 @*/
3314 PetscErrorCode PetscSectionSetSym(PetscSection section, PetscSectionSym sym)
3315 {
3316   PetscFunctionBegin;
3317   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3318   PetscCall(PetscSectionSymDestroy(&(section->sym)));
3319   if (sym) {
3320     PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 2);
3321     PetscCheckSameComm(section, 1, sym, 2);
3322     PetscCall(PetscObjectReference((PetscObject)sym));
3323   }
3324   section->sym = sym;
3325   PetscFunctionReturn(PETSC_SUCCESS);
3326 }
3327 
3328 /*@
3329   PetscSectionGetSym - Get the symmetries for the data referred to by the section
3330 
3331   Not Collective
3332 
3333   Input Parameter:
3334 . section - the section describing data layout
3335 
3336   Output Parameter:
3337 . sym - the symmetry describing the affect of orientation on the access of the data, provided previously by `PetscSectionSetSym()`
3338 
3339   Level: developer
3340 
3341 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSetSym()`, `PetscSectionSymCreate()`
3342 @*/
3343 PetscErrorCode PetscSectionGetSym(PetscSection section, PetscSectionSym *sym)
3344 {
3345   PetscFunctionBegin;
3346   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3347   *sym = section->sym;
3348   PetscFunctionReturn(PETSC_SUCCESS);
3349 }
3350 
3351 /*@
3352   PetscSectionSetFieldSym - Set the symmetries for the data referred to by a field of the section
3353 
3354   Collective
3355 
3356   Input Parameters:
3357 + section - the section describing data layout
3358 . field   - the field number
3359 - sym     - the symmetry describing the affect of orientation on the access of the data
3360 
3361   Level: developer
3362 
3363 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetFieldSym()`, `PetscSectionSymCreate()`
3364 @*/
3365 PetscErrorCode PetscSectionSetFieldSym(PetscSection section, PetscInt field, PetscSectionSym sym)
3366 {
3367   PetscFunctionBegin;
3368   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3369   PetscSectionCheckValidField(field, section->numFields);
3370   PetscCall(PetscSectionSetSym(section->field[field], sym));
3371   PetscFunctionReturn(PETSC_SUCCESS);
3372 }
3373 
3374 /*@
3375   PetscSectionGetFieldSym - Get the symmetries for the data referred to by a field of the section
3376 
3377   Collective
3378 
3379   Input Parameters:
3380 + section - the section describing data layout
3381 - field   - the field number
3382 
3383   Output Parameter:
3384 . sym - the symmetry describing the affect of orientation on the access of the data
3385 
3386   Level: developer
3387 
3388 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSetFieldSym()`, `PetscSectionSymCreate()`
3389 @*/
3390 PetscErrorCode PetscSectionGetFieldSym(PetscSection section, PetscInt field, PetscSectionSym *sym)
3391 {
3392   PetscFunctionBegin;
3393   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3394   PetscSectionCheckValidField(field, section->numFields);
3395   *sym = section->field[field]->sym;
3396   PetscFunctionReturn(PETSC_SUCCESS);
3397 }
3398 
3399 /*@C
3400   PetscSectionGetPointSyms - Get the symmetries for a set of points in a `PetscSection` under specific orientations.
3401 
3402   Not Collective
3403 
3404   Input Parameters:
3405 + section   - the section
3406 . numPoints - the number of points
3407 - points    - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an
3408     arbitrary integer: its interpretation is up to sym.  Orientations are used by `DM`: for their interpretation in that
3409     context, see `DMPlexGetConeOrientation()`).
3410 
3411   Output Parameters:
3412 + perms - The permutations for the given orientations (or `NULL` if there is no symmetry or the permutation is the identity).
3413 - rots  - The field rotations symmetries for the given orientations (or `NULL` if there is no symmetry or the rotations are all
3414     identity).
3415 
3416   Example of usage, gathering dofs into a local array (lArray) from a section array (sArray):
3417 .vb
3418      const PetscInt    **perms;
3419      const PetscScalar **rots;
3420      PetscInt            lOffset;
3421 
3422      PetscSectionGetPointSyms(section,numPoints,points,&perms,&rots);
3423      for (i = 0, lOffset = 0; i < numPoints; i++) {
3424        PetscInt           point = points[2*i], dof, sOffset;
3425        const PetscInt    *perm  = perms ? perms[i] : NULL;
3426        const PetscScalar *rot   = rots  ? rots[i]  : NULL;
3427 
3428        PetscSectionGetDof(section,point,&dof);
3429        PetscSectionGetOffset(section,point,&sOffset);
3430 
3431        if (perm) {for (j = 0; j < dof; j++) {lArray[lOffset + perm[j]]  = sArray[sOffset + j];}}
3432        else      {for (j = 0; j < dof; j++) {lArray[lOffset +      j ]  = sArray[sOffset + j];}}
3433        if (rot)  {for (j = 0; j < dof; j++) {lArray[lOffset +      j ] *= rot[j];             }}
3434        lOffset += dof;
3435      }
3436      PetscSectionRestorePointSyms(section,numPoints,points,&perms,&rots);
3437 .ve
3438 
3439   Example of usage, adding dofs into a section array (sArray) from a local array (lArray):
3440 .vb
3441      const PetscInt    **perms;
3442      const PetscScalar **rots;
3443      PetscInt            lOffset;
3444 
3445      PetscSectionGetPointSyms(section,numPoints,points,&perms,&rots);
3446      for (i = 0, lOffset = 0; i < numPoints; i++) {
3447        PetscInt           point = points[2*i], dof, sOffset;
3448        const PetscInt    *perm  = perms ? perms[i] : NULL;
3449        const PetscScalar *rot   = rots  ? rots[i]  : NULL;
3450 
3451        PetscSectionGetDof(section,point,&dof);
3452        PetscSectionGetOffset(section,point,&sOff);
3453 
3454        if (perm) {for (j = 0; j < dof; j++) {sArray[sOffset + j] += lArray[lOffset + perm[j]] * (rot ? PetscConj(rot[perm[j]]) : 1.);}}
3455        else      {for (j = 0; j < dof; j++) {sArray[sOffset + j] += lArray[lOffset +      j ] * (rot ? PetscConj(rot[     j ]) : 1.);}}
3456        offset += dof;
3457      }
3458      PetscSectionRestorePointSyms(section,numPoints,points,&perms,&rots);
3459 .ve
3460 
3461   Level: developer
3462 
3463   Notes:
3464   `PetscSectionSetSym()` must have been previously called to provide the symmetries to the `PetscSection`
3465 
3466   Use `PetscSectionRestorePointSyms()` when finished with the data
3467 
3468 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionRestorePointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`
3469 @*/
3470 PetscErrorCode PetscSectionGetPointSyms(PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3471 {
3472   PetscSectionSym sym;
3473 
3474   PetscFunctionBegin;
3475   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3476   if (numPoints) PetscAssertPointer(points, 3);
3477   if (perms) *perms = NULL;
3478   if (rots) *rots = NULL;
3479   sym = section->sym;
3480   if (sym && (perms || rots)) {
3481     SymWorkLink link;
3482 
3483     if (sym->workin) {
3484       link        = sym->workin;
3485       sym->workin = sym->workin->next;
3486     } else {
3487       PetscCall(PetscNew(&link));
3488     }
3489     if (numPoints > link->numPoints) {
3490       PetscInt    **perms = (PetscInt **)link->perms;
3491       PetscScalar **rots  = (PetscScalar **)link->rots;
3492       PetscCall(PetscFree2(perms, rots));
3493       PetscCall(PetscMalloc2(numPoints, (PetscInt ***)&link->perms, numPoints, (PetscScalar ***)&link->rots));
3494       link->numPoints = numPoints;
3495     }
3496     link->next   = sym->workout;
3497     sym->workout = link;
3498     PetscCall(PetscArrayzero((PetscInt **)link->perms, numPoints));
3499     PetscCall(PetscArrayzero((PetscInt **)link->rots, numPoints));
3500     PetscCall((*sym->ops->getpoints)(sym, section, numPoints, points, link->perms, link->rots));
3501     if (perms) *perms = link->perms;
3502     if (rots) *rots = link->rots;
3503   }
3504   PetscFunctionReturn(PETSC_SUCCESS);
3505 }
3506 
3507 /*@C
3508   PetscSectionRestorePointSyms - Restore the symmetries returned by `PetscSectionGetPointSyms()`
3509 
3510   Not Collective
3511 
3512   Input Parameters:
3513 + section   - the section
3514 . numPoints - the number of points
3515 . points    - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an
3516     arbitrary integer: its interpretation is up to sym.  Orientations are used by `DM`: for their interpretation in that
3517     context, see `DMPlexGetConeOrientation()`).
3518 . perms     - The permutations for the given orientations: set to `NULL` at conclusion
3519 - rots      - The field rotations symmetries for the given orientations: set to `NULL` at conclusion
3520 
3521   Level: developer
3522 
3523 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetPointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`
3524 @*/
3525 PetscErrorCode PetscSectionRestorePointSyms(PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3526 {
3527   PetscSectionSym sym;
3528 
3529   PetscFunctionBegin;
3530   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3531   sym = section->sym;
3532   if (sym && (perms || rots)) {
3533     SymWorkLink *p, link;
3534 
3535     for (p = &sym->workout; (link = *p); p = &link->next) {
3536       if ((perms && link->perms == *perms) || (rots && link->rots == *rots)) {
3537         *p          = link->next;
3538         link->next  = sym->workin;
3539         sym->workin = link;
3540         if (perms) *perms = NULL;
3541         if (rots) *rots = NULL;
3542         PetscFunctionReturn(PETSC_SUCCESS);
3543       }
3544     }
3545     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Array was not checked out");
3546   }
3547   PetscFunctionReturn(PETSC_SUCCESS);
3548 }
3549 
3550 /*@C
3551   PetscSectionGetFieldPointSyms - Get the symmetries for a set of points in a field of a `PetscSection` under specific orientations.
3552 
3553   Not Collective
3554 
3555   Input Parameters:
3556 + section   - the section
3557 . field     - the field of the section
3558 . numPoints - the number of points
3559 - points    - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an
3560     arbitrary integer: its interpretation is up to sym.  Orientations are used by `DM`: for their interpretation in that
3561     context, see `DMPlexGetConeOrientation()`).
3562 
3563   Output Parameters:
3564 + perms - The permutations for the given orientations (or `NULL` if there is no symmetry or the permutation is the identity).
3565 - rots  - The field rotations symmetries for the given orientations (or `NULL` if there is no symmetry or the rotations are all
3566     identity).
3567 
3568   Level: developer
3569 
3570   Notes:
3571   `PetscSectionSetFieldSym()` must have been previously called to provide the symmetries to the `PetscSection`
3572 
3573   Use `PetscSectionRestoreFieldPointSyms()` when finished with the data
3574 
3575 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetPointSyms()`, `PetscSectionRestoreFieldPointSyms()`
3576 @*/
3577 PetscErrorCode PetscSectionGetFieldPointSyms(PetscSection section, PetscInt field, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3578 {
3579   PetscFunctionBegin;
3580   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3581   PetscCheck(field <= section->numFields, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "field %" PetscInt_FMT " greater than number of fields (%" PetscInt_FMT ") in section", field, section->numFields);
3582   PetscCall(PetscSectionGetPointSyms(section->field[field], numPoints, points, perms, rots));
3583   PetscFunctionReturn(PETSC_SUCCESS);
3584 }
3585 
3586 /*@C
3587   PetscSectionRestoreFieldPointSyms - Restore the symmetries returned by `PetscSectionGetFieldPointSyms()`
3588 
3589   Not Collective
3590 
3591   Input Parameters:
3592 + section   - the section
3593 . field     - the field number
3594 . numPoints - the number of points
3595 . points    - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an
3596     arbitrary integer: its interpretation is up to sym.  Orientations are used by `DM`: for their interpretation in that
3597     context, see `DMPlexGetConeOrientation()`).
3598 . perms     - The permutations for the given orientations: set to NULL at conclusion
3599 - rots      - The field rotations symmetries for the given orientations: set to NULL at conclusion
3600 
3601   Level: developer
3602 
3603 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionRestorePointSyms()`, `petscSectionGetFieldPointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`
3604 @*/
3605 PetscErrorCode PetscSectionRestoreFieldPointSyms(PetscSection section, PetscInt field, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3606 {
3607   PetscFunctionBegin;
3608   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3609   PetscCheck(field <= section->numFields, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "field %" PetscInt_FMT " greater than number of fields (%" PetscInt_FMT ") in section", field, section->numFields);
3610   PetscCall(PetscSectionRestorePointSyms(section->field[field], numPoints, points, perms, rots));
3611   PetscFunctionReturn(PETSC_SUCCESS);
3612 }
3613 
3614 /*@
3615   PetscSectionSymCopy - Copy the symmetries, assuming that the point structure is compatible
3616 
3617   Not Collective
3618 
3619   Input Parameter:
3620 . sym - the `PetscSectionSym`
3621 
3622   Output Parameter:
3623 . nsym - the equivalent symmetries
3624 
3625   Level: developer
3626 
3627 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`, `PetscSectionSymLabelSetStratum()`, `PetscSectionGetPointSyms()`
3628 @*/
3629 PetscErrorCode PetscSectionSymCopy(PetscSectionSym sym, PetscSectionSym nsym)
3630 {
3631   PetscFunctionBegin;
3632   PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1);
3633   PetscValidHeaderSpecific(nsym, PETSC_SECTION_SYM_CLASSID, 2);
3634   PetscTryTypeMethod(sym, copy, nsym);
3635   PetscFunctionReturn(PETSC_SUCCESS);
3636 }
3637 
3638 /*@
3639   PetscSectionSymDistribute - Distribute the symmetries in accordance with the input `PetscSF`
3640 
3641   Collective
3642 
3643   Input Parameters:
3644 + sym         - the `PetscSectionSym`
3645 - migrationSF - the distribution map from roots to leaves
3646 
3647   Output Parameter:
3648 . dsym - the redistributed symmetries
3649 
3650   Level: developer
3651 
3652 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`, `PetscSectionSymLabelSetStratum()`, `PetscSectionGetPointSyms()`
3653 @*/
3654 PetscErrorCode PetscSectionSymDistribute(PetscSectionSym sym, PetscSF migrationSF, PetscSectionSym *dsym)
3655 {
3656   PetscFunctionBegin;
3657   PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1);
3658   PetscValidHeaderSpecific(migrationSF, PETSCSF_CLASSID, 2);
3659   PetscAssertPointer(dsym, 3);
3660   PetscTryTypeMethod(sym, distribute, migrationSF, dsym);
3661   PetscFunctionReturn(PETSC_SUCCESS);
3662 }
3663 
3664 /*@
3665   PetscSectionGetUseFieldOffsets - Get the flag indicating if field offsets are used directly in a global section, rather than just the point offset
3666 
3667   Not Collective
3668 
3669   Input Parameter:
3670 . s - the global `PetscSection`
3671 
3672   Output Parameter:
3673 . flg - the flag
3674 
3675   Level: developer
3676 
3677 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSetChart()`, `PetscSectionCreate()`
3678 @*/
3679 PetscErrorCode PetscSectionGetUseFieldOffsets(PetscSection s, PetscBool *flg)
3680 {
3681   PetscFunctionBegin;
3682   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
3683   *flg = s->useFieldOff;
3684   PetscFunctionReturn(PETSC_SUCCESS);
3685 }
3686 
3687 /*@
3688   PetscSectionSetUseFieldOffsets - Set the flag to use field offsets directly in a global section, rather than just the point offset
3689 
3690   Not Collective
3691 
3692   Input Parameters:
3693 + s   - the global `PetscSection`
3694 - flg - the flag
3695 
3696   Level: developer
3697 
3698 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetUseFieldOffsets()`, `PetscSectionSetChart()`, `PetscSectionCreate()`
3699 @*/
3700 PetscErrorCode PetscSectionSetUseFieldOffsets(PetscSection s, PetscBool flg)
3701 {
3702   PetscFunctionBegin;
3703   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
3704   s->useFieldOff = flg;
3705   PetscFunctionReturn(PETSC_SUCCESS);
3706 }
3707 
3708 #define PetscSectionExpandPoints_Loop(TYPE) \
3709   do { \
3710     PetscInt i, n, o0, o1, size; \
3711     TYPE    *a0 = (TYPE *)origArray, *a1; \
3712     PetscCall(PetscSectionGetStorageSize(s, &size)); \
3713     PetscCall(PetscMalloc1(size, &a1)); \
3714     for (i = 0; i < npoints; i++) { \
3715       PetscCall(PetscSectionGetOffset(origSection, points_[i], &o0)); \
3716       PetscCall(PetscSectionGetOffset(s, i, &o1)); \
3717       PetscCall(PetscSectionGetDof(s, i, &n)); \
3718       PetscCall(PetscMemcpy(&a1[o1], &a0[o0], n *unitsize)); \
3719     } \
3720     *newArray = (void *)a1; \
3721   } while (0)
3722 
3723 /*@
3724   PetscSectionExtractDofsFromArray - Extracts elements of an array corresponding to DOFs of specified points.
3725 
3726   Not Collective
3727 
3728   Input Parameters:
3729 + origSection - the `PetscSection` describing the layout of the array
3730 . dataType    - `MPI_Datatype` describing the data type of the array (currently only `MPIU_INT`, `MPIU_SCALAR`, `MPIU_REAL`)
3731 . origArray   - the array; its size must be equal to the storage size of `origSection`
3732 - points      - `IS` with points to extract; its indices must lie in the chart of `origSection`
3733 
3734   Output Parameters:
3735 + newSection - the new `PetscSection` describing the layout of the new array (with points renumbered 0,1,... but preserving numbers of DOFs)
3736 - newArray   - the array of the extracted DOFs; its size is the storage size of `newSection`
3737 
3738   Level: developer
3739 
3740 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetChart()`, `PetscSectionGetDof()`, `PetscSectionGetStorageSize()`, `PetscSectionCreate()`
3741 @*/
3742 PetscErrorCode PetscSectionExtractDofsFromArray(PetscSection origSection, MPI_Datatype dataType, const void *origArray, IS points, PetscSection *newSection, void *newArray[])
3743 {
3744   PetscSection    s;
3745   const PetscInt *points_;
3746   PetscInt        i, n, npoints, pStart, pEnd;
3747   PetscMPIInt     unitsize;
3748 
3749   PetscFunctionBegin;
3750   PetscValidHeaderSpecific(origSection, PETSC_SECTION_CLASSID, 1);
3751   PetscAssertPointer(origArray, 3);
3752   PetscValidHeaderSpecific(points, IS_CLASSID, 4);
3753   if (newSection) PetscAssertPointer(newSection, 5);
3754   if (newArray) PetscAssertPointer(newArray, 6);
3755   PetscCallMPI(MPI_Type_size(dataType, &unitsize));
3756   PetscCall(ISGetLocalSize(points, &npoints));
3757   PetscCall(ISGetIndices(points, &points_));
3758   PetscCall(PetscSectionGetChart(origSection, &pStart, &pEnd));
3759   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s));
3760   PetscCall(PetscSectionSetChart(s, 0, npoints));
3761   for (i = 0; i < npoints; i++) {
3762     PetscCheck(points_[i] >= pStart && points_[i] < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "point %" PetscInt_FMT " (index %" PetscInt_FMT ") in input IS out of input section's chart", points_[i], i);
3763     PetscCall(PetscSectionGetDof(origSection, points_[i], &n));
3764     PetscCall(PetscSectionSetDof(s, i, n));
3765   }
3766   PetscCall(PetscSectionSetUp(s));
3767   if (newArray) {
3768     if (dataType == MPIU_INT) {
3769       PetscSectionExpandPoints_Loop(PetscInt);
3770     } else if (dataType == MPIU_SCALAR) {
3771       PetscSectionExpandPoints_Loop(PetscScalar);
3772     } else if (dataType == MPIU_REAL) {
3773       PetscSectionExpandPoints_Loop(PetscReal);
3774     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "not implemented for this MPI_Datatype");
3775   }
3776   if (newSection) {
3777     *newSection = s;
3778   } else {
3779     PetscCall(PetscSectionDestroy(&s));
3780   }
3781   PetscCall(ISRestoreIndices(points, &points_));
3782   PetscFunctionReturn(PETSC_SUCCESS);
3783 }
3784