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