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