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