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