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