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