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