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