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