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