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