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