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