xref: /petsc/src/vec/is/section/interface/section.c (revision 882cb04d3cffde17d09a8aa45d5f5a7ba5f0e0ee)
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   Compare 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 /*@C
745   PetscSectionGetBlockStarts - Returns a table indicating which points start new blocks
746 
747   Not Collective
748 
749   Input Parameter:
750 . s - the `PetscSection`
751 
752   Output Parameter:
753 . blockStarts - The `PetscBT` with a 1 for each point that begins a block
754 
755   Notes:
756   The table is on [0, `pEnd` - `pStart`).
757 
758   This information is used by `DMCreateMatrix()` to create a variable block size description which is set using `MatSetVariableBlockSizes()`.
759 
760   Level: intermediate
761 
762 .seealso: [](sec_scatter), `IS`, `PetscSection`, `PetscSectionSetBlockStarts()`, `PetscSectionCreate()`, `DMCreateMatrix()`, `MatSetVariableBlockSizes()`
763 @*/
764 PetscErrorCode PetscSectionGetBlockStarts(PetscSection s, PetscBT *blockStarts)
765 {
766   PetscFunctionBegin;
767   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
768   if (blockStarts) {
769     PetscAssertPointer(blockStarts, 2);
770     *blockStarts = s->blockStarts;
771   }
772   PetscFunctionReturn(PETSC_SUCCESS);
773 }
774 
775 /*@C
776   PetscSectionSetBlockStarts - Sets a table indicating which points start new blocks
777 
778   Not Collective
779 
780   Input Parameters:
781 + s           - the `PetscSection`
782 - blockStarts - The `PetscBT` with a 1 for each point that begins a block
783 
784   Level: intermediate
785 
786   Notes:
787   The table is on [0, `pEnd` - `pStart`). PETSc takes ownership of the `PetscBT` when it is passed in and will destroy it. The user should not destroy it.
788 
789   This information is used by `DMCreateMatrix()` to create a variable block size description which is set using `MatSetVariableBlockSizes()`.
790 
791 .seealso: [](sec_scatter), `IS`, `PetscSection`, `PetscSectionGetBlockStarts()`, `PetscSectionCreate()`, `DMCreateMatrix()`, `MatSetVariableBlockSizes()`
792 @*/
793 PetscErrorCode PetscSectionSetBlockStarts(PetscSection s, PetscBT blockStarts)
794 {
795   PetscFunctionBegin;
796   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
797   if (s->blockStarts != blockStarts) {
798     PetscCall(PetscBTDestroy(&s->blockStarts));
799     s->blockStarts = blockStarts;
800   }
801   PetscFunctionReturn(PETSC_SUCCESS);
802 }
803 
804 /*@
805   PetscSectionGetPointMajor - Returns the flag for dof ordering, `PETSC_TRUE` if it is point major, `PETSC_FALSE` if it is field major
806 
807   Not Collective
808 
809   Input Parameter:
810 . s - the `PetscSection`
811 
812   Output Parameter:
813 . pm - the flag for point major ordering
814 
815   Level: intermediate
816 
817 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetPointMajor()`
818 @*/
819 PetscErrorCode PetscSectionGetPointMajor(PetscSection s, PetscBool *pm)
820 {
821   PetscFunctionBegin;
822   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
823   PetscAssertPointer(pm, 2);
824   *pm = s->pointMajor;
825   PetscFunctionReturn(PETSC_SUCCESS);
826 }
827 
828 /*@
829   PetscSectionSetPointMajor - Sets the flag for dof ordering, `PETSC_TRUE` for point major, otherwise it will be field major
830 
831   Not Collective
832 
833   Input Parameters:
834 + s  - the `PetscSection`
835 - pm - the flag for point major ordering
836 
837   Level: intermediate
838 
839   Note:
840   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.
841 
842   Point major order means the degrees of freedom are stored as follows
843 .vb
844     all the degrees of freedom for each point are stored contiguously, one point after another (respecting a permutation set with `PetscSectionSetPermutation()`)
845     for each point
846        the degrees of freedom for each field (starting with the unnamed default field) are listed in order by field
847 .ve
848 
849   Field major order means the degrees of freedom are stored as follows
850 .vb
851     all degrees of freedom for each field (including the unnamed default field) are stored contiguously, one field after another
852     for each field (started with unnamed default field)
853       the degrees of freedom for each point are listed in order by point (respecting a permutation set with `PetscSectionSetPermutation()`)
854 .ve
855 
856 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetPointMajor()`, `PetscSectionSetPermutation()`
857 @*/
858 PetscErrorCode PetscSectionSetPointMajor(PetscSection s, PetscBool pm)
859 {
860   PetscFunctionBegin;
861   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
862   PetscCheck(!s->setup, PetscObjectComm((PetscObject)s), PETSC_ERR_ARG_WRONGSTATE, "Cannot set the dof ordering after the section is setup");
863   s->pointMajor = pm;
864   PetscFunctionReturn(PETSC_SUCCESS);
865 }
866 
867 /*@
868   PetscSectionGetIncludesConstraints - Returns the flag indicating if constrained dofs were included when computing offsets in the `PetscSection`.
869   The value is set with `PetscSectionSetIncludesConstraints()`
870 
871   Not Collective
872 
873   Input Parameter:
874 . s - the `PetscSection`
875 
876   Output Parameter:
877 . includesConstraints - the flag indicating if constrained dofs were included when computing offsets
878 
879   Level: intermediate
880 
881 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetIncludesConstraints()`
882 @*/
883 PetscErrorCode PetscSectionGetIncludesConstraints(PetscSection s, PetscBool *includesConstraints)
884 {
885   PetscFunctionBegin;
886   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
887   PetscAssertPointer(includesConstraints, 2);
888   *includesConstraints = s->includesConstraints;
889   PetscFunctionReturn(PETSC_SUCCESS);
890 }
891 
892 /*@
893   PetscSectionSetIncludesConstraints - Sets the flag indicating if constrained dofs are to be included when computing offsets
894 
895   Not Collective
896 
897   Input Parameters:
898 + s                   - the `PetscSection`
899 - includesConstraints - the flag indicating if constrained dofs are to be included when computing offsets
900 
901   Level: intermediate
902 
903 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetIncludesConstraints()`
904 @*/
905 PetscErrorCode PetscSectionSetIncludesConstraints(PetscSection s, PetscBool includesConstraints)
906 {
907   PetscFunctionBegin;
908   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
909   PetscCheck(!s->setup, PetscObjectComm((PetscObject)s), PETSC_ERR_ARG_WRONGSTATE, "Cannot set includesConstraints after the section is set up");
910   s->includesConstraints = includesConstraints;
911   PetscFunctionReturn(PETSC_SUCCESS);
912 }
913 
914 /*@
915   PetscSectionGetDof - Return the total number of degrees of freedom associated with a given point.
916 
917   Not Collective
918 
919   Input Parameters:
920 + s     - the `PetscSection`
921 - point - the point
922 
923   Output Parameter:
924 . numDof - the number of dof
925 
926   Level: intermediate
927 
928   Notes:
929   In a global section, this size will be negative for points not owned by this process.
930 
931   This number is for the unnamed default field at the given point plus all degrees of freedom associated with all fields at that point
932 
933 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetDof()`, `PetscSectionCreate()`
934 @*/
935 PetscErrorCode PetscSectionGetDof(PetscSection s, PetscInt point, PetscInt *numDof)
936 {
937   PetscFunctionBeginHot;
938   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
939   PetscAssertPointer(numDof, 3);
940   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);
941   *numDof = s->atlasDof[point - s->pStart];
942   PetscFunctionReturn(PETSC_SUCCESS);
943 }
944 
945 /*@
946   PetscSectionSetDof - Sets the total number of degrees of freedom associated with a given point.
947 
948   Not Collective
949 
950   Input Parameters:
951 + s      - the `PetscSection`
952 . point  - the point
953 - numDof - the number of dof, these values may be negative -(dof+1) to indicate they are off process
954 
955   Level: intermediate
956 
957   Note:
958   This number is for the unnamed default field at the given point plus all degrees of freedom associated with all fields at that point
959 
960 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionAddDof()`, `PetscSectionCreate()`
961 @*/
962 PetscErrorCode PetscSectionSetDof(PetscSection s, PetscInt point, PetscInt numDof)
963 {
964   PetscFunctionBegin;
965   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
966   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);
967   s->atlasDof[point - s->pStart] = numDof;
968   PetscCall(PetscSectionInvalidateMaxDof_Internal(s));
969   PetscFunctionReturn(PETSC_SUCCESS);
970 }
971 
972 /*@
973   PetscSectionAddDof - Adds to the total number of degrees of freedom associated with a given point.
974 
975   Not Collective
976 
977   Input Parameters:
978 + s      - the `PetscSection`
979 . point  - the point
980 - numDof - the number of additional dof
981 
982   Level: intermediate
983 
984   Note:
985   This number is for the unnamed default field at the given point plus all degrees of freedom associated with all fields at that point
986 
987 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionSetDof()`, `PetscSectionCreate()`
988 @*/
989 PetscErrorCode PetscSectionAddDof(PetscSection s, PetscInt point, PetscInt numDof)
990 {
991   PetscFunctionBeginHot;
992   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
993   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);
994   PetscCheck(numDof >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "numDof %" PetscInt_FMT " should not be negative", numDof);
995   s->atlasDof[point - s->pStart] += numDof;
996   PetscCall(PetscSectionInvalidateMaxDof_Internal(s));
997   PetscFunctionReturn(PETSC_SUCCESS);
998 }
999 
1000 /*@
1001   PetscSectionGetFieldDof - Return the number of degrees of freedom associated with a field on a given point.
1002 
1003   Not Collective
1004 
1005   Input Parameters:
1006 + s     - the `PetscSection`
1007 . point - the point
1008 - field - the field
1009 
1010   Output Parameter:
1011 . numDof - the number of dof
1012 
1013   Level: intermediate
1014 
1015 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetFieldDof()`, `PetscSectionCreate()`
1016 @*/
1017 PetscErrorCode PetscSectionGetFieldDof(PetscSection s, PetscInt point, PetscInt field, PetscInt *numDof)
1018 {
1019   PetscFunctionBegin;
1020   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1021   PetscAssertPointer(numDof, 4);
1022   PetscSectionCheckValidField(field, s->numFields);
1023   PetscCall(PetscSectionGetDof(s->field[field], point, numDof));
1024   PetscFunctionReturn(PETSC_SUCCESS);
1025 }
1026 
1027 /*@
1028   PetscSectionSetFieldDof - Sets the number of degrees of freedom associated with a field on a given point.
1029 
1030   Not Collective
1031 
1032   Input Parameters:
1033 + s      - the `PetscSection`
1034 . point  - the point
1035 . field  - the field
1036 - numDof - the number of dof, these values may be negative -(dof+1) to indicate they are off process
1037 
1038   Level: intermediate
1039 
1040   Note:
1041   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
1042   the fields and the unnamed default field) is correct by also calling `PetscSectionAddDof()` or `PetscSectionSetDof()`
1043 
1044   This is equivalent to
1045 .vb
1046      PetscSection fs;
1047      PetscSectionGetField(s,field,&fs)
1048      PetscSectionSetDof(fs,numDof)
1049 .ve
1050 
1051 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetFieldDof()`, `PetscSectionCreate()`, `PetscSectionAddDof()`, `PetscSectionSetDof()`
1052 @*/
1053 PetscErrorCode PetscSectionSetFieldDof(PetscSection s, PetscInt point, PetscInt field, PetscInt numDof)
1054 {
1055   PetscFunctionBegin;
1056   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1057   PetscSectionCheckValidField(field, s->numFields);
1058   PetscCall(PetscSectionSetDof(s->field[field], point, numDof));
1059   PetscFunctionReturn(PETSC_SUCCESS);
1060 }
1061 
1062 /*@
1063   PetscSectionAddFieldDof - Adds a number of degrees of freedom associated with a field on a given point.
1064 
1065   Not Collective
1066 
1067   Input Parameters:
1068 + s      - the `PetscSection`
1069 . point  - the point
1070 . field  - the field
1071 - numDof - the number of dof
1072 
1073   Level: intermediate
1074 
1075   Notes:
1076   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
1077   the fields and the unnamed default field) is correct by also calling `PetscSectionAddDof()` or `PetscSectionSetDof()`
1078 
1079   This is equivalent to
1080 .vb
1081      PetscSection fs;
1082      PetscSectionGetField(s,field,&fs)
1083      PetscSectionAddDof(fs,numDof)
1084 .ve
1085 
1086 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetFieldDof()`, `PetscSectionGetFieldDof()`, `PetscSectionCreate()`
1087 @*/
1088 PetscErrorCode PetscSectionAddFieldDof(PetscSection s, PetscInt point, PetscInt field, PetscInt numDof)
1089 {
1090   PetscFunctionBegin;
1091   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1092   PetscSectionCheckValidField(field, s->numFields);
1093   PetscCall(PetscSectionAddDof(s->field[field], point, numDof));
1094   PetscFunctionReturn(PETSC_SUCCESS);
1095 }
1096 
1097 /*@
1098   PetscSectionGetConstraintDof - Return the number of constrained degrees of freedom associated with a given point.
1099 
1100   Not Collective
1101 
1102   Input Parameters:
1103 + s     - the `PetscSection`
1104 - point - the point
1105 
1106   Output Parameter:
1107 . numDof - the number of dof which are fixed by constraints
1108 
1109   Level: intermediate
1110 
1111 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionSetConstraintDof()`, `PetscSectionCreate()`
1112 @*/
1113 PetscErrorCode PetscSectionGetConstraintDof(PetscSection s, PetscInt point, PetscInt *numDof)
1114 {
1115   PetscFunctionBegin;
1116   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1117   PetscAssertPointer(numDof, 3);
1118   if (s->bc) {
1119     PetscCall(PetscSectionGetDof(s->bc, point, numDof));
1120   } else *numDof = 0;
1121   PetscFunctionReturn(PETSC_SUCCESS);
1122 }
1123 
1124 /*@
1125   PetscSectionSetConstraintDof - Set the number of constrained degrees of freedom associated with a given point.
1126 
1127   Not Collective
1128 
1129   Input Parameters:
1130 + s      - the `PetscSection`
1131 . point  - the point
1132 - numDof - the number of dof which are fixed by constraints
1133 
1134   Level: intermediate
1135 
1136 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetDof()`, `PetscSectionGetConstraintDof()`, `PetscSectionCreate()`
1137 @*/
1138 PetscErrorCode PetscSectionSetConstraintDof(PetscSection s, PetscInt point, PetscInt numDof)
1139 {
1140   PetscFunctionBegin;
1141   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1142   if (numDof) {
1143     PetscCall(PetscSectionCheckConstraints_Private(s));
1144     PetscCall(PetscSectionSetDof(s->bc, point, numDof));
1145   }
1146   PetscFunctionReturn(PETSC_SUCCESS);
1147 }
1148 
1149 /*@
1150   PetscSectionAddConstraintDof - Increment the number of constrained degrees of freedom associated with a given point.
1151 
1152   Not Collective
1153 
1154   Input Parameters:
1155 + s      - the `PetscSection`
1156 . point  - the point
1157 - numDof - the number of additional dof which are fixed by constraints
1158 
1159   Level: intermediate
1160 
1161 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionAddDof()`, `PetscSectionGetConstraintDof()`, `PetscSectionCreate()`
1162 @*/
1163 PetscErrorCode PetscSectionAddConstraintDof(PetscSection s, PetscInt point, PetscInt numDof)
1164 {
1165   PetscFunctionBegin;
1166   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1167   if (numDof) {
1168     PetscCall(PetscSectionCheckConstraints_Private(s));
1169     PetscCall(PetscSectionAddDof(s->bc, point, numDof));
1170   }
1171   PetscFunctionReturn(PETSC_SUCCESS);
1172 }
1173 
1174 /*@
1175   PetscSectionGetFieldConstraintDof - Return the number of constrained degrees of freedom associated with a given field on a point.
1176 
1177   Not Collective
1178 
1179   Input Parameters:
1180 + s     - the `PetscSection`
1181 . point - the point
1182 - field - the field
1183 
1184   Output Parameter:
1185 . numDof - the number of dof which are fixed by constraints
1186 
1187   Level: intermediate
1188 
1189 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionSetFieldConstraintDof()`, `PetscSectionCreate()`
1190 @*/
1191 PetscErrorCode PetscSectionGetFieldConstraintDof(PetscSection s, PetscInt point, PetscInt field, PetscInt *numDof)
1192 {
1193   PetscFunctionBegin;
1194   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1195   PetscAssertPointer(numDof, 4);
1196   PetscSectionCheckValidField(field, s->numFields);
1197   PetscCall(PetscSectionGetConstraintDof(s->field[field], point, numDof));
1198   PetscFunctionReturn(PETSC_SUCCESS);
1199 }
1200 
1201 /*@
1202   PetscSectionSetFieldConstraintDof - Set the number of constrained degrees of freedom associated with a given field on a point.
1203 
1204   Not Collective
1205 
1206   Input Parameters:
1207 + s      - the `PetscSection`
1208 . point  - the point
1209 . field  - the field
1210 - numDof - the number of dof which are fixed by constraints
1211 
1212   Level: intermediate
1213 
1214 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetDof()`, `PetscSectionGetFieldConstraintDof()`, `PetscSectionCreate()`
1215 @*/
1216 PetscErrorCode PetscSectionSetFieldConstraintDof(PetscSection s, PetscInt point, PetscInt field, PetscInt numDof)
1217 {
1218   PetscFunctionBegin;
1219   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1220   PetscSectionCheckValidField(field, s->numFields);
1221   PetscCall(PetscSectionSetConstraintDof(s->field[field], point, numDof));
1222   PetscFunctionReturn(PETSC_SUCCESS);
1223 }
1224 
1225 /*@
1226   PetscSectionAddFieldConstraintDof - Increment the number of constrained degrees of freedom associated with a given field on a point.
1227 
1228   Not Collective
1229 
1230   Input Parameters:
1231 + s      - the `PetscSection`
1232 . point  - the point
1233 . field  - the field
1234 - numDof - the number of additional dof which are fixed by constraints
1235 
1236   Level: intermediate
1237 
1238 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionAddDof()`, `PetscSectionGetFieldConstraintDof()`, `PetscSectionCreate()`
1239 @*/
1240 PetscErrorCode PetscSectionAddFieldConstraintDof(PetscSection s, PetscInt point, PetscInt field, PetscInt numDof)
1241 {
1242   PetscFunctionBegin;
1243   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1244   PetscSectionCheckValidField(field, s->numFields);
1245   PetscCall(PetscSectionAddConstraintDof(s->field[field], point, numDof));
1246   PetscFunctionReturn(PETSC_SUCCESS);
1247 }
1248 
1249 /*@
1250   PetscSectionSetUpBC - Setup the subsections describing boundary conditions.
1251 
1252   Not Collective
1253 
1254   Input Parameter:
1255 . s - the `PetscSection`
1256 
1257   Level: advanced
1258 
1259 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetUp()`, `PetscSectionCreate()`
1260 @*/
1261 PetscErrorCode PetscSectionSetUpBC(PetscSection s)
1262 {
1263   PetscFunctionBegin;
1264   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1265   if (s->bc) {
1266     const PetscInt last = (s->bc->pEnd - s->bc->pStart) - 1;
1267 
1268     PetscCall(PetscSectionSetUp(s->bc));
1269     PetscCall(PetscMalloc1((last >= 0 ? s->bc->atlasOff[last] + s->bc->atlasDof[last] : 0), &s->bcIndices));
1270   }
1271   PetscFunctionReturn(PETSC_SUCCESS);
1272 }
1273 
1274 /*@
1275   PetscSectionSetUp - Calculate offsets based upon the number of degrees of freedom for each point in preparation for use of the `PetscSection`
1276 
1277   Not Collective
1278 
1279   Input Parameter:
1280 . s - the `PetscSection`
1281 
1282   Level: intermediate
1283 
1284   Notes:
1285   If used, `PetscSectionSetPermutation()` must be called before this routine.
1286 
1287   `PetscSectionSetPointMajor()`, cannot be called after this routine.
1288 
1289 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionSetPermutation()`
1290 @*/
1291 PetscErrorCode PetscSectionSetUp(PetscSection s)
1292 {
1293   const PetscInt *pind   = NULL;
1294   PetscInt        offset = 0, foff, p, f;
1295 
1296   PetscFunctionBegin;
1297   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1298   if (s->setup) PetscFunctionReturn(PETSC_SUCCESS);
1299   s->setup = PETSC_TRUE;
1300   /* Set offsets and field offsets for all points */
1301   /*   Assume that all fields have the same chart */
1302   PetscCheck(s->includesConstraints, PETSC_COMM_SELF, PETSC_ERR_SUP, "PetscSectionSetUp is currently unsupported for includesConstraints = PETSC_TRUE");
1303   if (s->perm) PetscCall(ISGetIndices(s->perm, &pind));
1304   if (s->pointMajor) {
1305     for (p = 0; p < s->pEnd - s->pStart; ++p) {
1306       const PetscInt q = pind ? pind[p] : p;
1307 
1308       /* Set point offset */
1309       s->atlasOff[q] = offset;
1310       offset += s->atlasDof[q];
1311       /* Set field offset */
1312       for (f = 0, foff = s->atlasOff[q]; f < s->numFields; ++f) {
1313         PetscSection sf = s->field[f];
1314 
1315         sf->atlasOff[q] = foff;
1316         foff += sf->atlasDof[q];
1317       }
1318     }
1319   } else {
1320     /* Set field offsets for all points */
1321     for (f = 0; f < s->numFields; ++f) {
1322       PetscSection sf = s->field[f];
1323 
1324       for (p = 0; p < s->pEnd - s->pStart; ++p) {
1325         const PetscInt q = pind ? pind[p] : p;
1326 
1327         sf->atlasOff[q] = offset;
1328         offset += sf->atlasDof[q];
1329       }
1330     }
1331     /* Disable point offsets since these are unused */
1332     for (p = 0; p < s->pEnd - s->pStart; ++p) s->atlasOff[p] = -1;
1333   }
1334   if (s->perm) PetscCall(ISRestoreIndices(s->perm, &pind));
1335   /* Setup BC sections */
1336   PetscCall(PetscSectionSetUpBC(s));
1337   for (f = 0; f < s->numFields; ++f) PetscCall(PetscSectionSetUpBC(s->field[f]));
1338   PetscFunctionReturn(PETSC_SUCCESS);
1339 }
1340 
1341 /*@
1342   PetscSectionGetMaxDof - Return the maximum number of degrees of freedom on any point in the `PetscSection`
1343 
1344   Not Collective
1345 
1346   Input Parameter:
1347 . s - the `PetscSection`
1348 
1349   Output Parameter:
1350 . maxDof - the maximum dof
1351 
1352   Level: intermediate
1353 
1354   Notes:
1355   The returned number is up-to-date without need for `PetscSectionSetUp()`.
1356 
1357   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
1358   the maximum over all points of the value returned by `PetscSectionGetDof()` on this MPI process
1359 
1360   Developer Notes:
1361   The returned number is calculated lazily and stashed.
1362 
1363   A call to `PetscSectionInvalidateMaxDof_Internal()` invalidates the stashed value.
1364 
1365   `PetscSectionInvalidateMaxDof_Internal()` is called in `PetscSectionSetDof()`, `PetscSectionAddDof()` and `PetscSectionReset()`
1366 
1367   It should also be called every time `atlasDof` is modified directly.
1368 
1369 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionSetDof()`, `PetscSectionAddDof()`, `PetscSectionCreate()`
1370 @*/
1371 PetscErrorCode PetscSectionGetMaxDof(PetscSection s, PetscInt *maxDof)
1372 {
1373   PetscInt p;
1374 
1375   PetscFunctionBegin;
1376   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1377   PetscAssertPointer(maxDof, 2);
1378   if (s->maxDof == PETSC_MIN_INT) {
1379     s->maxDof = 0;
1380     for (p = 0; p < s->pEnd - s->pStart; ++p) s->maxDof = PetscMax(s->maxDof, s->atlasDof[p]);
1381   }
1382   *maxDof = s->maxDof;
1383   PetscFunctionReturn(PETSC_SUCCESS);
1384 }
1385 
1386 /*@
1387   PetscSectionGetStorageSize - Return the size of an array or local `Vec` capable of holding all the degrees of freedom defined in a `PetscSection`
1388 
1389   Not Collective
1390 
1391   Input Parameter:
1392 . s - the `PetscSection`
1393 
1394   Output Parameter:
1395 . size - the size of an array which can hold all the dofs
1396 
1397   Level: intermediate
1398 
1399 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionGetConstrainedStorageSize()`, `PetscSectionCreate()`
1400 @*/
1401 PetscErrorCode PetscSectionGetStorageSize(PetscSection s, PetscInt *size)
1402 {
1403   PetscInt p, n = 0;
1404 
1405   PetscFunctionBegin;
1406   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1407   PetscAssertPointer(size, 2);
1408   for (p = 0; p < s->pEnd - s->pStart; ++p) n += s->atlasDof[p] > 0 ? s->atlasDof[p] : 0;
1409   *size = n;
1410   PetscFunctionReturn(PETSC_SUCCESS);
1411 }
1412 
1413 /*@
1414   PetscSectionGetConstrainedStorageSize - Return the size of an array or local `Vec` capable of holding all unconstrained degrees of freedom in a `PetscSection`
1415 
1416   Not Collective
1417 
1418   Input Parameter:
1419 . s - the `PetscSection`
1420 
1421   Output Parameter:
1422 . size - the size of an array which can hold all unconstrained dofs
1423 
1424   Level: intermediate
1425 
1426 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetStorageSize()`, `PetscSectionGetOffset()`, `PetscSectionCreate()`
1427 @*/
1428 PetscErrorCode PetscSectionGetConstrainedStorageSize(PetscSection s, PetscInt *size)
1429 {
1430   PetscInt p, n = 0;
1431 
1432   PetscFunctionBegin;
1433   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1434   PetscAssertPointer(size, 2);
1435   for (p = 0; p < s->pEnd - s->pStart; ++p) {
1436     const PetscInt cdof = s->bc ? s->bc->atlasDof[p] : 0;
1437     n += s->atlasDof[p] > 0 ? s->atlasDof[p] - cdof : 0;
1438   }
1439   *size = n;
1440   PetscFunctionReturn(PETSC_SUCCESS);
1441 }
1442 
1443 /*@
1444   PetscSectionCreateGlobalSection - Create a parallel section describing the global layout using
1445   a local (sequential) `PetscSection` on each MPI process and a `PetscSF` describing the section point overlap.
1446 
1447   Input Parameters:
1448 + s                  - The `PetscSection` for the local field layout
1449 . sf                 - The `PetscSF` describing parallel layout of the section points (leaves are unowned local points)
1450 . includeConstraints - By default this is `PETSC_FALSE`, meaning that the global field vector will not possess constrained dofs
1451 - localOffsets       - If `PETSC_TRUE`, use local rather than global offsets for the points
1452 
1453   Output Parameter:
1454 . gsection - The `PetscSection` for the global field layout
1455 
1456   Level: intermediate
1457 
1458   Notes:
1459   On each MPI process `gsection` inherits the chart of the `s` on that process.
1460 
1461   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`.
1462   In those locations the value of size is -(size+1) and the value of the offset on the remote process is -(off+1).
1463 
1464 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionCreateGlobalSectionCensored()`
1465 @*/
1466 PetscErrorCode PetscSectionCreateGlobalSection(PetscSection s, PetscSF sf, PetscBool includeConstraints, PetscBool localOffsets, PetscSection *gsection)
1467 {
1468   PetscSection    gs;
1469   const PetscInt *pind = NULL;
1470   PetscInt       *recv = NULL, *neg = NULL;
1471   PetscInt        pStart, pEnd, p, dof, cdof, off, foff, globalOff = 0, nroots, nlocal, maxleaf;
1472   PetscInt        numFields, f, numComponents;
1473 
1474   PetscFunctionBegin;
1475   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1476   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
1477   PetscValidLogicalCollectiveBool(s, includeConstraints, 3);
1478   PetscValidLogicalCollectiveBool(s, localOffsets, 4);
1479   PetscAssertPointer(gsection, 5);
1480   PetscCheck(s->pointMajor, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for field major ordering");
1481   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), &gs));
1482   PetscCall(PetscSectionGetNumFields(s, &numFields));
1483   if (numFields > 0) PetscCall(PetscSectionSetNumFields(gs, numFields));
1484   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
1485   PetscCall(PetscSectionSetChart(gs, pStart, pEnd));
1486   gs->includesConstraints = includeConstraints;
1487   PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL));
1488   nlocal = nroots; /* The local/leaf space matches global/root space */
1489   /* Must allocate for all points visible to SF, which may be more than this section */
1490   if (nroots >= 0) { /* nroots < 0 means that the graph has not been set, only happens in serial */
1491     PetscCall(PetscSFGetLeafRange(sf, NULL, &maxleaf));
1492     PetscCheck(nroots >= pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "SF roots %" PetscInt_FMT " < pEnd %" PetscInt_FMT, nroots, pEnd);
1493     PetscCheck(maxleaf < nroots, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Max local leaf %" PetscInt_FMT " >= nroots %" PetscInt_FMT, maxleaf, nroots);
1494     PetscCall(PetscMalloc2(nroots, &neg, nlocal, &recv));
1495     PetscCall(PetscArrayzero(neg, nroots));
1496   }
1497   /* Mark all local points with negative dof */
1498   for (p = pStart; p < pEnd; ++p) {
1499     PetscCall(PetscSectionGetDof(s, p, &dof));
1500     PetscCall(PetscSectionSetDof(gs, p, dof));
1501     PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
1502     if (!includeConstraints && cdof > 0) PetscCall(PetscSectionSetConstraintDof(gs, p, cdof));
1503     if (neg) neg[p] = -(dof + 1);
1504   }
1505   PetscCall(PetscSectionSetUpBC(gs));
1506   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]));
1507   if (nroots >= 0) {
1508     PetscCall(PetscArrayzero(recv, nlocal));
1509     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, recv, MPI_REPLACE));
1510     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, recv, MPI_REPLACE));
1511     for (p = pStart; p < pEnd; ++p) {
1512       if (recv[p] < 0) {
1513         gs->atlasDof[p - pStart] = recv[p];
1514         PetscCall(PetscSectionGetDof(s, p, &dof));
1515         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);
1516       }
1517     }
1518   }
1519   /* Calculate new sizes, get process offset, and calculate point offsets */
1520   if (s->perm) PetscCall(ISGetIndices(s->perm, &pind));
1521   for (p = 0, off = 0; p < pEnd - pStart; ++p) {
1522     const PetscInt q = pind ? pind[p] : p;
1523 
1524     cdof            = (!includeConstraints && s->bc) ? s->bc->atlasDof[q] : 0;
1525     gs->atlasOff[q] = off;
1526     off += gs->atlasDof[q] > 0 ? gs->atlasDof[q] - cdof : 0;
1527   }
1528   if (!localOffsets) {
1529     PetscCallMPI(MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)s)));
1530     globalOff -= off;
1531   }
1532   for (p = pStart, off = 0; p < pEnd; ++p) {
1533     gs->atlasOff[p - pStart] += globalOff;
1534     if (neg) neg[p] = -(gs->atlasOff[p - pStart] + 1);
1535   }
1536   if (s->perm) PetscCall(ISRestoreIndices(s->perm, &pind));
1537   /* Put in negative offsets for ghost points */
1538   if (nroots >= 0) {
1539     PetscCall(PetscArrayzero(recv, nlocal));
1540     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, recv, MPI_REPLACE));
1541     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, recv, MPI_REPLACE));
1542     for (p = pStart; p < pEnd; ++p) {
1543       if (recv[p] < 0) gs->atlasOff[p - pStart] = recv[p];
1544     }
1545   }
1546   PetscCall(PetscFree2(neg, recv));
1547   /* Set field dofs/offsets/constraints */
1548   for (f = 0; f < numFields; ++f) {
1549     gs->field[f]->includesConstraints = includeConstraints;
1550     PetscCall(PetscSectionGetFieldComponents(s, f, &numComponents));
1551     PetscCall(PetscSectionSetFieldComponents(gs, f, numComponents));
1552   }
1553   for (p = pStart; p < pEnd; ++p) {
1554     PetscCall(PetscSectionGetOffset(gs, p, &off));
1555     for (f = 0, foff = off; f < numFields; ++f) {
1556       PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cdof));
1557       if (!includeConstraints && cdof > 0) PetscCall(PetscSectionSetFieldConstraintDof(gs, p, f, cdof));
1558       PetscCall(PetscSectionGetFieldDof(s, p, f, &dof));
1559       PetscCall(PetscSectionSetFieldDof(gs, p, f, off < 0 ? -(dof + 1) : dof));
1560       PetscCall(PetscSectionSetFieldOffset(gs, p, f, foff));
1561       PetscCall(PetscSectionGetFieldConstraintDof(gs, p, f, &cdof));
1562       foff = off < 0 ? foff - (dof - cdof) : foff + (dof - cdof);
1563     }
1564   }
1565   for (f = 0; f < numFields; ++f) {
1566     PetscSection gfs = gs->field[f];
1567 
1568     PetscCall(PetscSectionSetUpBC(gfs));
1569     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]));
1570   }
1571   gs->setup = PETSC_TRUE;
1572   PetscCall(PetscSectionViewFromOptions(gs, NULL, "-global_section_view"));
1573   *gsection = gs;
1574   PetscFunctionReturn(PETSC_SUCCESS);
1575 }
1576 
1577 /*@
1578   PetscSectionCreateGlobalSectionCensored - Create a `PetscSection` describing the globallayout using
1579   a local (sequential) `PetscSection` on each MPI process and an `PetscSF` describing the section point overlap.
1580 
1581   Input Parameters:
1582 + s                  - The `PetscSection` for the local field layout
1583 . sf                 - The `PetscSF` describing parallel layout of the section points
1584 . includeConstraints - By default this is `PETSC_FALSE`, meaning that the global vector will not possess constrained dofs
1585 . numExcludes        - The number of exclusion ranges, this must have the same value on all MPI processes
1586 - 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
1587 
1588   Output Parameter:
1589 . gsection - The `PetscSection` for the global field layout
1590 
1591   Level: advanced
1592 
1593   Notes:
1594   On each MPI process `gsection` inherits the chart of the `s` on that process.
1595 
1596   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`.
1597   In those locations the value of size is -(size+1) and the value of the offset on the remote process is -(off+1).
1598 
1599   This routine augments `PetscSectionCreateGlobalSection()` by allowing one to exclude certain ranges in the chart of the `PetscSection`
1600 
1601   Developer Notes:
1602   This is a terrible function name
1603 
1604 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`
1605 @*/
1606 PetscErrorCode PetscSectionCreateGlobalSectionCensored(PetscSection s, PetscSF sf, PetscBool includeConstraints, PetscInt numExcludes, const PetscInt excludes[], PetscSection *gsection)
1607 {
1608   const PetscInt *pind = NULL;
1609   PetscInt       *neg = NULL, *tmpOff = NULL;
1610   PetscInt        pStart, pEnd, p, e, dof, cdof, off, globalOff = 0, nroots;
1611 
1612   PetscFunctionBegin;
1613   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1614   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
1615   PetscAssertPointer(gsection, 6);
1616   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), gsection));
1617   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
1618   PetscCall(PetscSectionSetChart(*gsection, pStart, pEnd));
1619   PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL));
1620   if (nroots >= 0) {
1621     PetscCheck(nroots >= pEnd - pStart, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %" PetscInt_FMT " < %" PetscInt_FMT " section size", nroots, pEnd - pStart);
1622     PetscCall(PetscCalloc1(nroots, &neg));
1623     if (nroots > pEnd - pStart) {
1624       PetscCall(PetscCalloc1(nroots, &tmpOff));
1625     } else {
1626       tmpOff = &(*gsection)->atlasDof[-pStart];
1627     }
1628   }
1629   /* Mark ghost points with negative dof */
1630   for (p = pStart; p < pEnd; ++p) {
1631     for (e = 0; e < numExcludes; ++e) {
1632       if ((p >= excludes[e * 2 + 0]) && (p < excludes[e * 2 + 1])) {
1633         PetscCall(PetscSectionSetDof(*gsection, p, 0));
1634         break;
1635       }
1636     }
1637     if (e < numExcludes) continue;
1638     PetscCall(PetscSectionGetDof(s, p, &dof));
1639     PetscCall(PetscSectionSetDof(*gsection, p, dof));
1640     PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
1641     if (!includeConstraints && cdof > 0) PetscCall(PetscSectionSetConstraintDof(*gsection, p, cdof));
1642     if (neg) neg[p] = -(dof + 1);
1643   }
1644   PetscCall(PetscSectionSetUpBC(*gsection));
1645   if (nroots >= 0) {
1646     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
1647     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
1648     if (nroots > pEnd - pStart) {
1649       for (p = pStart; p < pEnd; ++p) {
1650         if (tmpOff[p] < 0) (*gsection)->atlasDof[p - pStart] = tmpOff[p];
1651       }
1652     }
1653   }
1654   /* Calculate new sizes, get process offset, and calculate point offsets */
1655   if (s->perm) PetscCall(ISGetIndices(s->perm, &pind));
1656   for (p = 0, off = 0; p < pEnd - pStart; ++p) {
1657     const PetscInt q = pind ? pind[p] : p;
1658 
1659     cdof                     = (!includeConstraints && s->bc) ? s->bc->atlasDof[q] : 0;
1660     (*gsection)->atlasOff[q] = off;
1661     off += (*gsection)->atlasDof[q] > 0 ? (*gsection)->atlasDof[q] - cdof : 0;
1662   }
1663   PetscCallMPI(MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)s)));
1664   globalOff -= off;
1665   for (p = 0, off = 0; p < pEnd - pStart; ++p) {
1666     (*gsection)->atlasOff[p] += globalOff;
1667     if (neg) neg[p + pStart] = -((*gsection)->atlasOff[p] + 1);
1668   }
1669   if (s->perm) PetscCall(ISRestoreIndices(s->perm, &pind));
1670   /* Put in negative offsets for ghost points */
1671   if (nroots >= 0) {
1672     if (nroots == pEnd - pStart) tmpOff = &(*gsection)->atlasOff[-pStart];
1673     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
1674     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
1675     if (nroots > pEnd - pStart) {
1676       for (p = pStart; p < pEnd; ++p) {
1677         if (tmpOff[p] < 0) (*gsection)->atlasOff[p - pStart] = tmpOff[p];
1678       }
1679     }
1680   }
1681   if (nroots >= 0 && nroots > pEnd - pStart) PetscCall(PetscFree(tmpOff));
1682   PetscCall(PetscFree(neg));
1683   PetscFunctionReturn(PETSC_SUCCESS);
1684 }
1685 
1686 /*@
1687   PetscSectionGetPointLayout - Get a `PetscLayout` for the points with nonzero dof counts of the unnamed default field within this `PetscSection`s local chart
1688 
1689   Collective
1690 
1691   Input Parameters:
1692 + comm - The `MPI_Comm`
1693 - s    - The `PetscSection`
1694 
1695   Output Parameter:
1696 . layout - The point layout for the data that defines the section
1697 
1698   Level: advanced
1699 
1700   Notes:
1701   `PetscSectionGetValueLayout()` provides similar information but counting the total number of degrees of freedom on the MPI process (excluding constrained
1702   degrees of freedom).
1703 
1704   This count includes constrained degrees of freedom
1705 
1706   This is usually called on the default global section.
1707 
1708   Example:
1709 .vb
1710      The chart is [2,5), point 2 has 2 dof, point 3 has 0 dof, point 4 has 1 dof
1711      The local size of the `PetscLayout` is 2 since 2 points have a non-zero number of dof
1712 .ve
1713 
1714   Developer Notes:
1715   I find the names of these two functions extremely non-informative
1716 
1717 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetValueLayout()`, `PetscSectionCreate()`
1718 @*/
1719 PetscErrorCode PetscSectionGetPointLayout(MPI_Comm comm, PetscSection s, PetscLayout *layout)
1720 {
1721   PetscInt pStart, pEnd, p, localSize = 0;
1722 
1723   PetscFunctionBegin;
1724   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
1725   for (p = pStart; p < pEnd; ++p) {
1726     PetscInt dof;
1727 
1728     PetscCall(PetscSectionGetDof(s, p, &dof));
1729     if (dof >= 0) ++localSize;
1730   }
1731   PetscCall(PetscLayoutCreate(comm, layout));
1732   PetscCall(PetscLayoutSetLocalSize(*layout, localSize));
1733   PetscCall(PetscLayoutSetBlockSize(*layout, 1));
1734   PetscCall(PetscLayoutSetUp(*layout));
1735   PetscFunctionReturn(PETSC_SUCCESS);
1736 }
1737 
1738 /*@
1739   PetscSectionGetValueLayout - Get the `PetscLayout` associated with the section dofs of a `PetscSection`
1740 
1741   Collective
1742 
1743   Input Parameters:
1744 + comm - The `MPI_Comm`
1745 - s    - The `PetscSection`
1746 
1747   Output Parameter:
1748 . layout - The dof layout for the section
1749 
1750   Level: advanced
1751 
1752   Notes:
1753   `PetscSectionGetPointLayout()` provides similar information but only counting the number of points with nonzero degrees of freedom and
1754   including the constrained degrees of freedom
1755 
1756   This is usually called for the default global section.
1757 
1758   Example:
1759 .vb
1760      The chart is [2,5), point 2 has 4 dof (2 constrained), point 3 has 0 dof, point 4 has 1 dof (not constrained)
1761      The local size of the `PetscLayout` is 3 since there are 3 unconstrained degrees of freedom on this MPI process
1762 .ve
1763 
1764 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetPointLayout()`, `PetscSectionCreate()`
1765 @*/
1766 PetscErrorCode PetscSectionGetValueLayout(MPI_Comm comm, PetscSection s, PetscLayout *layout)
1767 {
1768   PetscInt pStart, pEnd, p, localSize = 0;
1769 
1770   PetscFunctionBegin;
1771   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 2);
1772   PetscAssertPointer(layout, 3);
1773   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
1774   for (p = pStart; p < pEnd; ++p) {
1775     PetscInt dof, cdof;
1776 
1777     PetscCall(PetscSectionGetDof(s, p, &dof));
1778     PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
1779     if (dof - cdof > 0) localSize += dof - cdof;
1780   }
1781   PetscCall(PetscLayoutCreate(comm, layout));
1782   PetscCall(PetscLayoutSetLocalSize(*layout, localSize));
1783   PetscCall(PetscLayoutSetBlockSize(*layout, 1));
1784   PetscCall(PetscLayoutSetUp(*layout));
1785   PetscFunctionReturn(PETSC_SUCCESS);
1786 }
1787 
1788 /*@
1789   PetscSectionGetOffset - Return the offset into an array or `Vec` for the dof associated with the given point.
1790 
1791   Not Collective
1792 
1793   Input Parameters:
1794 + s     - the `PetscSection`
1795 - point - the point
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   This is for the unnamed default field in the `PetscSection` not the named fields
1806 
1807   The `offset` values are different depending on a value set with `PetscSectionSetPointMajor()`
1808 
1809 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetFieldOffset()`, `PetscSectionCreate()`, `PetscSectionSetPointMajor()`
1810 @*/
1811 PetscErrorCode PetscSectionGetOffset(PetscSection s, PetscInt point, PetscInt *offset)
1812 {
1813   PetscFunctionBegin;
1814   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1815   PetscAssertPointer(offset, 3);
1816   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);
1817   *offset = s->atlasOff[point - s->pStart];
1818   PetscFunctionReturn(PETSC_SUCCESS);
1819 }
1820 
1821 /*@
1822   PetscSectionSetOffset - Set the offset into an array or `Vec` for the dof associated with the given point.
1823 
1824   Not Collective
1825 
1826   Input Parameters:
1827 + s      - the `PetscSection`
1828 . point  - the point
1829 - offset - the offset, these values may be negative indicating the values are off process
1830 
1831   Level: developer
1832 
1833   Note:
1834   The user usually does not call this function, but uses `PetscSectionSetUp()`
1835 
1836 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetFieldOffset()`, `PetscSectionCreate()`, `PetscSectionSetUp()`
1837 @*/
1838 PetscErrorCode PetscSectionSetOffset(PetscSection s, PetscInt point, PetscInt offset)
1839 {
1840   PetscFunctionBegin;
1841   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1842   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);
1843   s->atlasOff[point - s->pStart] = offset;
1844   PetscFunctionReturn(PETSC_SUCCESS);
1845 }
1846 
1847 /*@
1848   PetscSectionGetFieldOffset - Return the offset into an array or `Vec` for the field dof associated with the given point.
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: intermediate
1861 
1862   Notes:
1863   In a global section, `offset` will be negative for points not owned by this process.
1864 
1865   The `offset` values are different depending on a value set with `PetscSectionSetPointMajor()`
1866 
1867 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionCreate()`, `PetscSectionGetFieldPointOffset()`
1868 @*/
1869 PetscErrorCode PetscSectionGetFieldOffset(PetscSection s, PetscInt point, PetscInt field, PetscInt *offset)
1870 {
1871   PetscFunctionBegin;
1872   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1873   PetscAssertPointer(offset, 4);
1874   PetscSectionCheckValidField(field, s->numFields);
1875   PetscCall(PetscSectionGetOffset(s->field[field], point, offset));
1876   PetscFunctionReturn(PETSC_SUCCESS);
1877 }
1878 
1879 /*@
1880   PetscSectionSetFieldOffset - Set the offset into an array or `Vec` for the dof associated with the given field at a point.
1881 
1882   Not Collective
1883 
1884   Input Parameters:
1885 + s      - the `PetscSection`
1886 . point  - the point
1887 . field  - the field
1888 - offset - the offset, these values may be negative indicating the values are off process
1889 
1890   Level: developer
1891 
1892   Note:
1893   The user usually does not call this function, but uses `PetscSectionSetUp()`
1894 
1895 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetFieldOffset()`, `PetscSectionSetOffset()`, `PetscSectionCreate()`, `PetscSectionSetUp()`
1896 @*/
1897 PetscErrorCode PetscSectionSetFieldOffset(PetscSection s, PetscInt point, PetscInt field, PetscInt offset)
1898 {
1899   PetscFunctionBegin;
1900   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1901   PetscSectionCheckValidField(field, s->numFields);
1902   PetscCall(PetscSectionSetOffset(s->field[field], point, offset));
1903   PetscFunctionReturn(PETSC_SUCCESS);
1904 }
1905 
1906 /*@
1907   PetscSectionGetFieldPointOffset - Return the offset for the first field dof associated with the given point relative to the offset for that point for the
1908   unnamed default field's first dof
1909 
1910   Not Collective
1911 
1912   Input Parameters:
1913 + s     - the `PetscSection`
1914 . point - the point
1915 - field - the field
1916 
1917   Output Parameter:
1918 . offset - the offset
1919 
1920   Level: advanced
1921 
1922   Note:
1923   This ignores constraints
1924 
1925   Example:
1926 .vb
1927   if PetscSectionSetPointMajor(s,PETSC_TRUE)
1928   The unnamed default field has 3 dof at `point`
1929   Field 0 has 2 dof at `point`
1930   Then PetscSectionGetFieldPointOffset(s,point,1,&offset) returns and offset of 5
1931 .ve
1932 
1933 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionCreate()`, `PetscSectionGetFieldOffset()`
1934 @*/
1935 PetscErrorCode PetscSectionGetFieldPointOffset(PetscSection s, PetscInt point, PetscInt field, PetscInt *offset)
1936 {
1937   PetscInt off, foff;
1938 
1939   PetscFunctionBegin;
1940   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1941   PetscAssertPointer(offset, 4);
1942   PetscSectionCheckValidField(field, s->numFields);
1943   PetscCall(PetscSectionGetOffset(s, point, &off));
1944   PetscCall(PetscSectionGetOffset(s->field[field], point, &foff));
1945   *offset = foff - off;
1946   PetscFunctionReturn(PETSC_SUCCESS);
1947 }
1948 
1949 /*@
1950   PetscSectionGetOffsetRange - Return the full range of offsets [`start`, `end`) for a `PetscSection`
1951 
1952   Not Collective
1953 
1954   Input Parameter:
1955 . s - the `PetscSection`
1956 
1957   Output Parameters:
1958 + start - the minimum offset
1959 - end   - one more than the maximum offset
1960 
1961   Level: intermediate
1962 
1963 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionCreate()`
1964 @*/
1965 PetscErrorCode PetscSectionGetOffsetRange(PetscSection s, PetscInt *start, PetscInt *end)
1966 {
1967   PetscInt os = 0, oe = 0, pStart, pEnd, p;
1968 
1969   PetscFunctionBegin;
1970   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1971   if (s->atlasOff) {
1972     os = s->atlasOff[0];
1973     oe = s->atlasOff[0];
1974   }
1975   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
1976   for (p = 0; p < pEnd - pStart; ++p) {
1977     PetscInt dof = s->atlasDof[p], off = s->atlasOff[p];
1978 
1979     if (off >= 0) {
1980       os = PetscMin(os, off);
1981       oe = PetscMax(oe, off + dof);
1982     }
1983   }
1984   if (start) *start = os;
1985   if (end) *end = oe;
1986   PetscFunctionReturn(PETSC_SUCCESS);
1987 }
1988 
1989 /*@
1990   PetscSectionCreateSubsection - Create a new, smaller `PetscSection` composed of only selected fields
1991 
1992   Collective
1993 
1994   Input Parameters:
1995 + s      - the `PetscSection`
1996 . len    - the number of subfields
1997 - fields - the subfield numbers
1998 
1999   Output Parameter:
2000 . subs - the subsection
2001 
2002   Level: advanced
2003 
2004   Notes:
2005   The chart of `subs` is the same as the chart of `s`
2006 
2007   This will error if a fieldnumber is out of range
2008 
2009 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreateSupersection()`, `PetscSectionCreate()`
2010 @*/
2011 PetscErrorCode PetscSectionCreateSubsection(PetscSection s, PetscInt len, const PetscInt fields[], PetscSection *subs)
2012 {
2013   PetscInt nF, f, c, pStart, pEnd, p, maxCdof = 0;
2014 
2015   PetscFunctionBegin;
2016   if (!len) PetscFunctionReturn(PETSC_SUCCESS);
2017   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2018   PetscAssertPointer(fields, 3);
2019   PetscAssertPointer(subs, 4);
2020   PetscCall(PetscSectionGetNumFields(s, &nF));
2021   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);
2022   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), subs));
2023   PetscCall(PetscSectionSetNumFields(*subs, len));
2024   for (f = 0; f < len; ++f) {
2025     const char     *name    = NULL;
2026     PetscInt        numComp = 0;
2027     PetscSectionSym sym;
2028 
2029     PetscCall(PetscSectionGetFieldName(s, fields[f], &name));
2030     PetscCall(PetscSectionSetFieldName(*subs, f, name));
2031     PetscCall(PetscSectionGetFieldComponents(s, fields[f], &numComp));
2032     PetscCall(PetscSectionSetFieldComponents(*subs, f, numComp));
2033     for (c = 0; c < s->numFieldComponents[fields[f]]; ++c) {
2034       PetscCall(PetscSectionGetComponentName(s, fields[f], c, &name));
2035       PetscCall(PetscSectionSetComponentName(*subs, f, c, name));
2036     }
2037     PetscCall(PetscSectionGetFieldSym(s, fields[f], &sym));
2038     PetscCall(PetscSectionSetFieldSym(*subs, f, sym));
2039   }
2040   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
2041   PetscCall(PetscSectionSetChart(*subs, pStart, pEnd));
2042   for (p = pStart; p < pEnd; ++p) {
2043     PetscInt dof = 0, cdof = 0, fdof = 0, cfdof = 0;
2044 
2045     for (f = 0; f < len; ++f) {
2046       PetscCall(PetscSectionGetFieldDof(s, p, fields[f], &fdof));
2047       PetscCall(PetscSectionSetFieldDof(*subs, p, f, fdof));
2048       PetscCall(PetscSectionGetFieldConstraintDof(s, p, fields[f], &cfdof));
2049       if (cfdof) PetscCall(PetscSectionSetFieldConstraintDof(*subs, p, f, cfdof));
2050       dof += fdof;
2051       cdof += cfdof;
2052     }
2053     PetscCall(PetscSectionSetDof(*subs, p, dof));
2054     if (cdof) PetscCall(PetscSectionSetConstraintDof(*subs, p, cdof));
2055     maxCdof = PetscMax(cdof, maxCdof);
2056   }
2057   PetscCall(PetscSectionSetUp(*subs));
2058   if (maxCdof) {
2059     PetscInt *indices;
2060 
2061     PetscCall(PetscMalloc1(maxCdof, &indices));
2062     for (p = pStart; p < pEnd; ++p) {
2063       PetscInt cdof;
2064 
2065       PetscCall(PetscSectionGetConstraintDof(*subs, p, &cdof));
2066       if (cdof) {
2067         const PetscInt *oldIndices = NULL;
2068         PetscInt        fdof = 0, cfdof = 0, fc, numConst = 0, fOff = 0;
2069 
2070         for (f = 0; f < len; ++f) {
2071           PetscCall(PetscSectionGetFieldDof(s, p, fields[f], &fdof));
2072           PetscCall(PetscSectionGetFieldConstraintDof(s, p, fields[f], &cfdof));
2073           PetscCall(PetscSectionGetFieldConstraintIndices(s, p, fields[f], &oldIndices));
2074           PetscCall(PetscSectionSetFieldConstraintIndices(*subs, p, f, oldIndices));
2075           for (fc = 0; fc < cfdof; ++fc) indices[numConst + fc] = oldIndices[fc] + fOff;
2076           numConst += cfdof;
2077           fOff += fdof;
2078         }
2079         PetscCall(PetscSectionSetConstraintIndices(*subs, p, indices));
2080       }
2081     }
2082     PetscCall(PetscFree(indices));
2083   }
2084   PetscFunctionReturn(PETSC_SUCCESS);
2085 }
2086 
2087 /*@
2088   PetscSectionCreateSupersection - Create a new, larger section composed of multiple `PetscSection`s
2089 
2090   Collective
2091 
2092   Input Parameters:
2093 + s   - the input sections
2094 - len - the number of input sections
2095 
2096   Output Parameter:
2097 . supers - the supersection
2098 
2099   Level: advanced
2100 
2101   Notes:
2102   The section offsets now refer to a new, larger vector.
2103 
2104   Developer Notes:
2105   Needs to explain how the sections are composed
2106 
2107 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreateSubsection()`, `PetscSectionCreate()`
2108 @*/
2109 PetscErrorCode PetscSectionCreateSupersection(PetscSection s[], PetscInt len, PetscSection *supers)
2110 {
2111   PetscInt Nf = 0, f, pStart = PETSC_MAX_INT, pEnd = 0, p, maxCdof = 0, i;
2112 
2113   PetscFunctionBegin;
2114   if (!len) PetscFunctionReturn(PETSC_SUCCESS);
2115   for (i = 0; i < len; ++i) {
2116     PetscInt nf, pStarti, pEndi;
2117 
2118     PetscCall(PetscSectionGetNumFields(s[i], &nf));
2119     PetscCall(PetscSectionGetChart(s[i], &pStarti, &pEndi));
2120     pStart = PetscMin(pStart, pStarti);
2121     pEnd   = PetscMax(pEnd, pEndi);
2122     Nf += nf;
2123   }
2124   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s[0]), supers));
2125   PetscCall(PetscSectionSetNumFields(*supers, Nf));
2126   for (i = 0, f = 0; i < len; ++i) {
2127     PetscInt nf, fi, ci;
2128 
2129     PetscCall(PetscSectionGetNumFields(s[i], &nf));
2130     for (fi = 0; fi < nf; ++fi, ++f) {
2131       const char *name    = NULL;
2132       PetscInt    numComp = 0;
2133 
2134       PetscCall(PetscSectionGetFieldName(s[i], fi, &name));
2135       PetscCall(PetscSectionSetFieldName(*supers, f, name));
2136       PetscCall(PetscSectionGetFieldComponents(s[i], fi, &numComp));
2137       PetscCall(PetscSectionSetFieldComponents(*supers, f, numComp));
2138       for (ci = 0; ci < s[i]->numFieldComponents[fi]; ++ci) {
2139         PetscCall(PetscSectionGetComponentName(s[i], fi, ci, &name));
2140         PetscCall(PetscSectionSetComponentName(*supers, f, ci, name));
2141       }
2142     }
2143   }
2144   PetscCall(PetscSectionSetChart(*supers, pStart, pEnd));
2145   for (p = pStart; p < pEnd; ++p) {
2146     PetscInt dof = 0, cdof = 0;
2147 
2148     for (i = 0, f = 0; i < len; ++i) {
2149       PetscInt nf, fi, pStarti, pEndi;
2150       PetscInt fdof = 0, cfdof = 0;
2151 
2152       PetscCall(PetscSectionGetNumFields(s[i], &nf));
2153       PetscCall(PetscSectionGetChart(s[i], &pStarti, &pEndi));
2154       if ((p < pStarti) || (p >= pEndi)) continue;
2155       for (fi = 0; fi < nf; ++fi, ++f) {
2156         PetscCall(PetscSectionGetFieldDof(s[i], p, fi, &fdof));
2157         PetscCall(PetscSectionAddFieldDof(*supers, p, f, fdof));
2158         PetscCall(PetscSectionGetFieldConstraintDof(s[i], p, fi, &cfdof));
2159         if (cfdof) PetscCall(PetscSectionAddFieldConstraintDof(*supers, p, f, cfdof));
2160         dof += fdof;
2161         cdof += cfdof;
2162       }
2163     }
2164     PetscCall(PetscSectionSetDof(*supers, p, dof));
2165     if (cdof) PetscCall(PetscSectionSetConstraintDof(*supers, p, cdof));
2166     maxCdof = PetscMax(cdof, maxCdof);
2167   }
2168   PetscCall(PetscSectionSetUp(*supers));
2169   if (maxCdof) {
2170     PetscInt *indices;
2171 
2172     PetscCall(PetscMalloc1(maxCdof, &indices));
2173     for (p = pStart; p < pEnd; ++p) {
2174       PetscInt cdof;
2175 
2176       PetscCall(PetscSectionGetConstraintDof(*supers, p, &cdof));
2177       if (cdof) {
2178         PetscInt dof, numConst = 0, fOff = 0;
2179 
2180         for (i = 0, f = 0; i < len; ++i) {
2181           const PetscInt *oldIndices = NULL;
2182           PetscInt        nf, fi, pStarti, pEndi, fdof, cfdof, fc;
2183 
2184           PetscCall(PetscSectionGetNumFields(s[i], &nf));
2185           PetscCall(PetscSectionGetChart(s[i], &pStarti, &pEndi));
2186           if ((p < pStarti) || (p >= pEndi)) continue;
2187           for (fi = 0; fi < nf; ++fi, ++f) {
2188             PetscCall(PetscSectionGetFieldDof(s[i], p, fi, &fdof));
2189             PetscCall(PetscSectionGetFieldConstraintDof(s[i], p, fi, &cfdof));
2190             PetscCall(PetscSectionGetFieldConstraintIndices(s[i], p, fi, &oldIndices));
2191             for (fc = 0; fc < cfdof; ++fc) indices[numConst + fc] = oldIndices[fc];
2192             PetscCall(PetscSectionSetFieldConstraintIndices(*supers, p, f, &indices[numConst]));
2193             for (fc = 0; fc < cfdof; ++fc) indices[numConst + fc] += fOff;
2194             numConst += cfdof;
2195           }
2196           PetscCall(PetscSectionGetDof(s[i], p, &dof));
2197           fOff += dof;
2198         }
2199         PetscCall(PetscSectionSetConstraintIndices(*supers, p, indices));
2200       }
2201     }
2202     PetscCall(PetscFree(indices));
2203   }
2204   PetscFunctionReturn(PETSC_SUCCESS);
2205 }
2206 
2207 static PetscErrorCode PetscSectionCreateSubplexSection_Private(PetscSection s, IS subpointMap, PetscBool renumberPoints, PetscSection *subs)
2208 {
2209   const PetscInt *points = NULL, *indices = NULL;
2210   PetscInt        numFields, f, c, numSubpoints = 0, pStart, pEnd, p, spStart, spEnd, subp;
2211 
2212   PetscFunctionBegin;
2213   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2214   PetscValidHeaderSpecific(subpointMap, IS_CLASSID, 2);
2215   PetscAssertPointer(subs, 4);
2216   PetscCall(PetscSectionGetNumFields(s, &numFields));
2217   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), subs));
2218   if (numFields) PetscCall(PetscSectionSetNumFields(*subs, numFields));
2219   for (f = 0; f < numFields; ++f) {
2220     const char *name    = NULL;
2221     PetscInt    numComp = 0;
2222 
2223     PetscCall(PetscSectionGetFieldName(s, f, &name));
2224     PetscCall(PetscSectionSetFieldName(*subs, f, name));
2225     PetscCall(PetscSectionGetFieldComponents(s, f, &numComp));
2226     PetscCall(PetscSectionSetFieldComponents(*subs, f, numComp));
2227     for (c = 0; c < s->numFieldComponents[f]; ++c) {
2228       PetscCall(PetscSectionGetComponentName(s, f, c, &name));
2229       PetscCall(PetscSectionSetComponentName(*subs, f, c, name));
2230     }
2231   }
2232   /* For right now, we do not try to squeeze the subchart */
2233   if (subpointMap) {
2234     PetscCall(ISGetSize(subpointMap, &numSubpoints));
2235     PetscCall(ISGetIndices(subpointMap, &points));
2236   }
2237   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
2238   if (renumberPoints) {
2239     spStart = 0;
2240     spEnd   = numSubpoints;
2241   } else {
2242     PetscCall(ISGetMinMax(subpointMap, &spStart, &spEnd));
2243     ++spEnd;
2244   }
2245   PetscCall(PetscSectionSetChart(*subs, spStart, spEnd));
2246   for (p = pStart; p < pEnd; ++p) {
2247     PetscInt dof, cdof, fdof = 0, cfdof = 0;
2248 
2249     PetscCall(PetscFindInt(p, numSubpoints, points, &subp));
2250     if (subp < 0) continue;
2251     if (!renumberPoints) subp = p;
2252     for (f = 0; f < numFields; ++f) {
2253       PetscCall(PetscSectionGetFieldDof(s, p, f, &fdof));
2254       PetscCall(PetscSectionSetFieldDof(*subs, subp, f, fdof));
2255       PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cfdof));
2256       if (cfdof) PetscCall(PetscSectionSetFieldConstraintDof(*subs, subp, f, cfdof));
2257     }
2258     PetscCall(PetscSectionGetDof(s, p, &dof));
2259     PetscCall(PetscSectionSetDof(*subs, subp, dof));
2260     PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
2261     if (cdof) PetscCall(PetscSectionSetConstraintDof(*subs, subp, cdof));
2262   }
2263   PetscCall(PetscSectionSetUp(*subs));
2264   /* Change offsets to original offsets */
2265   for (p = pStart; p < pEnd; ++p) {
2266     PetscInt off, foff = 0;
2267 
2268     PetscCall(PetscFindInt(p, numSubpoints, points, &subp));
2269     if (subp < 0) continue;
2270     if (!renumberPoints) subp = p;
2271     for (f = 0; f < numFields; ++f) {
2272       PetscCall(PetscSectionGetFieldOffset(s, p, f, &foff));
2273       PetscCall(PetscSectionSetFieldOffset(*subs, subp, f, foff));
2274     }
2275     PetscCall(PetscSectionGetOffset(s, p, &off));
2276     PetscCall(PetscSectionSetOffset(*subs, subp, off));
2277   }
2278   /* Copy constraint indices */
2279   for (subp = spStart; subp < spEnd; ++subp) {
2280     PetscInt cdof;
2281 
2282     PetscCall(PetscSectionGetConstraintDof(*subs, subp, &cdof));
2283     if (cdof) {
2284       for (f = 0; f < numFields; ++f) {
2285         PetscCall(PetscSectionGetFieldConstraintIndices(s, points[subp - spStart], f, &indices));
2286         PetscCall(PetscSectionSetFieldConstraintIndices(*subs, subp, f, indices));
2287       }
2288       PetscCall(PetscSectionGetConstraintIndices(s, points[subp - spStart], &indices));
2289       PetscCall(PetscSectionSetConstraintIndices(*subs, subp, indices));
2290     }
2291   }
2292   if (subpointMap) PetscCall(ISRestoreIndices(subpointMap, &points));
2293   PetscFunctionReturn(PETSC_SUCCESS);
2294 }
2295 
2296 /*@
2297   PetscSectionCreateSubmeshSection - Create a new, smaller section with support on the submesh
2298 
2299   Collective
2300 
2301   Input Parameters:
2302 + s           - the `PetscSection`
2303 - subpointMap - a sorted list of points in the original mesh which are in the submesh
2304 
2305   Output Parameter:
2306 . subs - the subsection
2307 
2308   Level: advanced
2309 
2310   Notes:
2311   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))`
2312 
2313   Compare this with `PetscSectionCreateSubdomainSection()` that does not map the points numbers to start at zero but leaves them as before
2314 
2315   Developer Notes:
2316   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`
2317 
2318 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreateSubdomainSection()`, `PetscSectionCreateSubsection()`, `DMPlexGetSubpointMap()`, `PetscSectionCreate()`
2319 @*/
2320 PetscErrorCode PetscSectionCreateSubmeshSection(PetscSection s, IS subpointMap, PetscSection *subs)
2321 {
2322   PetscFunctionBegin;
2323   PetscCall(PetscSectionCreateSubplexSection_Private(s, subpointMap, PETSC_TRUE, subs));
2324   PetscFunctionReturn(PETSC_SUCCESS);
2325 }
2326 
2327 /*@
2328   PetscSectionCreateSubdomainSection - Create a new, smaller section with support on a subdomain of the mesh
2329 
2330   Collective
2331 
2332   Input Parameters:
2333 + s           - the `PetscSection`
2334 - subpointMap - a sorted list of points in the original mesh which are in the subdomain
2335 
2336   Output Parameter:
2337 . subs - the subsection
2338 
2339   Level: advanced
2340 
2341   Notes:
2342   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`
2343   is `[min(subpointMap),max(subpointMap)+1)`
2344 
2345   Compare this with `PetscSectionCreateSubmeshSection()` that maps the point numbers to start at zero
2346 
2347   Developer Notes:
2348   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`
2349 
2350 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreateSubmeshSection()`, `PetscSectionCreateSubsection()`, `DMPlexGetSubpointMap()`, `PetscSectionCreate()`
2351 @*/
2352 PetscErrorCode PetscSectionCreateSubdomainSection(PetscSection s, IS subpointMap, PetscSection *subs)
2353 {
2354   PetscFunctionBegin;
2355   PetscCall(PetscSectionCreateSubplexSection_Private(s, subpointMap, PETSC_FALSE, subs));
2356   PetscFunctionReturn(PETSC_SUCCESS);
2357 }
2358 
2359 static PetscErrorCode PetscSectionView_ASCII(PetscSection s, PetscViewer viewer)
2360 {
2361   PetscInt    p;
2362   PetscMPIInt rank;
2363 
2364   PetscFunctionBegin;
2365   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
2366   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
2367   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank));
2368   for (p = 0; p < s->pEnd - s->pStart; ++p) {
2369     if (s->bc && s->bc->atlasDof[p] > 0) {
2370       PetscInt b;
2371       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT " constrained", p + s->pStart, s->atlasDof[p], s->atlasOff[p]));
2372       if (s->bcIndices) {
2373         for (b = 0; b < s->bc->atlasDof[p]; ++b) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, s->bcIndices[s->bc->atlasOff[p] + b]));
2374       }
2375       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
2376     } else {
2377       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT "\n", p + s->pStart, s->atlasDof[p], s->atlasOff[p]));
2378     }
2379   }
2380   PetscCall(PetscViewerFlush(viewer));
2381   PetscCall(PetscViewerASCIIPopSynchronized(viewer));
2382   if (s->sym) {
2383     PetscCall(PetscViewerASCIIPushTab(viewer));
2384     PetscCall(PetscSectionSymView(s->sym, viewer));
2385     PetscCall(PetscViewerASCIIPopTab(viewer));
2386   }
2387   PetscFunctionReturn(PETSC_SUCCESS);
2388 }
2389 
2390 /*@C
2391   PetscSectionViewFromOptions - View the `PetscSection` based on values in the options database
2392 
2393   Collective
2394 
2395   Input Parameters:
2396 + A    - the `PetscSection` object to view
2397 . obj  - Optional object that provides the options prefix used for the options
2398 - name - command line option
2399 
2400   Level: intermediate
2401 
2402   Note:
2403   See `PetscObjectViewFromOptions()` for available values of `PetscViewer` and `PetscViewerFormat`
2404 
2405 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionView`, `PetscObjectViewFromOptions()`, `PetscSectionCreate()`, `PetscSectionView()`
2406 @*/
2407 PetscErrorCode PetscSectionViewFromOptions(PetscSection A, PetscObject obj, const char name[])
2408 {
2409   PetscFunctionBegin;
2410   PetscValidHeaderSpecific(A, PETSC_SECTION_CLASSID, 1);
2411   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
2412   PetscFunctionReturn(PETSC_SUCCESS);
2413 }
2414 
2415 /*@C
2416   PetscSectionView - Views a `PetscSection`
2417 
2418   Collective
2419 
2420   Input Parameters:
2421 + s      - the `PetscSection` object to view
2422 - viewer - the viewer
2423 
2424   Level: beginner
2425 
2426   Note:
2427   `PetscSectionView()`, when viewer is of type `PETSCVIEWERHDF5`, only saves
2428   distribution independent data, such as dofs, offsets, constraint dofs,
2429   and constraint indices. Points that have negative dofs, for instance,
2430   are not saved as they represent points owned by other processes.
2431   Point numbering and rank assignment is currently not stored.
2432   The saved section can be loaded with `PetscSectionLoad()`.
2433 
2434 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()`, `PetscSectionLoad()`, `PetscViewer`
2435 @*/
2436 PetscErrorCode PetscSectionView(PetscSection s, PetscViewer viewer)
2437 {
2438   PetscBool isascii, ishdf5;
2439   PetscInt  f;
2440 
2441   PetscFunctionBegin;
2442   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2443   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)s), &viewer));
2444   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2445   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
2446   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2447   if (isascii) {
2448     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)s, viewer));
2449     if (s->numFields) {
2450       PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " fields\n", s->numFields));
2451       for (f = 0; f < s->numFields; ++f) {
2452         PetscCall(PetscViewerASCIIPrintf(viewer, "  field %" PetscInt_FMT " with %" PetscInt_FMT " components\n", f, s->numFieldComponents[f]));
2453         PetscCall(PetscSectionView_ASCII(s->field[f], viewer));
2454       }
2455     } else {
2456       PetscCall(PetscSectionView_ASCII(s, viewer));
2457     }
2458   } else if (ishdf5) {
2459 #if PetscDefined(HAVE_HDF5)
2460     PetscCall(PetscSectionView_HDF5_Internal(s, viewer));
2461 #else
2462     SETERRQ(PetscObjectComm((PetscObject)s), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2463 #endif
2464   }
2465   PetscFunctionReturn(PETSC_SUCCESS);
2466 }
2467 
2468 /*@C
2469   PetscSectionLoad - Loads a `PetscSection`
2470 
2471   Collective
2472 
2473   Input Parameters:
2474 + s      - the `PetscSection` object to load
2475 - viewer - the viewer
2476 
2477   Level: beginner
2478 
2479   Note:
2480   `PetscSectionLoad()`, when viewer is of type `PETSCVIEWERHDF5`, loads
2481   a section saved with `PetscSectionView()`. The number of processes
2482   used here (N) does not need to be the same as that used when saving.
2483   After calling this function, the chart of s on rank i will be set
2484   to [0, E_i), where \sum_{i=0}^{N-1}E_i equals to the total number of
2485   saved section points.
2486 
2487 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()`, `PetscSectionView()`
2488 @*/
2489 PetscErrorCode PetscSectionLoad(PetscSection s, PetscViewer viewer)
2490 {
2491   PetscBool ishdf5;
2492 
2493   PetscFunctionBegin;
2494   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2495   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2496   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2497   if (ishdf5) {
2498 #if PetscDefined(HAVE_HDF5)
2499     PetscCall(PetscSectionLoad_HDF5_Internal(s, viewer));
2500     PetscFunctionReturn(PETSC_SUCCESS);
2501 #else
2502     SETERRQ(PetscObjectComm((PetscObject)s), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2503 #endif
2504   } else SETERRQ(PetscObjectComm((PetscObject)s), PETSC_ERR_SUP, "Viewer type %s not yet supported for PetscSection loading", ((PetscObject)viewer)->type_name);
2505 }
2506 
2507 /*@
2508   PetscSectionResetClosurePermutation - Remove any existing closure permutation
2509 
2510   Input Parameter:
2511 . section - The `PetscSection`
2512 
2513   Level: intermediate
2514 
2515 .seealso: `PetscSectionSetClosurePermutation()`, `PetscSectionSetClosureIndex()`, `PetscSectionReset()`
2516 @*/
2517 PetscErrorCode PetscSectionResetClosurePermutation(PetscSection section)
2518 {
2519   PetscSectionClosurePermVal clVal;
2520 
2521   PetscFunctionBegin;
2522   if (!section->clHash) PetscFunctionReturn(PETSC_SUCCESS);
2523   kh_foreach_value(section->clHash, clVal, {
2524     PetscCall(PetscFree(clVal.perm));
2525     PetscCall(PetscFree(clVal.invPerm));
2526   });
2527   kh_destroy(ClPerm, section->clHash);
2528   section->clHash = NULL;
2529   PetscFunctionReturn(PETSC_SUCCESS);
2530 }
2531 
2532 /*@
2533   PetscSectionReset - Frees all section data, the section is then as if `PetscSectionCreate()` had just been called.
2534 
2535   Not Collective
2536 
2537   Input Parameter:
2538 . s - the `PetscSection`
2539 
2540   Level: beginner
2541 
2542 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`
2543 @*/
2544 PetscErrorCode PetscSectionReset(PetscSection s)
2545 {
2546   PetscInt f, c;
2547 
2548   PetscFunctionBegin;
2549   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2550   for (f = 0; f < s->numFields; ++f) {
2551     PetscCall(PetscSectionDestroy(&s->field[f]));
2552     PetscCall(PetscFree(s->fieldNames[f]));
2553     for (c = 0; c < s->numFieldComponents[f]; ++c) PetscCall(PetscFree(s->compNames[f][c]));
2554     PetscCall(PetscFree(s->compNames[f]));
2555   }
2556   PetscCall(PetscFree(s->numFieldComponents));
2557   PetscCall(PetscFree(s->fieldNames));
2558   PetscCall(PetscFree(s->compNames));
2559   PetscCall(PetscFree(s->field));
2560   PetscCall(PetscSectionDestroy(&s->bc));
2561   PetscCall(PetscFree(s->bcIndices));
2562   PetscCall(PetscFree2(s->atlasDof, s->atlasOff));
2563   PetscCall(PetscSectionDestroy(&s->clSection));
2564   PetscCall(ISDestroy(&s->clPoints));
2565   PetscCall(ISDestroy(&s->perm));
2566   PetscCall(PetscBTDestroy(&s->blockStarts));
2567   PetscCall(PetscSectionResetClosurePermutation(s));
2568   PetscCall(PetscSectionSymDestroy(&s->sym));
2569   PetscCall(PetscSectionDestroy(&s->clSection));
2570   PetscCall(ISDestroy(&s->clPoints));
2571   PetscCall(PetscSectionInvalidateMaxDof_Internal(s));
2572   s->pStart    = -1;
2573   s->pEnd      = -1;
2574   s->maxDof    = 0;
2575   s->setup     = PETSC_FALSE;
2576   s->numFields = 0;
2577   s->clObj     = NULL;
2578   PetscFunctionReturn(PETSC_SUCCESS);
2579 }
2580 
2581 /*@
2582   PetscSectionDestroy - Frees a `PetscSection`
2583 
2584   Not Collective
2585 
2586   Input Parameter:
2587 . s - the `PetscSection`
2588 
2589   Level: beginner
2590 
2591 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionReset()`
2592 @*/
2593 PetscErrorCode PetscSectionDestroy(PetscSection *s)
2594 {
2595   PetscFunctionBegin;
2596   if (!*s) PetscFunctionReturn(PETSC_SUCCESS);
2597   PetscValidHeaderSpecific(*s, PETSC_SECTION_CLASSID, 1);
2598   if (--((PetscObject)(*s))->refct > 0) {
2599     *s = NULL;
2600     PetscFunctionReturn(PETSC_SUCCESS);
2601   }
2602   PetscCall(PetscSectionReset(*s));
2603   PetscCall(PetscHeaderDestroy(s));
2604   PetscFunctionReturn(PETSC_SUCCESS);
2605 }
2606 
2607 static PetscErrorCode VecIntGetValuesSection_Private(const PetscInt *baseArray, PetscSection s, PetscInt point, const PetscInt **values)
2608 {
2609   const PetscInt p = point - s->pStart;
2610 
2611   PetscFunctionBegin;
2612   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 2);
2613   *values = &baseArray[s->atlasOff[p]];
2614   PetscFunctionReturn(PETSC_SUCCESS);
2615 }
2616 
2617 static PetscErrorCode VecIntSetValuesSection_Private(PetscInt *baseArray, PetscSection s, PetscInt point, const PetscInt values[], InsertMode mode)
2618 {
2619   PetscInt      *array;
2620   const PetscInt p           = point - s->pStart;
2621   const PetscInt orientation = 0; /* Needs to be included for use in closure operations */
2622   PetscInt       cDim        = 0;
2623 
2624   PetscFunctionBegin;
2625   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 2);
2626   PetscCall(PetscSectionGetConstraintDof(s, p, &cDim));
2627   array = &baseArray[s->atlasOff[p]];
2628   if (!cDim) {
2629     if (orientation >= 0) {
2630       const PetscInt dim = s->atlasDof[p];
2631       PetscInt       i;
2632 
2633       if (mode == INSERT_VALUES) {
2634         for (i = 0; i < dim; ++i) array[i] = values ? values[i] : i;
2635       } else {
2636         for (i = 0; i < dim; ++i) array[i] += values[i];
2637       }
2638     } else {
2639       PetscInt offset = 0;
2640       PetscInt j      = -1, field, i;
2641 
2642       for (field = 0; field < s->numFields; ++field) {
2643         const PetscInt dim = s->field[field]->atlasDof[p];
2644 
2645         for (i = dim - 1; i >= 0; --i) array[++j] = values ? values[i + offset] : i + offset;
2646         offset += dim;
2647       }
2648     }
2649   } else {
2650     if (orientation >= 0) {
2651       const PetscInt  dim  = s->atlasDof[p];
2652       PetscInt        cInd = 0, i;
2653       const PetscInt *cDof;
2654 
2655       PetscCall(PetscSectionGetConstraintIndices(s, point, &cDof));
2656       if (mode == INSERT_VALUES) {
2657         for (i = 0; i < dim; ++i) {
2658           if ((cInd < cDim) && (i == cDof[cInd])) {
2659             ++cInd;
2660             continue;
2661           }
2662           array[i] = values ? values[i] : i;
2663         }
2664       } else {
2665         for (i = 0; i < dim; ++i) {
2666           if ((cInd < cDim) && (i == cDof[cInd])) {
2667             ++cInd;
2668             continue;
2669           }
2670           array[i] += values[i];
2671         }
2672       }
2673     } else {
2674       const PetscInt *cDof;
2675       PetscInt        offset  = 0;
2676       PetscInt        cOffset = 0;
2677       PetscInt        j       = 0, field;
2678 
2679       PetscCall(PetscSectionGetConstraintIndices(s, point, &cDof));
2680       for (field = 0; field < s->numFields; ++field) {
2681         const PetscInt dim  = s->field[field]->atlasDof[p];     /* PetscSectionGetFieldDof() */
2682         const PetscInt tDim = s->field[field]->bc->atlasDof[p]; /* PetscSectionGetFieldConstraintDof() */
2683         const PetscInt sDim = dim - tDim;
2684         PetscInt       cInd = 0, i, k;
2685 
2686         for (i = 0, k = dim + offset - 1; i < dim; ++i, ++j, --k) {
2687           if ((cInd < sDim) && (j == cDof[cInd + cOffset])) {
2688             ++cInd;
2689             continue;
2690           }
2691           array[j] = values ? values[k] : k;
2692         }
2693         offset += dim;
2694         cOffset += dim - tDim;
2695       }
2696     }
2697   }
2698   PetscFunctionReturn(PETSC_SUCCESS);
2699 }
2700 
2701 /*@C
2702   PetscSectionHasConstraints - Determine whether a `PetscSection` has constrained dofs
2703 
2704   Not Collective
2705 
2706   Input Parameter:
2707 . s - The `PetscSection`
2708 
2709   Output Parameter:
2710 . hasConstraints - flag indicating that the section has constrained dofs
2711 
2712   Level: intermediate
2713 
2714 .seealso: [PetscSection](sec_petscsection), `PetscSectionSetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection`
2715 @*/
2716 PetscErrorCode PetscSectionHasConstraints(PetscSection s, PetscBool *hasConstraints)
2717 {
2718   PetscFunctionBegin;
2719   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2720   PetscAssertPointer(hasConstraints, 2);
2721   *hasConstraints = s->bc ? PETSC_TRUE : PETSC_FALSE;
2722   PetscFunctionReturn(PETSC_SUCCESS);
2723 }
2724 
2725 /*@C
2726   PetscSectionGetConstraintIndices - Get the point dof numbers, in [0, dof), which are constrained for a given point
2727 
2728   Not Collective
2729 
2730   Input Parameters:
2731 + s     - The `PetscSection`
2732 - point - The point
2733 
2734   Output Parameter:
2735 . indices - The constrained dofs
2736 
2737   Level: intermediate
2738 
2739   Fortran Notes:
2740   Use `PetscSectionGetConstraintIndicesF90()` and `PetscSectionRestoreConstraintIndicesF90()`
2741 
2742 .seealso: [PetscSection](sec_petscsection), `PetscSectionSetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection`
2743 @*/
2744 PetscErrorCode PetscSectionGetConstraintIndices(PetscSection s, PetscInt point, const PetscInt **indices)
2745 {
2746   PetscFunctionBegin;
2747   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2748   if (s->bc) {
2749     PetscCall(VecIntGetValuesSection_Private(s->bcIndices, s->bc, point, indices));
2750   } else *indices = NULL;
2751   PetscFunctionReturn(PETSC_SUCCESS);
2752 }
2753 
2754 /*@C
2755   PetscSectionSetConstraintIndices - Set the point dof numbers, in [0, dof), which are constrained
2756 
2757   Not Collective
2758 
2759   Input Parameters:
2760 + s       - The `PetscSection`
2761 . point   - The point
2762 - indices - The constrained dofs
2763 
2764   Level: intermediate
2765 
2766   Fortran Notes:
2767   Use `PetscSectionSetConstraintIndicesF90()`
2768 
2769 .seealso: [PetscSection](sec_petscsection), `PetscSectionGetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection`
2770 @*/
2771 PetscErrorCode PetscSectionSetConstraintIndices(PetscSection s, PetscInt point, const PetscInt indices[])
2772 {
2773   PetscFunctionBegin;
2774   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2775   if (s->bc) {
2776     const PetscInt dof  = s->atlasDof[point];
2777     const PetscInt cdof = s->bc->atlasDof[point];
2778     PetscInt       d;
2779 
2780     if (indices)
2781       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]);
2782     PetscCall(VecIntSetValuesSection_Private(s->bcIndices, s->bc, point, indices, INSERT_VALUES));
2783   }
2784   PetscFunctionReturn(PETSC_SUCCESS);
2785 }
2786 
2787 /*@C
2788   PetscSectionGetFieldConstraintIndices - Get the field dof numbers, in [0, fdof), which are constrained
2789 
2790   Not Collective
2791 
2792   Input Parameters:
2793 + s     - The `PetscSection`
2794 . field - The field number
2795 - point - The point
2796 
2797   Output Parameter:
2798 . indices - The constrained dofs sorted in ascending order
2799 
2800   Level: intermediate
2801 
2802   Note:
2803   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()`.
2804 
2805   Fortran Notes:
2806   Use `PetscSectionGetFieldConstraintIndicesF90()` and `PetscSectionRestoreFieldConstraintIndicesF90()`
2807 
2808 .seealso: [PetscSection](sec_petscsection), `PetscSectionSetFieldConstraintIndices()`, `PetscSectionGetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection`
2809 @*/
2810 PetscErrorCode PetscSectionGetFieldConstraintIndices(PetscSection s, PetscInt point, PetscInt field, const PetscInt **indices)
2811 {
2812   PetscFunctionBegin;
2813   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2814   PetscAssertPointer(indices, 4);
2815   PetscSectionCheckValidField(field, s->numFields);
2816   PetscCall(PetscSectionGetConstraintIndices(s->field[field], point, indices));
2817   PetscFunctionReturn(PETSC_SUCCESS);
2818 }
2819 
2820 /*@C
2821   PetscSectionSetFieldConstraintIndices - Set the field dof numbers, in [0, fdof), which are constrained
2822 
2823   Not Collective
2824 
2825   Input Parameters:
2826 + s       - The `PetscSection`
2827 . point   - The point
2828 . field   - The field number
2829 - indices - The constrained dofs
2830 
2831   Level: intermediate
2832 
2833   Fortran Notes:
2834   Use `PetscSectionSetFieldConstraintIndicesF90()`
2835 
2836 .seealso: [PetscSection](sec_petscsection), `PetscSectionSetConstraintIndices()`, `PetscSectionGetFieldConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection`
2837 @*/
2838 PetscErrorCode PetscSectionSetFieldConstraintIndices(PetscSection s, PetscInt point, PetscInt field, const PetscInt indices[])
2839 {
2840   PetscFunctionBegin;
2841   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2842   PetscSectionCheckValidField(field, s->numFields);
2843   PetscCall(PetscSectionSetConstraintIndices(s->field[field], point, indices));
2844   PetscFunctionReturn(PETSC_SUCCESS);
2845 }
2846 
2847 /*@
2848   PetscSectionPermute - Reorder the section according to the input point permutation
2849 
2850   Collective
2851 
2852   Input Parameters:
2853 + section     - The `PetscSection` object
2854 - permutation - The point permutation, old point p becomes new point perm[p]
2855 
2856   Output Parameter:
2857 . sectionNew - The permuted `PetscSection`
2858 
2859   Level: intermediate
2860 
2861   Note:
2862   The data and the access to the data via `PetscSectionGetFieldOffset()` and `PetscSectionGetOffset()` are both changed in `sectionNew`
2863 
2864   Compare to `PetscSectionSetPermutation()`
2865 
2866 .seealso: [PetscSection](sec_petscsection), `IS`, `PetscSection`, `MatPermute()`, `PetscSectionSetPermutation()`
2867 @*/
2868 PetscErrorCode PetscSectionPermute(PetscSection section, IS permutation, PetscSection *sectionNew)
2869 {
2870   PetscSection    s = section, sNew;
2871   const PetscInt *perm;
2872   PetscInt        numFields, f, c, numPoints, pStart, pEnd, p;
2873 
2874   PetscFunctionBegin;
2875   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
2876   PetscValidHeaderSpecific(permutation, IS_CLASSID, 2);
2877   PetscAssertPointer(sectionNew, 3);
2878   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), &sNew));
2879   PetscCall(PetscSectionGetNumFields(s, &numFields));
2880   if (numFields) PetscCall(PetscSectionSetNumFields(sNew, numFields));
2881   for (f = 0; f < numFields; ++f) {
2882     const char *name;
2883     PetscInt    numComp;
2884 
2885     PetscCall(PetscSectionGetFieldName(s, f, &name));
2886     PetscCall(PetscSectionSetFieldName(sNew, f, name));
2887     PetscCall(PetscSectionGetFieldComponents(s, f, &numComp));
2888     PetscCall(PetscSectionSetFieldComponents(sNew, f, numComp));
2889     for (c = 0; c < s->numFieldComponents[f]; ++c) {
2890       PetscCall(PetscSectionGetComponentName(s, f, c, &name));
2891       PetscCall(PetscSectionSetComponentName(sNew, f, c, name));
2892     }
2893   }
2894   PetscCall(ISGetLocalSize(permutation, &numPoints));
2895   PetscCall(ISGetIndices(permutation, &perm));
2896   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
2897   PetscCall(PetscSectionSetChart(sNew, pStart, pEnd));
2898   PetscCheck(numPoints >= pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Permutation size %" PetscInt_FMT " is less than largest Section point %" PetscInt_FMT, numPoints, pEnd);
2899   for (p = pStart; p < pEnd; ++p) {
2900     PetscInt dof, cdof;
2901 
2902     PetscCall(PetscSectionGetDof(s, p, &dof));
2903     PetscCall(PetscSectionSetDof(sNew, perm[p], dof));
2904     PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
2905     if (cdof) PetscCall(PetscSectionSetConstraintDof(sNew, perm[p], cdof));
2906     for (f = 0; f < numFields; ++f) {
2907       PetscCall(PetscSectionGetFieldDof(s, p, f, &dof));
2908       PetscCall(PetscSectionSetFieldDof(sNew, perm[p], f, dof));
2909       PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cdof));
2910       if (cdof) PetscCall(PetscSectionSetFieldConstraintDof(sNew, perm[p], f, cdof));
2911     }
2912   }
2913   PetscCall(PetscSectionSetUp(sNew));
2914   for (p = pStart; p < pEnd; ++p) {
2915     const PetscInt *cind;
2916     PetscInt        cdof;
2917 
2918     PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
2919     if (cdof) {
2920       PetscCall(PetscSectionGetConstraintIndices(s, p, &cind));
2921       PetscCall(PetscSectionSetConstraintIndices(sNew, perm[p], cind));
2922     }
2923     for (f = 0; f < numFields; ++f) {
2924       PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cdof));
2925       if (cdof) {
2926         PetscCall(PetscSectionGetFieldConstraintIndices(s, p, f, &cind));
2927         PetscCall(PetscSectionSetFieldConstraintIndices(sNew, perm[p], f, cind));
2928       }
2929     }
2930   }
2931   PetscCall(ISRestoreIndices(permutation, &perm));
2932   *sectionNew = sNew;
2933   PetscFunctionReturn(PETSC_SUCCESS);
2934 }
2935 
2936 /*@
2937   PetscSectionSetClosureIndex - Create an internal data structure to speed up closure queries.
2938 
2939   Collective
2940 
2941   Input Parameters:
2942 + section   - The `PetscSection`
2943 . obj       - A `PetscObject` which serves as the key for this index
2944 . clSection - `PetscSection` giving the size of the closure of each point
2945 - clPoints  - `IS` giving the points in each closure
2946 
2947   Level: advanced
2948 
2949   Note:
2950   This function creates an internal map from each point to its closure. We compress out closure points with no dofs in this section.
2951 
2952   Developer Notes:
2953   The information provided here is completely opaque
2954 
2955 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetClosureIndex()`, `DMPlexCreateClosureIndex()`
2956 @*/
2957 PetscErrorCode PetscSectionSetClosureIndex(PetscSection section, PetscObject obj, PetscSection clSection, IS clPoints)
2958 {
2959   PetscFunctionBegin;
2960   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
2961   PetscValidHeaderSpecific(clSection, PETSC_SECTION_CLASSID, 3);
2962   PetscValidHeaderSpecific(clPoints, IS_CLASSID, 4);
2963   if (section->clObj != obj) PetscCall(PetscSectionResetClosurePermutation(section));
2964   section->clObj = obj;
2965   PetscCall(PetscObjectReference((PetscObject)clSection));
2966   PetscCall(PetscObjectReference((PetscObject)clPoints));
2967   PetscCall(PetscSectionDestroy(&section->clSection));
2968   PetscCall(ISDestroy(&section->clPoints));
2969   section->clSection = clSection;
2970   section->clPoints  = clPoints;
2971   PetscFunctionReturn(PETSC_SUCCESS);
2972 }
2973 
2974 /*@
2975   PetscSectionGetClosureIndex - Get the cache of points in the closure of each point in the section set with `PetscSectionSetClosureIndex()`
2976 
2977   Collective
2978 
2979   Input Parameters:
2980 + section - The `PetscSection`
2981 - obj     - A `PetscObject` which serves as the key for this index
2982 
2983   Output Parameters:
2984 + clSection - `PetscSection` giving the size of the closure of each point
2985 - clPoints  - `IS` giving the points in each closure
2986 
2987   Level: advanced
2988 
2989 .seealso: [PetscSection](sec_petscsection), `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()`
2990 @*/
2991 PetscErrorCode PetscSectionGetClosureIndex(PetscSection section, PetscObject obj, PetscSection *clSection, IS *clPoints)
2992 {
2993   PetscFunctionBegin;
2994   if (section->clObj == obj) {
2995     if (clSection) *clSection = section->clSection;
2996     if (clPoints) *clPoints = section->clPoints;
2997   } else {
2998     if (clSection) *clSection = NULL;
2999     if (clPoints) *clPoints = NULL;
3000   }
3001   PetscFunctionReturn(PETSC_SUCCESS);
3002 }
3003 
3004 PetscErrorCode PetscSectionSetClosurePermutation_Internal(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, PetscCopyMode mode, PetscInt *clPerm)
3005 {
3006   PetscInt                    i;
3007   khiter_t                    iter;
3008   int                         new_entry;
3009   PetscSectionClosurePermKey  key = {depth, clSize};
3010   PetscSectionClosurePermVal *val;
3011 
3012   PetscFunctionBegin;
3013   if (section->clObj != obj) {
3014     PetscCall(PetscSectionDestroy(&section->clSection));
3015     PetscCall(ISDestroy(&section->clPoints));
3016   }
3017   section->clObj = obj;
3018   if (!section->clHash) PetscCall(PetscClPermCreate(&section->clHash));
3019   iter = kh_put(ClPerm, section->clHash, key, &new_entry);
3020   val  = &kh_val(section->clHash, iter);
3021   if (!new_entry) {
3022     PetscCall(PetscFree(val->perm));
3023     PetscCall(PetscFree(val->invPerm));
3024   }
3025   if (mode == PETSC_COPY_VALUES) {
3026     PetscCall(PetscMalloc1(clSize, &val->perm));
3027     PetscCall(PetscArraycpy(val->perm, clPerm, clSize));
3028   } else if (mode == PETSC_OWN_POINTER) {
3029     val->perm = clPerm;
3030   } else SETERRQ(PetscObjectComm(obj), PETSC_ERR_SUP, "Do not support borrowed arrays");
3031   PetscCall(PetscMalloc1(clSize, &val->invPerm));
3032   for (i = 0; i < clSize; ++i) val->invPerm[clPerm[i]] = i;
3033   PetscFunctionReturn(PETSC_SUCCESS);
3034 }
3035 
3036 /*@
3037   PetscSectionSetClosurePermutation - Set the dof permutation for the closure of each cell in the section, meaning clPerm[newIndex] = oldIndex.
3038 
3039   Not Collective
3040 
3041   Input Parameters:
3042 + section - The `PetscSection`
3043 . obj     - A `PetscObject` which serves as the key for this index (usually a `DM`)
3044 . depth   - Depth of points on which to apply the given permutation
3045 - perm    - Permutation of the cell dof closure
3046 
3047   Level: intermediate
3048 
3049   Notes:
3050   The specified permutation will only be applied to points at depth whose closure size matches the length of perm.  In a
3051   mixed-topology or variable-degree finite element space, this function can be called multiple times at each depth for
3052   each topology and degree.
3053 
3054   This approach assumes that (depth, len(perm)) uniquely identifies the desired permutation; this might not be true for
3055   exotic/enriched spaces on mixed topology meshes.
3056 
3057 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `IS`, `PetscSectionGetClosurePermutation()`, `PetscSectionGetClosureIndex()`, `DMPlexCreateClosureIndex()`, `PetscCopyMode`
3058 @*/
3059 PetscErrorCode PetscSectionSetClosurePermutation(PetscSection section, PetscObject obj, PetscInt depth, IS perm)
3060 {
3061   const PetscInt *clPerm = NULL;
3062   PetscInt        clSize = 0;
3063 
3064   PetscFunctionBegin;
3065   if (perm) {
3066     PetscCall(ISGetLocalSize(perm, &clSize));
3067     PetscCall(ISGetIndices(perm, &clPerm));
3068   }
3069   PetscCall(PetscSectionSetClosurePermutation_Internal(section, obj, depth, clSize, PETSC_COPY_VALUES, (PetscInt *)clPerm));
3070   if (perm) PetscCall(ISRestoreIndices(perm, &clPerm));
3071   PetscFunctionReturn(PETSC_SUCCESS);
3072 }
3073 
3074 static PetscErrorCode PetscSectionGetClosurePermutation_Private(PetscSection section, PetscObject obj, PetscInt depth, PetscInt size, const PetscInt *perm[])
3075 {
3076   PetscFunctionBegin;
3077   if (section->clObj == obj) {
3078     PetscSectionClosurePermKey k = {depth, size};
3079     PetscSectionClosurePermVal v;
3080 
3081     PetscCall(PetscClPermGet(section->clHash, k, &v));
3082     if (perm) *perm = v.perm;
3083   } else {
3084     if (perm) *perm = NULL;
3085   }
3086   PetscFunctionReturn(PETSC_SUCCESS);
3087 }
3088 
3089 /*@
3090   PetscSectionGetClosurePermutation - Get the dof permutation for the closure of each cell in the section, meaning clPerm[newIndex] = oldIndex.
3091 
3092   Not Collective
3093 
3094   Input Parameters:
3095 + section - The `PetscSection`
3096 . obj     - A `PetscObject` which serves as the key for this index (usually a DM)
3097 . depth   - Depth stratum on which to obtain closure permutation
3098 - clSize  - Closure size to be permuted (e.g., may vary with element topology and degree)
3099 
3100   Output Parameter:
3101 . perm - The dof closure permutation
3102 
3103   Level: intermediate
3104 
3105   Note:
3106   The user must destroy the `IS` that is returned.
3107 
3108 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `IS`, `PetscSectionSetClosurePermutation()`, `PetscSectionGetClosureInversePermutation()`, `PetscSectionGetClosureIndex()`, `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()`
3109 @*/
3110 PetscErrorCode PetscSectionGetClosurePermutation(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, IS *perm)
3111 {
3112   const PetscInt *clPerm = NULL;
3113 
3114   PetscFunctionBegin;
3115   PetscCall(PetscSectionGetClosurePermutation_Private(section, obj, depth, clSize, &clPerm));
3116   PetscCheck(clPerm, PetscObjectComm((PetscObject)obj), PETSC_ERR_ARG_WRONG, "There is no closure permutation associated with this object for depth %" PetscInt_FMT " of size %" PetscInt_FMT, depth, clSize);
3117   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, clSize, clPerm, PETSC_USE_POINTER, perm));
3118   PetscFunctionReturn(PETSC_SUCCESS);
3119 }
3120 
3121 PetscErrorCode PetscSectionGetClosureInversePermutation_Internal(PetscSection section, PetscObject obj, PetscInt depth, PetscInt size, const PetscInt *perm[])
3122 {
3123   PetscFunctionBegin;
3124   if (section->clObj == obj && section->clHash) {
3125     PetscSectionClosurePermKey k = {depth, size};
3126     PetscSectionClosurePermVal v;
3127     PetscCall(PetscClPermGet(section->clHash, k, &v));
3128     if (perm) *perm = v.invPerm;
3129   } else {
3130     if (perm) *perm = NULL;
3131   }
3132   PetscFunctionReturn(PETSC_SUCCESS);
3133 }
3134 
3135 /*@
3136   PetscSectionGetClosureInversePermutation - Get the inverse dof permutation for the closure of each cell in the section, meaning clPerm[oldIndex] = newIndex.
3137 
3138   Not Collective
3139 
3140   Input Parameters:
3141 + section - The `PetscSection`
3142 . obj     - A `PetscObject` which serves as the key for this index (usually a `DM`)
3143 . depth   - Depth stratum on which to obtain closure permutation
3144 - clSize  - Closure size to be permuted (e.g., may vary with element topology and degree)
3145 
3146   Output Parameter:
3147 . perm - The dof closure permutation
3148 
3149   Level: intermediate
3150 
3151   Note:
3152   The user must destroy the `IS` that is returned.
3153 
3154 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `IS`, `PetscSectionSetClosurePermutation()`, `PetscSectionGetClosureIndex()`, `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()`
3155 @*/
3156 PetscErrorCode PetscSectionGetClosureInversePermutation(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, IS *perm)
3157 {
3158   const PetscInt *clPerm = NULL;
3159 
3160   PetscFunctionBegin;
3161   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, obj, depth, clSize, &clPerm));
3162   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, clSize, clPerm, PETSC_USE_POINTER, perm));
3163   PetscFunctionReturn(PETSC_SUCCESS);
3164 }
3165 
3166 /*@
3167   PetscSectionGetField - Get the `PetscSection` associated with a single field
3168 
3169   Input Parameters:
3170 + s     - The `PetscSection`
3171 - field - The field number
3172 
3173   Output Parameter:
3174 . subs - The `PetscSection` for the given field, note the chart of `subs` is not set
3175 
3176   Level: intermediate
3177 
3178   Note:
3179   Does not increase the reference count of the selected sub-section. There is no matching `PetscSectionRestoreField()`
3180 
3181 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `IS`, `PetscSectionSetNumFields()`
3182 @*/
3183 PetscErrorCode PetscSectionGetField(PetscSection s, PetscInt field, PetscSection *subs)
3184 {
3185   PetscFunctionBegin;
3186   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
3187   PetscAssertPointer(subs, 3);
3188   PetscSectionCheckValidField(field, s->numFields);
3189   *subs = s->field[field];
3190   PetscFunctionReturn(PETSC_SUCCESS);
3191 }
3192 
3193 PetscClassId      PETSC_SECTION_SYM_CLASSID;
3194 PetscFunctionList PetscSectionSymList = NULL;
3195 
3196 /*@
3197   PetscSectionSymCreate - Creates an empty `PetscSectionSym` object.
3198 
3199   Collective
3200 
3201   Input Parameter:
3202 . comm - the MPI communicator
3203 
3204   Output Parameter:
3205 . sym - pointer to the new set of symmetries
3206 
3207   Level: developer
3208 
3209 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSym`, `PetscSectionSymDestroy()`
3210 @*/
3211 PetscErrorCode PetscSectionSymCreate(MPI_Comm comm, PetscSectionSym *sym)
3212 {
3213   PetscFunctionBegin;
3214   PetscAssertPointer(sym, 2);
3215   PetscCall(ISInitializePackage());
3216   PetscCall(PetscHeaderCreate(*sym, PETSC_SECTION_SYM_CLASSID, "PetscSectionSym", "Section Symmetry", "IS", comm, PetscSectionSymDestroy, PetscSectionSymView));
3217   PetscFunctionReturn(PETSC_SUCCESS);
3218 }
3219 
3220 /*@C
3221   PetscSectionSymSetType - Builds a `PetscSectionSym`, for a particular implementation.
3222 
3223   Collective
3224 
3225   Input Parameters:
3226 + sym    - The section symmetry object
3227 - method - The name of the section symmetry type
3228 
3229   Level: developer
3230 
3231 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymGetType()`, `PetscSectionSymCreate()`
3232 @*/
3233 PetscErrorCode PetscSectionSymSetType(PetscSectionSym sym, PetscSectionSymType method)
3234 {
3235   PetscErrorCode (*r)(PetscSectionSym);
3236   PetscBool match;
3237 
3238   PetscFunctionBegin;
3239   PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1);
3240   PetscCall(PetscObjectTypeCompare((PetscObject)sym, method, &match));
3241   if (match) PetscFunctionReturn(PETSC_SUCCESS);
3242 
3243   PetscCall(PetscFunctionListFind(PetscSectionSymList, method, &r));
3244   PetscCheck(r, PetscObjectComm((PetscObject)sym), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscSectionSym type: %s", method);
3245   PetscTryTypeMethod(sym, destroy);
3246   sym->ops->destroy = NULL;
3247 
3248   PetscCall((*r)(sym));
3249   PetscCall(PetscObjectChangeTypeName((PetscObject)sym, method));
3250   PetscFunctionReturn(PETSC_SUCCESS);
3251 }
3252 
3253 /*@C
3254   PetscSectionSymGetType - Gets the section symmetry type name (as a string) from the `PetscSectionSym`.
3255 
3256   Not Collective
3257 
3258   Input Parameter:
3259 . sym - The section symmetry
3260 
3261   Output Parameter:
3262 . type - The index set type name
3263 
3264   Level: developer
3265 
3266 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymSetType()`, `PetscSectionSymCreate()`
3267 @*/
3268 PetscErrorCode PetscSectionSymGetType(PetscSectionSym sym, PetscSectionSymType *type)
3269 {
3270   PetscFunctionBegin;
3271   PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1);
3272   PetscAssertPointer(type, 2);
3273   *type = ((PetscObject)sym)->type_name;
3274   PetscFunctionReturn(PETSC_SUCCESS);
3275 }
3276 
3277 /*@C
3278   PetscSectionSymRegister - Registers a new section symmetry implementation
3279 
3280   Not Collective
3281 
3282   Input Parameters:
3283 + sname    - The name of a new user-defined creation routine
3284 - function - The creation routine itself
3285 
3286   Level: developer
3287 
3288   Notes:
3289   `PetscSectionSymRegister()` may be called multiple times to add several user-defined vectors
3290 
3291 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymCreate()`, `PetscSectionSymSetType()`
3292 @*/
3293 PetscErrorCode PetscSectionSymRegister(const char sname[], PetscErrorCode (*function)(PetscSectionSym))
3294 {
3295   PetscFunctionBegin;
3296   PetscCall(ISInitializePackage());
3297   PetscCall(PetscFunctionListAdd(&PetscSectionSymList, sname, function));
3298   PetscFunctionReturn(PETSC_SUCCESS);
3299 }
3300 
3301 /*@
3302   PetscSectionSymDestroy - Destroys a section symmetry.
3303 
3304   Collective
3305 
3306   Input Parameter:
3307 . sym - the section symmetry
3308 
3309   Level: developer
3310 
3311 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()`
3312 @*/
3313 PetscErrorCode PetscSectionSymDestroy(PetscSectionSym *sym)
3314 {
3315   SymWorkLink link, next;
3316 
3317   PetscFunctionBegin;
3318   if (!*sym) PetscFunctionReturn(PETSC_SUCCESS);
3319   PetscValidHeaderSpecific((*sym), PETSC_SECTION_SYM_CLASSID, 1);
3320   if (--((PetscObject)(*sym))->refct > 0) {
3321     *sym = NULL;
3322     PetscFunctionReturn(PETSC_SUCCESS);
3323   }
3324   if ((*sym)->ops->destroy) PetscCall((*(*sym)->ops->destroy)(*sym));
3325   PetscCheck(!(*sym)->workout, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Work array still checked out");
3326   for (link = (*sym)->workin; link; link = next) {
3327     PetscInt    **perms = (PetscInt **)link->perms;
3328     PetscScalar **rots  = (PetscScalar **)link->rots;
3329     PetscCall(PetscFree2(perms, rots));
3330     next = link->next;
3331     PetscCall(PetscFree(link));
3332   }
3333   (*sym)->workin = NULL;
3334   PetscCall(PetscHeaderDestroy(sym));
3335   PetscFunctionReturn(PETSC_SUCCESS);
3336 }
3337 
3338 /*@C
3339   PetscSectionSymView - Displays a section symmetry
3340 
3341   Collective
3342 
3343   Input Parameters:
3344 + sym    - the index set
3345 - viewer - viewer used to display the set, for example `PETSC_VIEWER_STDOUT_SELF`.
3346 
3347   Level: developer
3348 
3349 .seealso: `PetscSectionSym`, `PetscViewer`, `PetscViewerASCIIOpen()`
3350 @*/
3351 PetscErrorCode PetscSectionSymView(PetscSectionSym sym, PetscViewer viewer)
3352 {
3353   PetscFunctionBegin;
3354   PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1);
3355   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sym), &viewer));
3356   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
3357   PetscCheckSameComm(sym, 1, viewer, 2);
3358   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)sym, viewer));
3359   PetscTryTypeMethod(sym, view, viewer);
3360   PetscFunctionReturn(PETSC_SUCCESS);
3361 }
3362 
3363 /*@
3364   PetscSectionSetSym - Set the symmetries for the data referred to by the section
3365 
3366   Collective
3367 
3368   Input Parameters:
3369 + section - the section describing data layout
3370 - sym     - the symmetry describing the affect of orientation on the access of the data
3371 
3372   Level: developer
3373 
3374 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetSym()`, `PetscSectionSymCreate()`
3375 @*/
3376 PetscErrorCode PetscSectionSetSym(PetscSection section, PetscSectionSym sym)
3377 {
3378   PetscFunctionBegin;
3379   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3380   PetscCall(PetscSectionSymDestroy(&(section->sym)));
3381   if (sym) {
3382     PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 2);
3383     PetscCheckSameComm(section, 1, sym, 2);
3384     PetscCall(PetscObjectReference((PetscObject)sym));
3385   }
3386   section->sym = sym;
3387   PetscFunctionReturn(PETSC_SUCCESS);
3388 }
3389 
3390 /*@
3391   PetscSectionGetSym - Get the symmetries for the data referred to by the section
3392 
3393   Not Collective
3394 
3395   Input Parameter:
3396 . section - the section describing data layout
3397 
3398   Output Parameter:
3399 . sym - the symmetry describing the affect of orientation on the access of the data, provided previously by `PetscSectionSetSym()`
3400 
3401   Level: developer
3402 
3403 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSetSym()`, `PetscSectionSymCreate()`
3404 @*/
3405 PetscErrorCode PetscSectionGetSym(PetscSection section, PetscSectionSym *sym)
3406 {
3407   PetscFunctionBegin;
3408   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3409   *sym = section->sym;
3410   PetscFunctionReturn(PETSC_SUCCESS);
3411 }
3412 
3413 /*@
3414   PetscSectionSetFieldSym - Set the symmetries for the data referred to by a field of the section
3415 
3416   Collective
3417 
3418   Input Parameters:
3419 + section - the section describing data layout
3420 . field   - the field number
3421 - sym     - the symmetry describing the affect of orientation on the access of the data
3422 
3423   Level: developer
3424 
3425 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetFieldSym()`, `PetscSectionSymCreate()`
3426 @*/
3427 PetscErrorCode PetscSectionSetFieldSym(PetscSection section, PetscInt field, PetscSectionSym sym)
3428 {
3429   PetscFunctionBegin;
3430   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3431   PetscSectionCheckValidField(field, section->numFields);
3432   PetscCall(PetscSectionSetSym(section->field[field], sym));
3433   PetscFunctionReturn(PETSC_SUCCESS);
3434 }
3435 
3436 /*@
3437   PetscSectionGetFieldSym - Get the symmetries for the data referred to by a field of the section
3438 
3439   Collective
3440 
3441   Input Parameters:
3442 + section - the section describing data layout
3443 - field   - the field number
3444 
3445   Output Parameter:
3446 . sym - the symmetry describing the affect of orientation on the access of the data
3447 
3448   Level: developer
3449 
3450 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSetFieldSym()`, `PetscSectionSymCreate()`
3451 @*/
3452 PetscErrorCode PetscSectionGetFieldSym(PetscSection section, PetscInt field, PetscSectionSym *sym)
3453 {
3454   PetscFunctionBegin;
3455   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3456   PetscSectionCheckValidField(field, section->numFields);
3457   *sym = section->field[field]->sym;
3458   PetscFunctionReturn(PETSC_SUCCESS);
3459 }
3460 
3461 /*@C
3462   PetscSectionGetPointSyms - Get the symmetries for a set of points in a `PetscSection` under specific orientations.
3463 
3464   Not Collective
3465 
3466   Input Parameters:
3467 + section   - the section
3468 . numPoints - the number of points
3469 - points    - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an
3470     arbitrary integer: its interpretation is up to sym.  Orientations are used by `DM`: for their interpretation in that
3471     context, see `DMPlexGetConeOrientation()`).
3472 
3473   Output Parameters:
3474 + perms - The permutations for the given orientations (or `NULL` if there is no symmetry or the permutation is the identity).
3475 - rots  - The field rotations symmetries for the given orientations (or `NULL` if there is no symmetry or the rotations are all
3476     identity).
3477 
3478   Example of usage, gathering dofs into a local array (lArray) from a section array (sArray):
3479 .vb
3480      const PetscInt    **perms;
3481      const PetscScalar **rots;
3482      PetscInt            lOffset;
3483 
3484      PetscSectionGetPointSyms(section,numPoints,points,&perms,&rots);
3485      for (i = 0, lOffset = 0; i < numPoints; i++) {
3486        PetscInt           point = points[2*i], dof, sOffset;
3487        const PetscInt    *perm  = perms ? perms[i] : NULL;
3488        const PetscScalar *rot   = rots  ? rots[i]  : NULL;
3489 
3490        PetscSectionGetDof(section,point,&dof);
3491        PetscSectionGetOffset(section,point,&sOffset);
3492 
3493        if (perm) {for (j = 0; j < dof; j++) {lArray[lOffset + perm[j]]  = sArray[sOffset + j];}}
3494        else      {for (j = 0; j < dof; j++) {lArray[lOffset +      j ]  = sArray[sOffset + j];}}
3495        if (rot)  {for (j = 0; j < dof; j++) {lArray[lOffset +      j ] *= rot[j];             }}
3496        lOffset += dof;
3497      }
3498      PetscSectionRestorePointSyms(section,numPoints,points,&perms,&rots);
3499 .ve
3500 
3501   Example of usage, adding dofs into a section array (sArray) from a local array (lArray):
3502 .vb
3503      const PetscInt    **perms;
3504      const PetscScalar **rots;
3505      PetscInt            lOffset;
3506 
3507      PetscSectionGetPointSyms(section,numPoints,points,&perms,&rots);
3508      for (i = 0, lOffset = 0; i < numPoints; i++) {
3509        PetscInt           point = points[2*i], dof, sOffset;
3510        const PetscInt    *perm  = perms ? perms[i] : NULL;
3511        const PetscScalar *rot   = rots  ? rots[i]  : NULL;
3512 
3513        PetscSectionGetDof(section,point,&dof);
3514        PetscSectionGetOffset(section,point,&sOff);
3515 
3516        if (perm) {for (j = 0; j < dof; j++) {sArray[sOffset + j] += lArray[lOffset + perm[j]] * (rot ? PetscConj(rot[perm[j]]) : 1.);}}
3517        else      {for (j = 0; j < dof; j++) {sArray[sOffset + j] += lArray[lOffset +      j ] * (rot ? PetscConj(rot[     j ]) : 1.);}}
3518        offset += dof;
3519      }
3520      PetscSectionRestorePointSyms(section,numPoints,points,&perms,&rots);
3521 .ve
3522 
3523   Level: developer
3524 
3525   Notes:
3526   `PetscSectionSetSym()` must have been previously called to provide the symmetries to the `PetscSection`
3527 
3528   Use `PetscSectionRestorePointSyms()` when finished with the data
3529 
3530 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionRestorePointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`
3531 @*/
3532 PetscErrorCode PetscSectionGetPointSyms(PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3533 {
3534   PetscSectionSym sym;
3535 
3536   PetscFunctionBegin;
3537   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3538   if (numPoints) PetscAssertPointer(points, 3);
3539   if (perms) *perms = NULL;
3540   if (rots) *rots = NULL;
3541   sym = section->sym;
3542   if (sym && (perms || rots)) {
3543     SymWorkLink link;
3544 
3545     if (sym->workin) {
3546       link        = sym->workin;
3547       sym->workin = sym->workin->next;
3548     } else {
3549       PetscCall(PetscNew(&link));
3550     }
3551     if (numPoints > link->numPoints) {
3552       PetscInt    **perms = (PetscInt **)link->perms;
3553       PetscScalar **rots  = (PetscScalar **)link->rots;
3554       PetscCall(PetscFree2(perms, rots));
3555       PetscCall(PetscMalloc2(numPoints, (PetscInt ***)&link->perms, numPoints, (PetscScalar ***)&link->rots));
3556       link->numPoints = numPoints;
3557     }
3558     link->next   = sym->workout;
3559     sym->workout = link;
3560     PetscCall(PetscArrayzero((PetscInt **)link->perms, numPoints));
3561     PetscCall(PetscArrayzero((PetscInt **)link->rots, numPoints));
3562     PetscCall((*sym->ops->getpoints)(sym, section, numPoints, points, link->perms, link->rots));
3563     if (perms) *perms = link->perms;
3564     if (rots) *rots = link->rots;
3565   }
3566   PetscFunctionReturn(PETSC_SUCCESS);
3567 }
3568 
3569 /*@C
3570   PetscSectionRestorePointSyms - Restore the symmetries returned by `PetscSectionGetPointSyms()`
3571 
3572   Not Collective
3573 
3574   Input Parameters:
3575 + section   - the section
3576 . numPoints - the number of points
3577 . points    - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an
3578     arbitrary integer: its interpretation is up to sym.  Orientations are used by `DM`: for their interpretation in that
3579     context, see `DMPlexGetConeOrientation()`).
3580 . perms     - The permutations for the given orientations: set to `NULL` at conclusion
3581 - rots      - The field rotations symmetries for the given orientations: set to `NULL` at conclusion
3582 
3583   Level: developer
3584 
3585 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetPointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`
3586 @*/
3587 PetscErrorCode PetscSectionRestorePointSyms(PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3588 {
3589   PetscSectionSym sym;
3590 
3591   PetscFunctionBegin;
3592   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3593   sym = section->sym;
3594   if (sym && (perms || rots)) {
3595     SymWorkLink *p, link;
3596 
3597     for (p = &sym->workout; (link = *p); p = &link->next) {
3598       if ((perms && link->perms == *perms) || (rots && link->rots == *rots)) {
3599         *p          = link->next;
3600         link->next  = sym->workin;
3601         sym->workin = link;
3602         if (perms) *perms = NULL;
3603         if (rots) *rots = NULL;
3604         PetscFunctionReturn(PETSC_SUCCESS);
3605       }
3606     }
3607     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Array was not checked out");
3608   }
3609   PetscFunctionReturn(PETSC_SUCCESS);
3610 }
3611 
3612 /*@C
3613   PetscSectionGetFieldPointSyms - Get the symmetries for a set of points in a field of a `PetscSection` under specific orientations.
3614 
3615   Not Collective
3616 
3617   Input Parameters:
3618 + section   - the section
3619 . field     - the field of the section
3620 . numPoints - the number of points
3621 - points    - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an
3622     arbitrary integer: its interpretation is up to sym.  Orientations are used by `DM`: for their interpretation in that
3623     context, see `DMPlexGetConeOrientation()`).
3624 
3625   Output Parameters:
3626 + perms - The permutations for the given orientations (or `NULL` if there is no symmetry or the permutation is the identity).
3627 - rots  - The field rotations symmetries for the given orientations (or `NULL` if there is no symmetry or the rotations are all
3628     identity).
3629 
3630   Level: developer
3631 
3632   Notes:
3633   `PetscSectionSetFieldSym()` must have been previously called to provide the symmetries to the `PetscSection`
3634 
3635   Use `PetscSectionRestoreFieldPointSyms()` when finished with the data
3636 
3637 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetPointSyms()`, `PetscSectionRestoreFieldPointSyms()`
3638 @*/
3639 PetscErrorCode PetscSectionGetFieldPointSyms(PetscSection section, PetscInt field, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3640 {
3641   PetscFunctionBegin;
3642   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3643   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);
3644   PetscCall(PetscSectionGetPointSyms(section->field[field], numPoints, points, perms, rots));
3645   PetscFunctionReturn(PETSC_SUCCESS);
3646 }
3647 
3648 /*@C
3649   PetscSectionRestoreFieldPointSyms - Restore the symmetries returned by `PetscSectionGetFieldPointSyms()`
3650 
3651   Not Collective
3652 
3653   Input Parameters:
3654 + section   - the section
3655 . field     - the field number
3656 . numPoints - the number of points
3657 . points    - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an
3658     arbitrary integer: its interpretation is up to sym.  Orientations are used by `DM`: for their interpretation in that
3659     context, see `DMPlexGetConeOrientation()`).
3660 . perms     - The permutations for the given orientations: set to NULL at conclusion
3661 - rots      - The field rotations symmetries for the given orientations: set to NULL at conclusion
3662 
3663   Level: developer
3664 
3665 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionRestorePointSyms()`, `petscSectionGetFieldPointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`
3666 @*/
3667 PetscErrorCode PetscSectionRestoreFieldPointSyms(PetscSection section, PetscInt field, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3668 {
3669   PetscFunctionBegin;
3670   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3671   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);
3672   PetscCall(PetscSectionRestorePointSyms(section->field[field], numPoints, points, perms, rots));
3673   PetscFunctionReturn(PETSC_SUCCESS);
3674 }
3675 
3676 /*@
3677   PetscSectionSymCopy - Copy the symmetries, assuming that the point structure is compatible
3678 
3679   Not Collective
3680 
3681   Input Parameter:
3682 . sym - the `PetscSectionSym`
3683 
3684   Output Parameter:
3685 . nsym - the equivalent symmetries
3686 
3687   Level: developer
3688 
3689 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`, `PetscSectionSymLabelSetStratum()`, `PetscSectionGetPointSyms()`
3690 @*/
3691 PetscErrorCode PetscSectionSymCopy(PetscSectionSym sym, PetscSectionSym nsym)
3692 {
3693   PetscFunctionBegin;
3694   PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1);
3695   PetscValidHeaderSpecific(nsym, PETSC_SECTION_SYM_CLASSID, 2);
3696   PetscTryTypeMethod(sym, copy, nsym);
3697   PetscFunctionReturn(PETSC_SUCCESS);
3698 }
3699 
3700 /*@
3701   PetscSectionSymDistribute - Distribute the symmetries in accordance with the input `PetscSF`
3702 
3703   Collective
3704 
3705   Input Parameters:
3706 + sym         - the `PetscSectionSym`
3707 - migrationSF - the distribution map from roots to leaves
3708 
3709   Output Parameter:
3710 . dsym - the redistributed symmetries
3711 
3712   Level: developer
3713 
3714 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`, `PetscSectionSymLabelSetStratum()`, `PetscSectionGetPointSyms()`
3715 @*/
3716 PetscErrorCode PetscSectionSymDistribute(PetscSectionSym sym, PetscSF migrationSF, PetscSectionSym *dsym)
3717 {
3718   PetscFunctionBegin;
3719   PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1);
3720   PetscValidHeaderSpecific(migrationSF, PETSCSF_CLASSID, 2);
3721   PetscAssertPointer(dsym, 3);
3722   PetscTryTypeMethod(sym, distribute, migrationSF, dsym);
3723   PetscFunctionReturn(PETSC_SUCCESS);
3724 }
3725 
3726 /*@
3727   PetscSectionGetUseFieldOffsets - Get the flag indicating if field offsets are used directly in a global section, rather than just the point offset
3728 
3729   Not Collective
3730 
3731   Input Parameter:
3732 . s - the global `PetscSection`
3733 
3734   Output Parameter:
3735 . flg - the flag
3736 
3737   Level: developer
3738 
3739 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSetChart()`, `PetscSectionCreate()`
3740 @*/
3741 PetscErrorCode PetscSectionGetUseFieldOffsets(PetscSection s, PetscBool *flg)
3742 {
3743   PetscFunctionBegin;
3744   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
3745   *flg = s->useFieldOff;
3746   PetscFunctionReturn(PETSC_SUCCESS);
3747 }
3748 
3749 /*@
3750   PetscSectionSetUseFieldOffsets - Set the flag to use field offsets directly in a global section, rather than just the point offset
3751 
3752   Not Collective
3753 
3754   Input Parameters:
3755 + s   - the global `PetscSection`
3756 - flg - the flag
3757 
3758   Level: developer
3759 
3760 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetUseFieldOffsets()`, `PetscSectionSetChart()`, `PetscSectionCreate()`
3761 @*/
3762 PetscErrorCode PetscSectionSetUseFieldOffsets(PetscSection s, PetscBool flg)
3763 {
3764   PetscFunctionBegin;
3765   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
3766   s->useFieldOff = flg;
3767   PetscFunctionReturn(PETSC_SUCCESS);
3768 }
3769 
3770 #define PetscSectionExpandPoints_Loop(TYPE) \
3771   do { \
3772     PetscInt i, n, o0, o1, size; \
3773     TYPE    *a0 = (TYPE *)origArray, *a1; \
3774     PetscCall(PetscSectionGetStorageSize(s, &size)); \
3775     PetscCall(PetscMalloc1(size, &a1)); \
3776     for (i = 0; i < npoints; i++) { \
3777       PetscCall(PetscSectionGetOffset(origSection, points_[i], &o0)); \
3778       PetscCall(PetscSectionGetOffset(s, i, &o1)); \
3779       PetscCall(PetscSectionGetDof(s, i, &n)); \
3780       PetscCall(PetscMemcpy(&a1[o1], &a0[o0], n *unitsize)); \
3781     } \
3782     *newArray = (void *)a1; \
3783   } while (0)
3784 
3785 /*@
3786   PetscSectionExtractDofsFromArray - Extracts elements of an array corresponding to DOFs of specified points.
3787 
3788   Not Collective
3789 
3790   Input Parameters:
3791 + origSection - the `PetscSection` describing the layout of the array
3792 . dataType    - `MPI_Datatype` describing the data type of the array (currently only `MPIU_INT`, `MPIU_SCALAR`, `MPIU_REAL`)
3793 . origArray   - the array; its size must be equal to the storage size of `origSection`
3794 - points      - `IS` with points to extract; its indices must lie in the chart of `origSection`
3795 
3796   Output Parameters:
3797 + newSection - the new `PetscSection` describing the layout of the new array (with points renumbered 0,1,... but preserving numbers of DOFs)
3798 - newArray   - the array of the extracted DOFs; its size is the storage size of `newSection`
3799 
3800   Level: developer
3801 
3802 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetChart()`, `PetscSectionGetDof()`, `PetscSectionGetStorageSize()`, `PetscSectionCreate()`
3803 @*/
3804 PetscErrorCode PetscSectionExtractDofsFromArray(PetscSection origSection, MPI_Datatype dataType, const void *origArray, IS points, PetscSection *newSection, void *newArray[])
3805 {
3806   PetscSection    s;
3807   const PetscInt *points_;
3808   PetscInt        i, n, npoints, pStart, pEnd;
3809   PetscMPIInt     unitsize;
3810 
3811   PetscFunctionBegin;
3812   PetscValidHeaderSpecific(origSection, PETSC_SECTION_CLASSID, 1);
3813   PetscAssertPointer(origArray, 3);
3814   PetscValidHeaderSpecific(points, IS_CLASSID, 4);
3815   if (newSection) PetscAssertPointer(newSection, 5);
3816   if (newArray) PetscAssertPointer(newArray, 6);
3817   PetscCallMPI(MPI_Type_size(dataType, &unitsize));
3818   PetscCall(ISGetLocalSize(points, &npoints));
3819   PetscCall(ISGetIndices(points, &points_));
3820   PetscCall(PetscSectionGetChart(origSection, &pStart, &pEnd));
3821   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s));
3822   PetscCall(PetscSectionSetChart(s, 0, npoints));
3823   for (i = 0; i < npoints; i++) {
3824     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);
3825     PetscCall(PetscSectionGetDof(origSection, points_[i], &n));
3826     PetscCall(PetscSectionSetDof(s, i, n));
3827   }
3828   PetscCall(PetscSectionSetUp(s));
3829   if (newArray) {
3830     if (dataType == MPIU_INT) {
3831       PetscSectionExpandPoints_Loop(PetscInt);
3832     } else if (dataType == MPIU_SCALAR) {
3833       PetscSectionExpandPoints_Loop(PetscScalar);
3834     } else if (dataType == MPIU_REAL) {
3835       PetscSectionExpandPoints_Loop(PetscReal);
3836     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "not implemented for this MPI_Datatype");
3837   }
3838   if (newSection) {
3839     *newSection = s;
3840   } else {
3841     PetscCall(PetscSectionDestroy(&s));
3842   }
3843   PetscCall(ISRestoreIndices(points, &points_));
3844   PetscFunctionReturn(PETSC_SUCCESS);
3845 }
3846