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