xref: /petsc/src/vec/is/section/interface/section.c (revision 140a147293a25251a9cb594f525bcfe7ceee4ef4)
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 
2049   s->pStart    = -1;
2050   s->pEnd      = -1;
2051   s->maxDof    = 0;
2052   s->setup     = PETSC_FALSE;
2053   s->numFields = 0;
2054   s->clObj     = NULL;
2055   PetscFunctionReturn(0);
2056 }
2057 
2058 /*@
2059   PetscSectionDestroy - Frees a section object and frees its range if that exists.
2060 
2061   Not collective
2062 
2063   Input Parameters:
2064 . s - the PetscSection
2065 
2066   Level: beginner
2067 
2068 .seealso: PetscSection, PetscSectionCreate()
2069 @*/
2070 PetscErrorCode PetscSectionDestroy(PetscSection *s)
2071 {
2072   PetscErrorCode ierr;
2073 
2074   PetscFunctionBegin;
2075   if (!*s) PetscFunctionReturn(0);
2076   PetscValidHeaderSpecific(*s,PETSC_SECTION_CLASSID,1);
2077   if (--((PetscObject)(*s))->refct > 0) {
2078     *s = NULL;
2079     PetscFunctionReturn(0);
2080   }
2081   ierr = PetscSectionReset(*s);CHKERRQ(ierr);
2082   ierr = PetscHeaderDestroy(s);CHKERRQ(ierr);
2083   PetscFunctionReturn(0);
2084 }
2085 
2086 PetscErrorCode VecIntGetValuesSection(PetscInt *baseArray, PetscSection s, PetscInt point, const PetscInt **values)
2087 {
2088   const PetscInt p = point - s->pStart;
2089 
2090   PetscFunctionBegin;
2091   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 2);
2092   *values = &baseArray[s->atlasOff[p]];
2093   PetscFunctionReturn(0);
2094 }
2095 
2096 PetscErrorCode VecIntSetValuesSection(PetscInt *baseArray, PetscSection s, PetscInt point, const PetscInt values[], InsertMode mode)
2097 {
2098   PetscInt       *array;
2099   const PetscInt p           = point - s->pStart;
2100   const PetscInt orientation = 0; /* Needs to be included for use in closure operations */
2101   PetscInt       cDim        = 0;
2102   PetscErrorCode ierr;
2103 
2104   PetscFunctionBegin;
2105   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 2);
2106   ierr  = PetscSectionGetConstraintDof(s, p, &cDim);CHKERRQ(ierr);
2107   array = &baseArray[s->atlasOff[p]];
2108   if (!cDim) {
2109     if (orientation >= 0) {
2110       const PetscInt dim = s->atlasDof[p];
2111       PetscInt       i;
2112 
2113       if (mode == INSERT_VALUES) {
2114         for (i = 0; i < dim; ++i) array[i] = values[i];
2115       } else {
2116         for (i = 0; i < dim; ++i) array[i] += values[i];
2117       }
2118     } else {
2119       PetscInt offset = 0;
2120       PetscInt j      = -1, field, i;
2121 
2122       for (field = 0; field < s->numFields; ++field) {
2123         const PetscInt dim = s->field[field]->atlasDof[p];
2124 
2125         for (i = dim-1; i >= 0; --i) array[++j] = values[i+offset];
2126         offset += dim;
2127       }
2128     }
2129   } else {
2130     if (orientation >= 0) {
2131       const PetscInt dim  = s->atlasDof[p];
2132       PetscInt       cInd = 0, i;
2133       const PetscInt *cDof;
2134 
2135       ierr = PetscSectionGetConstraintIndices(s, point, &cDof);CHKERRQ(ierr);
2136       if (mode == INSERT_VALUES) {
2137         for (i = 0; i < dim; ++i) {
2138           if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
2139           array[i] = values[i];
2140         }
2141       } else {
2142         for (i = 0; i < dim; ++i) {
2143           if ((cInd < cDim) && (i == cDof[cInd])) {++cInd; continue;}
2144           array[i] += values[i];
2145         }
2146       }
2147     } else {
2148       const PetscInt *cDof;
2149       PetscInt       offset  = 0;
2150       PetscInt       cOffset = 0;
2151       PetscInt       j       = 0, field;
2152 
2153       ierr = PetscSectionGetConstraintIndices(s, point, &cDof);CHKERRQ(ierr);
2154       for (field = 0; field < s->numFields; ++field) {
2155         const PetscInt dim  = s->field[field]->atlasDof[p];     /* PetscSectionGetFieldDof() */
2156         const PetscInt tDim = s->field[field]->bc->atlasDof[p]; /* PetscSectionGetFieldConstraintDof() */
2157         const PetscInt sDim = dim - tDim;
2158         PetscInt       cInd = 0, i,k;
2159 
2160         for (i = 0, k = dim+offset-1; i < dim; ++i, ++j, --k) {
2161           if ((cInd < sDim) && (j == cDof[cInd+cOffset])) {++cInd; continue;}
2162           array[j] = values[k];
2163         }
2164         offset  += dim;
2165         cOffset += dim - tDim;
2166       }
2167     }
2168   }
2169   PetscFunctionReturn(0);
2170 }
2171 
2172 /*@C
2173   PetscSectionHasConstraints - Determine whether a section has constrained dofs
2174 
2175   Not collective
2176 
2177   Input Parameter:
2178 . s - The PetscSection
2179 
2180   Output Parameter:
2181 . hasConstraints - flag indicating that the section has constrained dofs
2182 
2183   Level: intermediate
2184 
2185 .seealso: PetscSectionSetConstraintIndices(), PetscSectionGetConstraintDof(), PetscSection
2186 @*/
2187 PetscErrorCode PetscSectionHasConstraints(PetscSection s, PetscBool *hasConstraints)
2188 {
2189   PetscFunctionBegin;
2190   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2191   PetscValidPointer(hasConstraints, 2);
2192   *hasConstraints = s->bc ? PETSC_TRUE : PETSC_FALSE;
2193   PetscFunctionReturn(0);
2194 }
2195 
2196 /*@C
2197   PetscSectionGetConstraintIndices - Get the point dof numbers, in [0, dof), which are constrained
2198 
2199   Not collective
2200 
2201   Input Parameters:
2202 + s     - The PetscSection
2203 - point - The point
2204 
2205   Output Parameter:
2206 . indices - The constrained dofs
2207 
2208   Note: In Fortran, you call PetscSectionGetConstraintIndicesF90() and PetscSectionRestoreConstraintIndicesF90()
2209 
2210   Level: intermediate
2211 
2212 .seealso: PetscSectionSetConstraintIndices(), PetscSectionGetConstraintDof(), PetscSection
2213 @*/
2214 PetscErrorCode PetscSectionGetConstraintIndices(PetscSection s, PetscInt point, const PetscInt **indices)
2215 {
2216   PetscErrorCode ierr;
2217 
2218   PetscFunctionBegin;
2219   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2220   if (s->bc) {
2221     ierr = VecIntGetValuesSection(s->bcIndices, s->bc, point, indices);CHKERRQ(ierr);
2222   } else *indices = NULL;
2223   PetscFunctionReturn(0);
2224 }
2225 
2226 /*@C
2227   PetscSectionSetConstraintIndices - Set the point dof numbers, in [0, dof), which are constrained
2228 
2229   Not collective
2230 
2231   Input Parameters:
2232 + s     - The PetscSection
2233 . point - The point
2234 - indices - The constrained dofs
2235 
2236   Note: The Fortran is PetscSectionSetConstraintIndicesF90()
2237 
2238   Level: intermediate
2239 
2240 .seealso: PetscSectionGetConstraintIndices(), PetscSectionGetConstraintDof(), PetscSection
2241 @*/
2242 PetscErrorCode PetscSectionSetConstraintIndices(PetscSection s, PetscInt point, const PetscInt indices[])
2243 {
2244   PetscErrorCode ierr;
2245 
2246   PetscFunctionBegin;
2247   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2248   if (s->bc) {
2249     ierr = VecIntSetValuesSection(s->bcIndices, s->bc, point, indices, INSERT_VALUES);CHKERRQ(ierr);
2250   }
2251   PetscFunctionReturn(0);
2252 }
2253 
2254 /*@C
2255   PetscSectionGetFieldConstraintIndices - Get the field dof numbers, in [0, fdof), which are constrained
2256 
2257   Not collective
2258 
2259   Input Parameters:
2260 + s     - The PetscSection
2261 . field  - The field number
2262 - point - The point
2263 
2264   Output Parameter:
2265 . indices - The constrained dofs
2266 
2267   Note: In Fortran, you call PetscSectionGetFieldConstraintIndicesF90() and PetscSectionRestoreFieldConstraintIndicesF90()
2268 
2269   Level: intermediate
2270 
2271 .seealso: PetscSectionSetFieldConstraintIndices(), PetscSectionGetConstraintIndices(), PetscSectionGetConstraintDof(), PetscSection
2272 @*/
2273 PetscErrorCode PetscSectionGetFieldConstraintIndices(PetscSection s, PetscInt point, PetscInt field, const PetscInt **indices)
2274 {
2275   PetscErrorCode ierr;
2276 
2277   PetscFunctionBegin;
2278   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2279   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);
2280   ierr = PetscSectionGetConstraintIndices(s->field[field], point, indices);CHKERRQ(ierr);
2281   PetscFunctionReturn(0);
2282 }
2283 
2284 /*@C
2285   PetscSectionSetFieldConstraintIndices - Set the field dof numbers, in [0, fdof), which are constrained
2286 
2287   Not collective
2288 
2289   Input Parameters:
2290 + s       - The PetscSection
2291 . point   - The point
2292 . field   - The field number
2293 - indices - The constrained dofs
2294 
2295   Note: The Fortran is PetscSectionSetFieldConstraintIndicesF90()
2296 
2297   Level: intermediate
2298 
2299 .seealso: PetscSectionSetConstraintIndices(), PetscSectionGetFieldConstraintIndices(), PetscSectionGetConstraintDof(), PetscSection
2300 @*/
2301 PetscErrorCode PetscSectionSetFieldConstraintIndices(PetscSection s, PetscInt point, PetscInt field, const PetscInt indices[])
2302 {
2303   PetscErrorCode ierr;
2304 
2305   PetscFunctionBegin;
2306   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2307   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);
2308   ierr = PetscSectionSetConstraintIndices(s->field[field], point, indices);CHKERRQ(ierr);
2309   PetscFunctionReturn(0);
2310 }
2311 
2312 /*@
2313   PetscSectionPermute - Reorder the section according to the input point permutation
2314 
2315   Collective on PetscSection
2316 
2317   Input Parameter:
2318 + section - The PetscSection object
2319 - perm - The point permutation, old point p becomes new point perm[p]
2320 
2321   Output Parameter:
2322 . sectionNew - The permuted PetscSection
2323 
2324   Level: intermediate
2325 
2326 .seealso: MatPermute()
2327 @*/
2328 PetscErrorCode PetscSectionPermute(PetscSection section, IS permutation, PetscSection *sectionNew)
2329 {
2330   PetscSection    s = section, sNew;
2331   const PetscInt *perm;
2332   PetscInt        numFields, f, numPoints, pStart, pEnd, p;
2333   PetscErrorCode  ierr;
2334 
2335   PetscFunctionBegin;
2336   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1);
2337   PetscValidHeaderSpecific(permutation, IS_CLASSID, 2);
2338   PetscValidPointer(sectionNew, 3);
2339   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) s), &sNew);CHKERRQ(ierr);
2340   ierr = PetscSectionGetNumFields(s, &numFields);CHKERRQ(ierr);
2341   if (numFields) {ierr = PetscSectionSetNumFields(sNew, numFields);CHKERRQ(ierr);}
2342   for (f = 0; f < numFields; ++f) {
2343     const char *name;
2344     PetscInt    numComp;
2345 
2346     ierr = PetscSectionGetFieldName(s, f, &name);CHKERRQ(ierr);
2347     ierr = PetscSectionSetFieldName(sNew, f, name);CHKERRQ(ierr);
2348     ierr = PetscSectionGetFieldComponents(s, f, &numComp);CHKERRQ(ierr);
2349     ierr = PetscSectionSetFieldComponents(sNew, f, numComp);CHKERRQ(ierr);
2350   }
2351   ierr = ISGetLocalSize(permutation, &numPoints);CHKERRQ(ierr);
2352   ierr = ISGetIndices(permutation, &perm);CHKERRQ(ierr);
2353   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
2354   ierr = PetscSectionSetChart(sNew, pStart, pEnd);CHKERRQ(ierr);
2355   if (numPoints < pEnd) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Permutation size %D is less than largest Section point %D", numPoints, pEnd);
2356   for (p = pStart; p < pEnd; ++p) {
2357     PetscInt dof, cdof;
2358 
2359     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
2360     ierr = PetscSectionSetDof(sNew, perm[p], dof);CHKERRQ(ierr);
2361     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
2362     if (cdof) {ierr = PetscSectionSetConstraintDof(sNew, perm[p], cdof);CHKERRQ(ierr);}
2363     for (f = 0; f < numFields; ++f) {
2364       ierr = PetscSectionGetFieldDof(s, p, f, &dof);CHKERRQ(ierr);
2365       ierr = PetscSectionSetFieldDof(sNew, perm[p], f, dof);CHKERRQ(ierr);
2366       ierr = PetscSectionGetFieldConstraintDof(s, p, f, &cdof);CHKERRQ(ierr);
2367       if (cdof) {ierr = PetscSectionSetFieldConstraintDof(sNew, perm[p], f, cdof);CHKERRQ(ierr);}
2368     }
2369   }
2370   ierr = PetscSectionSetUp(sNew);CHKERRQ(ierr);
2371   for (p = pStart; p < pEnd; ++p) {
2372     const PetscInt *cind;
2373     PetscInt        cdof;
2374 
2375     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
2376     if (cdof) {
2377       ierr = PetscSectionGetConstraintIndices(s, p, &cind);CHKERRQ(ierr);
2378       ierr = PetscSectionSetConstraintIndices(sNew, perm[p], cind);CHKERRQ(ierr);
2379     }
2380     for (f = 0; f < numFields; ++f) {
2381       ierr = PetscSectionGetFieldConstraintDof(s, p, f, &cdof);CHKERRQ(ierr);
2382       if (cdof) {
2383         ierr = PetscSectionGetFieldConstraintIndices(s, p, f, &cind);CHKERRQ(ierr);
2384         ierr = PetscSectionSetFieldConstraintIndices(sNew, perm[p], f, cind);CHKERRQ(ierr);
2385       }
2386     }
2387   }
2388   ierr = ISRestoreIndices(permutation, &perm);CHKERRQ(ierr);
2389   *sectionNew = sNew;
2390   PetscFunctionReturn(0);
2391 }
2392 
2393 /* TODO: the next three functions should be moved to sf/utils */
2394 #include <petsc/private/sfimpl.h>
2395 
2396 /*@C
2397   PetscSFDistributeSection - Create a new PetscSection reorganized, moving from the root to the leaves of the SF
2398 
2399   Collective on sf
2400 
2401   Input Parameters:
2402 + sf - The SF
2403 - rootSection - Section defined on root space
2404 
2405   Output Parameters:
2406 + remoteOffsets - root offsets in leaf storage, or NULL
2407 - leafSection - Section defined on the leaf space
2408 
2409   Level: advanced
2410 
2411 .seealso: PetscSFCreate()
2412 @*/
2413 PetscErrorCode PetscSFDistributeSection(PetscSF sf, PetscSection rootSection, PetscInt **remoteOffsets, PetscSection leafSection)
2414 {
2415   PetscSF        embedSF;
2416   const PetscInt *indices;
2417   IS             selected;
2418   PetscInt       numFields, nroots, rpStart, rpEnd, lpStart = PETSC_MAX_INT, lpEnd = -1, f;
2419   PetscBool      *sub, hasc;
2420   PetscErrorCode ierr;
2421 
2422   PetscFunctionBegin;
2423   ierr = PetscLogEventBegin(PETSCSF_DistSect,sf,0,0,0);CHKERRQ(ierr);
2424   ierr = PetscSectionGetNumFields(rootSection, &numFields);CHKERRQ(ierr);
2425   if (numFields) {ierr = PetscSectionSetNumFields(leafSection, numFields);CHKERRQ(ierr);}
2426   ierr = PetscMalloc1(numFields+2, &sub);CHKERRQ(ierr);
2427   sub[1] = rootSection->bc ? PETSC_TRUE : PETSC_FALSE;
2428   for (f = 0; f < numFields; ++f) {
2429     PetscSectionSym sym;
2430     const char      *name   = NULL;
2431     PetscInt        numComp = 0;
2432 
2433     sub[2 + f] = rootSection->field[f]->bc ? PETSC_TRUE : PETSC_FALSE;
2434     ierr = PetscSectionGetFieldComponents(rootSection, f, &numComp);CHKERRQ(ierr);
2435     ierr = PetscSectionGetFieldName(rootSection, f, &name);CHKERRQ(ierr);
2436     ierr = PetscSectionGetFieldSym(rootSection, f, &sym);CHKERRQ(ierr);
2437     ierr = PetscSectionSetFieldComponents(leafSection, f, numComp);CHKERRQ(ierr);
2438     ierr = PetscSectionSetFieldName(leafSection, f, name);CHKERRQ(ierr);
2439     ierr = PetscSectionSetFieldSym(leafSection, f, sym);CHKERRQ(ierr);
2440   }
2441   ierr = PetscSectionGetChart(rootSection, &rpStart, &rpEnd);CHKERRQ(ierr);
2442   ierr = PetscSFGetGraph(sf,&nroots,NULL,NULL,NULL);CHKERRQ(ierr);
2443   rpEnd = PetscMin(rpEnd,nroots);
2444   rpEnd = PetscMax(rpStart,rpEnd);
2445   /* see if we can avoid creating the embedded SF, since it can cost more than an allreduce */
2446   sub[0] = (PetscBool)(nroots != rpEnd - rpStart);
2447   ierr = MPIU_Allreduce(MPI_IN_PLACE, sub, 2+numFields, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)sf));CHKERRQ(ierr);
2448   if (sub[0]) {
2449     ierr = ISCreateStride(PETSC_COMM_SELF, rpEnd - rpStart, rpStart, 1, &selected);CHKERRQ(ierr);
2450     ierr = ISGetIndices(selected, &indices);CHKERRQ(ierr);
2451     ierr = PetscSFCreateEmbeddedSF(sf, rpEnd - rpStart, indices, &embedSF);CHKERRQ(ierr);
2452     ierr = ISRestoreIndices(selected, &indices);CHKERRQ(ierr);
2453     ierr = ISDestroy(&selected);CHKERRQ(ierr);
2454   } else {
2455     ierr = PetscObjectReference((PetscObject)sf);CHKERRQ(ierr);
2456     embedSF = sf;
2457   }
2458   ierr = PetscSFGetLeafRange(embedSF, &lpStart, &lpEnd);CHKERRQ(ierr);
2459   lpEnd++;
2460 
2461   ierr = PetscSectionSetChart(leafSection, lpStart, lpEnd);CHKERRQ(ierr);
2462 
2463   /* Constrained dof section */
2464   hasc = sub[1];
2465   for (f = 0; f < numFields; ++f) hasc = (PetscBool)(hasc || sub[2+f]);
2466 
2467   /* Could fuse these at the cost of copies and extra allocation */
2468   ierr = PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->atlasDof[-rpStart], &leafSection->atlasDof[-lpStart]);CHKERRQ(ierr);
2469   ierr = PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->atlasDof[-rpStart], &leafSection->atlasDof[-lpStart]);CHKERRQ(ierr);
2470   if (sub[1]) {
2471     ierr = PetscSectionCheckConstraints_Static(rootSection);CHKERRQ(ierr);
2472     ierr = PetscSectionCheckConstraints_Static(leafSection);CHKERRQ(ierr);
2473     ierr = PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->bc->atlasDof[-rpStart], &leafSection->bc->atlasDof[-lpStart]);CHKERRQ(ierr);
2474     ierr = PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->bc->atlasDof[-rpStart], &leafSection->bc->atlasDof[-lpStart]);CHKERRQ(ierr);
2475   }
2476   for (f = 0; f < numFields; ++f) {
2477     ierr = PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->field[f]->atlasDof[-rpStart], &leafSection->field[f]->atlasDof[-lpStart]);CHKERRQ(ierr);
2478     ierr = PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->field[f]->atlasDof[-rpStart], &leafSection->field[f]->atlasDof[-lpStart]);CHKERRQ(ierr);
2479     if (sub[2+f]) {
2480       ierr = PetscSectionCheckConstraints_Static(rootSection->field[f]);CHKERRQ(ierr);
2481       ierr = PetscSectionCheckConstraints_Static(leafSection->field[f]);CHKERRQ(ierr);
2482       ierr = PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasDof[-rpStart], &leafSection->field[f]->bc->atlasDof[-lpStart]);CHKERRQ(ierr);
2483       ierr = PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasDof[-rpStart], &leafSection->field[f]->bc->atlasDof[-lpStart]);CHKERRQ(ierr);
2484     }
2485   }
2486   if (remoteOffsets) {
2487     ierr = PetscMalloc1(lpEnd - lpStart, remoteOffsets);CHKERRQ(ierr);
2488     ierr = PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->atlasOff[-rpStart], &(*remoteOffsets)[-lpStart]);CHKERRQ(ierr);
2489     ierr = PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->atlasOff[-rpStart], &(*remoteOffsets)[-lpStart]);CHKERRQ(ierr);
2490   }
2491   ierr = PetscSectionSetUp(leafSection);CHKERRQ(ierr);
2492   if (hasc) { /* need to communicate bcIndices */
2493     PetscSF  bcSF;
2494     PetscInt *rOffBc;
2495 
2496     ierr = PetscMalloc1(lpEnd - lpStart, &rOffBc);CHKERRQ(ierr);
2497     if (sub[1]) {
2498       ierr = PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->bc->atlasOff[-rpStart], &rOffBc[-lpStart]);CHKERRQ(ierr);
2499       ierr = PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->bc->atlasOff[-rpStart], &rOffBc[-lpStart]);CHKERRQ(ierr);
2500       ierr = PetscSFCreateSectionSF(embedSF, rootSection->bc, rOffBc, leafSection->bc, &bcSF);CHKERRQ(ierr);
2501       ierr = PetscSFBcastBegin(bcSF, MPIU_INT, rootSection->bcIndices, leafSection->bcIndices);CHKERRQ(ierr);
2502       ierr = PetscSFBcastEnd(bcSF, MPIU_INT, rootSection->bcIndices, leafSection->bcIndices);CHKERRQ(ierr);
2503       ierr = PetscSFDestroy(&bcSF);CHKERRQ(ierr);
2504     }
2505     for (f = 0; f < numFields; ++f) {
2506       if (sub[2+f]) {
2507         ierr = PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasOff[-rpStart], &rOffBc[-lpStart]);CHKERRQ(ierr);
2508         ierr = PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->field[f]->bc->atlasOff[-rpStart], &rOffBc[-lpStart]);CHKERRQ(ierr);
2509         ierr = PetscSFCreateSectionSF(embedSF, rootSection->field[f]->bc, rOffBc, leafSection->field[f]->bc, &bcSF);CHKERRQ(ierr);
2510         ierr = PetscSFBcastBegin(bcSF, MPIU_INT, rootSection->field[f]->bcIndices, leafSection->field[f]->bcIndices);CHKERRQ(ierr);
2511         ierr = PetscSFBcastEnd(bcSF, MPIU_INT, rootSection->field[f]->bcIndices, leafSection->field[f]->bcIndices);CHKERRQ(ierr);
2512         ierr = PetscSFDestroy(&bcSF);CHKERRQ(ierr);
2513       }
2514     }
2515     ierr = PetscFree(rOffBc);CHKERRQ(ierr);
2516   }
2517   ierr = PetscSFDestroy(&embedSF);CHKERRQ(ierr);
2518   ierr = PetscFree(sub);CHKERRQ(ierr);
2519   ierr = PetscLogEventEnd(PETSCSF_DistSect,sf,0,0,0);CHKERRQ(ierr);
2520   PetscFunctionReturn(0);
2521 }
2522 
2523 /*@C
2524   PetscSFCreateRemoteOffsets - Create offsets for point data on remote processes
2525 
2526   Collective on sf
2527 
2528   Input Parameters:
2529 + sf          - The SF
2530 . rootSection - Data layout of remote points for outgoing data (this is layout for SF roots)
2531 - leafSection - Data layout of local points for incoming data  (this is layout for SF leaves)
2532 
2533   Output Parameter:
2534 . remoteOffsets - Offsets for point data on remote processes (these are offsets from the root section), or NULL
2535 
2536   Level: developer
2537 
2538 .seealso: PetscSFCreate()
2539 @*/
2540 PetscErrorCode PetscSFCreateRemoteOffsets(PetscSF sf, PetscSection rootSection, PetscSection leafSection, PetscInt **remoteOffsets)
2541 {
2542   PetscSF         embedSF;
2543   const PetscInt *indices;
2544   IS              selected;
2545   PetscInt        numRoots, rpStart = 0, rpEnd = 0, lpStart = 0, lpEnd = 0;
2546   PetscErrorCode  ierr;
2547 
2548   PetscFunctionBegin;
2549   *remoteOffsets = NULL;
2550   ierr = PetscSFGetGraph(sf, &numRoots, NULL, NULL, NULL);CHKERRQ(ierr);
2551   if (numRoots < 0) PetscFunctionReturn(0);
2552   ierr = PetscLogEventBegin(PETSCSF_RemoteOff,sf,0,0,0);CHKERRQ(ierr);
2553   ierr = PetscSectionGetChart(rootSection, &rpStart, &rpEnd);CHKERRQ(ierr);
2554   ierr = PetscSectionGetChart(leafSection, &lpStart, &lpEnd);CHKERRQ(ierr);
2555   ierr = ISCreateStride(PETSC_COMM_SELF, rpEnd - rpStart, rpStart, 1, &selected);CHKERRQ(ierr);
2556   ierr = ISGetIndices(selected, &indices);CHKERRQ(ierr);
2557   ierr = PetscSFCreateEmbeddedSF(sf, rpEnd - rpStart, indices, &embedSF);CHKERRQ(ierr);
2558   ierr = ISRestoreIndices(selected, &indices);CHKERRQ(ierr);
2559   ierr = ISDestroy(&selected);CHKERRQ(ierr);
2560   ierr = PetscCalloc1(lpEnd - lpStart, remoteOffsets);CHKERRQ(ierr);
2561   ierr = PetscSFBcastBegin(embedSF, MPIU_INT, &rootSection->atlasOff[-rpStart], &(*remoteOffsets)[-lpStart]);CHKERRQ(ierr);
2562   ierr = PetscSFBcastEnd(embedSF, MPIU_INT, &rootSection->atlasOff[-rpStart], &(*remoteOffsets)[-lpStart]);CHKERRQ(ierr);
2563   ierr = PetscSFDestroy(&embedSF);CHKERRQ(ierr);
2564   ierr = PetscLogEventEnd(PETSCSF_RemoteOff,sf,0,0,0);CHKERRQ(ierr);
2565   PetscFunctionReturn(0);
2566 }
2567 
2568 /*@C
2569   PetscSFCreateSectionSF - Create an expanded SF of dofs, assuming the input SF relates points
2570 
2571   Collective on sf
2572 
2573   Input Parameters:
2574 + sf - The SF
2575 . rootSection - Data layout of remote points for outgoing data (this is usually the serial section)
2576 . remoteOffsets - Offsets for point data on remote processes (these are offsets from the root section), or NULL
2577 - leafSection - Data layout of local points for incoming data  (this is the distributed section)
2578 
2579   Output Parameters:
2580 - sectionSF - The new SF
2581 
2582   Note: Either rootSection or remoteOffsets can be specified
2583 
2584   Level: advanced
2585 
2586 .seealso: PetscSFCreate()
2587 @*/
2588 PetscErrorCode PetscSFCreateSectionSF(PetscSF sf, PetscSection rootSection, PetscInt remoteOffsets[], PetscSection leafSection, PetscSF *sectionSF)
2589 {
2590   MPI_Comm          comm;
2591   const PetscInt    *localPoints;
2592   const PetscSFNode *remotePoints;
2593   PetscInt          lpStart, lpEnd;
2594   PetscInt          numRoots, numSectionRoots, numPoints, numIndices = 0;
2595   PetscInt          *localIndices;
2596   PetscSFNode       *remoteIndices;
2597   PetscInt          i, ind;
2598   PetscErrorCode    ierr;
2599 
2600   PetscFunctionBegin;
2601   PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1);
2602   PetscValidPointer(rootSection,2);
2603   /* Cannot check PetscValidIntPointer(remoteOffsets,3) because it can be NULL if sf does not reference any points in leafSection */
2604   PetscValidPointer(leafSection,4);
2605   PetscValidPointer(sectionSF,5);
2606   ierr = PetscObjectGetComm((PetscObject)sf,&comm);CHKERRQ(ierr);
2607   ierr = PetscSFCreate(comm, sectionSF);CHKERRQ(ierr);
2608   ierr = PetscSectionGetChart(leafSection, &lpStart, &lpEnd);CHKERRQ(ierr);
2609   ierr = PetscSectionGetStorageSize(rootSection, &numSectionRoots);CHKERRQ(ierr);
2610   ierr = PetscSFGetGraph(sf, &numRoots, &numPoints, &localPoints, &remotePoints);CHKERRQ(ierr);
2611   if (numRoots < 0) PetscFunctionReturn(0);
2612   ierr = PetscLogEventBegin(PETSCSF_SectSF,sf,0,0,0);CHKERRQ(ierr);
2613   for (i = 0; i < numPoints; ++i) {
2614     PetscInt localPoint = localPoints ? localPoints[i] : i;
2615     PetscInt dof;
2616 
2617     if ((localPoint >= lpStart) && (localPoint < lpEnd)) {
2618       ierr = PetscSectionGetDof(leafSection, localPoint, &dof);CHKERRQ(ierr);
2619       numIndices += dof;
2620     }
2621   }
2622   ierr = PetscMalloc1(numIndices, &localIndices);CHKERRQ(ierr);
2623   ierr = PetscMalloc1(numIndices, &remoteIndices);CHKERRQ(ierr);
2624   /* Create new index graph */
2625   for (i = 0, ind = 0; i < numPoints; ++i) {
2626     PetscInt localPoint = localPoints ? localPoints[i] : i;
2627     PetscInt rank       = remotePoints[i].rank;
2628 
2629     if ((localPoint >= lpStart) && (localPoint < lpEnd)) {
2630       PetscInt remoteOffset = remoteOffsets[localPoint-lpStart];
2631       PetscInt loff, dof, d;
2632 
2633       ierr = PetscSectionGetOffset(leafSection, localPoint, &loff);CHKERRQ(ierr);
2634       ierr = PetscSectionGetDof(leafSection, localPoint, &dof);CHKERRQ(ierr);
2635       for (d = 0; d < dof; ++d, ++ind) {
2636         localIndices[ind]        = loff+d;
2637         remoteIndices[ind].rank  = rank;
2638         remoteIndices[ind].index = remoteOffset+d;
2639       }
2640     }
2641   }
2642   if (numIndices != ind) SETERRQ2(comm, PETSC_ERR_PLIB, "Inconsistency in indices, %D should be %D", ind, numIndices);
2643   ierr = PetscSFSetGraph(*sectionSF, numSectionRoots, numIndices, localIndices, PETSC_OWN_POINTER, remoteIndices, PETSC_OWN_POINTER);CHKERRQ(ierr);
2644   ierr = PetscSFSetUp(*sectionSF);CHKERRQ(ierr);
2645   ierr = PetscLogEventEnd(PETSCSF_SectSF,sf,0,0,0);CHKERRQ(ierr);
2646   PetscFunctionReturn(0);
2647 }
2648 
2649 /*@
2650   PetscSectionSetClosureIndex - Set a cache of points in the closure of each point in the section
2651 
2652   Collective on section
2653 
2654   Input Parameters:
2655 + section   - The PetscSection
2656 . obj       - A PetscObject which serves as the key for this index
2657 . clSection - Section giving the size of the closure of each point
2658 - clPoints  - IS giving the points in each closure
2659 
2660   Note: We compress out closure points with no dofs in this section
2661 
2662   Level: advanced
2663 
2664 .seealso: PetscSectionGetClosureIndex(), DMPlexCreateClosureIndex()
2665 @*/
2666 PetscErrorCode PetscSectionSetClosureIndex(PetscSection section, PetscObject obj, PetscSection clSection, IS clPoints)
2667 {
2668   PetscErrorCode ierr;
2669 
2670   PetscFunctionBegin;
2671   if (section->clObj != obj) {ierr = PetscFree(section->clPerm);CHKERRQ(ierr);ierr = PetscFree(section->clInvPerm);CHKERRQ(ierr);}
2672   section->clObj     = obj;
2673   ierr = PetscSectionDestroy(&section->clSection);CHKERRQ(ierr);
2674   ierr = ISDestroy(&section->clPoints);CHKERRQ(ierr);
2675   section->clSection = clSection;
2676   section->clPoints  = clPoints;
2677   PetscFunctionReturn(0);
2678 }
2679 
2680 /*@
2681   PetscSectionGetClosureIndex - Get the cache of points in the closure of each point in the section
2682 
2683   Collective on section
2684 
2685   Input Parameters:
2686 + section   - The PetscSection
2687 - obj       - A PetscObject which serves as the key for this index
2688 
2689   Output Parameters:
2690 + clSection - Section giving the size of the closure of each point
2691 - clPoints  - IS giving the points in each closure
2692 
2693   Note: We compress out closure points with no dofs in this section
2694 
2695   Level: advanced
2696 
2697 .seealso: PetscSectionSetClosureIndex(), DMPlexCreateClosureIndex()
2698 @*/
2699 PetscErrorCode PetscSectionGetClosureIndex(PetscSection section, PetscObject obj, PetscSection *clSection, IS *clPoints)
2700 {
2701   PetscFunctionBegin;
2702   if (section->clObj == obj) {
2703     if (clSection) *clSection = section->clSection;
2704     if (clPoints)  *clPoints  = section->clPoints;
2705   } else {
2706     if (clSection) *clSection = NULL;
2707     if (clPoints)  *clPoints  = NULL;
2708   }
2709   PetscFunctionReturn(0);
2710 }
2711 
2712 PetscErrorCode PetscSectionSetClosurePermutation_Internal(PetscSection section, PetscObject obj, PetscInt clSize, PetscCopyMode mode, PetscInt *clPerm)
2713 {
2714   PetscInt       i;
2715   PetscErrorCode ierr;
2716 
2717   PetscFunctionBegin;
2718   if (section->clObj != obj) {
2719     ierr = PetscSectionDestroy(&section->clSection);CHKERRQ(ierr);
2720     ierr = ISDestroy(&section->clPoints);CHKERRQ(ierr);
2721   }
2722   section->clObj  = obj;
2723   ierr = PetscFree(section->clPerm);CHKERRQ(ierr);
2724   ierr = PetscFree(section->clInvPerm);CHKERRQ(ierr);
2725   section->clSize = clSize;
2726   if (mode == PETSC_COPY_VALUES) {
2727     ierr = PetscMalloc1(clSize, &section->clPerm);CHKERRQ(ierr);
2728     ierr = PetscLogObjectMemory((PetscObject) obj, clSize*sizeof(PetscInt));CHKERRQ(ierr);
2729     ierr = PetscArraycpy(section->clPerm, clPerm, clSize);CHKERRQ(ierr);
2730   } else if (mode == PETSC_OWN_POINTER) {
2731     section->clPerm = clPerm;
2732   } else SETERRQ(PetscObjectComm(obj), PETSC_ERR_SUP, "Do not support borrowed arrays");
2733   ierr = PetscMalloc1(clSize, &section->clInvPerm);CHKERRQ(ierr);
2734   for (i = 0; i < clSize; ++i) section->clInvPerm[section->clPerm[i]] = i;
2735   PetscFunctionReturn(0);
2736 }
2737 
2738 /*@
2739   PetscSectionSetClosurePermutation - Get the dof permutation for the closure of each cell in the section, meaning clPerm[newIndex] = oldIndex.
2740 
2741   Not Collective
2742 
2743   Input Parameters:
2744 + section - The PetscSection
2745 . obj     - A PetscObject which serves as the key for this index
2746 - perm    - Permutation of the cell dof closure
2747 
2748   Note: This strategy only works when all cells have the same size dof closure, and no closures are retrieved for
2749   other points (like faces).
2750 
2751   Level: intermediate
2752 
2753 .seealso: PetscSectionGetClosurePermutation(), PetscSectionGetClosureIndex(), DMPlexCreateClosureIndex(), PetscCopyMode
2754 @*/
2755 PetscErrorCode PetscSectionSetClosurePermutation(PetscSection section, PetscObject obj, IS perm)
2756 {
2757   const PetscInt *clPerm = NULL;
2758   PetscInt        clSize = 0;
2759   PetscErrorCode  ierr;
2760 
2761   PetscFunctionBegin;
2762   if (perm) {
2763     ierr = ISGetLocalSize(perm, &clSize);CHKERRQ(ierr);
2764     ierr = ISGetIndices(perm, &clPerm);CHKERRQ(ierr);
2765   }
2766   ierr = PetscSectionSetClosurePermutation_Internal(section, obj, clSize, PETSC_COPY_VALUES, (PetscInt *) clPerm);CHKERRQ(ierr);
2767   if (perm) {ierr = ISRestoreIndices(perm, &clPerm);CHKERRQ(ierr);}
2768   PetscFunctionReturn(0);
2769 }
2770 
2771 PetscErrorCode PetscSectionGetClosurePermutation_Internal(PetscSection section, PetscObject obj, PetscInt *size, const PetscInt *perm[])
2772 {
2773   PetscFunctionBegin;
2774   if (section->clObj == obj) {
2775     if (size) *size = section->clSize;
2776     if (perm) *perm = section->clPerm;
2777   } else {
2778     if (size) *size = 0;
2779     if (perm) *perm = NULL;
2780   }
2781   PetscFunctionReturn(0);
2782 }
2783 
2784 /*@
2785   PetscSectionGetClosurePermutation - Get the dof permutation for the closure of each cell in the section, meaning clPerm[newIndex] = oldIndex.
2786 
2787   Not collective
2788 
2789   Input Parameters:
2790 + section   - The PetscSection
2791 - obj       - A PetscObject which serves as the key for this index
2792 
2793   Output Parameter:
2794 . perm - The dof closure permutation
2795 
2796   Note: This strategy only works when all cells have the same size dof closure, and no closures are retrieved for
2797   other points (like faces).
2798 
2799   The user must destroy the IS that is returned.
2800 
2801   Level: intermediate
2802 
2803 .seealso: PetscSectionSetClosurePermutation(), PetscSectionGetClosureInversePermutation(), PetscSectionGetClosureIndex(), PetscSectionSetClosureIndex(), DMPlexCreateClosureIndex()
2804 @*/
2805 PetscErrorCode PetscSectionGetClosurePermutation(PetscSection section, PetscObject obj, IS *perm)
2806 {
2807   const PetscInt *clPerm;
2808   PetscInt        clSize;
2809   PetscErrorCode  ierr;
2810 
2811   PetscFunctionBegin;
2812   ierr = PetscSectionGetClosurePermutation_Internal(section, obj, &clSize, &clPerm);CHKERRQ(ierr);
2813   ierr = ISCreateGeneral(PETSC_COMM_SELF, clSize, clPerm, PETSC_USE_POINTER, perm);CHKERRQ(ierr);
2814   PetscFunctionReturn(0);
2815 }
2816 
2817 PetscErrorCode PetscSectionGetClosureInversePermutation_Internal(PetscSection section, PetscObject obj, PetscInt *size, const PetscInt *perm[])
2818 {
2819   PetscFunctionBegin;
2820   if (section->clObj == obj) {
2821     if (size) *size = section->clSize;
2822     if (perm) *perm = section->clInvPerm;
2823   } else {
2824     if (size) *size = 0;
2825     if (perm) *perm = NULL;
2826   }
2827   PetscFunctionReturn(0);
2828 }
2829 
2830 /*@
2831   PetscSectionGetClosureInversePermutation - Get the inverse dof permutation for the closure of each cell in the section, meaning clPerm[oldIndex] = newIndex.
2832 
2833   Not collective
2834 
2835   Input Parameters:
2836 + section   - The PetscSection
2837 - obj       - A PetscObject which serves as the key for this index
2838 
2839   Output Parameters:
2840 + size - The dof closure size
2841 - perm - The dof closure permutation
2842 
2843   Note: This strategy only works when all cells have the same size dof closure, and no closures are retrieved for
2844   other points (like faces).
2845 
2846   The user must destroy the IS that is returned.
2847 
2848   Level: intermediate
2849 
2850 .seealso: PetscSectionSetClosurePermutation(), PetscSectionGetClosureIndex(), PetscSectionSetClosureIndex(), DMPlexCreateClosureIndex()
2851 @*/
2852 PetscErrorCode PetscSectionGetClosureInversePermutation(PetscSection section, PetscObject obj, IS *perm)
2853 {
2854   const PetscInt *clPerm;
2855   PetscInt        clSize;
2856   PetscErrorCode  ierr;
2857 
2858   PetscFunctionBegin;
2859   ierr = PetscSectionGetClosureInversePermutation_Internal(section, obj, &clSize, &clPerm);CHKERRQ(ierr);
2860   ierr = ISCreateGeneral(PETSC_COMM_SELF, clSize, clPerm, PETSC_USE_POINTER, perm);CHKERRQ(ierr);
2861   PetscFunctionReturn(0);
2862 }
2863 
2864 /*@
2865   PetscSectionGetField - Get the subsection associated with a single field
2866 
2867   Input Parameters:
2868 + s     - The PetscSection
2869 - field - The field number
2870 
2871   Output Parameter:
2872 . subs  - The subsection for the given field
2873 
2874   Level: intermediate
2875 
2876 .seealso: PetscSectionSetNumFields()
2877 @*/
2878 PetscErrorCode PetscSectionGetField(PetscSection s, PetscInt field, PetscSection *subs)
2879 {
2880   PetscFunctionBegin;
2881   PetscValidHeaderSpecific(s,PETSC_SECTION_CLASSID,1);
2882   PetscValidPointer(subs,3);
2883   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);
2884   *subs = s->field[field];
2885   PetscFunctionReturn(0);
2886 }
2887 
2888 PetscClassId      PETSC_SECTION_SYM_CLASSID;
2889 PetscFunctionList PetscSectionSymList = NULL;
2890 
2891 /*@
2892   PetscSectionSymCreate - Creates an empty PetscSectionSym object.
2893 
2894   Collective
2895 
2896   Input Parameter:
2897 . comm - the MPI communicator
2898 
2899   Output Parameter:
2900 . sym - pointer to the new set of symmetries
2901 
2902   Level: developer
2903 
2904 .seealso: PetscSectionSym, PetscSectionSymDestroy()
2905 @*/
2906 PetscErrorCode PetscSectionSymCreate(MPI_Comm comm, PetscSectionSym *sym)
2907 {
2908   PetscErrorCode ierr;
2909 
2910   PetscFunctionBegin;
2911   PetscValidPointer(sym,2);
2912   ierr = ISInitializePackage();CHKERRQ(ierr);
2913   ierr = PetscHeaderCreate(*sym,PETSC_SECTION_SYM_CLASSID,"PetscSectionSym","Section Symmetry","IS",comm,PetscSectionSymDestroy,PetscSectionSymView);CHKERRQ(ierr);
2914   PetscFunctionReturn(0);
2915 }
2916 
2917 /*@C
2918   PetscSectionSymSetType - Builds a PetscSection symmetry, for a particular implementation.
2919 
2920   Collective on PetscSectionSym
2921 
2922   Input Parameters:
2923 + sym    - The section symmetry object
2924 - method - The name of the section symmetry type
2925 
2926   Level: developer
2927 
2928 .seealso: PetscSectionSymGetType(), PetscSectionSymCreate()
2929 @*/
2930 PetscErrorCode  PetscSectionSymSetType(PetscSectionSym sym, PetscSectionSymType method)
2931 {
2932   PetscErrorCode (*r)(PetscSectionSym);
2933   PetscBool      match;
2934   PetscErrorCode ierr;
2935 
2936   PetscFunctionBegin;
2937   PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID,1);
2938   ierr = PetscObjectTypeCompare((PetscObject) sym, method, &match);CHKERRQ(ierr);
2939   if (match) PetscFunctionReturn(0);
2940 
2941   ierr = PetscFunctionListFind(PetscSectionSymList,method,&r);CHKERRQ(ierr);
2942   if (!r) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscSectionSym type: %s", method);
2943   if (sym->ops->destroy) {
2944     ierr = (*sym->ops->destroy)(sym);CHKERRQ(ierr);
2945     sym->ops->destroy = NULL;
2946   }
2947   ierr = (*r)(sym);CHKERRQ(ierr);
2948   ierr = PetscObjectChangeTypeName((PetscObject)sym,method);CHKERRQ(ierr);
2949   PetscFunctionReturn(0);
2950 }
2951 
2952 
2953 /*@C
2954   PetscSectionSymGetType - Gets the section symmetry type name (as a string) from the PetscSectionSym.
2955 
2956   Not Collective
2957 
2958   Input Parameter:
2959 . sym  - The section symmetry
2960 
2961   Output Parameter:
2962 . type - The index set type name
2963 
2964   Level: developer
2965 
2966 .seealso: PetscSectionSymSetType(), PetscSectionSymCreate()
2967 @*/
2968 PetscErrorCode PetscSectionSymGetType(PetscSectionSym sym, PetscSectionSymType *type)
2969 {
2970   PetscFunctionBegin;
2971   PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID,1);
2972   PetscValidCharPointer(type,2);
2973   *type = ((PetscObject)sym)->type_name;
2974   PetscFunctionReturn(0);
2975 }
2976 
2977 /*@C
2978   PetscSectionSymRegister - Adds a new section symmetry implementation
2979 
2980   Not Collective
2981 
2982   Input Parameters:
2983 + name        - The name of a new user-defined creation routine
2984 - create_func - The creation routine itself
2985 
2986   Notes:
2987   PetscSectionSymRegister() may be called multiple times to add several user-defined vectors
2988 
2989   Level: developer
2990 
2991 .seealso: PetscSectionSymCreate(), PetscSectionSymSetType()
2992 @*/
2993 PetscErrorCode PetscSectionSymRegister(const char sname[], PetscErrorCode (*function)(PetscSectionSym))
2994 {
2995   PetscErrorCode ierr;
2996 
2997   PetscFunctionBegin;
2998   ierr = ISInitializePackage();CHKERRQ(ierr);
2999   ierr = PetscFunctionListAdd(&PetscSectionSymList,sname,function);CHKERRQ(ierr);
3000   PetscFunctionReturn(0);
3001 }
3002 
3003 /*@
3004    PetscSectionSymDestroy - Destroys a section symmetry.
3005 
3006    Collective on PetscSectionSym
3007 
3008    Input Parameters:
3009 .  sym - the section symmetry
3010 
3011    Level: developer
3012 
3013 .seealso: PetscSectionSymCreate(), PetscSectionSymDestroy()
3014 @*/
3015 PetscErrorCode PetscSectionSymDestroy(PetscSectionSym *sym)
3016 {
3017   SymWorkLink    link,next;
3018   PetscErrorCode ierr;
3019 
3020   PetscFunctionBegin;
3021   if (!*sym) PetscFunctionReturn(0);
3022   PetscValidHeaderSpecific((*sym),PETSC_SECTION_SYM_CLASSID,1);
3023   if (--((PetscObject)(*sym))->refct > 0) {*sym = 0; PetscFunctionReturn(0);}
3024   if ((*sym)->ops->destroy) {
3025     ierr = (*(*sym)->ops->destroy)(*sym);CHKERRQ(ierr);
3026   }
3027   if ((*sym)->workout) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Work array still checked out");
3028   for (link=(*sym)->workin; link; link=next) {
3029     next = link->next;
3030     ierr = PetscFree2(*(PetscInt***)&link->perms,*(PetscScalar***)&link->rots);CHKERRQ(ierr);
3031     ierr = PetscFree(link);CHKERRQ(ierr);
3032   }
3033   (*sym)->workin = NULL;
3034   ierr = PetscHeaderDestroy(sym);CHKERRQ(ierr);
3035   PetscFunctionReturn(0);
3036 }
3037 
3038 /*@C
3039    PetscSectionSymView - Displays a section symmetry
3040 
3041    Collective on PetscSectionSym
3042 
3043    Input Parameters:
3044 +  sym - the index set
3045 -  viewer - viewer used to display the set, for example PETSC_VIEWER_STDOUT_SELF.
3046 
3047    Level: developer
3048 
3049 .seealso: PetscViewerASCIIOpen()
3050 @*/
3051 PetscErrorCode PetscSectionSymView(PetscSectionSym sym,PetscViewer viewer)
3052 {
3053   PetscErrorCode ierr;
3054 
3055   PetscFunctionBegin;
3056   PetscValidHeaderSpecific(sym,PETSC_SECTION_SYM_CLASSID,1);
3057   if (!viewer) {
3058     ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sym),&viewer);CHKERRQ(ierr);
3059   }
3060   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
3061   PetscCheckSameComm(sym,1,viewer,2);
3062   ierr = PetscObjectPrintClassNamePrefixType((PetscObject)sym,viewer);CHKERRQ(ierr);
3063   if (sym->ops->view) {
3064     ierr = (*sym->ops->view)(sym,viewer);CHKERRQ(ierr);
3065   }
3066   PetscFunctionReturn(0);
3067 }
3068 
3069 /*@
3070   PetscSectionSetSym - Set the symmetries for the data referred to by the section
3071 
3072   Collective on PetscSection
3073 
3074   Input Parameters:
3075 + section - the section describing data layout
3076 - sym - the symmetry describing the affect of orientation on the access of the data
3077 
3078   Level: developer
3079 
3080 .seealso: PetscSectionGetSym(), PetscSectionSymCreate()
3081 @*/
3082 PetscErrorCode PetscSectionSetSym(PetscSection section, PetscSectionSym sym)
3083 {
3084   PetscErrorCode ierr;
3085 
3086   PetscFunctionBegin;
3087   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,1);
3088   ierr = PetscSectionSymDestroy(&(section->sym));CHKERRQ(ierr);
3089   if (sym) {
3090     PetscValidHeaderSpecific(sym,PETSC_SECTION_SYM_CLASSID,2);
3091     PetscCheckSameComm(section,1,sym,2);
3092     ierr = PetscObjectReference((PetscObject) sym);CHKERRQ(ierr);
3093   }
3094   section->sym = sym;
3095   PetscFunctionReturn(0);
3096 }
3097 
3098 /*@
3099   PetscSectionGetSym - Get the symmetries for the data referred to by the section
3100 
3101   Not collective
3102 
3103   Input Parameters:
3104 . section - the section describing data layout
3105 
3106   Output Parameters:
3107 . sym - the symmetry describing the affect of orientation on the access of the data
3108 
3109   Level: developer
3110 
3111 .seealso: PetscSectionSetSym(), PetscSectionSymCreate()
3112 @*/
3113 PetscErrorCode PetscSectionGetSym(PetscSection section, PetscSectionSym *sym)
3114 {
3115   PetscFunctionBegin;
3116   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,1);
3117   *sym = section->sym;
3118   PetscFunctionReturn(0);
3119 }
3120 
3121 /*@
3122   PetscSectionSetFieldSym - Set the symmetries for the data referred to by a field of the section
3123 
3124   Collective on PetscSection
3125 
3126   Input Parameters:
3127 + section - the section describing data layout
3128 . field - the field number
3129 - sym - the symmetry describing the affect of orientation on the access of the data
3130 
3131   Level: developer
3132 
3133 .seealso: PetscSectionGetFieldSym(), PetscSectionSymCreate()
3134 @*/
3135 PetscErrorCode PetscSectionSetFieldSym(PetscSection section, PetscInt field, PetscSectionSym sym)
3136 {
3137   PetscErrorCode ierr;
3138 
3139   PetscFunctionBegin;
3140   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,1);
3141   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);
3142   ierr = PetscSectionSetSym(section->field[field],sym);CHKERRQ(ierr);
3143   PetscFunctionReturn(0);
3144 }
3145 
3146 /*@
3147   PetscSectionGetFieldSym - Get the symmetries for the data referred to by a field of the section
3148 
3149   Collective on PetscSection
3150 
3151   Input Parameters:
3152 + section - the section describing data layout
3153 - field - the field number
3154 
3155   Output Parameters:
3156 . sym - the symmetry describing the affect of orientation on the access of the data
3157 
3158   Level: developer
3159 
3160 .seealso: PetscSectionSetFieldSym(), PetscSectionSymCreate()
3161 @*/
3162 PetscErrorCode PetscSectionGetFieldSym(PetscSection section, PetscInt field, PetscSectionSym *sym)
3163 {
3164   PetscFunctionBegin;
3165   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,1);
3166   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);
3167   *sym = section->field[field]->sym;
3168   PetscFunctionReturn(0);
3169 }
3170 
3171 /*@C
3172   PetscSectionGetPointSyms - Get the symmetries for a set of points in a PetscSection under specific orientations.
3173 
3174   Not collective
3175 
3176   Input Parameters:
3177 + section - the section
3178 . numPoints - the number of points
3179 - points - an array of size 2 * numPoints, containing a list of (point, orientation) pairs. (An orientation is an
3180     arbitrary integer: its interpretation is up to sym.  Orientations are used by DM: for their interpretation in that
3181     context, see DMPlexGetConeOrientation()).
3182 
3183   Output Parameter:
3184 + perms - The permutations for the given orientations (or NULL if there is no symmetry or the permutation is the identity).
3185 - rots - The field rotations symmetries for the given orientations (or NULL if there is no symmetry or the rotations are all
3186     identity).
3187 
3188   Example of usage, gathering dofs into a local array (lArray) from a section array (sArray):
3189 .vb
3190      const PetscInt    **perms;
3191      const PetscScalar **rots;
3192      PetscInt            lOffset;
3193 
3194      PetscSectionGetPointSyms(section,numPoints,points,&perms,&rots);
3195      for (i = 0, lOffset = 0; i < numPoints; i++) {
3196        PetscInt           point = points[2*i], dof, sOffset;
3197        const PetscInt    *perm  = perms ? perms[i] : NULL;
3198        const PetscScalar *rot   = rots  ? rots[i]  : NULL;
3199 
3200        PetscSectionGetDof(section,point,&dof);
3201        PetscSectionGetOffset(section,point,&sOffset);
3202 
3203        if (perm) {for (j = 0; j < dof; j++) {lArray[lOffset + perm[j]]  = sArray[sOffset + j];}}
3204        else      {for (j = 0; j < dof; j++) {lArray[lOffset +      j ]  = sArray[sOffset + j];}}
3205        if (rot)  {for (j = 0; j < dof; j++) {lArray[lOffset +      j ] *= rot[j];             }}
3206        lOffset += dof;
3207      }
3208      PetscSectionRestorePointSyms(section,numPoints,points,&perms,&rots);
3209 .ve
3210 
3211   Example of usage, adding dofs into a section array (sArray) from a local array (lArray):
3212 .vb
3213      const PetscInt    **perms;
3214      const PetscScalar **rots;
3215      PetscInt            lOffset;
3216 
3217      PetscSectionGetPointSyms(section,numPoints,points,&perms,&rots);
3218      for (i = 0, lOffset = 0; i < numPoints; i++) {
3219        PetscInt           point = points[2*i], dof, sOffset;
3220        const PetscInt    *perm  = perms ? perms[i] : NULL;
3221        const PetscScalar *rot   = rots  ? rots[i]  : NULL;
3222 
3223        PetscSectionGetDof(section,point,&dof);
3224        PetscSectionGetOffset(section,point,&sOff);
3225 
3226        if (perm) {for (j = 0; j < dof; j++) {sArray[sOffset + j] += lArray[lOffset + perm[j]] * (rot ? PetscConj(rot[perm[j]]) : 1.);}}
3227        else      {for (j = 0; j < dof; j++) {sArray[sOffset + j] += lArray[lOffset +      j ] * (rot ? PetscConj(rot[     j ]) : 1.);}}
3228        offset += dof;
3229      }
3230      PetscSectionRestorePointSyms(section,numPoints,points,&perms,&rots);
3231 .ve
3232 
3233   Level: developer
3234 
3235 .seealso: PetscSectionRestorePointSyms(), PetscSectionSymCreate(), PetscSectionSetSym(), PetscSectionGetSym()
3236 @*/
3237 PetscErrorCode PetscSectionGetPointSyms(PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3238 {
3239   PetscSectionSym sym;
3240   PetscErrorCode  ierr;
3241 
3242   PetscFunctionBegin;
3243   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,1);
3244   if (numPoints) PetscValidIntPointer(points,3);
3245   if (perms) *perms = NULL;
3246   if (rots)  *rots  = NULL;
3247   sym = section->sym;
3248   if (sym && (perms || rots)) {
3249     SymWorkLink link;
3250 
3251     if (sym->workin) {
3252       link        = sym->workin;
3253       sym->workin = sym->workin->next;
3254     } else {
3255       ierr = PetscNewLog(sym,&link);CHKERRQ(ierr);
3256     }
3257     if (numPoints > link->numPoints) {
3258       ierr = PetscFree2(*(PetscInt***)&link->perms,*(PetscInt***)&link->rots);CHKERRQ(ierr);
3259       ierr = PetscMalloc2(numPoints,(PetscInt***)&link->perms,numPoints,(PetscScalar***)&link->rots);CHKERRQ(ierr);
3260       link->numPoints = numPoints;
3261     }
3262     link->next   = sym->workout;
3263     sym->workout = link;
3264     ierr = PetscArrayzero((PetscInt**)link->perms,numPoints);CHKERRQ(ierr);
3265     ierr = PetscArrayzero((PetscInt**)link->rots,numPoints);CHKERRQ(ierr);
3266     ierr = (*sym->ops->getpoints) (sym, section, numPoints, points, link->perms, link->rots);CHKERRQ(ierr);
3267     if (perms) *perms = link->perms;
3268     if (rots)  *rots  = link->rots;
3269   }
3270   PetscFunctionReturn(0);
3271 }
3272 
3273 /*@C
3274   PetscSectionRestorePointSyms - Restore the symmetries returned by PetscSectionGetPointSyms()
3275 
3276   Not collective
3277 
3278   Input Parameters:
3279 + section - the section
3280 . numPoints - the number of points
3281 - points - an array of size 2 * numPoints, containing a list of (point, orientation) pairs. (An orientation is an
3282     arbitrary integer: its interpretation is up to sym.  Orientations are used by DM: for their interpretation in that
3283     context, see DMPlexGetConeOrientation()).
3284 
3285   Output Parameter:
3286 + perms - The permutations for the given orientations: set to NULL at conclusion
3287 - rots - The field rotations symmetries for the given orientations: set to NULL at conclusion
3288 
3289   Level: developer
3290 
3291 .seealso: PetscSectionGetPointSyms(), PetscSectionSymCreate(), PetscSectionSetSym(), PetscSectionGetSym()
3292 @*/
3293 PetscErrorCode PetscSectionRestorePointSyms(PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3294 {
3295   PetscSectionSym sym;
3296 
3297   PetscFunctionBegin;
3298   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,1);
3299   sym = section->sym;
3300   if (sym && (perms || rots)) {
3301     SymWorkLink *p,link;
3302 
3303     for (p=&sym->workout; (link=*p); p=&link->next) {
3304       if ((perms && link->perms == *perms) || (rots && link->rots == *rots)) {
3305         *p          = link->next;
3306         link->next  = sym->workin;
3307         sym->workin = link;
3308         if (perms) *perms = NULL;
3309         if (rots)  *rots  = NULL;
3310         PetscFunctionReturn(0);
3311       }
3312     }
3313     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Array was not checked out");
3314   }
3315   PetscFunctionReturn(0);
3316 }
3317 
3318 /*@C
3319   PetscSectionGetFieldPointSyms - Get the symmetries for a set of points in a field of a PetscSection under specific orientations.
3320 
3321   Not collective
3322 
3323   Input Parameters:
3324 + section - the section
3325 . field - the field of the section
3326 . numPoints - the number of points
3327 - points - an array of size 2 * numPoints, containing a list of (point, orientation) pairs. (An orientation is an
3328     arbitrary integer: its interpretation is up to sym.  Orientations are used by DM: for their interpretation in that
3329     context, see DMPlexGetConeOrientation()).
3330 
3331   Output Parameter:
3332 + perms - The permutations for the given orientations (or NULL if there is no symmetry or the permutation is the identity).
3333 - rots - The field rotations symmetries for the given orientations (or NULL if there is no symmetry or the rotations are all
3334     identity).
3335 
3336   Level: developer
3337 
3338 .seealso: PetscSectionGetPointSyms(), PetscSectionRestoreFieldPointSyms()
3339 @*/
3340 PetscErrorCode PetscSectionGetFieldPointSyms(PetscSection section, PetscInt field, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3341 {
3342   PetscErrorCode ierr;
3343 
3344   PetscFunctionBegin;
3345   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,1);
3346   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);
3347   ierr = PetscSectionGetPointSyms(section->field[field],numPoints,points,perms,rots);CHKERRQ(ierr);
3348   PetscFunctionReturn(0);
3349 }
3350 
3351 /*@C
3352   PetscSectionRestoreFieldPointSyms - Restore the symmetries returned by PetscSectionGetFieldPointSyms()
3353 
3354   Not collective
3355 
3356   Input Parameters:
3357 + section - the section
3358 . field - the field number
3359 . numPoints - the number of points
3360 - points - an array of size 2 * numPoints, containing a list of (point, orientation) pairs. (An orientation is an
3361     arbitrary integer: its interpretation is up to sym.  Orientations are used by DM: for their interpretation in that
3362     context, see DMPlexGetConeOrientation()).
3363 
3364   Output Parameter:
3365 + perms - The permutations for the given orientations: set to NULL at conclusion
3366 - rots - The field rotations symmetries for the given orientations: set to NULL at conclusion
3367 
3368   Level: developer
3369 
3370 .seealso: PetscSectionRestorePointSyms(), petscSectionGetFieldPointSyms(), PetscSectionSymCreate(), PetscSectionSetSym(), PetscSectionGetSym()
3371 @*/
3372 PetscErrorCode PetscSectionRestoreFieldPointSyms(PetscSection section, PetscInt field, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3373 {
3374   PetscErrorCode ierr;
3375 
3376   PetscFunctionBegin;
3377   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,1);
3378   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);
3379   ierr = PetscSectionRestorePointSyms(section->field[field],numPoints,points,perms,rots);CHKERRQ(ierr);
3380   PetscFunctionReturn(0);
3381 }
3382 
3383 /*@
3384   PetscSectionGetUseFieldOffsets - Get the flag to use field offsets directly in a global section, rather than just the point offset
3385 
3386   Not collective
3387 
3388   Input Parameter:
3389 . s - the global PetscSection
3390 
3391   Output Parameters:
3392 . flg - the flag
3393 
3394   Level: developer
3395 
3396 .seealso: PetscSectionSetChart(), PetscSectionCreate()
3397 @*/
3398 PetscErrorCode PetscSectionGetUseFieldOffsets(PetscSection s, PetscBool *flg)
3399 {
3400   PetscFunctionBegin;
3401   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
3402   *flg = s->useFieldOff;
3403   PetscFunctionReturn(0);
3404 }
3405 
3406 /*@
3407   PetscSectionSetUseFieldOffsets - Set the flag to use field offsets directly in a global section, rather than just the point offset
3408 
3409   Not collective
3410 
3411   Input Parameters:
3412 + s   - the global PetscSection
3413 - flg - the flag
3414 
3415   Level: developer
3416 
3417 .seealso: PetscSectionGetUseFieldOffsets(), PetscSectionSetChart(), PetscSectionCreate()
3418 @*/
3419 PetscErrorCode PetscSectionSetUseFieldOffsets(PetscSection s, PetscBool flg)
3420 {
3421   PetscFunctionBegin;
3422   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
3423   s->useFieldOff = flg;
3424   PetscFunctionReturn(0);
3425 }
3426 
3427 #define PetscSectionExpandPoints_Loop(TYPE) \
3428 { \
3429   PetscInt i, n, o0, o1, size; \
3430   TYPE *a0 = (TYPE*)origArray, *a1; \
3431   ierr = PetscSectionGetStorageSize(s, &size);CHKERRQ(ierr); \
3432   ierr = PetscMalloc1(size, &a1);CHKERRQ(ierr); \
3433   for (i=0; i<npoints; i++) { \
3434     ierr = PetscSectionGetOffset(origSection, points_[i], &o0);CHKERRQ(ierr); \
3435     ierr = PetscSectionGetOffset(s, i, &o1);CHKERRQ(ierr); \
3436     ierr = PetscSectionGetDof(s, i, &n);CHKERRQ(ierr); \
3437     ierr = PetscMemcpy(&a1[o1], &a0[o0], n*unitsize);CHKERRQ(ierr); \
3438   } \
3439   *newArray = (void*)a1; \
3440 }
3441 
3442 /*@
3443   PetscSectionExtractDofsFromArray - Extracts elements of an array corresponding to DOFs of specified points.
3444 
3445   Not collective
3446 
3447   Input Parameters:
3448 + origSection - the PetscSection describing the layout of the array
3449 . dataType - MPI_Datatype describing the data type of the array (currently only MPIU_INT, MPIU_SCALAR, MPIU_REAL)
3450 . origArray - the array; its size must be equal to the storage size of origSection
3451 - points - IS with points to extract; its indices must lie in the chart of origSection
3452 
3453   Output Parameters:
3454 + newSection - the new PetscSection desribing the layout of the new array (with points renumbered 0,1,... but preserving numbers of DOFs)
3455 - newArray - the array of the extracted DOFs; its size is the storage size of newSection
3456 
3457   Level: developer
3458 
3459 .seealso: PetscSectionGetChart(), PetscSectionGetDof(), PetscSectionGetStorageSize(), PetscSectionCreate()
3460 @*/
3461 PetscErrorCode PetscSectionExtractDofsFromArray(PetscSection origSection, MPI_Datatype dataType, const void *origArray, IS points, PetscSection *newSection, void *newArray[])
3462 {
3463   PetscSection        s;
3464   const PetscInt      *points_;
3465   PetscInt            i, n, npoints, pStart, pEnd;
3466   PetscMPIInt         unitsize;
3467   PetscErrorCode      ierr;
3468 
3469   PetscFunctionBegin;
3470   PetscValidHeaderSpecific(origSection, PETSC_SECTION_CLASSID, 1);
3471   PetscValidPointer(origArray, 3);
3472   PetscValidHeaderSpecific(points, IS_CLASSID, 4);
3473   if (newSection) PetscValidPointer(newSection, 5);
3474   if (newArray) PetscValidPointer(newArray, 6);
3475   ierr = MPI_Type_size(dataType, &unitsize);CHKERRQ(ierr);
3476   ierr = ISGetLocalSize(points, &npoints);CHKERRQ(ierr);
3477   ierr = ISGetIndices(points, &points_);CHKERRQ(ierr);
3478   ierr = PetscSectionGetChart(origSection, &pStart, &pEnd);CHKERRQ(ierr);
3479   ierr = PetscSectionCreate(PETSC_COMM_SELF, &s);CHKERRQ(ierr);
3480   ierr = PetscSectionSetChart(s, 0, npoints);CHKERRQ(ierr);
3481   for (i=0; i<npoints; i++) {
3482     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);
3483     ierr = PetscSectionGetDof(origSection, points_[i], &n);CHKERRQ(ierr);
3484     ierr = PetscSectionSetDof(s, i, n);CHKERRQ(ierr);
3485   }
3486   ierr = PetscSectionSetUp(s);CHKERRQ(ierr);
3487   if (newArray) {
3488     if (dataType == MPIU_INT)           {PetscSectionExpandPoints_Loop(PetscInt);}
3489     else if (dataType == MPIU_SCALAR)   {PetscSectionExpandPoints_Loop(PetscScalar);}
3490     else if (dataType == MPIU_REAL)     {PetscSectionExpandPoints_Loop(PetscReal);}
3491     else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "not implemented for this MPI_Datatype");
3492   }
3493   if (newSection) {
3494     *newSection = s;
3495   } else {
3496     ierr = PetscSectionDestroy(&s);CHKERRQ(ierr);
3497   }
3498   PetscFunctionReturn(0);
3499 }
3500