xref: /petsc/src/vec/is/section/interface/section.c (revision d1e02d5a62c87991d613f70ecdd7c45f93285b39)
1 /*
2    This file contains routines for basic section object implementation.
3 */
4 
5 #include <petsc/private/sectionimpl.h>   /*I  "petscsection.h"   I*/
6 #include <petscsf.h>
7 
8 PetscClassId PETSC_SECTION_CLASSID;
9 
10 /*@
11   PetscSectionCreate - Allocates PetscSection space and sets the map contents to the default.
12 
13   Collective
14 
15   Input Parameters:
16 + comm - the MPI communicator
17 - s    - pointer to the section
18 
19   Level: beginner
20 
21   Notes:
22   Typical calling sequence
23 $       PetscSectionCreate(MPI_Comm,PetscSection *);
24 $       PetscSectionSetNumFields(PetscSection, numFields);
25 $       PetscSectionSetChart(PetscSection,low,high);
26 $       PetscSectionSetDof(PetscSection,point,numdof);
27 $       PetscSectionSetUp(PetscSection);
28 $       PetscSectionGetOffset(PetscSection,point,PetscInt *);
29 $       PetscSectionDestroy(PetscSection);
30 
31   The PetscSection object and methods are intended to be used in the PETSc Vec and Mat implementions; it is
32   recommended they not be used in user codes unless you really gain something in their use.
33 
34 .seealso: PetscSection, PetscSectionDestroy()
35 @*/
36 PetscErrorCode PetscSectionCreate(MPI_Comm comm, PetscSection *s)
37 {
38   PetscErrorCode ierr;
39 
40   PetscFunctionBegin;
41   PetscValidPointer(s,2);
42   ierr = ISInitializePackage();CHKERRQ(ierr);
43 
44   ierr = PetscHeaderCreate(*s,PETSC_SECTION_CLASSID,"PetscSection","Section","IS",comm,PetscSectionDestroy,PetscSectionView);CHKERRQ(ierr);
45 
46   (*s)->pStart              = -1;
47   (*s)->pEnd                = -1;
48   (*s)->perm                = NULL;
49   (*s)->pointMajor          = PETSC_TRUE;
50   (*s)->includesConstraints = PETSC_TRUE;
51   (*s)->maxDof              = 0;
52   (*s)->atlasDof            = NULL;
53   (*s)->atlasOff            = NULL;
54   (*s)->bc                  = NULL;
55   (*s)->bcIndices           = NULL;
56   (*s)->setup               = PETSC_FALSE;
57   (*s)->numFields           = 0;
58   (*s)->fieldNames          = NULL;
59   (*s)->field               = NULL;
60   (*s)->useFieldOff         = PETSC_FALSE;
61   (*s)->compNames           = NULL;
62   (*s)->clObj               = NULL;
63   (*s)->clHash              = NULL;
64   (*s)->clSection           = NULL;
65   (*s)->clPoints            = NULL;
66   PetscFunctionReturn(0);
67 }
68 
69 /*@
70   PetscSectionCopy - Creates a shallow (if possible) copy of the PetscSection
71 
72   Collective
73 
74   Input Parameter:
75 . section - the PetscSection
76 
77   Output Parameter:
78 . newSection - the copy
79 
80   Level: intermediate
81 
82 .seealso: PetscSection, PetscSectionCreate(), PetscSectionDestroy()
83 @*/
84 PetscErrorCode PetscSectionCopy(PetscSection section, PetscSection newSection)
85 {
86   PetscSectionSym sym;
87   IS              perm;
88   PetscInt        numFields, f, c, pStart, pEnd, p;
89   PetscErrorCode  ierr;
90 
91   PetscFunctionBegin;
92   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
93   PetscValidHeaderSpecific(newSection, PETSC_SECTION_CLASSID, 2);
94   ierr = PetscSectionReset(newSection);CHKERRQ(ierr);
95   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
96   if (numFields) {ierr = PetscSectionSetNumFields(newSection, numFields);CHKERRQ(ierr);}
97   for (f = 0; f < numFields; ++f) {
98     const char *fieldName = NULL, *compName = NULL;
99     PetscInt   numComp = 0;
100 
101     ierr = PetscSectionGetFieldName(section, f, &fieldName);CHKERRQ(ierr);
102     ierr = PetscSectionSetFieldName(newSection, f, fieldName);CHKERRQ(ierr);
103     ierr = PetscSectionGetFieldComponents(section, f, &numComp);CHKERRQ(ierr);
104     ierr = PetscSectionSetFieldComponents(newSection, f, numComp);CHKERRQ(ierr);
105     for (c = 0; c < numComp; ++c) {
106       ierr = PetscSectionGetComponentName(section, f, c, &compName);CHKERRQ(ierr);
107       ierr = PetscSectionSetComponentName(newSection, f, c, compName);CHKERRQ(ierr);
108     }
109     ierr = PetscSectionGetFieldSym(section, f, &sym);CHKERRQ(ierr);
110     ierr = PetscSectionSetFieldSym(newSection, f, sym);CHKERRQ(ierr);
111   }
112   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
113   ierr = PetscSectionSetChart(newSection, pStart, pEnd);CHKERRQ(ierr);
114   ierr = PetscSectionGetPermutation(section, &perm);CHKERRQ(ierr);
115   ierr = PetscSectionSetPermutation(newSection, perm);CHKERRQ(ierr);
116   ierr = PetscSectionGetSym(section, &sym);CHKERRQ(ierr);
117   ierr = PetscSectionSetSym(newSection, sym);CHKERRQ(ierr);
118   for (p = pStart; p < pEnd; ++p) {
119     PetscInt dof, cdof, fcdof = 0;
120 
121     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
122     ierr = PetscSectionSetDof(newSection, p, dof);CHKERRQ(ierr);
123     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
124     if (cdof) {ierr = PetscSectionSetConstraintDof(newSection, p, cdof);CHKERRQ(ierr);}
125     for (f = 0; f < numFields; ++f) {
126       ierr = PetscSectionGetFieldDof(section, p, f, &dof);CHKERRQ(ierr);
127       ierr = PetscSectionSetFieldDof(newSection, p, f, dof);CHKERRQ(ierr);
128       if (cdof) {
129         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
130         if (fcdof) {ierr = PetscSectionSetFieldConstraintDof(newSection, p, f, fcdof);CHKERRQ(ierr);}
131       }
132     }
133   }
134   ierr = PetscSectionSetUp(newSection);CHKERRQ(ierr);
135   for (p = pStart; p < pEnd; ++p) {
136     PetscInt       off, cdof, fcdof = 0;
137     const PetscInt *cInd;
138 
139     /* Must set offsets in case they do not agree with the prefix sums */
140     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
141     ierr = PetscSectionSetOffset(newSection, p, off);CHKERRQ(ierr);
142     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
143     if (cdof) {
144       ierr = PetscSectionGetConstraintIndices(section, p, &cInd);CHKERRQ(ierr);
145       ierr = PetscSectionSetConstraintIndices(newSection, p, cInd);CHKERRQ(ierr);
146       for (f = 0; f < numFields; ++f) {
147         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
148         if (fcdof) {
149           ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &cInd);CHKERRQ(ierr);
150           ierr = PetscSectionSetFieldConstraintIndices(newSection, p, f, cInd);CHKERRQ(ierr);
151         }
152       }
153     }
154   }
155   PetscFunctionReturn(0);
156 }
157 
158 /*@
159   PetscSectionClone - Creates a shallow (if possible) copy of the PetscSection
160 
161   Collective
162 
163   Input Parameter:
164 . section - the PetscSection
165 
166   Output Parameter:
167 . newSection - the copy
168 
169   Level: beginner
170 
171 .seealso: PetscSection, PetscSectionCreate(), PetscSectionDestroy()
172 @*/
173 PetscErrorCode PetscSectionClone(PetscSection section, PetscSection *newSection)
174 {
175   PetscErrorCode ierr;
176 
177   PetscFunctionBegin;
178   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
179   PetscValidPointer(newSection, 2);
180   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) section), newSection);CHKERRQ(ierr);
181   ierr = PetscSectionCopy(section, *newSection);CHKERRQ(ierr);
182   PetscFunctionReturn(0);
183 }
184 
185 /*@
186   PetscSectionSetFromOptions - sets parameters in a PetscSection from the options database
187 
188   Collective on PetscSection
189 
190   Input Parameter:
191 . section - the PetscSection
192 
193   Options Database:
194 . -petscsection_point_major the dof order
195 
196   Level: intermediate
197 
198 .seealso: PetscSection, PetscSectionCreate(), PetscSectionDestroy()
199 @*/
200 PetscErrorCode PetscSectionSetFromOptions(PetscSection s)
201 {
202   PetscErrorCode ierr;
203 
204   PetscFunctionBegin;
205   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
206   ierr = PetscObjectOptionsBegin((PetscObject) s);CHKERRQ(ierr);
207   ierr = PetscOptionsBool("-petscsection_point_major", "The for ordering, either point major or field major", "PetscSectionSetPointMajor", s->pointMajor, &s->pointMajor, NULL);CHKERRQ(ierr);
208   /* process any options handlers added with PetscObjectAddOptionsHandler() */
209   ierr = PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) s);CHKERRQ(ierr);
210   ierr = PetscOptionsEnd();CHKERRQ(ierr);
211   ierr = PetscObjectViewFromOptions((PetscObject) s, NULL, "-petscsection_view");CHKERRQ(ierr);
212   PetscFunctionReturn(0);
213 }
214 
215 /*@
216   PetscSectionCompare - Compares two sections
217 
218   Collective on PetscSection
219 
220   Input Parameters:
221 + s1 - the first PetscSection
222 - s2 - the second PetscSection
223 
224   Output Parameter:
225 . congruent - PETSC_TRUE if the two sections are congruent, PETSC_FALSE otherwise
226 
227   Level: intermediate
228 
229   Notes:
230   Field names are disregarded.
231 
232 .seealso: PetscSection, PetscSectionCreate(), PetscSectionCopy(), PetscSectionClone()
233 @*/
234 PetscErrorCode PetscSectionCompare(PetscSection s1, PetscSection s2, PetscBool *congruent)
235 {
236   PetscInt pStart, pEnd, nfields, ncdof, nfcdof, p, f, n1, n2;
237   const PetscInt *idx1, *idx2;
238   IS perm1, perm2;
239   PetscBool flg;
240   PetscMPIInt mflg;
241   PetscErrorCode ierr;
242 
243   PetscFunctionBegin;
244   PetscValidHeaderSpecific(s1, PETSC_SECTION_CLASSID, 1);
245   PetscValidHeaderSpecific(s2, PETSC_SECTION_CLASSID, 2);
246   PetscValidBoolPointer(congruent,3);
247   flg = PETSC_FALSE;
248 
249   ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)s1),PetscObjectComm((PetscObject)s2),&mflg);CHKERRMPI(ierr);
250   if (mflg != MPI_CONGRUENT && mflg != MPI_IDENT) {
251     *congruent = PETSC_FALSE;
252     PetscFunctionReturn(0);
253   }
254 
255   ierr = PetscSectionGetChart(s1, &pStart, &pEnd);CHKERRQ(ierr);
256   ierr = PetscSectionGetChart(s2, &n1, &n2);CHKERRQ(ierr);
257   if (pStart != n1 || pEnd != n2) goto not_congruent;
258 
259   ierr = PetscSectionGetPermutation(s1, &perm1);CHKERRQ(ierr);
260   ierr = PetscSectionGetPermutation(s2, &perm2);CHKERRQ(ierr);
261   if (perm1 && perm2) {
262     ierr = ISEqual(perm1, perm2, congruent);CHKERRQ(ierr);
263     if (!(*congruent)) goto not_congruent;
264   } else if (perm1 != perm2) goto not_congruent;
265 
266   for (p = pStart; p < pEnd; ++p) {
267     ierr = PetscSectionGetOffset(s1, p, &n1);CHKERRQ(ierr);
268     ierr = PetscSectionGetOffset(s2, p, &n2);CHKERRQ(ierr);
269     if (n1 != n2) goto not_congruent;
270 
271     ierr = PetscSectionGetDof(s1, p, &n1);CHKERRQ(ierr);
272     ierr = PetscSectionGetDof(s2, p, &n2);CHKERRQ(ierr);
273     if (n1 != n2) goto not_congruent;
274 
275     ierr = PetscSectionGetConstraintDof(s1, p, &ncdof);CHKERRQ(ierr);
276     ierr = PetscSectionGetConstraintDof(s2, p, &n2);CHKERRQ(ierr);
277     if (ncdof != n2) goto not_congruent;
278 
279     ierr = PetscSectionGetConstraintIndices(s1, p, &idx1);CHKERRQ(ierr);
280     ierr = PetscSectionGetConstraintIndices(s2, p, &idx2);CHKERRQ(ierr);
281     ierr = PetscArraycmp(idx1, idx2, ncdof, congruent);CHKERRQ(ierr);
282     if (!(*congruent)) goto not_congruent;
283   }
284 
285   ierr = PetscSectionGetNumFields(s1, &nfields);CHKERRQ(ierr);
286   ierr = PetscSectionGetNumFields(s2, &n2);CHKERRQ(ierr);
287   if (nfields != n2) goto not_congruent;
288 
289   for (f = 0; f < nfields; ++f) {
290     ierr = PetscSectionGetFieldComponents(s1, f, &n1);CHKERRQ(ierr);
291     ierr = PetscSectionGetFieldComponents(s2, f, &n2);CHKERRQ(ierr);
292     if (n1 != n2) goto not_congruent;
293 
294     for (p = pStart; p < pEnd; ++p) {
295       ierr = PetscSectionGetFieldOffset(s1, p, f, &n1);CHKERRQ(ierr);
296       ierr = PetscSectionGetFieldOffset(s2, p, f, &n2);CHKERRQ(ierr);
297       if (n1 != n2) goto not_congruent;
298 
299       ierr = PetscSectionGetFieldDof(s1, p, f, &n1);CHKERRQ(ierr);
300       ierr = PetscSectionGetFieldDof(s2, p, f, &n2);CHKERRQ(ierr);
301       if (n1 != n2) goto not_congruent;
302 
303       ierr = PetscSectionGetFieldConstraintDof(s1, p, f, &nfcdof);CHKERRQ(ierr);
304       ierr = PetscSectionGetFieldConstraintDof(s2, p, f, &n2);CHKERRQ(ierr);
305       if (nfcdof != n2) goto not_congruent;
306 
307       ierr = PetscSectionGetFieldConstraintIndices(s1, p, f, &idx1);CHKERRQ(ierr);
308       ierr = PetscSectionGetFieldConstraintIndices(s2, p, f, &idx2);CHKERRQ(ierr);
309       ierr = PetscArraycmp(idx1, idx2, nfcdof, congruent);CHKERRQ(ierr);
310       if (!(*congruent)) goto not_congruent;
311     }
312   }
313 
314   flg = PETSC_TRUE;
315 not_congruent:
316   ierr = MPIU_Allreduce(&flg,congruent,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)s1));CHKERRMPI(ierr);
317   PetscFunctionReturn(0);
318 }
319 
320 /*@
321   PetscSectionGetNumFields - Returns the number of fields, or 0 if no fields were defined.
322 
323   Not collective
324 
325   Input Parameter:
326 . s - the PetscSection
327 
328   Output Parameter:
329 . numFields - the number of fields defined, or 0 if none were defined
330 
331   Level: intermediate
332 
333 .seealso: PetscSectionSetNumFields()
334 @*/
335 PetscErrorCode PetscSectionGetNumFields(PetscSection s, PetscInt *numFields)
336 {
337   PetscFunctionBegin;
338   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
339   PetscValidPointer(numFields,2);
340   *numFields = s->numFields;
341   PetscFunctionReturn(0);
342 }
343 
344 /*@
345   PetscSectionSetNumFields - Sets the number of fields.
346 
347   Not collective
348 
349   Input Parameters:
350 + s - the PetscSection
351 - numFields - the number of fields
352 
353   Level: intermediate
354 
355 .seealso: PetscSectionGetNumFields()
356 @*/
357 PetscErrorCode PetscSectionSetNumFields(PetscSection s, PetscInt numFields)
358 {
359   PetscInt       f;
360   PetscErrorCode ierr;
361 
362   PetscFunctionBegin;
363   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
364   PetscCheckFalse(numFields <= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "The number of fields %" PetscInt_FMT " must be positive", numFields);
365   ierr = PetscSectionReset(s);CHKERRQ(ierr);
366 
367   s->numFields = numFields;
368   ierr = PetscMalloc1(s->numFields, &s->numFieldComponents);CHKERRQ(ierr);
369   ierr = PetscMalloc1(s->numFields, &s->fieldNames);CHKERRQ(ierr);
370   ierr = PetscMalloc1(s->numFields, &s->compNames);CHKERRQ(ierr);
371   ierr = PetscMalloc1(s->numFields, &s->field);CHKERRQ(ierr);
372   for (f = 0; f < s->numFields; ++f) {
373     char name[64];
374 
375     s->numFieldComponents[f] = 1;
376 
377     ierr = PetscSectionCreate(PetscObjectComm((PetscObject) s), &s->field[f]);CHKERRQ(ierr);
378     ierr = PetscSNPrintf(name, 64, "Field_%" PetscInt_FMT, f);CHKERRQ(ierr);
379     ierr = PetscStrallocpy(name, (char **) &s->fieldNames[f]);CHKERRQ(ierr);
380     ierr = PetscSNPrintf(name, 64, "Component_0");CHKERRQ(ierr);
381     ierr = PetscMalloc1(s->numFieldComponents[f], &s->compNames[f]);CHKERRQ(ierr);
382     ierr = PetscStrallocpy(name, (char **) &s->compNames[f][0]);CHKERRQ(ierr);
383   }
384   PetscFunctionReturn(0);
385 }
386 
387 /*@C
388   PetscSectionGetFieldName - Returns the name of a field in the PetscSection
389 
390   Not Collective
391 
392   Input Parameters:
393 + s     - the PetscSection
394 - field - the field number
395 
396   Output Parameter:
397 . fieldName - the field name
398 
399   Level: intermediate
400 
401 .seealso: PetscSectionSetFieldName()
402 @*/
403 PetscErrorCode PetscSectionGetFieldName(PetscSection s, PetscInt field, const char *fieldName[])
404 {
405   PetscFunctionBegin;
406   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
407   PetscValidPointer(fieldName, 3);
408   PetscSectionCheckValidField(field,s->numFields);
409   *fieldName = s->fieldNames[field];
410   PetscFunctionReturn(0);
411 }
412 
413 /*@C
414   PetscSectionSetFieldName - Sets the name of a field in the PetscSection
415 
416   Not Collective
417 
418   Input Parameters:
419 + s     - the PetscSection
420 . field - the field number
421 - fieldName - the field name
422 
423   Level: intermediate
424 
425 .seealso: PetscSectionGetFieldName()
426 @*/
427 PetscErrorCode PetscSectionSetFieldName(PetscSection s, PetscInt field, const char fieldName[])
428 {
429   PetscErrorCode ierr;
430 
431   PetscFunctionBegin;
432   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
433   if (fieldName) PetscValidCharPointer(fieldName, 3);
434   PetscSectionCheckValidField(field,s->numFields);
435   ierr = PetscFree(s->fieldNames[field]);CHKERRQ(ierr);
436   ierr = PetscStrallocpy(fieldName, (char**) &s->fieldNames[field]);CHKERRQ(ierr);
437   PetscFunctionReturn(0);
438 }
439 
440 /*@C
441   PetscSectionGetComponentName - Gets the name of a field component in the PetscSection
442 
443   Not Collective
444 
445   Input Parameters:
446 + s     - the PetscSection
447 . field - the field number
448 . comp  - the component number
449 - compName - the component name
450 
451   Level: intermediate
452 
453 .seealso: PetscSectionSetComponentName()
454 @*/
455 PetscErrorCode PetscSectionGetComponentName(PetscSection s, PetscInt field, PetscInt comp, const char *compName[])
456 {
457   PetscFunctionBegin;
458   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
459   PetscValidPointer(compName, 4);
460   PetscSectionCheckValidField(field,s->numFields);
461   PetscSectionCheckValidFieldComponent(comp,s->numFieldComponents[field]);
462   *compName = s->compNames[field][comp];
463   PetscFunctionReturn(0);
464 }
465 
466 /*@C
467   PetscSectionSetComponentName - Sets the name of a field component in the PetscSection
468 
469   Not Collective
470 
471   Input Parameters:
472 + s     - the PetscSection
473 . field - the field number
474 . comp  - the component number
475 - compName - the component name
476 
477   Level: intermediate
478 
479 .seealso: PetscSectionGetComponentName()
480 @*/
481 PetscErrorCode PetscSectionSetComponentName(PetscSection s, PetscInt field, PetscInt comp, const char compName[])
482 {
483   PetscErrorCode ierr;
484 
485   PetscFunctionBegin;
486   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
487   if (compName) PetscValidCharPointer(compName, 4);
488   PetscSectionCheckValidField(field,s->numFields);
489   PetscSectionCheckValidFieldComponent(comp,s->numFieldComponents[field]);
490   ierr = PetscFree(s->compNames[field][comp]);CHKERRQ(ierr);
491   ierr = PetscStrallocpy(compName, (char**) &s->compNames[field][comp]);CHKERRQ(ierr);
492   PetscFunctionReturn(0);
493 }
494 
495 /*@
496   PetscSectionGetFieldComponents - Returns the number of field components for the given field.
497 
498   Not collective
499 
500   Input Parameters:
501 + s - the PetscSection
502 - field - the field number
503 
504   Output Parameter:
505 . numComp - the number of field components
506 
507   Level: intermediate
508 
509 .seealso: PetscSectionSetFieldComponents(), PetscSectionGetNumFields()
510 @*/
511 PetscErrorCode PetscSectionGetFieldComponents(PetscSection s, PetscInt field, PetscInt *numComp)
512 {
513   PetscFunctionBegin;
514   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
515   PetscValidIntPointer(numComp, 3);
516   PetscSectionCheckValidField(field,s->numFields);
517   *numComp = s->numFieldComponents[field];
518   PetscFunctionReturn(0);
519 }
520 
521 /*@
522   PetscSectionSetFieldComponents - Sets the number of field components for the given field.
523 
524   Not collective
525 
526   Input Parameters:
527 + s - the PetscSection
528 . field - the field number
529 - numComp - the number of field components
530 
531   Level: intermediate
532 
533 .seealso: PetscSectionGetFieldComponents(), PetscSectionGetNumFields()
534 @*/
535 PetscErrorCode PetscSectionSetFieldComponents(PetscSection s, PetscInt field, PetscInt numComp)
536 {
537   PetscErrorCode ierr;
538   PetscInt       c;
539 
540   PetscFunctionBegin;
541   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
542   PetscSectionCheckValidField(field,s->numFields);
543   if (s->compNames) {
544     for (c = 0; c < s->numFieldComponents[field]; ++c) {
545       ierr = PetscFree(s->compNames[field][c]);CHKERRQ(ierr);
546     }
547     ierr = PetscFree(s->compNames[field]);CHKERRQ(ierr);
548   }
549 
550   s->numFieldComponents[field] = numComp;
551   if (numComp) {
552     ierr = PetscMalloc1(numComp, (char ***) &s->compNames[field]);CHKERRQ(ierr);
553     for (c = 0; c < numComp; ++c) {
554       char name[64];
555 
556       ierr = PetscSNPrintf(name, 64, "%" PetscInt_FMT, c);CHKERRQ(ierr);
557       ierr = PetscStrallocpy(name, (char **) &s->compNames[field][c]);CHKERRQ(ierr);
558     }
559   }
560   PetscFunctionReturn(0);
561 }
562 
563 static PetscErrorCode PetscSectionCheckConstraints_Static(PetscSection s)
564 {
565   PetscErrorCode ierr;
566 
567   PetscFunctionBegin;
568   if (!s->bc) {
569     ierr = PetscSectionCreate(PETSC_COMM_SELF, &s->bc);CHKERRQ(ierr);
570     ierr = PetscSectionSetChart(s->bc, s->pStart, s->pEnd);CHKERRQ(ierr);
571   }
572   PetscFunctionReturn(0);
573 }
574 
575 /*@
576   PetscSectionGetChart - Returns the range [pStart, pEnd) in which points lie.
577 
578   Not collective
579 
580   Input Parameter:
581 . s - the PetscSection
582 
583   Output Parameters:
584 + pStart - the first point
585 - pEnd - one past the last point
586 
587   Level: intermediate
588 
589 .seealso: PetscSectionSetChart(), PetscSectionCreate()
590 @*/
591 PetscErrorCode PetscSectionGetChart(PetscSection s, PetscInt *pStart, PetscInt *pEnd)
592 {
593   PetscFunctionBegin;
594   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
595   if (pStart) *pStart = s->pStart;
596   if (pEnd)   *pEnd   = s->pEnd;
597   PetscFunctionReturn(0);
598 }
599 
600 /*@
601   PetscSectionSetChart - Sets the range [pStart, pEnd) in which points lie.
602 
603   Not collective
604 
605   Input Parameters:
606 + s - the PetscSection
607 . pStart - the first point
608 - pEnd - one past the last point
609 
610   Level: intermediate
611 
612 .seealso: PetscSectionGetChart(), PetscSectionCreate()
613 @*/
614 PetscErrorCode PetscSectionSetChart(PetscSection s, PetscInt pStart, PetscInt pEnd)
615 {
616   PetscInt       f;
617   PetscErrorCode ierr;
618 
619   PetscFunctionBegin;
620   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
621   if (pStart == s->pStart && pEnd == s->pEnd) PetscFunctionReturn(0);
622   /* Cannot Reset() because it destroys field information */
623   s->setup = PETSC_FALSE;
624   ierr = PetscSectionDestroy(&s->bc);CHKERRQ(ierr);
625   ierr = PetscFree(s->bcIndices);CHKERRQ(ierr);
626   ierr = PetscFree2(s->atlasDof, s->atlasOff);CHKERRQ(ierr);
627 
628   s->pStart = pStart;
629   s->pEnd   = pEnd;
630   ierr = PetscMalloc2((pEnd - pStart), &s->atlasDof, (pEnd - pStart), &s->atlasOff);CHKERRQ(ierr);
631   ierr = PetscArrayzero(s->atlasDof, pEnd - pStart);CHKERRQ(ierr);
632   for (f = 0; f < s->numFields; ++f) {
633     ierr = PetscSectionSetChart(s->field[f], pStart, pEnd);CHKERRQ(ierr);
634   }
635   PetscFunctionReturn(0);
636 }
637 
638 /*@
639   PetscSectionGetPermutation - Returns the permutation of [0, pEnd-pStart) or NULL
640 
641   Not collective
642 
643   Input Parameter:
644 . s - the PetscSection
645 
646   Output Parameters:
647 . perm - The permutation as an IS
648 
649   Level: intermediate
650 
651 .seealso: PetscSectionSetPermutation(), PetscSectionCreate()
652 @*/
653 PetscErrorCode PetscSectionGetPermutation(PetscSection s, IS *perm)
654 {
655   PetscFunctionBegin;
656   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
657   if (perm) {PetscValidPointer(perm, 2); *perm = s->perm;}
658   PetscFunctionReturn(0);
659 }
660 
661 /*@
662   PetscSectionSetPermutation - Sets the permutation for [0, pEnd-pStart)
663 
664   Not collective
665 
666   Input Parameters:
667 + s - the PetscSection
668 - perm - the permutation of points
669 
670   Level: intermediate
671 
672 .seealso: PetscSectionGetPermutation(), PetscSectionCreate()
673 @*/
674 PetscErrorCode PetscSectionSetPermutation(PetscSection s, IS perm)
675 {
676   PetscErrorCode ierr;
677 
678   PetscFunctionBegin;
679   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
680   if (perm) PetscValidHeaderSpecific(perm, IS_CLASSID, 2);
681   PetscCheckFalse(s->setup,PetscObjectComm((PetscObject) s), PETSC_ERR_ARG_WRONGSTATE, "Cannot set a permutation after the section is setup");
682   if (s->perm != perm) {
683     ierr = ISDestroy(&s->perm);CHKERRQ(ierr);
684     if (perm) {
685       s->perm = perm;
686       ierr = PetscObjectReference((PetscObject) s->perm);CHKERRQ(ierr);
687     }
688   }
689   PetscFunctionReturn(0);
690 }
691 
692 /*@
693   PetscSectionGetPointMajor - Returns the flag for dof ordering, true if it is point major, otherwise field major
694 
695   Not collective
696 
697   Input Parameter:
698 . s - the PetscSection
699 
700   Output Parameter:
701 . pm - the flag for point major ordering
702 
703   Level: intermediate
704 
705 .seealso: PetscSectionSetPointMajor()
706 @*/
707 PetscErrorCode PetscSectionGetPointMajor(PetscSection s, PetscBool *pm)
708 {
709   PetscFunctionBegin;
710   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
711   PetscValidPointer(pm,2);
712   *pm = s->pointMajor;
713   PetscFunctionReturn(0);
714 }
715 
716 /*@
717   PetscSectionSetPointMajor - Sets the flag for dof ordering, true if it is point major, otherwise field major
718 
719   Not collective
720 
721   Input Parameters:
722 + s  - the PetscSection
723 - pm - the flag for point major ordering
724 
725   Not collective
726 
727   Level: intermediate
728 
729 .seealso: PetscSectionGetPointMajor()
730 @*/
731 PetscErrorCode PetscSectionSetPointMajor(PetscSection s, PetscBool pm)
732 {
733   PetscFunctionBegin;
734   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
735   PetscCheckFalse(s->setup,PetscObjectComm((PetscObject) s), PETSC_ERR_ARG_WRONGSTATE, "Cannot set the dof ordering after the section is setup");
736   s->pointMajor = pm;
737   PetscFunctionReturn(0);
738 }
739 
740 /*@
741   PetscSectionGetIncludesConstraints - Returns the flag indicating if constrained dofs were included when computing offsets
742 
743   Not collective
744 
745   Input Parameter:
746 . s - the PetscSection
747 
748   Output Parameter:
749 . includesConstraints - the flag indicating if constrained dofs were included when computing offsets
750 
751   Level: intermediate
752 
753 .seealso: PetscSectionSetIncludesConstraints()
754 @*/
755 PetscErrorCode PetscSectionGetIncludesConstraints(PetscSection s, PetscBool *includesConstraints)
756 {
757   PetscFunctionBegin;
758   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
759   PetscValidBoolPointer(includesConstraints,2);
760   *includesConstraints = s->includesConstraints;
761   PetscFunctionReturn(0);
762 }
763 
764 /*@
765   PetscSectionSetIncludesConstraints - Sets the flag indicating if constrained dofs are to be included when computing offsets
766 
767   Not collective
768 
769   Input Parameters:
770 + s  - the PetscSection
771 - includesConstraints - the flag indicating if constrained dofs are to be included when computing offsets
772 
773   Not collective
774 
775   Level: intermediate
776 
777 .seealso: PetscSectionGetIncludesConstraints()
778 @*/
779 PetscErrorCode PetscSectionSetIncludesConstraints(PetscSection s, PetscBool includesConstraints)
780 {
781   PetscFunctionBegin;
782   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
783   PetscCheckFalse(s->setup,PetscObjectComm((PetscObject) s), PETSC_ERR_ARG_WRONGSTATE, "Cannot set includesConstraints after the section is set up");
784   s->includesConstraints = includesConstraints;
785   PetscFunctionReturn(0);
786 }
787 
788 /*@
789   PetscSectionGetDof - Return the number of degrees of freedom associated with a given point.
790 
791   Not collective
792 
793   Input Parameters:
794 + s - the PetscSection
795 - point - the point
796 
797   Output Parameter:
798 . numDof - the number of dof
799 
800   Level: intermediate
801 
802 .seealso: PetscSectionSetDof(), PetscSectionCreate()
803 @*/
804 PetscErrorCode PetscSectionGetDof(PetscSection s, PetscInt point, PetscInt *numDof)
805 {
806   PetscFunctionBeginHot;
807   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
808   PetscValidPointer(numDof, 3);
809   if (PetscDefined(USE_DEBUG)) {
810     PetscCheckFalse((point < s->pStart) || (point >= s->pEnd),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section point %" PetscInt_FMT " should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, s->pStart, s->pEnd);
811   }
812   *numDof = s->atlasDof[point - s->pStart];
813   PetscFunctionReturn(0);
814 }
815 
816 /*@
817   PetscSectionSetDof - Sets the number of degrees of freedom associated with a given point.
818 
819   Not collective
820 
821   Input Parameters:
822 + s - the PetscSection
823 . point - the point
824 - numDof - the number of dof
825 
826   Level: intermediate
827 
828 .seealso: PetscSectionGetDof(), PetscSectionAddDof(), PetscSectionCreate()
829 @*/
830 PetscErrorCode PetscSectionSetDof(PetscSection s, PetscInt point, PetscInt numDof)
831 {
832   PetscFunctionBegin;
833   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
834   PetscCheckFalse((point < s->pStart) || (point >= s->pEnd),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section point %" PetscInt_FMT " should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, s->pStart, s->pEnd);
835   s->atlasDof[point - s->pStart] = numDof;
836   PetscFunctionReturn(0);
837 }
838 
839 /*@
840   PetscSectionAddDof - Adds to the number of degrees of freedom associated with a given point.
841 
842   Not collective
843 
844   Input Parameters:
845 + s - the PetscSection
846 . point - the point
847 - numDof - the number of additional dof
848 
849   Level: intermediate
850 
851 .seealso: PetscSectionGetDof(), PetscSectionSetDof(), PetscSectionCreate()
852 @*/
853 PetscErrorCode PetscSectionAddDof(PetscSection s, PetscInt point, PetscInt numDof)
854 {
855   PetscFunctionBeginHot;
856   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
857   if (PetscDefined(USE_DEBUG)) {
858     PetscCheckFalse((point < s->pStart) || (point >= s->pEnd),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section point %" PetscInt_FMT " should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, s->pStart, s->pEnd);
859   }
860   s->atlasDof[point - s->pStart] += numDof;
861   PetscFunctionReturn(0);
862 }
863 
864 /*@
865   PetscSectionGetFieldDof - Return the number of degrees of freedom associated with a field on a given point.
866 
867   Not collective
868 
869   Input Parameters:
870 + s - the PetscSection
871 . point - the point
872 - field - the field
873 
874   Output Parameter:
875 . numDof - the number of dof
876 
877   Level: intermediate
878 
879 .seealso: PetscSectionSetFieldDof(), PetscSectionCreate()
880 @*/
881 PetscErrorCode PetscSectionGetFieldDof(PetscSection s, PetscInt point, PetscInt field, PetscInt *numDof)
882 {
883   PetscErrorCode ierr;
884 
885   PetscFunctionBegin;
886   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
887   PetscValidIntPointer(numDof,4);
888   PetscSectionCheckValidField(field,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   PetscSectionCheckValidField(field,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   PetscSectionCheckValidField(field,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   PetscValidIntPointer(numDof, 4);
1052   PetscSectionCheckValidField(field,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   PetscSectionCheckValidField(field,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   PetscSectionCheckValidField(field,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   PetscCheckFalse(!s->includesConstraints,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   PetscCheckFalse(!s->pointMajor,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     PetscCheckFalse(nroots < pEnd,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "SF roots %" PetscInt_FMT " < pEnd %" PetscInt_FMT, nroots, pEnd);
1331     PetscCheckFalse(maxleaf >= nroots,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Max local leaf %" PetscInt_FMT " >= nroots %" PetscInt_FMT, 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         PetscCheckFalse(-(recv[p]+1) != dof,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Global dof %" PetscInt_FMT " for point %" PetscInt_FMT " is not the unconstrained %" PetscInt_FMT, -(recv[p]+1), p, dof);
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     PetscCheckFalse(nroots < pEnd-pStart,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %" PetscInt_FMT " < %" PetscInt_FMT " 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     PetscCheckFalse((point < s->pStart) || (point >= s->pEnd),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section point %" PetscInt_FMT " should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, s->pStart, s->pEnd);
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   PetscCheckFalse((point < s->pStart) || (point >= s->pEnd),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section point %" PetscInt_FMT " should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, s->pStart, s->pEnd);
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   PetscValidIntPointer(offset, 4);
1668   PetscSectionCheckValidField(field,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   PetscSectionCheckValidField(field,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   PetscValidIntPointer(offset, 4);
1729   PetscSectionCheckValidField(field,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 Parameters:
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   PetscCheckFalse(len > nF,PetscObjectComm((PetscObject) s), PETSC_ERR_ARG_WRONG, "Number of requested fields %" PetscInt_FMT " greater than number of fields %" PetscInt_FMT, len, nF);
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           ierr = PetscSectionGetFieldDof(s, p, fields[f], &fdof);CHKERRQ(ierr);
1852           ierr = PetscSectionGetFieldConstraintDof(s, p, fields[f], &cfdof);CHKERRQ(ierr);
1853           ierr = PetscSectionGetFieldConstraintIndices(s, p, fields[f], &oldIndices);CHKERRQ(ierr);
1854           ierr = PetscSectionSetFieldConstraintIndices(*subs, p, f, oldIndices);CHKERRQ(ierr);
1855           for (fc = 0; fc < cfdof; ++fc) indices[numConst+fc] = oldIndices[fc] + fOff;
1856           numConst += cfdof;
1857           fOff     += fdof;
1858         }
1859         ierr = PetscSectionSetConstraintIndices(*subs, p, indices);CHKERRQ(ierr);
1860       }
1861     }
1862     ierr = PetscFree(indices);CHKERRQ(ierr);
1863   }
1864   PetscFunctionReturn(0);
1865 }
1866 
1867 /*@
1868   PetscSectionCreateSupersection - Create a new, larger section composed of the input sections
1869 
1870   Collective on s
1871 
1872   Input Parameters:
1873 + s     - the input sections
1874 - len   - the number of input sections
1875 
1876   Output Parameter:
1877 . supers - the supersection
1878 
1879   Note: The section offsets now refer to a new, larger vector.
1880 
1881   Level: advanced
1882 
1883 .seealso: PetscSectionCreateSubsection(), PetscSectionCreate()
1884 @*/
1885 PetscErrorCode PetscSectionCreateSupersection(PetscSection s[], PetscInt len, PetscSection *supers)
1886 {
1887   PetscInt       Nf = 0, f, pStart = PETSC_MAX_INT, pEnd = 0, p, maxCdof = 0, i;
1888   PetscErrorCode ierr;
1889 
1890   PetscFunctionBegin;
1891   if (!len) PetscFunctionReturn(0);
1892   for (i = 0; i < len; ++i) {
1893     PetscInt nf, pStarti, pEndi;
1894 
1895     ierr = PetscSectionGetNumFields(s[i], &nf);CHKERRQ(ierr);
1896     ierr = PetscSectionGetChart(s[i], &pStarti, &pEndi);CHKERRQ(ierr);
1897     pStart = PetscMin(pStart, pStarti);
1898     pEnd   = PetscMax(pEnd,   pEndi);
1899     Nf += nf;
1900   }
1901   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) s[0]), supers);CHKERRQ(ierr);
1902   ierr = PetscSectionSetNumFields(*supers, Nf);CHKERRQ(ierr);
1903   for (i = 0, f = 0; i < len; ++i) {
1904     PetscInt nf, fi, ci;
1905 
1906     ierr = PetscSectionGetNumFields(s[i], &nf);CHKERRQ(ierr);
1907     for (fi = 0; fi < nf; ++fi, ++f) {
1908       const char *name   = NULL;
1909       PetscInt   numComp = 0;
1910 
1911       ierr = PetscSectionGetFieldName(s[i], fi, &name);CHKERRQ(ierr);
1912       ierr = PetscSectionSetFieldName(*supers, f, name);CHKERRQ(ierr);
1913       ierr = PetscSectionGetFieldComponents(s[i], fi, &numComp);CHKERRQ(ierr);
1914       ierr = PetscSectionSetFieldComponents(*supers, f, numComp);CHKERRQ(ierr);
1915       for (ci = 0; ci < s[i]->numFieldComponents[fi]; ++ci) {
1916         ierr = PetscSectionGetComponentName(s[i], fi, ci, &name);CHKERRQ(ierr);
1917         ierr = PetscSectionSetComponentName(*supers, f, ci, name);CHKERRQ(ierr);
1918       }
1919     }
1920   }
1921   ierr = PetscSectionSetChart(*supers, pStart, pEnd);CHKERRQ(ierr);
1922   for (p = pStart; p < pEnd; ++p) {
1923     PetscInt dof = 0, cdof = 0;
1924 
1925     for (i = 0, f = 0; i < len; ++i) {
1926       PetscInt nf, fi, pStarti, pEndi;
1927       PetscInt fdof = 0, cfdof = 0;
1928 
1929       ierr = PetscSectionGetNumFields(s[i], &nf);CHKERRQ(ierr);
1930       ierr = PetscSectionGetChart(s[i], &pStarti, &pEndi);CHKERRQ(ierr);
1931       if ((p < pStarti) || (p >= pEndi)) continue;
1932       for (fi = 0; fi < nf; ++fi, ++f) {
1933         ierr = PetscSectionGetFieldDof(s[i], p, fi, &fdof);CHKERRQ(ierr);
1934         ierr = PetscSectionAddFieldDof(*supers, p, f, fdof);CHKERRQ(ierr);
1935         ierr = PetscSectionGetFieldConstraintDof(s[i], p, fi, &cfdof);CHKERRQ(ierr);
1936         if (cfdof) {ierr = PetscSectionAddFieldConstraintDof(*supers, p, f, cfdof);CHKERRQ(ierr);}
1937         dof  += fdof;
1938         cdof += cfdof;
1939       }
1940     }
1941     ierr = PetscSectionSetDof(*supers, p, dof);CHKERRQ(ierr);
1942     if (cdof) {ierr = PetscSectionSetConstraintDof(*supers, p, cdof);CHKERRQ(ierr);}
1943     maxCdof = PetscMax(cdof, maxCdof);
1944   }
1945   ierr = PetscSectionSetUp(*supers);CHKERRQ(ierr);
1946   if (maxCdof) {
1947     PetscInt *indices;
1948 
1949     ierr = PetscMalloc1(maxCdof, &indices);CHKERRQ(ierr);
1950     for (p = pStart; p < pEnd; ++p) {
1951       PetscInt cdof;
1952 
1953       ierr = PetscSectionGetConstraintDof(*supers, p, &cdof);CHKERRQ(ierr);
1954       if (cdof) {
1955         PetscInt dof, numConst = 0, fOff = 0;
1956 
1957         for (i = 0, f = 0; i < len; ++i) {
1958           const PetscInt *oldIndices = NULL;
1959           PetscInt        nf, fi, pStarti, pEndi, fdof, cfdof, fc;
1960 
1961           ierr = PetscSectionGetNumFields(s[i], &nf);CHKERRQ(ierr);
1962           ierr = PetscSectionGetChart(s[i], &pStarti, &pEndi);CHKERRQ(ierr);
1963           if ((p < pStarti) || (p >= pEndi)) continue;
1964           for (fi = 0; fi < nf; ++fi, ++f) {
1965             ierr = PetscSectionGetFieldDof(s[i], p, fi, &fdof);CHKERRQ(ierr);
1966             ierr = PetscSectionGetFieldConstraintDof(s[i], p, fi, &cfdof);CHKERRQ(ierr);
1967             ierr = PetscSectionGetFieldConstraintIndices(s[i], p, fi, &oldIndices);CHKERRQ(ierr);
1968             for (fc = 0; fc < cfdof; ++fc) indices[numConst+fc] = oldIndices[fc];
1969             ierr = PetscSectionSetFieldConstraintIndices(*supers, p, f, &indices[numConst]);CHKERRQ(ierr);
1970             for (fc = 0; fc < cfdof; ++fc) indices[numConst+fc] += fOff;
1971             numConst += cfdof;
1972           }
1973           ierr = PetscSectionGetDof(s[i], p, &dof);CHKERRQ(ierr);
1974           fOff += dof;
1975         }
1976         ierr = PetscSectionSetConstraintIndices(*supers, p, indices);CHKERRQ(ierr);
1977       }
1978     }
1979     ierr = PetscFree(indices);CHKERRQ(ierr);
1980   }
1981   PetscFunctionReturn(0);
1982 }
1983 
1984 /*@
1985   PetscSectionCreateSubmeshSection - Create a new, smaller section with support on the submesh
1986 
1987   Collective on s
1988 
1989   Input Parameters:
1990 + s           - the PetscSection
1991 - subpointMap - a sorted list of points in the original mesh which are in the submesh
1992 
1993   Output Parameter:
1994 . subs - the subsection
1995 
1996   Note: The section offsets now refer to a new, smaller vector.
1997 
1998   Level: advanced
1999 
2000 .seealso: PetscSectionCreateSubsection(), DMPlexGetSubpointMap(), PetscSectionCreate()
2001 @*/
2002 PetscErrorCode PetscSectionCreateSubmeshSection(PetscSection s, IS subpointMap, PetscSection *subs)
2003 {
2004   const PetscInt *points = NULL, *indices = NULL;
2005   PetscInt       numFields, f, c, numSubpoints = 0, pStart, pEnd, p, subp;
2006   PetscErrorCode ierr;
2007 
2008   PetscFunctionBegin;
2009   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2010   PetscValidHeaderSpecific(subpointMap, IS_CLASSID, 2);
2011   PetscValidPointer(subs, 3);
2012   ierr = PetscSectionGetNumFields(s, &numFields);CHKERRQ(ierr);
2013   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) s), subs);CHKERRQ(ierr);
2014   if (numFields) {ierr = PetscSectionSetNumFields(*subs, numFields);CHKERRQ(ierr);}
2015   for (f = 0; f < numFields; ++f) {
2016     const char *name   = NULL;
2017     PetscInt   numComp = 0;
2018 
2019     ierr = PetscSectionGetFieldName(s, f, &name);CHKERRQ(ierr);
2020     ierr = PetscSectionSetFieldName(*subs, f, name);CHKERRQ(ierr);
2021     ierr = PetscSectionGetFieldComponents(s, f, &numComp);CHKERRQ(ierr);
2022     ierr = PetscSectionSetFieldComponents(*subs, f, numComp);CHKERRQ(ierr);
2023     for (c = 0; c < s->numFieldComponents[f]; ++c) {
2024       ierr = PetscSectionGetComponentName(s, f, c, &name);CHKERRQ(ierr);
2025       ierr = PetscSectionSetComponentName(*subs, f, c, name);CHKERRQ(ierr);
2026     }
2027   }
2028   /* For right now, we do not try to squeeze the subchart */
2029   if (subpointMap) {
2030     ierr = ISGetSize(subpointMap, &numSubpoints);CHKERRQ(ierr);
2031     ierr = ISGetIndices(subpointMap, &points);CHKERRQ(ierr);
2032   }
2033   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
2034   ierr = PetscSectionSetChart(*subs, 0, numSubpoints);CHKERRQ(ierr);
2035   for (p = pStart; p < pEnd; ++p) {
2036     PetscInt dof, cdof, fdof = 0, cfdof = 0;
2037 
2038     ierr = PetscFindInt(p, numSubpoints, points, &subp);CHKERRQ(ierr);
2039     if (subp < 0) continue;
2040     for (f = 0; f < numFields; ++f) {
2041       ierr = PetscSectionGetFieldDof(s, p, f, &fdof);CHKERRQ(ierr);
2042       ierr = PetscSectionSetFieldDof(*subs, subp, f, fdof);CHKERRQ(ierr);
2043       ierr = PetscSectionGetFieldConstraintDof(s, p, f, &cfdof);CHKERRQ(ierr);
2044       if (cfdof) {ierr = PetscSectionSetFieldConstraintDof(*subs, subp, f, cfdof);CHKERRQ(ierr);}
2045     }
2046     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
2047     ierr = PetscSectionSetDof(*subs, subp, dof);CHKERRQ(ierr);
2048     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
2049     if (cdof) {ierr = PetscSectionSetConstraintDof(*subs, subp, cdof);CHKERRQ(ierr);}
2050   }
2051   ierr = PetscSectionSetUp(*subs);CHKERRQ(ierr);
2052   /* Change offsets to original offsets */
2053   for (p = pStart; p < pEnd; ++p) {
2054     PetscInt off, foff = 0;
2055 
2056     ierr = PetscFindInt(p, numSubpoints, points, &subp);CHKERRQ(ierr);
2057     if (subp < 0) continue;
2058     for (f = 0; f < numFields; ++f) {
2059       ierr = PetscSectionGetFieldOffset(s, p, f, &foff);CHKERRQ(ierr);
2060       ierr = PetscSectionSetFieldOffset(*subs, subp, f, foff);CHKERRQ(ierr);
2061     }
2062     ierr = PetscSectionGetOffset(s, p, &off);CHKERRQ(ierr);
2063     ierr = PetscSectionSetOffset(*subs, subp, off);CHKERRQ(ierr);
2064   }
2065   /* Copy constraint indices */
2066   for (subp = 0; subp < numSubpoints; ++subp) {
2067     PetscInt cdof;
2068 
2069     ierr = PetscSectionGetConstraintDof(*subs, subp, &cdof);CHKERRQ(ierr);
2070     if (cdof) {
2071       for (f = 0; f < numFields; ++f) {
2072         ierr = PetscSectionGetFieldConstraintIndices(s, points[subp], f, &indices);CHKERRQ(ierr);
2073         ierr = PetscSectionSetFieldConstraintIndices(*subs, subp, f, indices);CHKERRQ(ierr);
2074       }
2075       ierr = PetscSectionGetConstraintIndices(s, points[subp], &indices);CHKERRQ(ierr);
2076       ierr = PetscSectionSetConstraintIndices(*subs, subp, indices);CHKERRQ(ierr);
2077     }
2078   }
2079   if (subpointMap) {ierr = ISRestoreIndices(subpointMap, &points);CHKERRQ(ierr);}
2080   PetscFunctionReturn(0);
2081 }
2082 
2083 static PetscErrorCode PetscSectionView_ASCII(PetscSection s, PetscViewer viewer)
2084 {
2085   PetscInt       p;
2086   PetscMPIInt    rank;
2087   PetscErrorCode ierr;
2088 
2089   PetscFunctionBegin;
2090   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank);CHKERRMPI(ierr);
2091   ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
2092   ierr = PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank);CHKERRQ(ierr);
2093   for (p = 0; p < s->pEnd - s->pStart; ++p) {
2094     if ((s->bc) && (s->bc->atlasDof[p] > 0)) {
2095       PetscInt b;
2096 
2097       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT " constrained", p+s->pStart, s->atlasDof[p], s->atlasOff[p]);CHKERRQ(ierr);
2098       if (s->bcIndices) {
2099         for (b = 0; b < s->bc->atlasDof[p]; ++b) {
2100           ierr = PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, s->bcIndices[s->bc->atlasOff[p]+b]);CHKERRQ(ierr);
2101         }
2102       }
2103       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\n");CHKERRQ(ierr);
2104     } else {
2105       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT "\n", p+s->pStart, s->atlasDof[p], s->atlasOff[p]);CHKERRQ(ierr);
2106     }
2107   }
2108   ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
2109   ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
2110   if (s->sym) {
2111     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
2112     ierr = PetscSectionSymView(s->sym,viewer);CHKERRQ(ierr);
2113     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
2114   }
2115   PetscFunctionReturn(0);
2116 }
2117 
2118 /*@C
2119    PetscSectionViewFromOptions - View from Options
2120 
2121    Collective on PetscSection
2122 
2123    Input Parameters:
2124 +  A - the PetscSection object to view
2125 .  obj - Optional object
2126 -  name - command line option
2127 
2128    Level: intermediate
2129 .seealso:  PetscSection, PetscSectionView, PetscObjectViewFromOptions(), PetscSectionCreate()
2130 @*/
2131 PetscErrorCode  PetscSectionViewFromOptions(PetscSection A,PetscObject obj,const char name[])
2132 {
2133   PetscErrorCode ierr;
2134 
2135   PetscFunctionBegin;
2136   PetscValidHeaderSpecific(A,PETSC_SECTION_CLASSID,1);
2137   ierr = PetscObjectViewFromOptions((PetscObject)A,obj,name);CHKERRQ(ierr);
2138   PetscFunctionReturn(0);
2139 }
2140 
2141 /*@C
2142   PetscSectionView - Views a PetscSection
2143 
2144   Collective on PetscSection
2145 
2146   Input Parameters:
2147 + s - the PetscSection object to view
2148 - v - the viewer
2149 
2150   Note:
2151   PetscSectionView(), when viewer is of type PETSCVIEWERHDF5, only saves
2152   distribution independent data, such as dofs, offsets, constraint dofs,
2153   and constraint indices. Points that have negative dofs, for instance,
2154   are not saved as they represent points owned by other processes.
2155   Point numbering and rank assignment is currently not stored.
2156   The saved section can be loaded with PetscSectionLoad().
2157 
2158   Level: beginner
2159 
2160 .seealso PetscSectionCreate(), PetscSectionDestroy(), PetscSectionLoad()
2161 @*/
2162 PetscErrorCode PetscSectionView(PetscSection s, PetscViewer viewer)
2163 {
2164   PetscBool      isascii, ishdf5;
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   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
2174   if (isascii) {
2175     ierr = PetscObjectPrintClassNamePrefixType((PetscObject)s,viewer);CHKERRQ(ierr);
2176     if (s->numFields) {
2177       ierr = PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " fields\n", s->numFields);CHKERRQ(ierr);
2178       for (f = 0; f < s->numFields; ++f) {
2179         ierr = PetscViewerASCIIPrintf(viewer, "  field %" PetscInt_FMT " with %" PetscInt_FMT " components\n", f, s->numFieldComponents[f]);CHKERRQ(ierr);
2180         ierr = PetscSectionView_ASCII(s->field[f], viewer);CHKERRQ(ierr);
2181       }
2182     } else {
2183       ierr = PetscSectionView_ASCII(s, viewer);CHKERRQ(ierr);
2184     }
2185   } else if (ishdf5) {
2186 #if PetscDefined(HAVE_HDF5)
2187     ierr = PetscSectionView_HDF5_Internal(s, viewer);CHKERRQ(ierr);
2188 #else
2189     SETERRQ(PetscObjectComm((PetscObject) s), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2190 #endif
2191   }
2192   PetscFunctionReturn(0);
2193 }
2194 
2195 /*@C
2196   PetscSectionLoad - Loads a PetscSection
2197 
2198   Collective on PetscSection
2199 
2200   Input Parameters:
2201 + s - the PetscSection object to load
2202 - v - the viewer
2203 
2204   Note:
2205   PetscSectionLoad(), when viewer is of type PETSCVIEWERHDF5, loads
2206   a section saved with PetscSectionView(). The number of processes
2207   used here (N) does not need to be the same as that used when saving.
2208   After calling this function, the chart of s on rank i will be set
2209   to [0, E_i), where \sum_{i=0}^{N-1}E_i equals to the total number of
2210   saved section points.
2211 
2212   Level: beginner
2213 
2214 .seealso PetscSectionCreate(), PetscSectionDestroy(), PetscSectionView()
2215 @*/
2216 PetscErrorCode PetscSectionLoad(PetscSection s, PetscViewer viewer)
2217 {
2218   PetscBool      ishdf5;
2219   PetscErrorCode ierr;
2220 
2221   PetscFunctionBegin;
2222   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2223   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2224   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
2225   if (ishdf5) {
2226 #if PetscDefined(HAVE_HDF5)
2227     ierr = PetscSectionLoad_HDF5_Internal(s, viewer);CHKERRQ(ierr);
2228     PetscFunctionReturn(0);
2229 #else
2230     SETERRQ(PetscObjectComm((PetscObject) s), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2231 #endif
2232   } else SETERRQ(PetscObjectComm((PetscObject) s), PETSC_ERR_SUP, "Viewer type %s not yet supported for PetscSection loading", ((PetscObject)viewer)->type_name);
2233 }
2234 
2235 static PetscErrorCode PetscSectionResetClosurePermutation(PetscSection section)
2236 {
2237   PetscErrorCode ierr;
2238   PetscSectionClosurePermVal clVal;
2239 
2240   PetscFunctionBegin;
2241   if (!section->clHash) PetscFunctionReturn(0);
2242   kh_foreach_value(section->clHash, clVal, {
2243       ierr = PetscFree(clVal.perm);CHKERRQ(ierr);
2244       ierr = PetscFree(clVal.invPerm);CHKERRQ(ierr);
2245     });
2246   kh_destroy(ClPerm, section->clHash);
2247   section->clHash = NULL;
2248   PetscFunctionReturn(0);
2249 }
2250 
2251 /*@
2252   PetscSectionReset - Frees all section data.
2253 
2254   Not collective
2255 
2256   Input Parameters:
2257 . s - the PetscSection
2258 
2259   Level: beginner
2260 
2261 .seealso: PetscSection, PetscSectionCreate()
2262 @*/
2263 PetscErrorCode PetscSectionReset(PetscSection s)
2264 {
2265   PetscInt       f, c;
2266   PetscErrorCode ierr;
2267 
2268   PetscFunctionBegin;
2269   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2270   for (f = 0; f < s->numFields; ++f) {
2271     ierr = PetscSectionDestroy(&s->field[f]);CHKERRQ(ierr);
2272     ierr = PetscFree(s->fieldNames[f]);CHKERRQ(ierr);
2273     for (c = 0; c < s->numFieldComponents[f]; ++c) {
2274       ierr = PetscFree(s->compNames[f][c]);CHKERRQ(ierr);
2275     }
2276     ierr = PetscFree(s->compNames[f]);CHKERRQ(ierr);
2277   }
2278   ierr = PetscFree(s->numFieldComponents);CHKERRQ(ierr);
2279   ierr = PetscFree(s->fieldNames);CHKERRQ(ierr);
2280   ierr = PetscFree(s->compNames);CHKERRQ(ierr);
2281   ierr = PetscFree(s->field);CHKERRQ(ierr);
2282   ierr = PetscSectionDestroy(&s->bc);CHKERRQ(ierr);
2283   ierr = PetscFree(s->bcIndices);CHKERRQ(ierr);
2284   ierr = PetscFree2(s->atlasDof, s->atlasOff);CHKERRQ(ierr);
2285   ierr = PetscSectionDestroy(&s->clSection);CHKERRQ(ierr);
2286   ierr = ISDestroy(&s->clPoints);CHKERRQ(ierr);
2287   ierr = ISDestroy(&s->perm);CHKERRQ(ierr);
2288   ierr = PetscSectionResetClosurePermutation(s);CHKERRQ(ierr);
2289   ierr = PetscSectionSymDestroy(&s->sym);CHKERRQ(ierr);
2290   ierr = PetscSectionDestroy(&s->clSection);CHKERRQ(ierr);
2291   ierr = ISDestroy(&s->clPoints);CHKERRQ(ierr);
2292 
2293   s->pStart    = -1;
2294   s->pEnd      = -1;
2295   s->maxDof    = 0;
2296   s->setup     = PETSC_FALSE;
2297   s->numFields = 0;
2298   s->clObj     = NULL;
2299   PetscFunctionReturn(0);
2300 }
2301 
2302 /*@
2303   PetscSectionDestroy - Frees a section object and frees its range if that exists.
2304 
2305   Not collective
2306 
2307   Input Parameters:
2308 . s - the PetscSection
2309 
2310   Level: beginner
2311 
2312 .seealso: PetscSection, PetscSectionCreate()
2313 @*/
2314 PetscErrorCode PetscSectionDestroy(PetscSection *s)
2315 {
2316   PetscErrorCode ierr;
2317 
2318   PetscFunctionBegin;
2319   if (!*s) PetscFunctionReturn(0);
2320   PetscValidHeaderSpecific(*s,PETSC_SECTION_CLASSID,1);
2321   if (--((PetscObject)(*s))->refct > 0) {
2322     *s = NULL;
2323     PetscFunctionReturn(0);
2324   }
2325   ierr = PetscSectionReset(*s);CHKERRQ(ierr);
2326   ierr = PetscHeaderDestroy(s);CHKERRQ(ierr);
2327   PetscFunctionReturn(0);
2328 }
2329 
2330 PetscErrorCode VecIntGetValuesSection(PetscInt *baseArray, PetscSection s, PetscInt point, const PetscInt **values)
2331 {
2332   const PetscInt p = point - s->pStart;
2333 
2334   PetscFunctionBegin;
2335   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 2);
2336   *values = &baseArray[s->atlasOff[p]];
2337   PetscFunctionReturn(0);
2338 }
2339 
2340 PetscErrorCode VecIntSetValuesSection(PetscInt *baseArray, PetscSection s, PetscInt point, const PetscInt values[], InsertMode mode)
2341 {
2342   PetscInt       *array;
2343   const PetscInt p           = point - s->pStart;
2344   const PetscInt orientation = 0; /* Needs to be included for use in closure operations */
2345   PetscInt       cDim        = 0;
2346   PetscErrorCode ierr;
2347 
2348   PetscFunctionBegin;
2349   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 2);
2350   ierr  = PetscSectionGetConstraintDof(s, p, &cDim);CHKERRQ(ierr);
2351   array = &baseArray[s->atlasOff[p]];
2352   if (!cDim) {
2353     if (orientation >= 0) {
2354       const PetscInt dim = s->atlasDof[p];
2355       PetscInt       i;
2356 
2357       if (mode == INSERT_VALUES) {
2358         for (i = 0; i < dim; ++i) array[i] = values[i];
2359       } else {
2360         for (i = 0; i < dim; ++i) array[i] += values[i];
2361       }
2362     } else {
2363       PetscInt offset = 0;
2364       PetscInt j      = -1, field, i;
2365 
2366       for (field = 0; field < s->numFields; ++field) {
2367         const PetscInt dim = s->field[field]->atlasDof[p];
2368 
2369         for (i = dim-1; i >= 0; --i) array[++j] = values[i+offset];
2370         offset += dim;
2371       }
2372     }
2373   } else {
2374     if (orientation >= 0) {
2375       const PetscInt dim  = s->atlasDof[p];
2376       PetscInt       cInd = 0, i;
2377       const PetscInt *cDof;
2378 
2379       ierr = PetscSectionGetConstraintIndices(s, point, &cDof);CHKERRQ(ierr);
2380       if (mode == INSERT_VALUES) {
2381         for (i = 0; i < dim; ++i) {
2382           if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
2383           array[i] = values[i];
2384         }
2385       } else {
2386         for (i = 0; i < dim; ++i) {
2387           if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
2388           array[i] += values[i];
2389         }
2390       }
2391     } else {
2392       const PetscInt *cDof;
2393       PetscInt       offset  = 0;
2394       PetscInt       cOffset = 0;
2395       PetscInt       j       = 0, field;
2396 
2397       ierr = PetscSectionGetConstraintIndices(s, point, &cDof);CHKERRQ(ierr);
2398       for (field = 0; field < s->numFields; ++field) {
2399         const PetscInt dim  = s->field[field]->atlasDof[p];     /* PetscSectionGetFieldDof() */
2400         const PetscInt tDim = s->field[field]->bc->atlasDof[p]; /* PetscSectionGetFieldConstraintDof() */
2401         const PetscInt sDim = dim - tDim;
2402         PetscInt       cInd = 0, i,k;
2403 
2404         for (i = 0, k = dim+offset-1; i < dim; ++i, ++j, --k) {
2405           if ((cInd < sDim) && (j == cDof[cInd+cOffset])) {++cInd; continue;}
2406           array[j] = values[k];
2407         }
2408         offset  += dim;
2409         cOffset += dim - tDim;
2410       }
2411     }
2412   }
2413   PetscFunctionReturn(0);
2414 }
2415 
2416 /*@C
2417   PetscSectionHasConstraints - Determine whether a section has constrained dofs
2418 
2419   Not collective
2420 
2421   Input Parameter:
2422 . s - The PetscSection
2423 
2424   Output Parameter:
2425 . hasConstraints - flag indicating that the section has constrained dofs
2426 
2427   Level: intermediate
2428 
2429 .seealso: PetscSectionSetConstraintIndices(), PetscSectionGetConstraintDof(), PetscSection
2430 @*/
2431 PetscErrorCode PetscSectionHasConstraints(PetscSection s, PetscBool *hasConstraints)
2432 {
2433   PetscFunctionBegin;
2434   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2435   PetscValidPointer(hasConstraints, 2);
2436   *hasConstraints = s->bc ? PETSC_TRUE : PETSC_FALSE;
2437   PetscFunctionReturn(0);
2438 }
2439 
2440 /*@C
2441   PetscSectionGetConstraintIndices - Get the point dof numbers, in [0, dof), which are constrained
2442 
2443   Not collective
2444 
2445   Input Parameters:
2446 + s     - The PetscSection
2447 - point - The point
2448 
2449   Output Parameter:
2450 . indices - The constrained dofs
2451 
2452   Note: In Fortran, you call PetscSectionGetConstraintIndicesF90() and PetscSectionRestoreConstraintIndicesF90()
2453 
2454   Level: intermediate
2455 
2456 .seealso: PetscSectionSetConstraintIndices(), PetscSectionGetConstraintDof(), PetscSection
2457 @*/
2458 PetscErrorCode PetscSectionGetConstraintIndices(PetscSection s, PetscInt point, const PetscInt **indices)
2459 {
2460   PetscErrorCode ierr;
2461 
2462   PetscFunctionBegin;
2463   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2464   if (s->bc) {
2465     ierr = VecIntGetValuesSection(s->bcIndices, s->bc, point, indices);CHKERRQ(ierr);
2466   } else *indices = NULL;
2467   PetscFunctionReturn(0);
2468 }
2469 
2470 /*@C
2471   PetscSectionSetConstraintIndices - Set the point dof numbers, in [0, dof), which are constrained
2472 
2473   Not collective
2474 
2475   Input Parameters:
2476 + s     - The PetscSection
2477 . point - The point
2478 - indices - The constrained dofs
2479 
2480   Note: The Fortran is PetscSectionSetConstraintIndicesF90()
2481 
2482   Level: intermediate
2483 
2484 .seealso: PetscSectionGetConstraintIndices(), PetscSectionGetConstraintDof(), PetscSection
2485 @*/
2486 PetscErrorCode PetscSectionSetConstraintIndices(PetscSection s, PetscInt point, const PetscInt indices[])
2487 {
2488   PetscErrorCode ierr;
2489 
2490   PetscFunctionBegin;
2491   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2492   if (s->bc) {
2493     const PetscInt dof  = s->atlasDof[point];
2494     const PetscInt cdof = s->bc->atlasDof[point];
2495     PetscInt       d;
2496 
2497     for (d = 0; d < cdof; ++d) {
2498       PetscCheckFalse(indices[d] >= dof,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " dof %" PetscInt_FMT ", invalid constraint index[%" PetscInt_FMT "]: %" PetscInt_FMT, point, dof, d, indices[d]);
2499     }
2500     ierr = VecIntSetValuesSection(s->bcIndices, s->bc, point, indices, INSERT_VALUES);CHKERRQ(ierr);
2501   }
2502   PetscFunctionReturn(0);
2503 }
2504 
2505 /*@C
2506   PetscSectionGetFieldConstraintIndices - Get the field dof numbers, in [0, fdof), which are constrained
2507 
2508   Not collective
2509 
2510   Input Parameters:
2511 + s     - The PetscSection
2512 . field  - The field number
2513 - point - The point
2514 
2515   Output Parameter:
2516 . indices - The constrained dofs sorted in ascending order
2517 
2518   Notes:
2519   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().
2520 
2521   Fortran Note:
2522   In Fortran, you call PetscSectionGetFieldConstraintIndicesF90() and PetscSectionRestoreFieldConstraintIndicesF90()
2523 
2524   Level: intermediate
2525 
2526 .seealso: PetscSectionSetFieldConstraintIndices(), PetscSectionGetConstraintIndices(), PetscSectionGetConstraintDof(), PetscSection
2527 @*/
2528 PetscErrorCode PetscSectionGetFieldConstraintIndices(PetscSection s, PetscInt point, PetscInt field, const PetscInt **indices)
2529 {
2530   PetscErrorCode ierr;
2531 
2532   PetscFunctionBegin;
2533   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2534   PetscValidIntPointer(indices,4);
2535   PetscSectionCheckValidField(field,s->numFields);
2536   ierr = PetscSectionGetConstraintIndices(s->field[field], point, indices);CHKERRQ(ierr);
2537   PetscFunctionReturn(0);
2538 }
2539 
2540 /*@C
2541   PetscSectionSetFieldConstraintIndices - Set the field dof numbers, in [0, fdof), which are constrained
2542 
2543   Not collective
2544 
2545   Input Parameters:
2546 + s       - The PetscSection
2547 . point   - The point
2548 . field   - The field number
2549 - indices - The constrained dofs
2550 
2551   Note: The Fortran is PetscSectionSetFieldConstraintIndicesF90()
2552 
2553   Level: intermediate
2554 
2555 .seealso: PetscSectionSetConstraintIndices(), PetscSectionGetFieldConstraintIndices(), PetscSectionGetConstraintDof(), PetscSection
2556 @*/
2557 PetscErrorCode PetscSectionSetFieldConstraintIndices(PetscSection s, PetscInt point, PetscInt field, const PetscInt indices[])
2558 {
2559   PetscErrorCode ierr;
2560 
2561   PetscFunctionBegin;
2562   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2563   if (PetscDefined(USE_DEBUG)) {
2564     PetscInt ndof;
2565 
2566     ierr = PetscSectionGetConstraintDof(s,point,&ndof);CHKERRQ(ierr);
2567     if (ndof) PetscValidIntPointer(indices,4);
2568   }
2569   PetscSectionCheckValidField(field,s->numFields);
2570   ierr = PetscSectionSetConstraintIndices(s->field[field], point, indices);CHKERRQ(ierr);
2571   PetscFunctionReturn(0);
2572 }
2573 
2574 /*@
2575   PetscSectionPermute - Reorder the section according to the input point permutation
2576 
2577   Collective on PetscSection
2578 
2579   Input Parameters:
2580 + section - The PetscSection object
2581 - perm - The point permutation, old point p becomes new point perm[p]
2582 
2583   Output Parameter:
2584 . sectionNew - The permuted PetscSection
2585 
2586   Level: intermediate
2587 
2588 .seealso: MatPermute()
2589 @*/
2590 PetscErrorCode PetscSectionPermute(PetscSection section, IS permutation, PetscSection *sectionNew)
2591 {
2592   PetscSection    s = section, sNew;
2593   const PetscInt *perm;
2594   PetscInt        numFields, f, c, numPoints, pStart, pEnd, p;
2595   PetscErrorCode  ierr;
2596 
2597   PetscFunctionBegin;
2598   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
2599   PetscValidHeaderSpecific(permutation, IS_CLASSID, 2);
2600   PetscValidPointer(sectionNew, 3);
2601   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) s), &sNew);CHKERRQ(ierr);
2602   ierr = PetscSectionGetNumFields(s, &numFields);CHKERRQ(ierr);
2603   if (numFields) {ierr = PetscSectionSetNumFields(sNew, numFields);CHKERRQ(ierr);}
2604   for (f = 0; f < numFields; ++f) {
2605     const char *name;
2606     PetscInt    numComp;
2607 
2608     ierr = PetscSectionGetFieldName(s, f, &name);CHKERRQ(ierr);
2609     ierr = PetscSectionSetFieldName(sNew, f, name);CHKERRQ(ierr);
2610     ierr = PetscSectionGetFieldComponents(s, f, &numComp);CHKERRQ(ierr);
2611     ierr = PetscSectionSetFieldComponents(sNew, f, numComp);CHKERRQ(ierr);
2612     for (c = 0; c < s->numFieldComponents[f]; ++c) {
2613       ierr = PetscSectionGetComponentName(s, f, c, &name);CHKERRQ(ierr);
2614       ierr = PetscSectionSetComponentName(sNew, f, c, name);CHKERRQ(ierr);
2615     }
2616   }
2617   ierr = ISGetLocalSize(permutation, &numPoints);CHKERRQ(ierr);
2618   ierr = ISGetIndices(permutation, &perm);CHKERRQ(ierr);
2619   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
2620   ierr = PetscSectionSetChart(sNew, pStart, pEnd);CHKERRQ(ierr);
2621   PetscCheckFalse(numPoints < pEnd,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Permutation size %" PetscInt_FMT " is less than largest Section point %" PetscInt_FMT, numPoints, pEnd);
2622   for (p = pStart; p < pEnd; ++p) {
2623     PetscInt dof, cdof;
2624 
2625     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
2626     ierr = PetscSectionSetDof(sNew, perm[p], dof);CHKERRQ(ierr);
2627     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
2628     if (cdof) {ierr = PetscSectionSetConstraintDof(sNew, perm[p], cdof);CHKERRQ(ierr);}
2629     for (f = 0; f < numFields; ++f) {
2630       ierr = PetscSectionGetFieldDof(s, p, f, &dof);CHKERRQ(ierr);
2631       ierr = PetscSectionSetFieldDof(sNew, perm[p], f, dof);CHKERRQ(ierr);
2632       ierr = PetscSectionGetFieldConstraintDof(s, p, f, &cdof);CHKERRQ(ierr);
2633       if (cdof) {ierr = PetscSectionSetFieldConstraintDof(sNew, perm[p], f, cdof);CHKERRQ(ierr);}
2634     }
2635   }
2636   ierr = PetscSectionSetUp(sNew);CHKERRQ(ierr);
2637   for (p = pStart; p < pEnd; ++p) {
2638     const PetscInt *cind;
2639     PetscInt        cdof;
2640 
2641     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
2642     if (cdof) {
2643       ierr = PetscSectionGetConstraintIndices(s, p, &cind);CHKERRQ(ierr);
2644       ierr = PetscSectionSetConstraintIndices(sNew, perm[p], cind);CHKERRQ(ierr);
2645     }
2646     for (f = 0; f < numFields; ++f) {
2647       ierr = PetscSectionGetFieldConstraintDof(s, p, f, &cdof);CHKERRQ(ierr);
2648       if (cdof) {
2649         ierr = PetscSectionGetFieldConstraintIndices(s, p, f, &cind);CHKERRQ(ierr);
2650         ierr = PetscSectionSetFieldConstraintIndices(sNew, perm[p], f, cind);CHKERRQ(ierr);
2651       }
2652     }
2653   }
2654   ierr = ISRestoreIndices(permutation, &perm);CHKERRQ(ierr);
2655   *sectionNew = sNew;
2656   PetscFunctionReturn(0);
2657 }
2658 
2659 /*@
2660   PetscSectionSetClosureIndex - Set a cache of points in the closure of each point in the section
2661 
2662   Collective on section
2663 
2664   Input Parameters:
2665 + section   - The PetscSection
2666 . obj       - A PetscObject which serves as the key for this index
2667 . clSection - Section giving the size of the closure of each point
2668 - clPoints  - IS giving the points in each closure
2669 
2670   Note: We compress out closure points with no dofs in this section
2671 
2672   Level: advanced
2673 
2674 .seealso: PetscSectionGetClosureIndex(), DMPlexCreateClosureIndex()
2675 @*/
2676 PetscErrorCode PetscSectionSetClosureIndex(PetscSection section, PetscObject obj, PetscSection clSection, IS clPoints)
2677 {
2678   PetscErrorCode ierr;
2679 
2680   PetscFunctionBegin;
2681   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,1);
2682   PetscValidHeaderSpecific(clSection,PETSC_SECTION_CLASSID,3);
2683   PetscValidHeaderSpecific(clPoints,IS_CLASSID,4);
2684   if (section->clObj != obj) {ierr = PetscSectionResetClosurePermutation(section);CHKERRQ(ierr);}
2685   section->clObj     = obj;
2686   ierr = PetscObjectReference((PetscObject)clSection);CHKERRQ(ierr);
2687   ierr = PetscObjectReference((PetscObject)clPoints);CHKERRQ(ierr);
2688   ierr = PetscSectionDestroy(&section->clSection);CHKERRQ(ierr);
2689   ierr = ISDestroy(&section->clPoints);CHKERRQ(ierr);
2690   section->clSection = clSection;
2691   section->clPoints  = clPoints;
2692   PetscFunctionReturn(0);
2693 }
2694 
2695 /*@
2696   PetscSectionGetClosureIndex - Get the cache of points in the closure of each point in the section
2697 
2698   Collective on section
2699 
2700   Input Parameters:
2701 + section   - The PetscSection
2702 - obj       - A PetscObject which serves as the key for this index
2703 
2704   Output Parameters:
2705 + clSection - Section giving the size of the closure of each point
2706 - clPoints  - IS giving the points in each closure
2707 
2708   Note: We compress out closure points with no dofs in this section
2709 
2710   Level: advanced
2711 
2712 .seealso: PetscSectionSetClosureIndex(), DMPlexCreateClosureIndex()
2713 @*/
2714 PetscErrorCode PetscSectionGetClosureIndex(PetscSection section, PetscObject obj, PetscSection *clSection, IS *clPoints)
2715 {
2716   PetscFunctionBegin;
2717   if (section->clObj == obj) {
2718     if (clSection) *clSection = section->clSection;
2719     if (clPoints)  *clPoints  = section->clPoints;
2720   } else {
2721     if (clSection) *clSection = NULL;
2722     if (clPoints)  *clPoints  = NULL;
2723   }
2724   PetscFunctionReturn(0);
2725 }
2726 
2727 PetscErrorCode PetscSectionSetClosurePermutation_Internal(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, PetscCopyMode mode, PetscInt *clPerm)
2728 {
2729   PetscInt       i;
2730   khiter_t iter;
2731   int new_entry;
2732   PetscSectionClosurePermKey key = {depth, clSize};
2733   PetscSectionClosurePermVal *val;
2734   PetscErrorCode ierr;
2735 
2736   PetscFunctionBegin;
2737   if (section->clObj != obj) {
2738     ierr = PetscSectionDestroy(&section->clSection);CHKERRQ(ierr);
2739     ierr = ISDestroy(&section->clPoints);CHKERRQ(ierr);
2740   }
2741   section->clObj = obj;
2742   if (!section->clHash) {ierr = PetscClPermCreate(&section->clHash);CHKERRQ(ierr);}
2743   iter = kh_put(ClPerm, section->clHash, key, &new_entry);
2744   val = &kh_val(section->clHash, iter);
2745   if (!new_entry) {
2746     ierr = PetscFree(val->perm);CHKERRQ(ierr);
2747     ierr = PetscFree(val->invPerm);CHKERRQ(ierr);
2748   }
2749   if (mode == PETSC_COPY_VALUES) {
2750     ierr = PetscMalloc1(clSize, &val->perm);CHKERRQ(ierr);
2751     ierr = PetscLogObjectMemory((PetscObject) obj, clSize*sizeof(PetscInt));CHKERRQ(ierr);
2752     ierr = PetscArraycpy(val->perm, clPerm, clSize);CHKERRQ(ierr);
2753   } else if (mode == PETSC_OWN_POINTER) {
2754     val->perm = clPerm;
2755   } else SETERRQ(PetscObjectComm(obj), PETSC_ERR_SUP, "Do not support borrowed arrays");
2756   ierr = PetscMalloc1(clSize, &val->invPerm);CHKERRQ(ierr);
2757   for (i = 0; i < clSize; ++i) val->invPerm[clPerm[i]] = i;
2758   PetscFunctionReturn(0);
2759 }
2760 
2761 /*@
2762   PetscSectionSetClosurePermutation - Set the dof permutation for the closure of each cell in the section, meaning clPerm[newIndex] = oldIndex.
2763 
2764   Not Collective
2765 
2766   Input Parameters:
2767 + section - The PetscSection
2768 . obj     - A PetscObject which serves as the key for this index (usually a DM)
2769 . depth   - Depth of points on which to apply the given permutation
2770 - perm    - Permutation of the cell dof closure
2771 
2772   Note:
2773   The specified permutation will only be applied to points at depth whose closure size matches the length of perm.  In a
2774   mixed-topology or variable-degree finite element space, this function can be called multiple times at each depth for
2775   each topology and degree.
2776 
2777   This approach assumes that (depth, len(perm)) uniquely identifies the desired permutation; this might not be true for
2778   exotic/enriched spaces on mixed topology meshes.
2779 
2780   Level: intermediate
2781 
2782 .seealso: PetscSectionGetClosurePermutation(), PetscSectionGetClosureIndex(), DMPlexCreateClosureIndex(), PetscCopyMode
2783 @*/
2784 PetscErrorCode PetscSectionSetClosurePermutation(PetscSection section, PetscObject obj, PetscInt depth, IS perm)
2785 {
2786   const PetscInt *clPerm = NULL;
2787   PetscInt        clSize = 0;
2788   PetscErrorCode  ierr;
2789 
2790   PetscFunctionBegin;
2791   if (perm) {
2792     ierr = ISGetLocalSize(perm, &clSize);CHKERRQ(ierr);
2793     ierr = ISGetIndices(perm, &clPerm);CHKERRQ(ierr);
2794   }
2795   ierr = PetscSectionSetClosurePermutation_Internal(section, obj, depth, clSize, PETSC_COPY_VALUES, (PetscInt *) clPerm);CHKERRQ(ierr);
2796   if (perm) {ierr = ISRestoreIndices(perm, &clPerm);CHKERRQ(ierr);}
2797   PetscFunctionReturn(0);
2798 }
2799 
2800 PetscErrorCode PetscSectionGetClosurePermutation_Internal(PetscSection section, PetscObject obj, PetscInt depth, PetscInt size, const PetscInt *perm[])
2801 {
2802   PetscErrorCode ierr;
2803 
2804   PetscFunctionBegin;
2805   if (section->clObj == obj) {
2806     PetscSectionClosurePermKey k = {depth, size};
2807     PetscSectionClosurePermVal v;
2808     ierr = PetscClPermGet(section->clHash, k, &v);CHKERRQ(ierr);
2809     if (perm) *perm = v.perm;
2810   } else {
2811     if (perm) *perm = NULL;
2812   }
2813   PetscFunctionReturn(0);
2814 }
2815 
2816 /*@
2817   PetscSectionGetClosurePermutation - Get the dof permutation for the closure of each cell in the section, meaning clPerm[newIndex] = oldIndex.
2818 
2819   Not collective
2820 
2821   Input Parameters:
2822 + section   - The PetscSection
2823 . obj       - A PetscObject which serves as the key for this index (usually a DM)
2824 . depth     - Depth stratum on which to obtain closure permutation
2825 - clSize    - Closure size to be permuted (e.g., may vary with element topology and degree)
2826 
2827   Output Parameter:
2828 . perm - The dof closure permutation
2829 
2830   Note:
2831   The user must destroy the IS that is returned.
2832 
2833   Level: intermediate
2834 
2835 .seealso: PetscSectionSetClosurePermutation(), PetscSectionGetClosureInversePermutation(), PetscSectionGetClosureIndex(), PetscSectionSetClosureIndex(), DMPlexCreateClosureIndex()
2836 @*/
2837 PetscErrorCode PetscSectionGetClosurePermutation(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, IS *perm)
2838 {
2839   const PetscInt *clPerm;
2840   PetscErrorCode  ierr;
2841 
2842   PetscFunctionBegin;
2843   ierr = PetscSectionGetClosurePermutation_Internal(section, obj, depth, clSize, &clPerm);CHKERRQ(ierr);
2844   ierr = ISCreateGeneral(PETSC_COMM_SELF, clSize, clPerm, PETSC_USE_POINTER, perm);CHKERRQ(ierr);
2845   PetscFunctionReturn(0);
2846 }
2847 
2848 PetscErrorCode PetscSectionGetClosureInversePermutation_Internal(PetscSection section, PetscObject obj, PetscInt depth, PetscInt size, const PetscInt *perm[])
2849 {
2850   PetscErrorCode ierr;
2851 
2852   PetscFunctionBegin;
2853   if (section->clObj == obj && section->clHash) {
2854     PetscSectionClosurePermKey k = {depth, size};
2855     PetscSectionClosurePermVal v;
2856     ierr = PetscClPermGet(section->clHash, k, &v);CHKERRQ(ierr);
2857     if (perm) *perm = v.invPerm;
2858   } else {
2859     if (perm) *perm = NULL;
2860   }
2861   PetscFunctionReturn(0);
2862 }
2863 
2864 /*@
2865   PetscSectionGetClosureInversePermutation - Get the inverse dof permutation for the closure of each cell in the section, meaning clPerm[oldIndex] = newIndex.
2866 
2867   Not collective
2868 
2869   Input Parameters:
2870 + section   - The PetscSection
2871 . obj       - A PetscObject which serves as the key for this index (usually a DM)
2872 . depth     - Depth stratum on which to obtain closure permutation
2873 - clSize    - Closure size to be permuted (e.g., may vary with element topology and degree)
2874 
2875   Output Parameters:
2876 . perm - The dof closure permutation
2877 
2878   Note:
2879   The user must destroy the IS that is returned.
2880 
2881   Level: intermediate
2882 
2883 .seealso: PetscSectionSetClosurePermutation(), PetscSectionGetClosureIndex(), PetscSectionSetClosureIndex(), DMPlexCreateClosureIndex()
2884 @*/
2885 PetscErrorCode PetscSectionGetClosureInversePermutation(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, IS *perm)
2886 {
2887   const PetscInt *clPerm;
2888   PetscErrorCode  ierr;
2889 
2890   PetscFunctionBegin;
2891   ierr = PetscSectionGetClosureInversePermutation_Internal(section, obj, depth, clSize, &clPerm);CHKERRQ(ierr);
2892   ierr = ISCreateGeneral(PETSC_COMM_SELF, clSize, clPerm, PETSC_USE_POINTER, perm);CHKERRQ(ierr);
2893   PetscFunctionReturn(0);
2894 }
2895 
2896 /*@
2897   PetscSectionGetField - Get the subsection associated with a single field
2898 
2899   Input Parameters:
2900 + s     - The PetscSection
2901 - field - The field number
2902 
2903   Output Parameter:
2904 . subs  - The subsection for the given field
2905 
2906   Level: intermediate
2907 
2908 .seealso: PetscSectionSetNumFields()
2909 @*/
2910 PetscErrorCode PetscSectionGetField(PetscSection s, PetscInt field, PetscSection *subs)
2911 {
2912   PetscFunctionBegin;
2913   PetscValidHeaderSpecific(s,PETSC_SECTION_CLASSID,1);
2914   PetscValidPointer(subs,3);
2915   PetscSectionCheckValidField(field,s->numFields);
2916   *subs = s->field[field];
2917   PetscFunctionReturn(0);
2918 }
2919 
2920 PetscClassId      PETSC_SECTION_SYM_CLASSID;
2921 PetscFunctionList PetscSectionSymList = NULL;
2922 
2923 /*@
2924   PetscSectionSymCreate - Creates an empty PetscSectionSym object.
2925 
2926   Collective
2927 
2928   Input Parameter:
2929 . comm - the MPI communicator
2930 
2931   Output Parameter:
2932 . sym - pointer to the new set of symmetries
2933 
2934   Level: developer
2935 
2936 .seealso: PetscSectionSym, PetscSectionSymDestroy()
2937 @*/
2938 PetscErrorCode PetscSectionSymCreate(MPI_Comm comm, PetscSectionSym *sym)
2939 {
2940   PetscErrorCode ierr;
2941 
2942   PetscFunctionBegin;
2943   PetscValidPointer(sym,2);
2944   ierr = ISInitializePackage();CHKERRQ(ierr);
2945   ierr = PetscHeaderCreate(*sym,PETSC_SECTION_SYM_CLASSID,"PetscSectionSym","Section Symmetry","IS",comm,PetscSectionSymDestroy,PetscSectionSymView);CHKERRQ(ierr);
2946   PetscFunctionReturn(0);
2947 }
2948 
2949 /*@C
2950   PetscSectionSymSetType - Builds a PetscSection symmetry, for a particular implementation.
2951 
2952   Collective on PetscSectionSym
2953 
2954   Input Parameters:
2955 + sym    - The section symmetry object
2956 - method - The name of the section symmetry type
2957 
2958   Level: developer
2959 
2960 .seealso: PetscSectionSymGetType(), PetscSectionSymCreate()
2961 @*/
2962 PetscErrorCode  PetscSectionSymSetType(PetscSectionSym sym, PetscSectionSymType method)
2963 {
2964   PetscErrorCode (*r)(PetscSectionSym);
2965   PetscBool      match;
2966   PetscErrorCode ierr;
2967 
2968   PetscFunctionBegin;
2969   PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID,1);
2970   ierr = PetscObjectTypeCompare((PetscObject) sym, method, &match);CHKERRQ(ierr);
2971   if (match) PetscFunctionReturn(0);
2972 
2973   ierr = PetscFunctionListFind(PetscSectionSymList,method,&r);CHKERRQ(ierr);
2974   PetscCheckFalse(!r,PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscSectionSym type: %s", method);
2975   if (sym->ops->destroy) {
2976     ierr = (*sym->ops->destroy)(sym);CHKERRQ(ierr);
2977     sym->ops->destroy = NULL;
2978   }
2979   ierr = (*r)(sym);CHKERRQ(ierr);
2980   ierr = PetscObjectChangeTypeName((PetscObject)sym,method);CHKERRQ(ierr);
2981   PetscFunctionReturn(0);
2982 }
2983 
2984 /*@C
2985   PetscSectionSymGetType - Gets the section symmetry type name (as a string) from the PetscSectionSym.
2986 
2987   Not Collective
2988 
2989   Input Parameter:
2990 . sym  - The section symmetry
2991 
2992   Output Parameter:
2993 . type - The index set type name
2994 
2995   Level: developer
2996 
2997 .seealso: PetscSectionSymSetType(), PetscSectionSymCreate()
2998 @*/
2999 PetscErrorCode PetscSectionSymGetType(PetscSectionSym sym, PetscSectionSymType *type)
3000 {
3001   PetscFunctionBegin;
3002   PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID,1);
3003   PetscValidCharPointer(type,2);
3004   *type = ((PetscObject)sym)->type_name;
3005   PetscFunctionReturn(0);
3006 }
3007 
3008 /*@C
3009   PetscSectionSymRegister - Adds a new section symmetry implementation
3010 
3011   Not Collective
3012 
3013   Input Parameters:
3014 + name        - The name of a new user-defined creation routine
3015 - create_func - The creation routine itself
3016 
3017   Notes:
3018   PetscSectionSymRegister() may be called multiple times to add several user-defined vectors
3019 
3020   Level: developer
3021 
3022 .seealso: PetscSectionSymCreate(), PetscSectionSymSetType()
3023 @*/
3024 PetscErrorCode PetscSectionSymRegister(const char sname[], PetscErrorCode (*function)(PetscSectionSym))
3025 {
3026   PetscErrorCode ierr;
3027 
3028   PetscFunctionBegin;
3029   ierr = ISInitializePackage();CHKERRQ(ierr);
3030   ierr = PetscFunctionListAdd(&PetscSectionSymList,sname,function);CHKERRQ(ierr);
3031   PetscFunctionReturn(0);
3032 }
3033 
3034 /*@
3035    PetscSectionSymDestroy - Destroys a section symmetry.
3036 
3037    Collective on PetscSectionSym
3038 
3039    Input Parameters:
3040 .  sym - the section symmetry
3041 
3042    Level: developer
3043 
3044 .seealso: PetscSectionSymCreate(), PetscSectionSymDestroy()
3045 @*/
3046 PetscErrorCode PetscSectionSymDestroy(PetscSectionSym *sym)
3047 {
3048   SymWorkLink    link,next;
3049   PetscErrorCode ierr;
3050 
3051   PetscFunctionBegin;
3052   if (!*sym) PetscFunctionReturn(0);
3053   PetscValidHeaderSpecific((*sym),PETSC_SECTION_SYM_CLASSID,1);
3054   if (--((PetscObject)(*sym))->refct > 0) {*sym = NULL; PetscFunctionReturn(0);}
3055   if ((*sym)->ops->destroy) {
3056     ierr = (*(*sym)->ops->destroy)(*sym);CHKERRQ(ierr);
3057   }
3058   PetscCheckFalse((*sym)->workout,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Work array still checked out");
3059   for (link=(*sym)->workin; link; link=next) {
3060     next = link->next;
3061     ierr = PetscFree2(link->perms,link->rots);CHKERRQ(ierr);
3062     ierr = PetscFree(link);CHKERRQ(ierr);
3063   }
3064   (*sym)->workin = NULL;
3065   ierr = PetscHeaderDestroy(sym);CHKERRQ(ierr);
3066   PetscFunctionReturn(0);
3067 }
3068 
3069 /*@C
3070    PetscSectionSymView - Displays a section symmetry
3071 
3072    Collective on PetscSectionSym
3073 
3074    Input Parameters:
3075 +  sym - the index set
3076 -  viewer - viewer used to display the set, for example PETSC_VIEWER_STDOUT_SELF.
3077 
3078    Level: developer
3079 
3080 .seealso: PetscViewerASCIIOpen()
3081 @*/
3082 PetscErrorCode PetscSectionSymView(PetscSectionSym sym,PetscViewer viewer)
3083 {
3084   PetscErrorCode ierr;
3085 
3086   PetscFunctionBegin;
3087   PetscValidHeaderSpecific(sym,PETSC_SECTION_SYM_CLASSID,1);
3088   if (!viewer) {
3089     ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sym),&viewer);CHKERRQ(ierr);
3090   }
3091   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
3092   PetscCheckSameComm(sym,1,viewer,2);
3093   ierr = PetscObjectPrintClassNamePrefixType((PetscObject)sym,viewer);CHKERRQ(ierr);
3094   if (sym->ops->view) {
3095     ierr = (*sym->ops->view)(sym,viewer);CHKERRQ(ierr);
3096   }
3097   PetscFunctionReturn(0);
3098 }
3099 
3100 /*@
3101   PetscSectionSetSym - Set the symmetries for the data referred to by the section
3102 
3103   Collective on PetscSection
3104 
3105   Input Parameters:
3106 + section - the section describing data layout
3107 - sym - the symmetry describing the affect of orientation on the access of the data
3108 
3109   Level: developer
3110 
3111 .seealso: PetscSectionGetSym(), PetscSectionSymCreate()
3112 @*/
3113 PetscErrorCode PetscSectionSetSym(PetscSection section, PetscSectionSym sym)
3114 {
3115   PetscErrorCode ierr;
3116 
3117   PetscFunctionBegin;
3118   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,1);
3119   ierr = PetscSectionSymDestroy(&(section->sym));CHKERRQ(ierr);
3120   if (sym) {
3121     PetscValidHeaderSpecific(sym,PETSC_SECTION_SYM_CLASSID,2);
3122     PetscCheckSameComm(section,1,sym,2);
3123     ierr = PetscObjectReference((PetscObject) sym);CHKERRQ(ierr);
3124   }
3125   section->sym = sym;
3126   PetscFunctionReturn(0);
3127 }
3128 
3129 /*@
3130   PetscSectionGetSym - Get the symmetries for the data referred to by the section
3131 
3132   Not collective
3133 
3134   Input Parameters:
3135 . section - the section describing data layout
3136 
3137   Output Parameters:
3138 . sym - the symmetry describing the affect of orientation on the access of the data
3139 
3140   Level: developer
3141 
3142 .seealso: PetscSectionSetSym(), PetscSectionSymCreate()
3143 @*/
3144 PetscErrorCode PetscSectionGetSym(PetscSection section, PetscSectionSym *sym)
3145 {
3146   PetscFunctionBegin;
3147   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,1);
3148   *sym = section->sym;
3149   PetscFunctionReturn(0);
3150 }
3151 
3152 /*@
3153   PetscSectionSetFieldSym - Set the symmetries for the data referred to by a field of the section
3154 
3155   Collective on PetscSection
3156 
3157   Input Parameters:
3158 + section - the section describing data layout
3159 . field - the field number
3160 - sym - the symmetry describing the affect of orientation on the access of the data
3161 
3162   Level: developer
3163 
3164 .seealso: PetscSectionGetFieldSym(), PetscSectionSymCreate()
3165 @*/
3166 PetscErrorCode PetscSectionSetFieldSym(PetscSection section, PetscInt field, PetscSectionSym sym)
3167 {
3168   PetscErrorCode ierr;
3169 
3170   PetscFunctionBegin;
3171   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,1);
3172   PetscSectionCheckValidField(field,section->numFields);
3173   ierr = PetscSectionSetSym(section->field[field],sym);CHKERRQ(ierr);
3174   PetscFunctionReturn(0);
3175 }
3176 
3177 /*@
3178   PetscSectionGetFieldSym - Get the symmetries for the data referred to by a field of the section
3179 
3180   Collective on PetscSection
3181 
3182   Input Parameters:
3183 + section - the section describing data layout
3184 - field - the field number
3185 
3186   Output Parameters:
3187 . sym - the symmetry describing the affect of orientation on the access of the data
3188 
3189   Level: developer
3190 
3191 .seealso: PetscSectionSetFieldSym(), PetscSectionSymCreate()
3192 @*/
3193 PetscErrorCode PetscSectionGetFieldSym(PetscSection section, PetscInt field, PetscSectionSym *sym)
3194 {
3195   PetscFunctionBegin;
3196   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,1);
3197   PetscSectionCheckValidField(field,section->numFields);
3198   *sym = section->field[field]->sym;
3199   PetscFunctionReturn(0);
3200 }
3201 
3202 /*@C
3203   PetscSectionGetPointSyms - Get the symmetries for a set of points in a PetscSection under specific orientations.
3204 
3205   Not collective
3206 
3207   Input Parameters:
3208 + section - the section
3209 . numPoints - the number of points
3210 - points - an array of size 2 * numPoints, containing a list of (point, orientation) pairs. (An orientation is an
3211     arbitrary integer: its interpretation is up to sym.  Orientations are used by DM: for their interpretation in that
3212     context, see DMPlexGetConeOrientation()).
3213 
3214   Output Parameters:
3215 + perms - The permutations for the given orientations (or NULL if there is no symmetry or the permutation is the identity).
3216 - rots - The field rotations symmetries for the given orientations (or NULL if there is no symmetry or the rotations are all
3217     identity).
3218 
3219   Example of usage, gathering dofs into a local array (lArray) from a section array (sArray):
3220 .vb
3221      const PetscInt    **perms;
3222      const PetscScalar **rots;
3223      PetscInt            lOffset;
3224 
3225      PetscSectionGetPointSyms(section,numPoints,points,&perms,&rots);
3226      for (i = 0, lOffset = 0; i < numPoints; i++) {
3227        PetscInt           point = points[2*i], dof, sOffset;
3228        const PetscInt    *perm  = perms ? perms[i] : NULL;
3229        const PetscScalar *rot   = rots  ? rots[i]  : NULL;
3230 
3231        PetscSectionGetDof(section,point,&dof);
3232        PetscSectionGetOffset(section,point,&sOffset);
3233 
3234        if (perm) {for (j = 0; j < dof; j++) {lArray[lOffset + perm[j]]  = sArray[sOffset + j];}}
3235        else      {for (j = 0; j < dof; j++) {lArray[lOffset +      j ]  = sArray[sOffset + j];}}
3236        if (rot)  {for (j = 0; j < dof; j++) {lArray[lOffset +      j ] *= rot[j];             }}
3237        lOffset += dof;
3238      }
3239      PetscSectionRestorePointSyms(section,numPoints,points,&perms,&rots);
3240 .ve
3241 
3242   Example of usage, adding dofs into a section array (sArray) from a local array (lArray):
3243 .vb
3244      const PetscInt    **perms;
3245      const PetscScalar **rots;
3246      PetscInt            lOffset;
3247 
3248      PetscSectionGetPointSyms(section,numPoints,points,&perms,&rots);
3249      for (i = 0, lOffset = 0; i < numPoints; i++) {
3250        PetscInt           point = points[2*i], dof, sOffset;
3251        const PetscInt    *perm  = perms ? perms[i] : NULL;
3252        const PetscScalar *rot   = rots  ? rots[i]  : NULL;
3253 
3254        PetscSectionGetDof(section,point,&dof);
3255        PetscSectionGetOffset(section,point,&sOff);
3256 
3257        if (perm) {for (j = 0; j < dof; j++) {sArray[sOffset + j] += lArray[lOffset + perm[j]] * (rot ? PetscConj(rot[perm[j]]) : 1.);}}
3258        else      {for (j = 0; j < dof; j++) {sArray[sOffset + j] += lArray[lOffset +      j ] * (rot ? PetscConj(rot[     j ]) : 1.);}}
3259        offset += dof;
3260      }
3261      PetscSectionRestorePointSyms(section,numPoints,points,&perms,&rots);
3262 .ve
3263 
3264   Level: developer
3265 
3266 .seealso: PetscSectionRestorePointSyms(), PetscSectionSymCreate(), PetscSectionSetSym(), PetscSectionGetSym()
3267 @*/
3268 PetscErrorCode PetscSectionGetPointSyms(PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3269 {
3270   PetscSectionSym sym;
3271   PetscErrorCode  ierr;
3272 
3273   PetscFunctionBegin;
3274   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,1);
3275   if (numPoints) PetscValidIntPointer(points,3);
3276   if (perms) *perms = NULL;
3277   if (rots)  *rots  = NULL;
3278   sym = section->sym;
3279   if (sym && (perms || rots)) {
3280     SymWorkLink link;
3281 
3282     if (sym->workin) {
3283       link        = sym->workin;
3284       sym->workin = sym->workin->next;
3285     } else {
3286       ierr = PetscNewLog(sym,&link);CHKERRQ(ierr);
3287     }
3288     if (numPoints > link->numPoints) {
3289       ierr = PetscFree2(link->perms,link->rots);CHKERRQ(ierr);
3290       ierr = PetscMalloc2(numPoints,&link->perms,numPoints,&link->rots);CHKERRQ(ierr);
3291       link->numPoints = numPoints;
3292     }
3293     link->next   = sym->workout;
3294     sym->workout = link;
3295     ierr = PetscArrayzero((PetscInt**)link->perms,numPoints);CHKERRQ(ierr);
3296     ierr = PetscArrayzero((PetscInt**)link->rots,numPoints);CHKERRQ(ierr);
3297     ierr = (*sym->ops->getpoints) (sym, section, numPoints, points, link->perms, link->rots);CHKERRQ(ierr);
3298     if (perms) *perms = link->perms;
3299     if (rots)  *rots  = link->rots;
3300   }
3301   PetscFunctionReturn(0);
3302 }
3303 
3304 /*@C
3305   PetscSectionRestorePointSyms - Restore the symmetries returned by PetscSectionGetPointSyms()
3306 
3307   Not collective
3308 
3309   Input Parameters:
3310 + section - the section
3311 . numPoints - the number of points
3312 - points - an array of size 2 * numPoints, containing a list of (point, orientation) pairs. (An orientation is an
3313     arbitrary integer: its interpretation is up to sym.  Orientations are used by DM: for their interpretation in that
3314     context, see DMPlexGetConeOrientation()).
3315 
3316   Output Parameters:
3317 + perms - The permutations for the given orientations: set to NULL at conclusion
3318 - rots - The field rotations symmetries for the given orientations: set to NULL at conclusion
3319 
3320   Level: developer
3321 
3322 .seealso: PetscSectionGetPointSyms(), PetscSectionSymCreate(), PetscSectionSetSym(), PetscSectionGetSym()
3323 @*/
3324 PetscErrorCode PetscSectionRestorePointSyms(PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3325 {
3326   PetscSectionSym sym;
3327 
3328   PetscFunctionBegin;
3329   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,1);
3330   sym = section->sym;
3331   if (sym && (perms || rots)) {
3332     SymWorkLink *p,link;
3333 
3334     for (p=&sym->workout; (link=*p); p=&link->next) {
3335       if ((perms && link->perms == *perms) || (rots && link->rots == *rots)) {
3336         *p          = link->next;
3337         link->next  = sym->workin;
3338         sym->workin = link;
3339         if (perms) *perms = NULL;
3340         if (rots)  *rots  = NULL;
3341         PetscFunctionReturn(0);
3342       }
3343     }
3344     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Array was not checked out");
3345   }
3346   PetscFunctionReturn(0);
3347 }
3348 
3349 /*@C
3350   PetscSectionGetFieldPointSyms - Get the symmetries for a set of points in a field of a PetscSection under specific orientations.
3351 
3352   Not collective
3353 
3354   Input Parameters:
3355 + section - the section
3356 . field - the field of the section
3357 . numPoints - the number of points
3358 - points - an array of size 2 * numPoints, containing a list of (point, orientation) pairs. (An orientation is an
3359     arbitrary integer: its interpretation is up to sym.  Orientations are used by DM: for their interpretation in that
3360     context, see DMPlexGetConeOrientation()).
3361 
3362   Output Parameters:
3363 + perms - The permutations for the given orientations (or NULL if there is no symmetry or the permutation is the identity).
3364 - rots - The field rotations symmetries for the given orientations (or NULL if there is no symmetry or the rotations are all
3365     identity).
3366 
3367   Level: developer
3368 
3369 .seealso: PetscSectionGetPointSyms(), PetscSectionRestoreFieldPointSyms()
3370 @*/
3371 PetscErrorCode PetscSectionGetFieldPointSyms(PetscSection section, PetscInt field, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3372 {
3373   PetscErrorCode ierr;
3374 
3375   PetscFunctionBegin;
3376   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,1);
3377   PetscCheckFalse(field > section->numFields,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"field %" PetscInt_FMT " greater than number of fields (%" PetscInt_FMT ") in section",field,section->numFields);
3378   ierr = PetscSectionGetPointSyms(section->field[field],numPoints,points,perms,rots);CHKERRQ(ierr);
3379   PetscFunctionReturn(0);
3380 }
3381 
3382 /*@C
3383   PetscSectionRestoreFieldPointSyms - Restore the symmetries returned by PetscSectionGetFieldPointSyms()
3384 
3385   Not collective
3386 
3387   Input Parameters:
3388 + section - the section
3389 . field - the field number
3390 . numPoints - the number of points
3391 - points - an array of size 2 * numPoints, containing a list of (point, orientation) pairs. (An orientation is an
3392     arbitrary integer: its interpretation is up to sym.  Orientations are used by DM: for their interpretation in that
3393     context, see DMPlexGetConeOrientation()).
3394 
3395   Output Parameters:
3396 + perms - The permutations for the given orientations: set to NULL at conclusion
3397 - rots - The field rotations symmetries for the given orientations: set to NULL at conclusion
3398 
3399   Level: developer
3400 
3401 .seealso: PetscSectionRestorePointSyms(), petscSectionGetFieldPointSyms(), PetscSectionSymCreate(), PetscSectionSetSym(), PetscSectionGetSym()
3402 @*/
3403 PetscErrorCode PetscSectionRestoreFieldPointSyms(PetscSection section, PetscInt field, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3404 {
3405   PetscErrorCode ierr;
3406 
3407   PetscFunctionBegin;
3408   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,1);
3409   PetscCheckFalse(field > section->numFields,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"field %" PetscInt_FMT " greater than number of fields (%" PetscInt_FMT ") in section",field,section->numFields);
3410   ierr = PetscSectionRestorePointSyms(section->field[field],numPoints,points,perms,rots);CHKERRQ(ierr);
3411   PetscFunctionReturn(0);
3412 }
3413 
3414 /*@
3415   PetscSectionSymCopy - Copy the symmetries, assuming that the point structure is compatible
3416 
3417   Not collective
3418 
3419   Input Parameter:
3420 . sym - the PetscSectionSym
3421 
3422   Output Parameter:
3423 . nsym - the equivalent symmetries
3424 
3425   Level: developer
3426 
3427 .seealso: PetscSectionSymCreate(), PetscSectionSetSym(), PetscSectionGetSym(), PetscSectionSymLabelSetStratum(), PetscSectionGetPointSyms()
3428 @*/
3429 PetscErrorCode PetscSectionSymCopy(PetscSectionSym sym, PetscSectionSym nsym)
3430 {
3431   PetscErrorCode ierr;
3432 
3433   PetscFunctionBegin;
3434   PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1);
3435   PetscValidHeaderSpecific(nsym, PETSC_SECTION_SYM_CLASSID, 2);
3436   if (sym->ops->copy) {ierr = (*sym->ops->copy)(sym, nsym);CHKERRQ(ierr);}
3437   PetscFunctionReturn(0);
3438 }
3439 
3440 /*@
3441   PetscSectionSymDistribute - Distribute the symmetries in accordance with the input SF
3442 
3443   Collective
3444 
3445   Input Parameters:
3446 + sym - the PetscSectionSym
3447 - migrationSF - the distribution map from roots to leaves
3448 
3449   Output Parameters:
3450 . dsym - the redistributed symmetries
3451 
3452   Level: developer
3453 
3454 .seealso: PetscSectionSymCreate(), PetscSectionSetSym(), PetscSectionGetSym(), PetscSectionSymLabelSetStratum(), PetscSectionGetPointSyms()
3455 @*/
3456 PetscErrorCode PetscSectionSymDistribute(PetscSectionSym sym, PetscSF migrationSF, PetscSectionSym *dsym)
3457 {
3458   PetscErrorCode ierr;
3459 
3460   PetscFunctionBegin;
3461   PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1);
3462   PetscValidHeaderSpecific(migrationSF, PETSCSF_CLASSID, 2);
3463   PetscValidPointer(dsym, 3);
3464   if (sym->ops->distribute) {ierr = (*sym->ops->distribute)(sym, migrationSF, dsym);CHKERRQ(ierr);}
3465   PetscFunctionReturn(0);
3466 }
3467 
3468 /*@
3469   PetscSectionGetUseFieldOffsets - Get the flag to use field offsets directly in a global section, rather than just the point offset
3470 
3471   Not collective
3472 
3473   Input Parameter:
3474 . s - the global PetscSection
3475 
3476   Output Parameters:
3477 . flg - the flag
3478 
3479   Level: developer
3480 
3481 .seealso: PetscSectionSetChart(), PetscSectionCreate()
3482 @*/
3483 PetscErrorCode PetscSectionGetUseFieldOffsets(PetscSection s, PetscBool *flg)
3484 {
3485   PetscFunctionBegin;
3486   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
3487   *flg = s->useFieldOff;
3488   PetscFunctionReturn(0);
3489 }
3490 
3491 /*@
3492   PetscSectionSetUseFieldOffsets - Set the flag to use field offsets directly in a global section, rather than just the point offset
3493 
3494   Not collective
3495 
3496   Input Parameters:
3497 + s   - the global PetscSection
3498 - flg - the flag
3499 
3500   Level: developer
3501 
3502 .seealso: PetscSectionGetUseFieldOffsets(), PetscSectionSetChart(), PetscSectionCreate()
3503 @*/
3504 PetscErrorCode PetscSectionSetUseFieldOffsets(PetscSection s, PetscBool flg)
3505 {
3506   PetscFunctionBegin;
3507   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
3508   s->useFieldOff = flg;
3509   PetscFunctionReturn(0);
3510 }
3511 
3512 #define PetscSectionExpandPoints_Loop(TYPE) \
3513 { \
3514   PetscInt i, n, o0, o1, size; \
3515   TYPE *a0 = (TYPE*)origArray, *a1; \
3516   ierr = PetscSectionGetStorageSize(s, &size);CHKERRQ(ierr); \
3517   ierr = PetscMalloc1(size, &a1);CHKERRQ(ierr); \
3518   for (i=0; i<npoints; i++) { \
3519     ierr = PetscSectionGetOffset(origSection, points_[i], &o0);CHKERRQ(ierr); \
3520     ierr = PetscSectionGetOffset(s, i, &o1);CHKERRQ(ierr); \
3521     ierr = PetscSectionGetDof(s, i, &n);CHKERRQ(ierr); \
3522     ierr = PetscMemcpy(&a1[o1], &a0[o0], n*unitsize);CHKERRQ(ierr); \
3523   } \
3524   *newArray = (void*)a1; \
3525 }
3526 
3527 /*@
3528   PetscSectionExtractDofsFromArray - Extracts elements of an array corresponding to DOFs of specified points.
3529 
3530   Not collective
3531 
3532   Input Parameters:
3533 + origSection - the PetscSection describing the layout of the array
3534 . dataType - MPI_Datatype describing the data type of the array (currently only MPIU_INT, MPIU_SCALAR, MPIU_REAL)
3535 . origArray - the array; its size must be equal to the storage size of origSection
3536 - points - IS with points to extract; its indices must lie in the chart of origSection
3537 
3538   Output Parameters:
3539 + newSection - the new PetscSection desribing the layout of the new array (with points renumbered 0,1,... but preserving numbers of DOFs)
3540 - newArray - the array of the extracted DOFs; its size is the storage size of newSection
3541 
3542   Level: developer
3543 
3544 .seealso: PetscSectionGetChart(), PetscSectionGetDof(), PetscSectionGetStorageSize(), PetscSectionCreate()
3545 @*/
3546 PetscErrorCode PetscSectionExtractDofsFromArray(PetscSection origSection, MPI_Datatype dataType, const void *origArray, IS points, PetscSection *newSection, void *newArray[])
3547 {
3548   PetscSection        s;
3549   const PetscInt      *points_;
3550   PetscInt            i, n, npoints, pStart, pEnd;
3551   PetscMPIInt         unitsize;
3552   PetscErrorCode      ierr;
3553 
3554   PetscFunctionBegin;
3555   PetscValidHeaderSpecific(origSection, PETSC_SECTION_CLASSID, 1);
3556   PetscValidPointer(origArray, 3);
3557   PetscValidHeaderSpecific(points, IS_CLASSID, 4);
3558   if (newSection) PetscValidPointer(newSection, 5);
3559   if (newArray) PetscValidPointer(newArray, 6);
3560   ierr = MPI_Type_size(dataType, &unitsize);CHKERRMPI(ierr);
3561   ierr = ISGetLocalSize(points, &npoints);CHKERRQ(ierr);
3562   ierr = ISGetIndices(points, &points_);CHKERRQ(ierr);
3563   ierr = PetscSectionGetChart(origSection, &pStart, &pEnd);CHKERRQ(ierr);
3564   ierr = PetscSectionCreate(PETSC_COMM_SELF, &s);CHKERRQ(ierr);
3565   ierr = PetscSectionSetChart(s, 0, npoints);CHKERRQ(ierr);
3566   for (i=0; i<npoints; i++) {
3567     PetscCheckFalse(points_[i] < pStart || points_[i] >= pEnd,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "point %" PetscInt_FMT " (index %" PetscInt_FMT ") in input IS out of input section's chart", points_[i], i);
3568     ierr = PetscSectionGetDof(origSection, points_[i], &n);CHKERRQ(ierr);
3569     ierr = PetscSectionSetDof(s, i, n);CHKERRQ(ierr);
3570   }
3571   ierr = PetscSectionSetUp(s);CHKERRQ(ierr);
3572   if (newArray) {
3573     if (dataType == MPIU_INT)           {PetscSectionExpandPoints_Loop(PetscInt);}
3574     else if (dataType == MPIU_SCALAR)   {PetscSectionExpandPoints_Loop(PetscScalar);}
3575     else if (dataType == MPIU_REAL)     {PetscSectionExpandPoints_Loop(PetscReal);}
3576     else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "not implemented for this MPI_Datatype");
3577   }
3578   if (newSection) {
3579     *newSection = s;
3580   } else {
3581     ierr = PetscSectionDestroy(&s);CHKERRQ(ierr);
3582   }
3583   ierr = ISRestoreIndices(points, &points_);CHKERRQ(ierr);
3584   PetscFunctionReturn(0);
3585 }
3586