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