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