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