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