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