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