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