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