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