xref: /petsc/src/vec/is/section/interface/section.c (revision ad716f99139d51cfcf7a3214bcb88661972db5d8)
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 ? values[i] : 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 ? values[i + offset] : 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 ? values[i] : 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 ? values[k] : 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     if (indices)
2704       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]);
2705     PetscCall(VecIntSetValuesSection_Private(s->bcIndices, s->bc, point, indices, INSERT_VALUES));
2706   }
2707   PetscFunctionReturn(PETSC_SUCCESS);
2708 }
2709 
2710 /*@C
2711   PetscSectionGetFieldConstraintIndices - Get the field dof numbers, in [0, fdof), which are constrained
2712 
2713   Not Collective
2714 
2715   Input Parameters:
2716 + s     - The `PetscSection`
2717 . field - The field number
2718 - point - The point
2719 
2720   Output Parameter:
2721 . indices - The constrained dofs sorted in ascending order
2722 
2723   Level: intermediate
2724 
2725   Note:
2726   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()`.
2727 
2728   Fortran Notes:
2729   Use `PetscSectionGetFieldConstraintIndicesF90()` and `PetscSectionRestoreFieldConstraintIndicesF90()`
2730 
2731 .seealso: [PetscSection](sec_petscsection), `PetscSectionSetFieldConstraintIndices()`, `PetscSectionGetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection`
2732 @*/
2733 PetscErrorCode PetscSectionGetFieldConstraintIndices(PetscSection s, PetscInt point, PetscInt field, const PetscInt **indices)
2734 {
2735   PetscFunctionBegin;
2736   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2737   PetscAssertPointer(indices, 4);
2738   PetscSectionCheckValidField(field, s->numFields);
2739   PetscCall(PetscSectionGetConstraintIndices(s->field[field], point, indices));
2740   PetscFunctionReturn(PETSC_SUCCESS);
2741 }
2742 
2743 /*@C
2744   PetscSectionSetFieldConstraintIndices - Set the field dof numbers, in [0, fdof), which are constrained
2745 
2746   Not Collective
2747 
2748   Input Parameters:
2749 + s       - The `PetscSection`
2750 . point   - The point
2751 . field   - The field number
2752 - indices - The constrained dofs
2753 
2754   Level: intermediate
2755 
2756   Fortran Notes:
2757   Use `PetscSectionSetFieldConstraintIndicesF90()`
2758 
2759 .seealso: [PetscSection](sec_petscsection), `PetscSectionSetConstraintIndices()`, `PetscSectionGetFieldConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection`
2760 @*/
2761 PetscErrorCode PetscSectionSetFieldConstraintIndices(PetscSection s, PetscInt point, PetscInt field, const PetscInt indices[])
2762 {
2763   PetscFunctionBegin;
2764   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2765   PetscSectionCheckValidField(field, s->numFields);
2766   PetscCall(PetscSectionSetConstraintIndices(s->field[field], point, indices));
2767   PetscFunctionReturn(PETSC_SUCCESS);
2768 }
2769 
2770 /*@
2771   PetscSectionPermute - Reorder the section according to the input point permutation
2772 
2773   Collective
2774 
2775   Input Parameters:
2776 + section     - The `PetscSection` object
2777 - permutation - The point permutation, old point p becomes new point perm[p]
2778 
2779   Output Parameter:
2780 . sectionNew - The permuted `PetscSection`
2781 
2782   Level: intermediate
2783 
2784   Note:
2785   The data and the access to the data via `PetscSectionGetFieldOffset()` and `PetscSectionGetOffset()` are both changed in `sectionNew`
2786 
2787   Compare to `PetscSectionSetPermutation()`
2788 
2789 .seealso: [PetscSection](sec_petscsection), `IS`, `PetscSection`, `MatPermute()`, `PetscSectionSetPermutation()`
2790 @*/
2791 PetscErrorCode PetscSectionPermute(PetscSection section, IS permutation, PetscSection *sectionNew)
2792 {
2793   PetscSection    s = section, sNew;
2794   const PetscInt *perm;
2795   PetscInt        numFields, f, c, numPoints, pStart, pEnd, p;
2796 
2797   PetscFunctionBegin;
2798   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
2799   PetscValidHeaderSpecific(permutation, IS_CLASSID, 2);
2800   PetscAssertPointer(sectionNew, 3);
2801   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), &sNew));
2802   PetscCall(PetscSectionGetNumFields(s, &numFields));
2803   if (numFields) PetscCall(PetscSectionSetNumFields(sNew, numFields));
2804   for (f = 0; f < numFields; ++f) {
2805     const char *name;
2806     PetscInt    numComp;
2807 
2808     PetscCall(PetscSectionGetFieldName(s, f, &name));
2809     PetscCall(PetscSectionSetFieldName(sNew, f, name));
2810     PetscCall(PetscSectionGetFieldComponents(s, f, &numComp));
2811     PetscCall(PetscSectionSetFieldComponents(sNew, f, numComp));
2812     for (c = 0; c < s->numFieldComponents[f]; ++c) {
2813       PetscCall(PetscSectionGetComponentName(s, f, c, &name));
2814       PetscCall(PetscSectionSetComponentName(sNew, f, c, name));
2815     }
2816   }
2817   PetscCall(ISGetLocalSize(permutation, &numPoints));
2818   PetscCall(ISGetIndices(permutation, &perm));
2819   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
2820   PetscCall(PetscSectionSetChart(sNew, pStart, pEnd));
2821   PetscCheck(numPoints >= pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Permutation size %" PetscInt_FMT " is less than largest Section point %" PetscInt_FMT, numPoints, pEnd);
2822   for (p = pStart; p < pEnd; ++p) {
2823     PetscInt dof, cdof;
2824 
2825     PetscCall(PetscSectionGetDof(s, p, &dof));
2826     PetscCall(PetscSectionSetDof(sNew, perm[p], dof));
2827     PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
2828     if (cdof) PetscCall(PetscSectionSetConstraintDof(sNew, perm[p], cdof));
2829     for (f = 0; f < numFields; ++f) {
2830       PetscCall(PetscSectionGetFieldDof(s, p, f, &dof));
2831       PetscCall(PetscSectionSetFieldDof(sNew, perm[p], f, dof));
2832       PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cdof));
2833       if (cdof) PetscCall(PetscSectionSetFieldConstraintDof(sNew, perm[p], f, cdof));
2834     }
2835   }
2836   PetscCall(PetscSectionSetUp(sNew));
2837   for (p = pStart; p < pEnd; ++p) {
2838     const PetscInt *cind;
2839     PetscInt        cdof;
2840 
2841     PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
2842     if (cdof) {
2843       PetscCall(PetscSectionGetConstraintIndices(s, p, &cind));
2844       PetscCall(PetscSectionSetConstraintIndices(sNew, perm[p], cind));
2845     }
2846     for (f = 0; f < numFields; ++f) {
2847       PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cdof));
2848       if (cdof) {
2849         PetscCall(PetscSectionGetFieldConstraintIndices(s, p, f, &cind));
2850         PetscCall(PetscSectionSetFieldConstraintIndices(sNew, perm[p], f, cind));
2851       }
2852     }
2853   }
2854   PetscCall(ISRestoreIndices(permutation, &perm));
2855   *sectionNew = sNew;
2856   PetscFunctionReturn(PETSC_SUCCESS);
2857 }
2858 
2859 /*@
2860   PetscSectionSetClosureIndex - Create an internal data structure to speed up closure queries.
2861 
2862   Collective
2863 
2864   Input Parameters:
2865 + section   - The `PetscSection`
2866 . obj       - A `PetscObject` which serves as the key for this index
2867 . clSection - `PetscSection` giving the size of the closure of each point
2868 - clPoints  - `IS` giving the points in each closure
2869 
2870   Level: advanced
2871 
2872   Note:
2873   This function creates an internal map from each point to its closure. We compress out closure points with no dofs in this section.
2874 
2875   Developer Notes:
2876   The information provided here is completely opaque
2877 
2878 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetClosureIndex()`, `DMPlexCreateClosureIndex()`
2879 @*/
2880 PetscErrorCode PetscSectionSetClosureIndex(PetscSection section, PetscObject obj, PetscSection clSection, IS clPoints)
2881 {
2882   PetscFunctionBegin;
2883   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
2884   PetscValidHeaderSpecific(clSection, PETSC_SECTION_CLASSID, 3);
2885   PetscValidHeaderSpecific(clPoints, IS_CLASSID, 4);
2886   if (section->clObj != obj) PetscCall(PetscSectionResetClosurePermutation(section));
2887   section->clObj = obj;
2888   PetscCall(PetscObjectReference((PetscObject)clSection));
2889   PetscCall(PetscObjectReference((PetscObject)clPoints));
2890   PetscCall(PetscSectionDestroy(&section->clSection));
2891   PetscCall(ISDestroy(&section->clPoints));
2892   section->clSection = clSection;
2893   section->clPoints  = clPoints;
2894   PetscFunctionReturn(PETSC_SUCCESS);
2895 }
2896 
2897 /*@
2898   PetscSectionGetClosureIndex - Get the cache of points in the closure of each point in the section set with `PetscSectionSetClosureIndex()`
2899 
2900   Collective
2901 
2902   Input Parameters:
2903 + section - The `PetscSection`
2904 - obj     - A `PetscObject` which serves as the key for this index
2905 
2906   Output Parameters:
2907 + clSection - `PetscSection` giving the size of the closure of each point
2908 - clPoints  - `IS` giving the points in each closure
2909 
2910   Level: advanced
2911 
2912 .seealso: [PetscSection](sec_petscsection), `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()`
2913 @*/
2914 PetscErrorCode PetscSectionGetClosureIndex(PetscSection section, PetscObject obj, PetscSection *clSection, IS *clPoints)
2915 {
2916   PetscFunctionBegin;
2917   if (section->clObj == obj) {
2918     if (clSection) *clSection = section->clSection;
2919     if (clPoints) *clPoints = section->clPoints;
2920   } else {
2921     if (clSection) *clSection = NULL;
2922     if (clPoints) *clPoints = NULL;
2923   }
2924   PetscFunctionReturn(PETSC_SUCCESS);
2925 }
2926 
2927 PetscErrorCode PetscSectionSetClosurePermutation_Internal(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, PetscCopyMode mode, PetscInt *clPerm)
2928 {
2929   PetscInt                    i;
2930   khiter_t                    iter;
2931   int                         new_entry;
2932   PetscSectionClosurePermKey  key = {depth, clSize};
2933   PetscSectionClosurePermVal *val;
2934 
2935   PetscFunctionBegin;
2936   if (section->clObj != obj) {
2937     PetscCall(PetscSectionDestroy(&section->clSection));
2938     PetscCall(ISDestroy(&section->clPoints));
2939   }
2940   section->clObj = obj;
2941   if (!section->clHash) PetscCall(PetscClPermCreate(&section->clHash));
2942   iter = kh_put(ClPerm, section->clHash, key, &new_entry);
2943   val  = &kh_val(section->clHash, iter);
2944   if (!new_entry) {
2945     PetscCall(PetscFree(val->perm));
2946     PetscCall(PetscFree(val->invPerm));
2947   }
2948   if (mode == PETSC_COPY_VALUES) {
2949     PetscCall(PetscMalloc1(clSize, &val->perm));
2950     PetscCall(PetscArraycpy(val->perm, clPerm, clSize));
2951   } else if (mode == PETSC_OWN_POINTER) {
2952     val->perm = clPerm;
2953   } else SETERRQ(PetscObjectComm(obj), PETSC_ERR_SUP, "Do not support borrowed arrays");
2954   PetscCall(PetscMalloc1(clSize, &val->invPerm));
2955   for (i = 0; i < clSize; ++i) val->invPerm[clPerm[i]] = i;
2956   PetscFunctionReturn(PETSC_SUCCESS);
2957 }
2958 
2959 /*@
2960   PetscSectionSetClosurePermutation - Set the dof permutation for the closure of each cell in the section, meaning clPerm[newIndex] = oldIndex.
2961 
2962   Not Collective
2963 
2964   Input Parameters:
2965 + section - The `PetscSection`
2966 . obj     - A `PetscObject` which serves as the key for this index (usually a `DM`)
2967 . depth   - Depth of points on which to apply the given permutation
2968 - perm    - Permutation of the cell dof closure
2969 
2970   Level: intermediate
2971 
2972   Notes:
2973   The specified permutation will only be applied to points at depth whose closure size matches the length of perm.  In a
2974   mixed-topology or variable-degree finite element space, this function can be called multiple times at each depth for
2975   each topology and degree.
2976 
2977   This approach assumes that (depth, len(perm)) uniquely identifies the desired permutation; this might not be true for
2978   exotic/enriched spaces on mixed topology meshes.
2979 
2980 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `IS`, `PetscSectionGetClosurePermutation()`, `PetscSectionGetClosureIndex()`, `DMPlexCreateClosureIndex()`, `PetscCopyMode`
2981 @*/
2982 PetscErrorCode PetscSectionSetClosurePermutation(PetscSection section, PetscObject obj, PetscInt depth, IS perm)
2983 {
2984   const PetscInt *clPerm = NULL;
2985   PetscInt        clSize = 0;
2986 
2987   PetscFunctionBegin;
2988   if (perm) {
2989     PetscCall(ISGetLocalSize(perm, &clSize));
2990     PetscCall(ISGetIndices(perm, &clPerm));
2991   }
2992   PetscCall(PetscSectionSetClosurePermutation_Internal(section, obj, depth, clSize, PETSC_COPY_VALUES, (PetscInt *)clPerm));
2993   if (perm) PetscCall(ISRestoreIndices(perm, &clPerm));
2994   PetscFunctionReturn(PETSC_SUCCESS);
2995 }
2996 
2997 static PetscErrorCode PetscSectionGetClosurePermutation_Private(PetscSection section, PetscObject obj, PetscInt depth, PetscInt size, const PetscInt *perm[])
2998 {
2999   PetscFunctionBegin;
3000   if (section->clObj == obj) {
3001     PetscSectionClosurePermKey k = {depth, size};
3002     PetscSectionClosurePermVal v;
3003 
3004     PetscCall(PetscClPermGet(section->clHash, k, &v));
3005     if (perm) *perm = v.perm;
3006   } else {
3007     if (perm) *perm = NULL;
3008   }
3009   PetscFunctionReturn(PETSC_SUCCESS);
3010 }
3011 
3012 /*@
3013   PetscSectionGetClosurePermutation - Get the dof permutation for the closure of each cell in the section, meaning clPerm[newIndex] = oldIndex.
3014 
3015   Not Collective
3016 
3017   Input Parameters:
3018 + section - The `PetscSection`
3019 . obj     - A `PetscObject` which serves as the key for this index (usually a DM)
3020 . depth   - Depth stratum on which to obtain closure permutation
3021 - clSize  - Closure size to be permuted (e.g., may vary with element topology and degree)
3022 
3023   Output Parameter:
3024 . perm - The dof closure permutation
3025 
3026   Level: intermediate
3027 
3028   Note:
3029   The user must destroy the `IS` that is returned.
3030 
3031 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `IS`, `PetscSectionSetClosurePermutation()`, `PetscSectionGetClosureInversePermutation()`, `PetscSectionGetClosureIndex()`, `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()`
3032 @*/
3033 PetscErrorCode PetscSectionGetClosurePermutation(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, IS *perm)
3034 {
3035   const PetscInt *clPerm = NULL;
3036 
3037   PetscFunctionBegin;
3038   PetscCall(PetscSectionGetClosurePermutation_Private(section, obj, depth, clSize, &clPerm));
3039   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, clSize, clPerm, PETSC_USE_POINTER, perm));
3040   PetscFunctionReturn(PETSC_SUCCESS);
3041 }
3042 
3043 PetscErrorCode PetscSectionGetClosureInversePermutation_Internal(PetscSection section, PetscObject obj, PetscInt depth, PetscInt size, const PetscInt *perm[])
3044 {
3045   PetscFunctionBegin;
3046   if (section->clObj == obj && section->clHash) {
3047     PetscSectionClosurePermKey k = {depth, size};
3048     PetscSectionClosurePermVal v;
3049     PetscCall(PetscClPermGet(section->clHash, k, &v));
3050     if (perm) *perm = v.invPerm;
3051   } else {
3052     if (perm) *perm = NULL;
3053   }
3054   PetscFunctionReturn(PETSC_SUCCESS);
3055 }
3056 
3057 /*@
3058   PetscSectionGetClosureInversePermutation - Get the inverse dof permutation for the closure of each cell in the section, meaning clPerm[oldIndex] = newIndex.
3059 
3060   Not Collective
3061 
3062   Input Parameters:
3063 + section - The `PetscSection`
3064 . obj     - A `PetscObject` which serves as the key for this index (usually a `DM`)
3065 . depth   - Depth stratum on which to obtain closure permutation
3066 - clSize  - Closure size to be permuted (e.g., may vary with element topology and degree)
3067 
3068   Output Parameter:
3069 . perm - The dof closure permutation
3070 
3071   Level: intermediate
3072 
3073   Note:
3074   The user must destroy the `IS` that is returned.
3075 
3076 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `IS`, `PetscSectionSetClosurePermutation()`, `PetscSectionGetClosureIndex()`, `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()`
3077 @*/
3078 PetscErrorCode PetscSectionGetClosureInversePermutation(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, IS *perm)
3079 {
3080   const PetscInt *clPerm = NULL;
3081 
3082   PetscFunctionBegin;
3083   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, obj, depth, clSize, &clPerm));
3084   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, clSize, clPerm, PETSC_USE_POINTER, perm));
3085   PetscFunctionReturn(PETSC_SUCCESS);
3086 }
3087 
3088 /*@
3089   PetscSectionGetField - Get the `PetscSection` associated with a single field
3090 
3091   Input Parameters:
3092 + s     - The `PetscSection`
3093 - field - The field number
3094 
3095   Output Parameter:
3096 . subs - The `PetscSection` for the given field, note the chart of `subs` is not set
3097 
3098   Level: intermediate
3099 
3100   Note:
3101   Does not increase the reference count of the selected sub-section. There is no matching `PetscSectionRestoreField()`
3102 
3103 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `IS`, `PetscSectionSetNumFields()`
3104 @*/
3105 PetscErrorCode PetscSectionGetField(PetscSection s, PetscInt field, PetscSection *subs)
3106 {
3107   PetscFunctionBegin;
3108   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
3109   PetscAssertPointer(subs, 3);
3110   PetscSectionCheckValidField(field, s->numFields);
3111   *subs = s->field[field];
3112   PetscFunctionReturn(PETSC_SUCCESS);
3113 }
3114 
3115 PetscClassId      PETSC_SECTION_SYM_CLASSID;
3116 PetscFunctionList PetscSectionSymList = NULL;
3117 
3118 /*@
3119   PetscSectionSymCreate - Creates an empty `PetscSectionSym` object.
3120 
3121   Collective
3122 
3123   Input Parameter:
3124 . comm - the MPI communicator
3125 
3126   Output Parameter:
3127 . sym - pointer to the new set of symmetries
3128 
3129   Level: developer
3130 
3131 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSym`, `PetscSectionSymDestroy()`
3132 @*/
3133 PetscErrorCode PetscSectionSymCreate(MPI_Comm comm, PetscSectionSym *sym)
3134 {
3135   PetscFunctionBegin;
3136   PetscAssertPointer(sym, 2);
3137   PetscCall(ISInitializePackage());
3138   PetscCall(PetscHeaderCreate(*sym, PETSC_SECTION_SYM_CLASSID, "PetscSectionSym", "Section Symmetry", "IS", comm, PetscSectionSymDestroy, PetscSectionSymView));
3139   PetscFunctionReturn(PETSC_SUCCESS);
3140 }
3141 
3142 /*@C
3143   PetscSectionSymSetType - Builds a `PetscSectionSym`, for a particular implementation.
3144 
3145   Collective
3146 
3147   Input Parameters:
3148 + sym    - The section symmetry object
3149 - method - The name of the section symmetry type
3150 
3151   Level: developer
3152 
3153 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymGetType()`, `PetscSectionSymCreate()`
3154 @*/
3155 PetscErrorCode PetscSectionSymSetType(PetscSectionSym sym, PetscSectionSymType method)
3156 {
3157   PetscErrorCode (*r)(PetscSectionSym);
3158   PetscBool match;
3159 
3160   PetscFunctionBegin;
3161   PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1);
3162   PetscCall(PetscObjectTypeCompare((PetscObject)sym, method, &match));
3163   if (match) PetscFunctionReturn(PETSC_SUCCESS);
3164 
3165   PetscCall(PetscFunctionListFind(PetscSectionSymList, method, &r));
3166   PetscCheck(r, PetscObjectComm((PetscObject)sym), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscSectionSym type: %s", method);
3167   PetscTryTypeMethod(sym, destroy);
3168   sym->ops->destroy = NULL;
3169 
3170   PetscCall((*r)(sym));
3171   PetscCall(PetscObjectChangeTypeName((PetscObject)sym, method));
3172   PetscFunctionReturn(PETSC_SUCCESS);
3173 }
3174 
3175 /*@C
3176   PetscSectionSymGetType - Gets the section symmetry type name (as a string) from the `PetscSectionSym`.
3177 
3178   Not Collective
3179 
3180   Input Parameter:
3181 . sym - The section symmetry
3182 
3183   Output Parameter:
3184 . type - The index set type name
3185 
3186   Level: developer
3187 
3188 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymSetType()`, `PetscSectionSymCreate()`
3189 @*/
3190 PetscErrorCode PetscSectionSymGetType(PetscSectionSym sym, PetscSectionSymType *type)
3191 {
3192   PetscFunctionBegin;
3193   PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1);
3194   PetscAssertPointer(type, 2);
3195   *type = ((PetscObject)sym)->type_name;
3196   PetscFunctionReturn(PETSC_SUCCESS);
3197 }
3198 
3199 /*@C
3200   PetscSectionSymRegister - Registers a new section symmetry implementation
3201 
3202   Not Collective
3203 
3204   Input Parameters:
3205 + sname    - The name of a new user-defined creation routine
3206 - function - The creation routine itself
3207 
3208   Level: developer
3209 
3210   Notes:
3211   `PetscSectionSymRegister()` may be called multiple times to add several user-defined vectors
3212 
3213 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymCreate()`, `PetscSectionSymSetType()`
3214 @*/
3215 PetscErrorCode PetscSectionSymRegister(const char sname[], PetscErrorCode (*function)(PetscSectionSym))
3216 {
3217   PetscFunctionBegin;
3218   PetscCall(ISInitializePackage());
3219   PetscCall(PetscFunctionListAdd(&PetscSectionSymList, sname, function));
3220   PetscFunctionReturn(PETSC_SUCCESS);
3221 }
3222 
3223 /*@
3224   PetscSectionSymDestroy - Destroys a section symmetry.
3225 
3226   Collective
3227 
3228   Input Parameter:
3229 . sym - the section symmetry
3230 
3231   Level: developer
3232 
3233 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()`
3234 @*/
3235 PetscErrorCode PetscSectionSymDestroy(PetscSectionSym *sym)
3236 {
3237   SymWorkLink link, next;
3238 
3239   PetscFunctionBegin;
3240   if (!*sym) PetscFunctionReturn(PETSC_SUCCESS);
3241   PetscValidHeaderSpecific((*sym), PETSC_SECTION_SYM_CLASSID, 1);
3242   if (--((PetscObject)(*sym))->refct > 0) {
3243     *sym = NULL;
3244     PetscFunctionReturn(PETSC_SUCCESS);
3245   }
3246   if ((*sym)->ops->destroy) PetscCall((*(*sym)->ops->destroy)(*sym));
3247   PetscCheck(!(*sym)->workout, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Work array still checked out");
3248   for (link = (*sym)->workin; link; link = next) {
3249     PetscInt    **perms = (PetscInt **)link->perms;
3250     PetscScalar **rots  = (PetscScalar **)link->rots;
3251     PetscCall(PetscFree2(perms, rots));
3252     next = link->next;
3253     PetscCall(PetscFree(link));
3254   }
3255   (*sym)->workin = NULL;
3256   PetscCall(PetscHeaderDestroy(sym));
3257   PetscFunctionReturn(PETSC_SUCCESS);
3258 }
3259 
3260 /*@C
3261   PetscSectionSymView - Displays a section symmetry
3262 
3263   Collective
3264 
3265   Input Parameters:
3266 + sym    - the index set
3267 - viewer - viewer used to display the set, for example `PETSC_VIEWER_STDOUT_SELF`.
3268 
3269   Level: developer
3270 
3271 .seealso: `PetscSectionSym`, `PetscViewer`, `PetscViewerASCIIOpen()`
3272 @*/
3273 PetscErrorCode PetscSectionSymView(PetscSectionSym sym, PetscViewer viewer)
3274 {
3275   PetscFunctionBegin;
3276   PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1);
3277   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sym), &viewer));
3278   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
3279   PetscCheckSameComm(sym, 1, viewer, 2);
3280   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)sym, viewer));
3281   PetscTryTypeMethod(sym, view, viewer);
3282   PetscFunctionReturn(PETSC_SUCCESS);
3283 }
3284 
3285 /*@
3286   PetscSectionSetSym - Set the symmetries for the data referred to by the section
3287 
3288   Collective
3289 
3290   Input Parameters:
3291 + section - the section describing data layout
3292 - sym     - the symmetry describing the affect of orientation on the access of the data
3293 
3294   Level: developer
3295 
3296 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetSym()`, `PetscSectionSymCreate()`
3297 @*/
3298 PetscErrorCode PetscSectionSetSym(PetscSection section, PetscSectionSym sym)
3299 {
3300   PetscFunctionBegin;
3301   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3302   PetscCall(PetscSectionSymDestroy(&(section->sym)));
3303   if (sym) {
3304     PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 2);
3305     PetscCheckSameComm(section, 1, sym, 2);
3306     PetscCall(PetscObjectReference((PetscObject)sym));
3307   }
3308   section->sym = sym;
3309   PetscFunctionReturn(PETSC_SUCCESS);
3310 }
3311 
3312 /*@
3313   PetscSectionGetSym - Get the symmetries for the data referred to by the section
3314 
3315   Not Collective
3316 
3317   Input Parameter:
3318 . section - the section describing data layout
3319 
3320   Output Parameter:
3321 . sym - the symmetry describing the affect of orientation on the access of the data, provided previously by `PetscSectionSetSym()`
3322 
3323   Level: developer
3324 
3325 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSetSym()`, `PetscSectionSymCreate()`
3326 @*/
3327 PetscErrorCode PetscSectionGetSym(PetscSection section, PetscSectionSym *sym)
3328 {
3329   PetscFunctionBegin;
3330   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3331   *sym = section->sym;
3332   PetscFunctionReturn(PETSC_SUCCESS);
3333 }
3334 
3335 /*@
3336   PetscSectionSetFieldSym - Set the symmetries for the data referred to by a field of the section
3337 
3338   Collective
3339 
3340   Input Parameters:
3341 + section - the section describing data layout
3342 . field   - the field number
3343 - sym     - the symmetry describing the affect of orientation on the access of the data
3344 
3345   Level: developer
3346 
3347 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetFieldSym()`, `PetscSectionSymCreate()`
3348 @*/
3349 PetscErrorCode PetscSectionSetFieldSym(PetscSection section, PetscInt field, PetscSectionSym sym)
3350 {
3351   PetscFunctionBegin;
3352   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3353   PetscSectionCheckValidField(field, section->numFields);
3354   PetscCall(PetscSectionSetSym(section->field[field], sym));
3355   PetscFunctionReturn(PETSC_SUCCESS);
3356 }
3357 
3358 /*@
3359   PetscSectionGetFieldSym - Get the symmetries for the data referred to by a field of the section
3360 
3361   Collective
3362 
3363   Input Parameters:
3364 + section - the section describing data layout
3365 - field   - the field number
3366 
3367   Output Parameter:
3368 . sym - the symmetry describing the affect of orientation on the access of the data
3369 
3370   Level: developer
3371 
3372 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSetFieldSym()`, `PetscSectionSymCreate()`
3373 @*/
3374 PetscErrorCode PetscSectionGetFieldSym(PetscSection section, PetscInt field, PetscSectionSym *sym)
3375 {
3376   PetscFunctionBegin;
3377   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3378   PetscSectionCheckValidField(field, section->numFields);
3379   *sym = section->field[field]->sym;
3380   PetscFunctionReturn(PETSC_SUCCESS);
3381 }
3382 
3383 /*@C
3384   PetscSectionGetPointSyms - Get the symmetries for a set of points in a `PetscSection` under specific orientations.
3385 
3386   Not Collective
3387 
3388   Input Parameters:
3389 + section   - the section
3390 . numPoints - the number of points
3391 - points    - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an
3392     arbitrary integer: its interpretation is up to sym.  Orientations are used by `DM`: for their interpretation in that
3393     context, see `DMPlexGetConeOrientation()`).
3394 
3395   Output Parameters:
3396 + perms - The permutations for the given orientations (or `NULL` if there is no symmetry or the permutation is the identity).
3397 - rots  - The field rotations symmetries for the given orientations (or `NULL` if there is no symmetry or the rotations are all
3398     identity).
3399 
3400   Example of usage, gathering dofs into a local array (lArray) from a section array (sArray):
3401 .vb
3402      const PetscInt    **perms;
3403      const PetscScalar **rots;
3404      PetscInt            lOffset;
3405 
3406      PetscSectionGetPointSyms(section,numPoints,points,&perms,&rots);
3407      for (i = 0, lOffset = 0; i < numPoints; i++) {
3408        PetscInt           point = points[2*i], dof, sOffset;
3409        const PetscInt    *perm  = perms ? perms[i] : NULL;
3410        const PetscScalar *rot   = rots  ? rots[i]  : NULL;
3411 
3412        PetscSectionGetDof(section,point,&dof);
3413        PetscSectionGetOffset(section,point,&sOffset);
3414 
3415        if (perm) {for (j = 0; j < dof; j++) {lArray[lOffset + perm[j]]  = sArray[sOffset + j];}}
3416        else      {for (j = 0; j < dof; j++) {lArray[lOffset +      j ]  = sArray[sOffset + j];}}
3417        if (rot)  {for (j = 0; j < dof; j++) {lArray[lOffset +      j ] *= rot[j];             }}
3418        lOffset += dof;
3419      }
3420      PetscSectionRestorePointSyms(section,numPoints,points,&perms,&rots);
3421 .ve
3422 
3423   Example of usage, adding dofs into a section array (sArray) from a local array (lArray):
3424 .vb
3425      const PetscInt    **perms;
3426      const PetscScalar **rots;
3427      PetscInt            lOffset;
3428 
3429      PetscSectionGetPointSyms(section,numPoints,points,&perms,&rots);
3430      for (i = 0, lOffset = 0; i < numPoints; i++) {
3431        PetscInt           point = points[2*i], dof, sOffset;
3432        const PetscInt    *perm  = perms ? perms[i] : NULL;
3433        const PetscScalar *rot   = rots  ? rots[i]  : NULL;
3434 
3435        PetscSectionGetDof(section,point,&dof);
3436        PetscSectionGetOffset(section,point,&sOff);
3437 
3438        if (perm) {for (j = 0; j < dof; j++) {sArray[sOffset + j] += lArray[lOffset + perm[j]] * (rot ? PetscConj(rot[perm[j]]) : 1.);}}
3439        else      {for (j = 0; j < dof; j++) {sArray[sOffset + j] += lArray[lOffset +      j ] * (rot ? PetscConj(rot[     j ]) : 1.);}}
3440        offset += dof;
3441      }
3442      PetscSectionRestorePointSyms(section,numPoints,points,&perms,&rots);
3443 .ve
3444 
3445   Level: developer
3446 
3447   Notes:
3448   `PetscSectionSetSym()` must have been previously called to provide the symmetries to the `PetscSection`
3449 
3450   Use `PetscSectionRestorePointSyms()` when finished with the data
3451 
3452 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionRestorePointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`
3453 @*/
3454 PetscErrorCode PetscSectionGetPointSyms(PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3455 {
3456   PetscSectionSym sym;
3457 
3458   PetscFunctionBegin;
3459   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3460   if (numPoints) PetscAssertPointer(points, 3);
3461   if (perms) *perms = NULL;
3462   if (rots) *rots = NULL;
3463   sym = section->sym;
3464   if (sym && (perms || rots)) {
3465     SymWorkLink link;
3466 
3467     if (sym->workin) {
3468       link        = sym->workin;
3469       sym->workin = sym->workin->next;
3470     } else {
3471       PetscCall(PetscNew(&link));
3472     }
3473     if (numPoints > link->numPoints) {
3474       PetscInt    **perms = (PetscInt **)link->perms;
3475       PetscScalar **rots  = (PetscScalar **)link->rots;
3476       PetscCall(PetscFree2(perms, rots));
3477       PetscCall(PetscMalloc2(numPoints, (PetscInt ***)&link->perms, numPoints, (PetscScalar ***)&link->rots));
3478       link->numPoints = numPoints;
3479     }
3480     link->next   = sym->workout;
3481     sym->workout = link;
3482     PetscCall(PetscArrayzero((PetscInt **)link->perms, numPoints));
3483     PetscCall(PetscArrayzero((PetscInt **)link->rots, numPoints));
3484     PetscCall((*sym->ops->getpoints)(sym, section, numPoints, points, link->perms, link->rots));
3485     if (perms) *perms = link->perms;
3486     if (rots) *rots = link->rots;
3487   }
3488   PetscFunctionReturn(PETSC_SUCCESS);
3489 }
3490 
3491 /*@C
3492   PetscSectionRestorePointSyms - Restore the symmetries returned by `PetscSectionGetPointSyms()`
3493 
3494   Not Collective
3495 
3496   Input Parameters:
3497 + section   - the section
3498 . numPoints - the number of points
3499 . points    - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an
3500     arbitrary integer: its interpretation is up to sym.  Orientations are used by `DM`: for their interpretation in that
3501     context, see `DMPlexGetConeOrientation()`).
3502 . perms     - The permutations for the given orientations: set to `NULL` at conclusion
3503 - rots      - The field rotations symmetries for the given orientations: set to `NULL` at conclusion
3504 
3505   Level: developer
3506 
3507 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetPointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`
3508 @*/
3509 PetscErrorCode PetscSectionRestorePointSyms(PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3510 {
3511   PetscSectionSym sym;
3512 
3513   PetscFunctionBegin;
3514   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3515   sym = section->sym;
3516   if (sym && (perms || rots)) {
3517     SymWorkLink *p, link;
3518 
3519     for (p = &sym->workout; (link = *p); p = &link->next) {
3520       if ((perms && link->perms == *perms) || (rots && link->rots == *rots)) {
3521         *p          = link->next;
3522         link->next  = sym->workin;
3523         sym->workin = link;
3524         if (perms) *perms = NULL;
3525         if (rots) *rots = NULL;
3526         PetscFunctionReturn(PETSC_SUCCESS);
3527       }
3528     }
3529     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Array was not checked out");
3530   }
3531   PetscFunctionReturn(PETSC_SUCCESS);
3532 }
3533 
3534 /*@C
3535   PetscSectionGetFieldPointSyms - Get the symmetries for a set of points in a field of a `PetscSection` under specific orientations.
3536 
3537   Not Collective
3538 
3539   Input Parameters:
3540 + section   - the section
3541 . field     - the field of the section
3542 . numPoints - the number of points
3543 - points    - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an
3544     arbitrary integer: its interpretation is up to sym.  Orientations are used by `DM`: for their interpretation in that
3545     context, see `DMPlexGetConeOrientation()`).
3546 
3547   Output Parameters:
3548 + perms - The permutations for the given orientations (or `NULL` if there is no symmetry or the permutation is the identity).
3549 - rots  - The field rotations symmetries for the given orientations (or `NULL` if there is no symmetry or the rotations are all
3550     identity).
3551 
3552   Level: developer
3553 
3554   Notes:
3555   `PetscSectionSetFieldSym()` must have been previously called to provide the symmetries to the `PetscSection`
3556 
3557   Use `PetscSectionRestoreFieldPointSyms()` when finished with the data
3558 
3559 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetPointSyms()`, `PetscSectionRestoreFieldPointSyms()`
3560 @*/
3561 PetscErrorCode PetscSectionGetFieldPointSyms(PetscSection section, PetscInt field, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3562 {
3563   PetscFunctionBegin;
3564   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3565   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);
3566   PetscCall(PetscSectionGetPointSyms(section->field[field], numPoints, points, perms, rots));
3567   PetscFunctionReturn(PETSC_SUCCESS);
3568 }
3569 
3570 /*@C
3571   PetscSectionRestoreFieldPointSyms - Restore the symmetries returned by `PetscSectionGetFieldPointSyms()`
3572 
3573   Not Collective
3574 
3575   Input Parameters:
3576 + section   - the section
3577 . field     - the field number
3578 . numPoints - the number of points
3579 . points    - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an
3580     arbitrary integer: its interpretation is up to sym.  Orientations are used by `DM`: for their interpretation in that
3581     context, see `DMPlexGetConeOrientation()`).
3582 . perms     - The permutations for the given orientations: set to NULL at conclusion
3583 - rots      - The field rotations symmetries for the given orientations: set to NULL at conclusion
3584 
3585   Level: developer
3586 
3587 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionRestorePointSyms()`, `petscSectionGetFieldPointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`
3588 @*/
3589 PetscErrorCode PetscSectionRestoreFieldPointSyms(PetscSection section, PetscInt field, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3590 {
3591   PetscFunctionBegin;
3592   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
3593   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);
3594   PetscCall(PetscSectionRestorePointSyms(section->field[field], numPoints, points, perms, rots));
3595   PetscFunctionReturn(PETSC_SUCCESS);
3596 }
3597 
3598 /*@
3599   PetscSectionSymCopy - Copy the symmetries, assuming that the point structure is compatible
3600 
3601   Not Collective
3602 
3603   Input Parameter:
3604 . sym - the `PetscSectionSym`
3605 
3606   Output Parameter:
3607 . nsym - the equivalent symmetries
3608 
3609   Level: developer
3610 
3611 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`, `PetscSectionSymLabelSetStratum()`, `PetscSectionGetPointSyms()`
3612 @*/
3613 PetscErrorCode PetscSectionSymCopy(PetscSectionSym sym, PetscSectionSym nsym)
3614 {
3615   PetscFunctionBegin;
3616   PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1);
3617   PetscValidHeaderSpecific(nsym, PETSC_SECTION_SYM_CLASSID, 2);
3618   PetscTryTypeMethod(sym, copy, nsym);
3619   PetscFunctionReturn(PETSC_SUCCESS);
3620 }
3621 
3622 /*@
3623   PetscSectionSymDistribute - Distribute the symmetries in accordance with the input `PetscSF`
3624 
3625   Collective
3626 
3627   Input Parameters:
3628 + sym         - the `PetscSectionSym`
3629 - migrationSF - the distribution map from roots to leaves
3630 
3631   Output Parameter:
3632 . dsym - the redistributed symmetries
3633 
3634   Level: developer
3635 
3636 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`, `PetscSectionSymLabelSetStratum()`, `PetscSectionGetPointSyms()`
3637 @*/
3638 PetscErrorCode PetscSectionSymDistribute(PetscSectionSym sym, PetscSF migrationSF, PetscSectionSym *dsym)
3639 {
3640   PetscFunctionBegin;
3641   PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1);
3642   PetscValidHeaderSpecific(migrationSF, PETSCSF_CLASSID, 2);
3643   PetscAssertPointer(dsym, 3);
3644   PetscTryTypeMethod(sym, distribute, migrationSF, dsym);
3645   PetscFunctionReturn(PETSC_SUCCESS);
3646 }
3647 
3648 /*@
3649   PetscSectionGetUseFieldOffsets - Get the flag indicating if field offsets are used directly in a global section, rather than just the point offset
3650 
3651   Not Collective
3652 
3653   Input Parameter:
3654 . s - the global `PetscSection`
3655 
3656   Output Parameter:
3657 . flg - the flag
3658 
3659   Level: developer
3660 
3661 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSetChart()`, `PetscSectionCreate()`
3662 @*/
3663 PetscErrorCode PetscSectionGetUseFieldOffsets(PetscSection s, PetscBool *flg)
3664 {
3665   PetscFunctionBegin;
3666   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
3667   *flg = s->useFieldOff;
3668   PetscFunctionReturn(PETSC_SUCCESS);
3669 }
3670 
3671 /*@
3672   PetscSectionSetUseFieldOffsets - Set the flag to use field offsets directly in a global section, rather than just the point offset
3673 
3674   Not Collective
3675 
3676   Input Parameters:
3677 + s   - the global `PetscSection`
3678 - flg - the flag
3679 
3680   Level: developer
3681 
3682 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetUseFieldOffsets()`, `PetscSectionSetChart()`, `PetscSectionCreate()`
3683 @*/
3684 PetscErrorCode PetscSectionSetUseFieldOffsets(PetscSection s, PetscBool flg)
3685 {
3686   PetscFunctionBegin;
3687   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
3688   s->useFieldOff = flg;
3689   PetscFunctionReturn(PETSC_SUCCESS);
3690 }
3691 
3692 #define PetscSectionExpandPoints_Loop(TYPE) \
3693   do { \
3694     PetscInt i, n, o0, o1, size; \
3695     TYPE    *a0 = (TYPE *)origArray, *a1; \
3696     PetscCall(PetscSectionGetStorageSize(s, &size)); \
3697     PetscCall(PetscMalloc1(size, &a1)); \
3698     for (i = 0; i < npoints; i++) { \
3699       PetscCall(PetscSectionGetOffset(origSection, points_[i], &o0)); \
3700       PetscCall(PetscSectionGetOffset(s, i, &o1)); \
3701       PetscCall(PetscSectionGetDof(s, i, &n)); \
3702       PetscCall(PetscMemcpy(&a1[o1], &a0[o0], n *unitsize)); \
3703     } \
3704     *newArray = (void *)a1; \
3705   } while (0)
3706 
3707 /*@
3708   PetscSectionExtractDofsFromArray - Extracts elements of an array corresponding to DOFs of specified points.
3709 
3710   Not Collective
3711 
3712   Input Parameters:
3713 + origSection - the `PetscSection` describing the layout of the array
3714 . dataType    - `MPI_Datatype` describing the data type of the array (currently only `MPIU_INT`, `MPIU_SCALAR`, `MPIU_REAL`)
3715 . origArray   - the array; its size must be equal to the storage size of `origSection`
3716 - points      - `IS` with points to extract; its indices must lie in the chart of `origSection`
3717 
3718   Output Parameters:
3719 + newSection - the new `PetscSection` describing the layout of the new array (with points renumbered 0,1,... but preserving numbers of DOFs)
3720 - newArray   - the array of the extracted DOFs; its size is the storage size of `newSection`
3721 
3722   Level: developer
3723 
3724 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetChart()`, `PetscSectionGetDof()`, `PetscSectionGetStorageSize()`, `PetscSectionCreate()`
3725 @*/
3726 PetscErrorCode PetscSectionExtractDofsFromArray(PetscSection origSection, MPI_Datatype dataType, const void *origArray, IS points, PetscSection *newSection, void *newArray[])
3727 {
3728   PetscSection    s;
3729   const PetscInt *points_;
3730   PetscInt        i, n, npoints, pStart, pEnd;
3731   PetscMPIInt     unitsize;
3732 
3733   PetscFunctionBegin;
3734   PetscValidHeaderSpecific(origSection, PETSC_SECTION_CLASSID, 1);
3735   PetscAssertPointer(origArray, 3);
3736   PetscValidHeaderSpecific(points, IS_CLASSID, 4);
3737   if (newSection) PetscAssertPointer(newSection, 5);
3738   if (newArray) PetscAssertPointer(newArray, 6);
3739   PetscCallMPI(MPI_Type_size(dataType, &unitsize));
3740   PetscCall(ISGetLocalSize(points, &npoints));
3741   PetscCall(ISGetIndices(points, &points_));
3742   PetscCall(PetscSectionGetChart(origSection, &pStart, &pEnd));
3743   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s));
3744   PetscCall(PetscSectionSetChart(s, 0, npoints));
3745   for (i = 0; i < npoints; i++) {
3746     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);
3747     PetscCall(PetscSectionGetDof(origSection, points_[i], &n));
3748     PetscCall(PetscSectionSetDof(s, i, n));
3749   }
3750   PetscCall(PetscSectionSetUp(s));
3751   if (newArray) {
3752     if (dataType == MPIU_INT) {
3753       PetscSectionExpandPoints_Loop(PetscInt);
3754     } else if (dataType == MPIU_SCALAR) {
3755       PetscSectionExpandPoints_Loop(PetscScalar);
3756     } else if (dataType == MPIU_REAL) {
3757       PetscSectionExpandPoints_Loop(PetscReal);
3758     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "not implemented for this MPI_Datatype");
3759   }
3760   if (newSection) {
3761     *newSection = s;
3762   } else {
3763     PetscCall(PetscSectionDestroy(&s));
3764   }
3765   PetscCall(ISRestoreIndices(points, &points_));
3766   PetscFunctionReturn(PETSC_SUCCESS);
3767 }
3768