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