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