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