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