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