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