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