Actual source code: section.c

  1: /*
  2:    This file contains routines for basic section object implementation.
  3: */

  5: #include <petsc/private/sectionimpl.h>
  6: #include <petscsf.h>

  8: PetscClassId PETSC_SECTION_CLASSID;

 10: /*@
 11:   PetscSectionCreate - Allocates a `PetscSection` and sets the map contents to the default.

 13:   Collective

 15:   Input Parameters:
 16: + comm - the MPI communicator
 17: - s    - pointer to the section

 19:   Level: beginner

 21:   Notes:
 22:   Typical calling sequence
 23: .vb
 24:        PetscSectionCreate(MPI_Comm,PetscSection *);!
 25:        PetscSectionSetNumFields(PetscSection, numFields);
 26:        PetscSectionSetChart(PetscSection,low,high);
 27:        PetscSectionSetDof(PetscSection,point,numdof);
 28:        PetscSectionSetUp(PetscSection);
 29:        PetscSectionGetOffset(PetscSection,point,PetscInt *);
 30:        PetscSectionDestroy(PetscSection);
 31: .ve

 33:   The `PetscSection` object and methods are intended to be used in the PETSc `Vec` and `Mat` implementations. The indices returned by the `PetscSection` are appropriate for the kind of `Vec` it is associated with. For example, if the vector being indexed is a local vector, we call the section a local section. If the section indexes a global vector, we call it a global section. For parallel vectors, like global vectors, we use negative indices to indicate dofs owned by other processes.

 35: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionDestroy()`, `PetscSectionCreateGlobalSection()`
 36: @*/
 37: PetscErrorCode PetscSectionCreate(MPI_Comm comm, PetscSection *s)
 38: {
 39:   PetscFunctionBegin;
 41:   PetscCall(ISInitializePackage());

 43:   PetscCall(PetscHeaderCreate(*s, PETSC_SECTION_CLASSID, "PetscSection", "Section", "IS", comm, PetscSectionDestroy, PetscSectionView));

 45:   (*s)->pStart              = -1;
 46:   (*s)->pEnd                = -1;
 47:   (*s)->perm                = NULL;
 48:   (*s)->pointMajor          = PETSC_TRUE;
 49:   (*s)->includesConstraints = PETSC_TRUE;
 50:   (*s)->atlasDof            = NULL;
 51:   (*s)->atlasOff            = NULL;
 52:   (*s)->bc                  = NULL;
 53:   (*s)->bcIndices           = NULL;
 54:   (*s)->setup               = PETSC_FALSE;
 55:   (*s)->numFields           = 0;
 56:   (*s)->fieldNames          = NULL;
 57:   (*s)->field               = NULL;
 58:   (*s)->useFieldOff         = PETSC_FALSE;
 59:   (*s)->compNames           = NULL;
 60:   (*s)->clObj               = NULL;
 61:   (*s)->clHash              = NULL;
 62:   (*s)->clSection           = NULL;
 63:   (*s)->clPoints            = NULL;
 64:   PetscCall(PetscSectionInvalidateMaxDof_Internal(*s));
 65:   PetscFunctionReturn(PETSC_SUCCESS);
 66: }

 68: /*@
 69:   PetscSectionCopy - Creates a shallow (if possible) copy of the `PetscSection`

 71:   Collective

 73:   Input Parameter:
 74: . section - the `PetscSection`

 76:   Output Parameter:
 77: . newSection - the copy

 79:   Level: intermediate

 81:   Developer Note:
 82:   What exactly does shallow mean in this context?

 84: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()`
 85: @*/
 86: PetscErrorCode PetscSectionCopy(PetscSection section, PetscSection newSection)
 87: {
 88:   PetscSectionSym sym;
 89:   IS              perm;
 90:   PetscInt        numFields, f, c, pStart, pEnd, p;

 92:   PetscFunctionBegin;
 95:   PetscCall(PetscSectionReset(newSection));
 96:   PetscCall(PetscSectionGetNumFields(section, &numFields));
 97:   if (numFields) PetscCall(PetscSectionSetNumFields(newSection, numFields));
 98:   for (f = 0; f < numFields; ++f) {
 99:     const char *fieldName = NULL, *compName = NULL;
100:     PetscInt    numComp = 0;

102:     PetscCall(PetscSectionGetFieldName(section, f, &fieldName));
103:     PetscCall(PetscSectionSetFieldName(newSection, f, fieldName));
104:     PetscCall(PetscSectionGetFieldComponents(section, f, &numComp));
105:     PetscCall(PetscSectionSetFieldComponents(newSection, f, numComp));
106:     for (c = 0; c < numComp; ++c) {
107:       PetscCall(PetscSectionGetComponentName(section, f, c, &compName));
108:       PetscCall(PetscSectionSetComponentName(newSection, f, c, compName));
109:     }
110:     PetscCall(PetscSectionGetFieldSym(section, f, &sym));
111:     PetscCall(PetscSectionSetFieldSym(newSection, f, sym));
112:   }
113:   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
114:   PetscCall(PetscSectionSetChart(newSection, pStart, pEnd));
115:   PetscCall(PetscSectionGetPermutation(section, &perm));
116:   PetscCall(PetscSectionSetPermutation(newSection, perm));
117:   PetscCall(PetscSectionGetSym(section, &sym));
118:   PetscCall(PetscSectionSetSym(newSection, sym));
119:   for (p = pStart; p < pEnd; ++p) {
120:     PetscInt dof, cdof, fcdof = 0;

122:     PetscCall(PetscSectionGetDof(section, p, &dof));
123:     PetscCall(PetscSectionSetDof(newSection, p, dof));
124:     PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
125:     if (cdof) PetscCall(PetscSectionSetConstraintDof(newSection, p, cdof));
126:     for (f = 0; f < numFields; ++f) {
127:       PetscCall(PetscSectionGetFieldDof(section, p, f, &dof));
128:       PetscCall(PetscSectionSetFieldDof(newSection, p, f, dof));
129:       if (cdof) {
130:         PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof));
131:         if (fcdof) PetscCall(PetscSectionSetFieldConstraintDof(newSection, p, f, fcdof));
132:       }
133:     }
134:   }
135:   PetscCall(PetscSectionSetUp(newSection));
136:   for (p = pStart; p < pEnd; ++p) {
137:     PetscInt        off, cdof, fcdof = 0;
138:     const PetscInt *cInd;

140:     /* Must set offsets in case they do not agree with the prefix sums */
141:     PetscCall(PetscSectionGetOffset(section, p, &off));
142:     PetscCall(PetscSectionSetOffset(newSection, p, off));
143:     PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
144:     if (cdof) {
145:       PetscCall(PetscSectionGetConstraintIndices(section, p, &cInd));
146:       PetscCall(PetscSectionSetConstraintIndices(newSection, p, cInd));
147:       for (f = 0; f < numFields; ++f) {
148:         PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof));
149:         if (fcdof) {
150:           PetscCall(PetscSectionGetFieldConstraintIndices(section, p, f, &cInd));
151:           PetscCall(PetscSectionSetFieldConstraintIndices(newSection, p, f, cInd));
152:         }
153:       }
154:     }
155:   }
156:   PetscFunctionReturn(PETSC_SUCCESS);
157: }

159: /*@
160:   PetscSectionClone - Creates a shallow (if possible) copy of the `PetscSection`

162:   Collective

164:   Input Parameter:
165: . section - the `PetscSection`

167:   Output Parameter:
168: . newSection - the copy

170:   Level: beginner

172:   Developer Note:
173:   With standard PETSc terminology this should be called `PetscSectionDuplicate()`

175: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()`, `PetscSectionCopy()`
176: @*/
177: PetscErrorCode PetscSectionClone(PetscSection section, PetscSection *newSection)
178: {
179:   PetscFunctionBegin;
182:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section), newSection));
183:   PetscCall(PetscSectionCopy(section, *newSection));
184:   PetscFunctionReturn(PETSC_SUCCESS);
185: }

187: /*@
188:   PetscSectionSetFromOptions - sets parameters in a `PetscSection` from the options database

190:   Collective

192:   Input Parameter:
193: . section - the `PetscSection`

195:   Options Database Key:
196: . -petscsection_point_major - `PETSC_TRUE` for point-major order

198:   Level: intermediate

200: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()`
201: @*/
202: PetscErrorCode PetscSectionSetFromOptions(PetscSection s)
203: {
204:   PetscFunctionBegin;
206:   PetscObjectOptionsBegin((PetscObject)s);
207:   PetscCall(PetscOptionsBool("-petscsection_point_major", "The for ordering, either point major or field major", "PetscSectionSetPointMajor", s->pointMajor, &s->pointMajor, NULL));
208:   /* process any options handlers added with PetscObjectAddOptionsHandler() */
209:   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)s, PetscOptionsObject));
210:   PetscOptionsEnd();
211:   PetscCall(PetscObjectViewFromOptions((PetscObject)s, NULL, "-petscsection_view"));
212:   PetscFunctionReturn(PETSC_SUCCESS);
213: }

215: /*@
216:   PetscSectionCompare - Compares two sections

218:   Collective

220:   Input Parameters:
221: + s1 - the first `PetscSection`
222: - s2 - the second `PetscSection`

224:   Output Parameter:
225: . congruent - `PETSC_TRUE` if the two sections are congruent, `PETSC_FALSE` otherwise

227:   Level: intermediate

229:   Note:
230:   Field names are disregarded.

232: .seealso: [PetscSection](sec_petscsection), `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;

242:   PetscFunctionBegin;
246:   flg = PETSC_FALSE;

248:   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)s1), PetscObjectComm((PetscObject)s2), &mflg));
249:   if (mflg != MPI_CONGRUENT && mflg != MPI_IDENT) {
250:     *congruent = PETSC_FALSE;
251:     PetscFunctionReturn(PETSC_SUCCESS);
252:   }

254:   PetscCall(PetscSectionGetChart(s1, &pStart, &pEnd));
255:   PetscCall(PetscSectionGetChart(s2, &n1, &n2));
256:   if (pStart != n1 || pEnd != n2) goto not_congruent;

258:   PetscCall(PetscSectionGetPermutation(s1, &perm1));
259:   PetscCall(PetscSectionGetPermutation(s2, &perm2));
260:   if (perm1 && perm2) {
261:     PetscCall(ISEqual(perm1, perm2, congruent));
262:     if (!(*congruent)) goto not_congruent;
263:   } else if (perm1 != perm2) goto not_congruent;

265:   for (p = pStart; p < pEnd; ++p) {
266:     PetscCall(PetscSectionGetOffset(s1, p, &n1));
267:     PetscCall(PetscSectionGetOffset(s2, p, &n2));
268:     if (n1 != n2) goto not_congruent;

270:     PetscCall(PetscSectionGetDof(s1, p, &n1));
271:     PetscCall(PetscSectionGetDof(s2, p, &n2));
272:     if (n1 != n2) goto not_congruent;

274:     PetscCall(PetscSectionGetConstraintDof(s1, p, &ncdof));
275:     PetscCall(PetscSectionGetConstraintDof(s2, p, &n2));
276:     if (ncdof != n2) goto not_congruent;

278:     PetscCall(PetscSectionGetConstraintIndices(s1, p, &idx1));
279:     PetscCall(PetscSectionGetConstraintIndices(s2, p, &idx2));
280:     PetscCall(PetscArraycmp(idx1, idx2, ncdof, congruent));
281:     if (!(*congruent)) goto not_congruent;
282:   }

284:   PetscCall(PetscSectionGetNumFields(s1, &nfields));
285:   PetscCall(PetscSectionGetNumFields(s2, &n2));
286:   if (nfields != n2) goto not_congruent;

288:   for (f = 0; f < nfields; ++f) {
289:     PetscCall(PetscSectionGetFieldComponents(s1, f, &n1));
290:     PetscCall(PetscSectionGetFieldComponents(s2, f, &n2));
291:     if (n1 != n2) goto not_congruent;

293:     for (p = pStart; p < pEnd; ++p) {
294:       PetscCall(PetscSectionGetFieldOffset(s1, p, f, &n1));
295:       PetscCall(PetscSectionGetFieldOffset(s2, p, f, &n2));
296:       if (n1 != n2) goto not_congruent;

298:       PetscCall(PetscSectionGetFieldDof(s1, p, f, &n1));
299:       PetscCall(PetscSectionGetFieldDof(s2, p, f, &n2));
300:       if (n1 != n2) goto not_congruent;

302:       PetscCall(PetscSectionGetFieldConstraintDof(s1, p, f, &nfcdof));
303:       PetscCall(PetscSectionGetFieldConstraintDof(s2, p, f, &n2));
304:       if (nfcdof != n2) goto not_congruent;

306:       PetscCall(PetscSectionGetFieldConstraintIndices(s1, p, f, &idx1));
307:       PetscCall(PetscSectionGetFieldConstraintIndices(s2, p, f, &idx2));
308:       PetscCall(PetscArraycmp(idx1, idx2, nfcdof, congruent));
309:       if (!(*congruent)) goto not_congruent;
310:     }
311:   }

313:   flg = PETSC_TRUE;
314: not_congruent:
315:   PetscCall(MPIU_Allreduce(&flg, congruent, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)s1)));
316:   PetscFunctionReturn(PETSC_SUCCESS);
317: }

319: /*@
320:   PetscSectionGetNumFields - Returns the number of fields in a `PetscSection`, or 0 if no fields were defined.

322:   Not Collective

324:   Input Parameter:
325: . s - the `PetscSection`

327:   Output Parameter:
328: . numFields - the number of fields defined, or 0 if none were defined

330:   Level: intermediate

332: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetNumFields()`
333: @*/
334: PetscErrorCode PetscSectionGetNumFields(PetscSection s, PetscInt *numFields)
335: {
336:   PetscFunctionBegin;
339:   *numFields = s->numFields;
340:   PetscFunctionReturn(PETSC_SUCCESS);
341: }

343: /*@
344:   PetscSectionSetNumFields - Sets the number of fields in a `PetscSection`

346:   Not Collective

348:   Input Parameters:
349: + s - the `PetscSection`
350: - numFields - the number of fields

352:   Level: intermediate

354: .seealso: [PetscSection](sec_petscsection), `PetscSection()`, `PetscSectionGetNumFields()`
355: @*/
356: PetscErrorCode PetscSectionSetNumFields(PetscSection s, PetscInt numFields)
357: {
358:   PetscInt f;

360:   PetscFunctionBegin;
362:   PetscCheck(numFields > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "The number of fields %" PetscInt_FMT " must be positive", numFields);
363:   PetscCall(PetscSectionReset(s));

365:   s->numFields = numFields;
366:   PetscCall(PetscMalloc1(s->numFields, &s->numFieldComponents));
367:   PetscCall(PetscMalloc1(s->numFields, &s->fieldNames));
368:   PetscCall(PetscMalloc1(s->numFields, &s->compNames));
369:   PetscCall(PetscMalloc1(s->numFields, &s->field));
370:   for (f = 0; f < s->numFields; ++f) {
371:     char name[64];

373:     s->numFieldComponents[f] = 1;

375:     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), &s->field[f]));
376:     PetscCall(PetscSNPrintf(name, 64, "Field_%" PetscInt_FMT, f));
377:     PetscCall(PetscStrallocpy(name, (char **)&s->fieldNames[f]));
378:     PetscCall(PetscSNPrintf(name, 64, "Component_0"));
379:     PetscCall(PetscMalloc1(s->numFieldComponents[f], &s->compNames[f]));
380:     PetscCall(PetscStrallocpy(name, (char **)&s->compNames[f][0]));
381:   }
382:   PetscFunctionReturn(PETSC_SUCCESS);
383: }

385: /*@C
386:   PetscSectionGetFieldName - Returns the name of a field in the `PetscSection`

388:   Not Collective

390:   Input Parameters:
391: + s     - the `PetscSection`
392: - field - the field number

394:   Output Parameter:
395: . fieldName - the field name

397:   Level: intermediate

399:   Note:
400:   Will error if the field number is out of range

402: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetFieldName()`, `PetscSectionSetNumFields()`, `PetscSectionGetNumFields()`
403: @*/
404: PetscErrorCode PetscSectionGetFieldName(PetscSection s, PetscInt field, const char *fieldName[])
405: {
406:   PetscFunctionBegin;
409:   PetscSectionCheckValidField(field, s->numFields);
410:   *fieldName = s->fieldNames[field];
411:   PetscFunctionReturn(PETSC_SUCCESS);
412: }

414: /*@C
415:   PetscSectionSetFieldName - Sets the name of a field in the `PetscSection`

417:   Not Collective

419:   Input Parameters:
420: + s     - the `PetscSection`
421: . field - the field number
422: - fieldName - the field name

424:   Level: intermediate

426:   Note:
427:   Will error if the field number is out of range

429: .seealso: [PetscSection](sec_petscsection), `PetscSectionGetFieldName()`, `PetscSectionSetNumFields()`, `PetscSectionGetNumFields()`
430: @*/
431: PetscErrorCode PetscSectionSetFieldName(PetscSection s, PetscInt field, const char fieldName[])
432: {
433:   PetscFunctionBegin;
436:   PetscSectionCheckValidField(field, s->numFields);
437:   PetscCall(PetscFree(s->fieldNames[field]));
438:   PetscCall(PetscStrallocpy(fieldName, (char **)&s->fieldNames[field]));
439:   PetscFunctionReturn(PETSC_SUCCESS);
440: }

442: /*@C
443:   PetscSectionGetComponentName - Gets the name of a field component in the `PetscSection`

445:   Not Collective

447:   Input Parameters:
448: + s     - the `PetscSection`
449: . field - the field number
450: - comp  - the component number

452:   Output Parameter:
453: . compName - the component name

455:   Level: intermediate

457:   Note:
458:   Will error if the field or component number do not exist

460: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetFieldName()`, `PetscSectionSetNumFields()`, `PetscSectionGetNumFields()`,
461:           `PetscSectionSetComponentName()`, `PetscSectionSetFieldName()`, `PetscSectionGetFieldComponents()`, `PetscSectionSetFieldComponents()`
462: @*/
463: PetscErrorCode PetscSectionGetComponentName(PetscSection s, PetscInt field, PetscInt comp, const char *compName[])
464: {
465:   PetscFunctionBegin;
468:   PetscSectionCheckValidField(field, s->numFields);
469:   PetscSectionCheckValidFieldComponent(comp, s->numFieldComponents[field]);
470:   *compName = s->compNames[field][comp];
471:   PetscFunctionReturn(PETSC_SUCCESS);
472: }

474: /*@C
475:   PetscSectionSetComponentName - Sets the name of a field component in the `PetscSection`

477:   Not Collective

479:   Input Parameters:
480: + s     - the `PetscSection`
481: . field - the field number
482: . comp  - the component number
483: - compName - the component name

485:   Level: intermediate

487:   Note:
488:   Will error if the field or component number do not exist

490: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetComponentName()`, `PetscSectionSetNumFields()`, `PetscSectionGetNumFields()`,
491:           `PetscSectionSetComponentName()`, `PetscSectionSetFieldName()`, `PetscSectionGetFieldComponents()`, `PetscSectionSetFieldComponents()`
492: @*/
493: PetscErrorCode PetscSectionSetComponentName(PetscSection s, PetscInt field, PetscInt comp, const char compName[])
494: {
495:   PetscFunctionBegin;
498:   PetscSectionCheckValidField(field, s->numFields);
499:   PetscSectionCheckValidFieldComponent(comp, s->numFieldComponents[field]);
500:   PetscCall(PetscFree(s->compNames[field][comp]));
501:   PetscCall(PetscStrallocpy(compName, (char **)&s->compNames[field][comp]));
502:   PetscFunctionReturn(PETSC_SUCCESS);
503: }

505: /*@
506:   PetscSectionGetFieldComponents - Returns the number of field components for the given field.

508:   Not Collective

510:   Input Parameters:
511: + s - the `PetscSection`
512: - field - the field number

514:   Output Parameter:
515: . numComp - the number of field components

517:   Level: intermediate

519:   Developer Note:
520:   This function is misnamed. There is a Num in `PetscSectionGetNumFields()` but not in this name

522: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetFieldComponents()`, `PetscSectionGetNumFields()`
523: @*/
524: PetscErrorCode PetscSectionGetFieldComponents(PetscSection s, PetscInt field, PetscInt *numComp)
525: {
526:   PetscFunctionBegin;
529:   PetscSectionCheckValidField(field, s->numFields);
530:   *numComp = s->numFieldComponents[field];
531:   PetscFunctionReturn(PETSC_SUCCESS);
532: }

534: /*@
535:   PetscSectionSetFieldComponents - Sets the number of field components for the given field.

537:   Not Collective

539:   Input Parameters:
540: + s - the `PetscSection`
541: . field - the field number
542: - numComp - the number of field components

544:   Level: intermediate

546: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetFieldComponents()`, `PetscSectionGetNumFields()`
547: @*/
548: PetscErrorCode PetscSectionSetFieldComponents(PetscSection s, PetscInt field, PetscInt numComp)
549: {
550:   PetscInt c;

552:   PetscFunctionBegin;
554:   PetscSectionCheckValidField(field, s->numFields);
555:   if (s->compNames) {
556:     for (c = 0; c < s->numFieldComponents[field]; ++c) PetscCall(PetscFree(s->compNames[field][c]));
557:     PetscCall(PetscFree(s->compNames[field]));
558:   }

560:   s->numFieldComponents[field] = numComp;
561:   if (numComp) {
562:     PetscCall(PetscMalloc1(numComp, (char ***)&s->compNames[field]));
563:     for (c = 0; c < numComp; ++c) {
564:       char name[64];

566:       PetscCall(PetscSNPrintf(name, 64, "%" PetscInt_FMT, c));
567:       PetscCall(PetscStrallocpy(name, (char **)&s->compNames[field][c]));
568:     }
569:   }
570:   PetscFunctionReturn(PETSC_SUCCESS);
571: }

573: /*@
574:   PetscSectionGetChart - Returns the range [`pStart`, `pEnd`) in which points (indices) lie for this `PetscSection`

576:   Not Collective

578:   Input Parameter:
579: . s - the `PetscSection`

581:   Output Parameters:
582: + pStart - the first point
583: - pEnd - one past the last point

585:   Level: intermediate

587: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetChart()`, `PetscSectionCreate()`
588: @*/
589: PetscErrorCode PetscSectionGetChart(PetscSection s, PetscInt *pStart, PetscInt *pEnd)
590: {
591:   PetscFunctionBegin;
593:   if (pStart) *pStart = s->pStart;
594:   if (pEnd) *pEnd = s->pEnd;
595:   PetscFunctionReturn(PETSC_SUCCESS);
596: }

598: /*@
599:   PetscSectionSetChart - Sets the range [`pStart`, `pEnd`) in which points (indices) lie for this `PetscSection`

601:   Not Collective

603:   Input Parameters:
604: + s - the `PetscSection`
605: . pStart - the first point
606: - pEnd - one past the last point

608:   Level: intermediate

610: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetChart()`, `PetscSectionCreate()`
611: @*/
612: PetscErrorCode PetscSectionSetChart(PetscSection s, PetscInt pStart, PetscInt pEnd)
613: {
614:   PetscInt f;

616:   PetscFunctionBegin;
618:   if (pStart == s->pStart && pEnd == s->pEnd) PetscFunctionReturn(PETSC_SUCCESS);
619:   /* Cannot Reset() because it destroys field information */
620:   s->setup = PETSC_FALSE;
621:   PetscCall(PetscSectionDestroy(&s->bc));
622:   PetscCall(PetscFree(s->bcIndices));
623:   PetscCall(PetscFree2(s->atlasDof, s->atlasOff));

625:   s->pStart = pStart;
626:   s->pEnd   = pEnd;
627:   PetscCall(PetscMalloc2((pEnd - pStart), &s->atlasDof, (pEnd - pStart), &s->atlasOff));
628:   PetscCall(PetscArrayzero(s->atlasDof, pEnd - pStart));
629:   for (f = 0; f < s->numFields; ++f) PetscCall(PetscSectionSetChart(s->field[f], pStart, pEnd));
630:   PetscFunctionReturn(PETSC_SUCCESS);
631: }

633: /*@
634:   PetscSectionGetPermutation - Returns the permutation of [0, `pEnd` - `pStart`) or `NULL` that was set with `PetscSectionSetPermutation()`

636:   Not Collective

638:   Input Parameter:
639: . s - the `PetscSection`

641:   Output Parameter:
642: . perm - The permutation as an `IS`

644:   Level: intermediate

646: .seealso: [](sec_scatter), `IS`, `PetscSection`, `PetscSectionSetPermutation()`, `PetscSectionCreate()`
647: @*/
648: PetscErrorCode PetscSectionGetPermutation(PetscSection s, IS *perm)
649: {
650:   PetscFunctionBegin;
652:   if (perm) {
654:     *perm = s->perm;
655:   }
656:   PetscFunctionReturn(PETSC_SUCCESS);
657: }

659: /*@
660:   PetscSectionSetPermutation - Sets the permutation for [0, `pEnd` - `pStart`)

662:   Not Collective

664:   Input Parameters:
665: + s - the `PetscSection`
666: - perm - the permutation of points

668:   Level: intermediate

670:   Developer Note:
671:   What purpose does this permutation serve?

673: .seealso: [](sec_scatter), `IS`, `PetscSection`, `PetscSectionGetPermutation()`, `PetscSectionCreate()`
674: @*/
675: PetscErrorCode PetscSectionSetPermutation(PetscSection s, IS perm)
676: {
677:   PetscFunctionBegin;
680:   PetscCheck(!s->setup, PetscObjectComm((PetscObject)s), PETSC_ERR_ARG_WRONGSTATE, "Cannot set a permutation after the section is setup");
681:   if (s->perm != perm) {
682:     PetscCall(ISDestroy(&s->perm));
683:     if (perm) {
684:       s->perm = perm;
685:       PetscCall(PetscObjectReference((PetscObject)s->perm));
686:     }
687:   }
688:   PetscFunctionReturn(PETSC_SUCCESS);
689: }

691: /*@
692:   PetscSectionGetPointMajor - Returns the flag for dof ordering, `PETSC_TRUE` if it is point major, `PETSC_FALSE` if it is field major

694:   Not Collective

696:   Input Parameter:
697: . s - the `PetscSection`

699:   Output Parameter:
700: . pm - the flag for point major ordering

702:   Level: intermediate

704: .seealso: [PetscSection](sec_petscsection), `PetscSection`, PetscSectionSetPointMajor()`
705: @*/
706: PetscErrorCode PetscSectionGetPointMajor(PetscSection s, PetscBool *pm)
707: {
708:   PetscFunctionBegin;
711:   *pm = s->pointMajor;
712:   PetscFunctionReturn(PETSC_SUCCESS);
713: }

715: /*@
716:   PetscSectionSetPointMajor - Sets the flag for dof ordering, `PETSC_TRUE` for point major, otherwise it will be field major

718:   Not Collective

720:   Input Parameters:
721: + s  - the `PetscSection`
722: - pm - the flag for point major ordering

724:   Level: intermediate

726: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetPointMajor()`
727: @*/
728: PetscErrorCode PetscSectionSetPointMajor(PetscSection s, PetscBool pm)
729: {
730:   PetscFunctionBegin;
732:   PetscCheck(!s->setup, PetscObjectComm((PetscObject)s), PETSC_ERR_ARG_WRONGSTATE, "Cannot set the dof ordering after the section is setup");
733:   s->pointMajor = pm;
734:   PetscFunctionReturn(PETSC_SUCCESS);
735: }

737: /*@
738:   PetscSectionGetIncludesConstraints - Returns the flag indicating if constrained dofs were included when computing offsets in the `PetscSection`.
739:   The value is set with `PetscSectionSetIncludesConstraints()`

741:   Not Collective

743:   Input Parameter:
744: . s - the `PetscSection`

746:   Output Parameter:
747: . includesConstraints - the flag indicating if constrained dofs were included when computing offsets

749:   Level: intermediate

751: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetIncludesConstraints()`
752: @*/
753: PetscErrorCode PetscSectionGetIncludesConstraints(PetscSection s, PetscBool *includesConstraints)
754: {
755:   PetscFunctionBegin;
758:   *includesConstraints = s->includesConstraints;
759:   PetscFunctionReturn(PETSC_SUCCESS);
760: }

762: /*@
763:   PetscSectionSetIncludesConstraints - Sets the flag indicating if constrained dofs are to be included when computing offsets

765:   Not Collective

767:   Input Parameters:
768: + s  - the `PetscSection`
769: - includesConstraints - the flag indicating if constrained dofs are to be included when computing offsets

771:   Level: intermediate

773: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetIncludesConstraints()`
774: @*/
775: PetscErrorCode PetscSectionSetIncludesConstraints(PetscSection s, PetscBool includesConstraints)
776: {
777:   PetscFunctionBegin;
779:   PetscCheck(!s->setup, PetscObjectComm((PetscObject)s), PETSC_ERR_ARG_WRONGSTATE, "Cannot set includesConstraints after the section is set up");
780:   s->includesConstraints = includesConstraints;
781:   PetscFunctionReturn(PETSC_SUCCESS);
782: }

784: /*@
785:   PetscSectionGetDof - Return the number of degrees of freedom associated with a given point.

787:   Not Collective

789:   Input Parameters:
790: + s - the `PetscSection`
791: - point - the point

793:   Output Parameter:
794: . numDof - the number of dof

796:   Note:
797:   In a global section, this size will be negative for points not owned by this process.

799:   Level: intermediate

801: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetDof()`, `PetscSectionCreate()`
802: @*/
803: PetscErrorCode PetscSectionGetDof(PetscSection s, PetscInt point, PetscInt *numDof)
804: {
805:   PetscFunctionBeginHot;
808:   PetscAssert(point >= s->pStart && point < s->pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section point %" PetscInt_FMT " should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, s->pStart, s->pEnd);
809:   *numDof = s->atlasDof[point - s->pStart];
810:   PetscFunctionReturn(PETSC_SUCCESS);
811: }

813: /*@
814:   PetscSectionSetDof - Sets the number of degrees of freedom associated with a given point.

816:   Not Collective

818:   Input Parameters:
819: + s - the `PetscSection`
820: . point - the point
821: - numDof - the number of dof

823:   Level: intermediate

825: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionAddDof()`, `PetscSectionCreate()`
826: @*/
827: PetscErrorCode PetscSectionSetDof(PetscSection s, PetscInt point, PetscInt numDof)
828: {
829:   PetscFunctionBegin;
831:   PetscAssert(point >= s->pStart && point < s->pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section point %" PetscInt_FMT " should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, s->pStart, s->pEnd);
832:   s->atlasDof[point - s->pStart] = numDof;
833:   PetscCall(PetscSectionInvalidateMaxDof_Internal(s));
834:   PetscFunctionReturn(PETSC_SUCCESS);
835: }

837: /*@
838:   PetscSectionAddDof - Adds to the number of degrees of freedom associated with a given point.

840:   Not Collective

842:   Input Parameters:
843: + s - the `PetscSection`
844: . point - the point
845: - numDof - the number of additional dof

847:   Level: intermediate

849: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionSetDof()`, `PetscSectionCreate()`
850: @*/
851: PetscErrorCode PetscSectionAddDof(PetscSection s, PetscInt point, PetscInt numDof)
852: {
853:   PetscFunctionBeginHot;
855:   PetscAssert(point >= s->pStart && point < s->pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section point %" PetscInt_FMT " should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, s->pStart, s->pEnd);
856:   s->atlasDof[point - s->pStart] += numDof;
857:   PetscCall(PetscSectionInvalidateMaxDof_Internal(s));
858:   PetscFunctionReturn(PETSC_SUCCESS);
859: }

861: /*@
862:   PetscSectionGetFieldDof - Return the number of degrees of freedom associated with a field on a given point.

864:   Not Collective

866:   Input Parameters:
867: + s - the `PetscSection`
868: . point - the point
869: - field - the field

871:   Output Parameter:
872: . numDof - the number of dof

874:   Level: intermediate

876: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetFieldDof()`, `PetscSectionCreate()`
877: @*/
878: PetscErrorCode PetscSectionGetFieldDof(PetscSection s, PetscInt point, PetscInt field, PetscInt *numDof)
879: {
880:   PetscFunctionBegin;
883:   PetscSectionCheckValidField(field, s->numFields);
884:   PetscCall(PetscSectionGetDof(s->field[field], point, numDof));
885:   PetscFunctionReturn(PETSC_SUCCESS);
886: }

888: /*@
889:   PetscSectionSetFieldDof - Sets the number of degrees of freedom associated with a field on a given point.

891:   Not Collective

893:   Input Parameters:
894: + s - the `PetscSection`
895: . point - the point
896: . field - the field
897: - numDof - the number of dof

899:   Level: intermediate

901: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetFieldDof()`, `PetscSectionCreate()`
902: @*/
903: PetscErrorCode PetscSectionSetFieldDof(PetscSection s, PetscInt point, PetscInt field, PetscInt numDof)
904: {
905:   PetscFunctionBegin;
907:   PetscSectionCheckValidField(field, s->numFields);
908:   PetscCall(PetscSectionSetDof(s->field[field], point, numDof));
909:   PetscFunctionReturn(PETSC_SUCCESS);
910: }

912: /*@
913:   PetscSectionAddFieldDof - Adds a number of degrees of freedom associated with a field on a given point.

915:   Not Collective

917:   Input Parameters:
918: + s - the `PetscSection`
919: . point - the point
920: . field - the field
921: - numDof - the number of dof

923:   Level: intermediate

925: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetFieldDof()`, `PetscSectionGetFieldDof()`, `PetscSectionCreate()`
926: @*/
927: PetscErrorCode PetscSectionAddFieldDof(PetscSection s, PetscInt point, PetscInt field, PetscInt numDof)
928: {
929:   PetscFunctionBegin;
931:   PetscSectionCheckValidField(field, s->numFields);
932:   PetscCall(PetscSectionAddDof(s->field[field], point, numDof));
933:   PetscFunctionReturn(PETSC_SUCCESS);
934: }

936: /*@
937:   PetscSectionGetConstraintDof - Return the number of constrained degrees of freedom associated with a given point.

939:   Not Collective

941:   Input Parameters:
942: + s - the `PetscSection`
943: - point - the point

945:   Output Parameter:
946: . numDof - the number of dof which are fixed by constraints

948:   Level: intermediate

950: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionSetConstraintDof()`, `PetscSectionCreate()`
951: @*/
952: PetscErrorCode PetscSectionGetConstraintDof(PetscSection s, PetscInt point, PetscInt *numDof)
953: {
954:   PetscFunctionBegin;
957:   if (s->bc) {
958:     PetscCall(PetscSectionGetDof(s->bc, point, numDof));
959:   } else *numDof = 0;
960:   PetscFunctionReturn(PETSC_SUCCESS);
961: }

963: /*@
964:   PetscSectionSetConstraintDof - Set the number of constrained degrees of freedom associated with a given point.

966:   Not Collective

968:   Input Parameters:
969: + s - the `PetscSection`
970: . point - the point
971: - numDof - the number of dof which are fixed by constraints

973:   Level: intermediate

975: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetDof()`, `PetscSectionGetConstraintDof()`, `PetscSectionCreate()`
976: @*/
977: PetscErrorCode PetscSectionSetConstraintDof(PetscSection s, PetscInt point, PetscInt numDof)
978: {
979:   PetscFunctionBegin;
981:   if (numDof) {
982:     PetscCall(PetscSectionCheckConstraints_Private(s));
983:     PetscCall(PetscSectionSetDof(s->bc, point, numDof));
984:   }
985:   PetscFunctionReturn(PETSC_SUCCESS);
986: }

988: /*@
989:   PetscSectionAddConstraintDof - Increment the number of constrained degrees of freedom associated with a given point.

991:   Not Collective

993:   Input Parameters:
994: + s - the `PetscSection`
995: . point - the point
996: - numDof - the number of additional dof which are fixed by constraints

998:   Level: intermediate

1000: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionAddDof()`, `PetscSectionGetConstraintDof()`, `PetscSectionCreate()`
1001: @*/
1002: PetscErrorCode PetscSectionAddConstraintDof(PetscSection s, PetscInt point, PetscInt numDof)
1003: {
1004:   PetscFunctionBegin;
1006:   if (numDof) {
1007:     PetscCall(PetscSectionCheckConstraints_Private(s));
1008:     PetscCall(PetscSectionAddDof(s->bc, point, numDof));
1009:   }
1010:   PetscFunctionReturn(PETSC_SUCCESS);
1011: }

1013: /*@
1014:   PetscSectionGetFieldConstraintDof - Return the number of constrained degrees of freedom associated with a given field on a point.

1016:   Not Collective

1018:   Input Parameters:
1019: + s - the `PetscSection`
1020: . point - the point
1021: - field - the field

1023:   Output Parameter:
1024: . numDof - the number of dof which are fixed by constraints

1026:   Level: intermediate

1028: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionSetFieldConstraintDof()`, `PetscSectionCreate()`
1029: @*/
1030: PetscErrorCode PetscSectionGetFieldConstraintDof(PetscSection s, PetscInt point, PetscInt field, PetscInt *numDof)
1031: {
1032:   PetscFunctionBegin;
1035:   PetscSectionCheckValidField(field, s->numFields);
1036:   PetscCall(PetscSectionGetConstraintDof(s->field[field], point, numDof));
1037:   PetscFunctionReturn(PETSC_SUCCESS);
1038: }

1040: /*@
1041:   PetscSectionSetFieldConstraintDof - Set the number of constrained degrees of freedom associated with a given field on a point.

1043:   Not Collective

1045:   Input Parameters:
1046: + s - the `PetscSection`
1047: . point - the point
1048: . field - the field
1049: - numDof - the number of dof which are fixed by constraints

1051:   Level: intermediate

1053: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetDof()`, `PetscSectionGetFieldConstraintDof()`, `PetscSectionCreate()`
1054: @*/
1055: PetscErrorCode PetscSectionSetFieldConstraintDof(PetscSection s, PetscInt point, PetscInt field, PetscInt numDof)
1056: {
1057:   PetscFunctionBegin;
1059:   PetscSectionCheckValidField(field, s->numFields);
1060:   PetscCall(PetscSectionSetConstraintDof(s->field[field], point, numDof));
1061:   PetscFunctionReturn(PETSC_SUCCESS);
1062: }

1064: /*@
1065:   PetscSectionAddFieldConstraintDof - Increment the number of constrained degrees of freedom associated with a given field on a point.

1067:   Not Collective

1069:   Input Parameters:
1070: + s - the `PetscSection`
1071: . point - the point
1072: . field - the field
1073: - numDof - the number of additional dof which are fixed by constraints

1075:   Level: intermediate

1077: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionAddDof()`, `PetscSectionGetFieldConstraintDof()`, `PetscSectionCreate()`
1078: @*/
1079: PetscErrorCode PetscSectionAddFieldConstraintDof(PetscSection s, PetscInt point, PetscInt field, PetscInt numDof)
1080: {
1081:   PetscFunctionBegin;
1083:   PetscSectionCheckValidField(field, s->numFields);
1084:   PetscCall(PetscSectionAddConstraintDof(s->field[field], point, numDof));
1085:   PetscFunctionReturn(PETSC_SUCCESS);
1086: }

1088: /*@
1089:   PetscSectionSetUpBC - Setup the subsections describing boundary conditions.

1091:   Not Collective

1093:   Input Parameter:
1094: . s - the `PetscSection`

1096:   Level: advanced

1098: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetUp()`, `PetscSectionCreate()`
1099: @*/
1100: PetscErrorCode PetscSectionSetUpBC(PetscSection s)
1101: {
1102:   PetscFunctionBegin;
1104:   if (s->bc) {
1105:     const PetscInt last = (s->bc->pEnd - s->bc->pStart) - 1;

1107:     PetscCall(PetscSectionSetUp(s->bc));
1108:     PetscCall(PetscMalloc1((last >= 0 ? s->bc->atlasOff[last] + s->bc->atlasDof[last] : 0), &s->bcIndices));
1109:   }
1110:   PetscFunctionReturn(PETSC_SUCCESS);
1111: }

1113: /*@
1114:   PetscSectionSetUp - Calculate offsets based upon the number of degrees of freedom for each point.

1116:   Not Collective

1118:   Input Parameter:
1119: . s - the `PetscSection`

1121:   Level: intermediate

1123: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`
1124: @*/
1125: PetscErrorCode PetscSectionSetUp(PetscSection s)
1126: {
1127:   const PetscInt *pind   = NULL;
1128:   PetscInt        offset = 0, foff, p, f;

1130:   PetscFunctionBegin;
1132:   if (s->setup) PetscFunctionReturn(PETSC_SUCCESS);
1133:   s->setup = PETSC_TRUE;
1134:   /* Set offsets and field offsets for all points */
1135:   /*   Assume that all fields have the same chart */
1136:   PetscCheck(s->includesConstraints, PETSC_COMM_SELF, PETSC_ERR_SUP, "PetscSectionSetUp is currently unsupported for includesConstraints = PETSC_TRUE");
1137:   if (s->perm) PetscCall(ISGetIndices(s->perm, &pind));
1138:   if (s->pointMajor) {
1139:     for (p = 0; p < s->pEnd - s->pStart; ++p) {
1140:       const PetscInt q = pind ? pind[p] : p;

1142:       /* Set point offset */
1143:       s->atlasOff[q] = offset;
1144:       offset += s->atlasDof[q];
1145:       /* Set field offset */
1146:       for (f = 0, foff = s->atlasOff[q]; f < s->numFields; ++f) {
1147:         PetscSection sf = s->field[f];

1149:         sf->atlasOff[q] = foff;
1150:         foff += sf->atlasDof[q];
1151:       }
1152:     }
1153:   } else {
1154:     /* Set field offsets for all points */
1155:     for (f = 0; f < s->numFields; ++f) {
1156:       PetscSection sf = s->field[f];

1158:       for (p = 0; p < s->pEnd - s->pStart; ++p) {
1159:         const PetscInt q = pind ? pind[p] : p;

1161:         sf->atlasOff[q] = offset;
1162:         offset += sf->atlasDof[q];
1163:       }
1164:     }
1165:     /* Disable point offsets since these are unused */
1166:     for (p = 0; p < s->pEnd - s->pStart; ++p) s->atlasOff[p] = -1;
1167:   }
1168:   if (s->perm) PetscCall(ISRestoreIndices(s->perm, &pind));
1169:   /* Setup BC sections */
1170:   PetscCall(PetscSectionSetUpBC(s));
1171:   for (f = 0; f < s->numFields; ++f) PetscCall(PetscSectionSetUpBC(s->field[f]));
1172:   PetscFunctionReturn(PETSC_SUCCESS);
1173: }

1175: /*@
1176:   PetscSectionGetMaxDof - Return the maximum number of degrees of freedom on any point in the `PetscSection`

1178:   Not Collective

1180:   Input Parameter:
1181: . s - the `PetscSection`

1183:   Output Parameter:
1184: . maxDof - the maximum dof

1186:   Level: intermediate

1188:   Note:
1189:   The returned number is up-to-date without need for `PetscSectionSetUp()`.

1191:   Developer Note:
1192:   The returned number is calculated lazily and stashed.

1194:   A call to `PetscSectionInvalidateMaxDof_Internal()` invalidates the stashed value.

1196:   `PetscSectionInvalidateMaxDof_Internal()` is called in `PetscSectionSetDof()`, `PetscSectionAddDof()` and `PetscSectionReset()`

1198:   It should also be called every time `atlasDof` is modified directly.

1200: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionSetDof()`, `PetscSectionAddDof()`, `PetscSectionCreate()`
1201: @*/
1202: PetscErrorCode PetscSectionGetMaxDof(PetscSection s, PetscInt *maxDof)
1203: {
1204:   PetscInt p;

1206:   PetscFunctionBegin;
1209:   if (s->maxDof == PETSC_MIN_INT) {
1210:     s->maxDof = 0;
1211:     for (p = 0; p < s->pEnd - s->pStart; ++p) s->maxDof = PetscMax(s->maxDof, s->atlasDof[p]);
1212:   }
1213:   *maxDof = s->maxDof;
1214:   PetscFunctionReturn(PETSC_SUCCESS);
1215: }

1217: /*@
1218:   PetscSectionGetStorageSize - Return the size of an array or local `Vec` capable of holding all the degrees of freedom defined in a `PetscSection`

1220:   Not Collective

1222:   Input Parameter:
1223: . s - the `PetscSection`

1225:   Output Parameter:
1226: . size - the size of an array which can hold all the dofs

1228:   Level: intermediate

1230: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionGetConstrainedStorageSize()`, `PetscSectionCreate()`
1231: @*/
1232: PetscErrorCode PetscSectionGetStorageSize(PetscSection s, PetscInt *size)
1233: {
1234:   PetscInt p, n = 0;

1236:   PetscFunctionBegin;
1239:   for (p = 0; p < s->pEnd - s->pStart; ++p) n += s->atlasDof[p] > 0 ? s->atlasDof[p] : 0;
1240:   *size = n;
1241:   PetscFunctionReturn(PETSC_SUCCESS);
1242: }

1244: /*@
1245:   PetscSectionGetConstrainedStorageSize - Return the size of an array or local `Vec` capable of holding all unconstrained degrees of freedom in a `PetscSection`

1247:   Not Collective

1249:   Input Parameter:
1250: . s - the `PetscSection`

1252:   Output Parameter:
1253: . size - the size of an array which can hold all unconstrained dofs

1255:   Level: intermediate

1257: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetStorageSize()`, `PetscSectionGetOffset()`, `PetscSectionCreate()`
1258: @*/
1259: PetscErrorCode PetscSectionGetConstrainedStorageSize(PetscSection s, PetscInt *size)
1260: {
1261:   PetscInt p, n = 0;

1263:   PetscFunctionBegin;
1266:   for (p = 0; p < s->pEnd - s->pStart; ++p) {
1267:     const PetscInt cdof = s->bc ? s->bc->atlasDof[p] : 0;
1268:     n += s->atlasDof[p] > 0 ? s->atlasDof[p] - cdof : 0;
1269:   }
1270:   *size = n;
1271:   PetscFunctionReturn(PETSC_SUCCESS);
1272: }

1274: /*@
1275:   PetscSectionCreateGlobalSection - Create a section describing the global field layout using
1276:   the local section and a `PetscSF` describing the section point overlap.

1278:   Input Parameters:
1279: + s - The `PetscSection` for the local field layout
1280: . sf - The `PetscSF` describing parallel layout of the section points (leaves are unowned local points)
1281: . includeConstraints - By default this is `PETSC_FALSE`, meaning that the global field vector will not possess constrained dofs
1282: - localOffsets - If `PETSC_TRUE`, use local rather than global offsets for the points

1284:   Output Parameter:
1285: . gsection - The `PetscSection` for the global field layout

1287:   Level: intermediate

1289:   Notes:
1290:   If we have a set of local sections defining the layout of a set of local vectors, and also a `PetscSF` to determine which section points are shared and the ownership,
1291:   we can calculate a global section defining the parallel data layout, and the associated global vector.

1293:   This gives negative sizes and offsets to points not owned by this process

1295: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionCreateGlobalSectionCensored()`
1296: @*/
1297: PetscErrorCode PetscSectionCreateGlobalSection(PetscSection s, PetscSF sf, PetscBool includeConstraints, PetscBool localOffsets, PetscSection *gsection)
1298: {
1299:   PetscSection    gs;
1300:   const PetscInt *pind = NULL;
1301:   PetscInt       *recv = NULL, *neg = NULL;
1302:   PetscInt        pStart, pEnd, p, dof, cdof, off, foff, globalOff = 0, nroots, nlocal, maxleaf;
1303:   PetscInt        numFields, f, numComponents;

1305:   PetscFunctionBegin;
1311:   PetscCheck(s->pointMajor, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for field major ordering");
1312:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), &gs));
1313:   PetscCall(PetscSectionGetNumFields(s, &numFields));
1314:   if (numFields > 0) PetscCall(PetscSectionSetNumFields(gs, numFields));
1315:   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
1316:   PetscCall(PetscSectionSetChart(gs, pStart, pEnd));
1317:   gs->includesConstraints = includeConstraints;
1318:   PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL));
1319:   nlocal = nroots; /* The local/leaf space matches global/root space */
1320:   /* Must allocate for all points visible to SF, which may be more than this section */
1321:   if (nroots >= 0) { /* nroots < 0 means that the graph has not been set, only happens in serial */
1322:     PetscCall(PetscSFGetLeafRange(sf, NULL, &maxleaf));
1323:     PetscCheck(nroots >= pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "SF roots %" PetscInt_FMT " < pEnd %" PetscInt_FMT, nroots, pEnd);
1324:     PetscCheck(maxleaf < nroots, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Max local leaf %" PetscInt_FMT " >= nroots %" PetscInt_FMT, maxleaf, nroots);
1325:     PetscCall(PetscMalloc2(nroots, &neg, nlocal, &recv));
1326:     PetscCall(PetscArrayzero(neg, nroots));
1327:   }
1328:   /* Mark all local points with negative dof */
1329:   for (p = pStart; p < pEnd; ++p) {
1330:     PetscCall(PetscSectionGetDof(s, p, &dof));
1331:     PetscCall(PetscSectionSetDof(gs, p, dof));
1332:     PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
1333:     if (!includeConstraints && cdof > 0) PetscCall(PetscSectionSetConstraintDof(gs, p, cdof));
1334:     if (neg) neg[p] = -(dof + 1);
1335:   }
1336:   PetscCall(PetscSectionSetUpBC(gs));
1337:   if (gs->bcIndices) PetscCall(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]));
1338:   if (nroots >= 0) {
1339:     PetscCall(PetscArrayzero(recv, nlocal));
1340:     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, recv, MPI_REPLACE));
1341:     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, recv, MPI_REPLACE));
1342:     for (p = pStart; p < pEnd; ++p) {
1343:       if (recv[p] < 0) {
1344:         gs->atlasDof[p - pStart] = recv[p];
1345:         PetscCall(PetscSectionGetDof(s, p, &dof));
1346:         PetscCheck(-(recv[p] + 1) == dof, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Global dof %" PetscInt_FMT " for point %" PetscInt_FMT " is not the unconstrained %" PetscInt_FMT, -(recv[p] + 1), p, dof);
1347:       }
1348:     }
1349:   }
1350:   /* Calculate new sizes, get process offset, and calculate point offsets */
1351:   if (s->perm) PetscCall(ISGetIndices(s->perm, &pind));
1352:   for (p = 0, off = 0; p < pEnd - pStart; ++p) {
1353:     const PetscInt q = pind ? pind[p] : p;

1355:     cdof            = (!includeConstraints && s->bc) ? s->bc->atlasDof[q] : 0;
1356:     gs->atlasOff[q] = off;
1357:     off += gs->atlasDof[q] > 0 ? gs->atlasDof[q] - cdof : 0;
1358:   }
1359:   if (!localOffsets) {
1360:     PetscCallMPI(MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)s)));
1361:     globalOff -= off;
1362:   }
1363:   for (p = pStart, off = 0; p < pEnd; ++p) {
1364:     gs->atlasOff[p - pStart] += globalOff;
1365:     if (neg) neg[p] = -(gs->atlasOff[p - pStart] + 1);
1366:   }
1367:   if (s->perm) PetscCall(ISRestoreIndices(s->perm, &pind));
1368:   /* Put in negative offsets for ghost points */
1369:   if (nroots >= 0) {
1370:     PetscCall(PetscArrayzero(recv, nlocal));
1371:     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, recv, MPI_REPLACE));
1372:     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, recv, MPI_REPLACE));
1373:     for (p = pStart; p < pEnd; ++p) {
1374:       if (recv[p] < 0) gs->atlasOff[p - pStart] = recv[p];
1375:     }
1376:   }
1377:   PetscCall(PetscFree2(neg, recv));
1378:   /* Set field dofs/offsets/constraints */
1379:   for (f = 0; f < numFields; ++f) {
1380:     gs->field[f]->includesConstraints = includeConstraints;
1381:     PetscCall(PetscSectionGetFieldComponents(s, f, &numComponents));
1382:     PetscCall(PetscSectionSetFieldComponents(gs, f, numComponents));
1383:   }
1384:   for (p = pStart; p < pEnd; ++p) {
1385:     PetscCall(PetscSectionGetOffset(gs, p, &off));
1386:     for (f = 0, foff = off; f < numFields; ++f) {
1387:       PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cdof));
1388:       if (!includeConstraints && cdof > 0) PetscCall(PetscSectionSetFieldConstraintDof(gs, p, f, cdof));
1389:       PetscCall(PetscSectionGetFieldDof(s, p, f, &dof));
1390:       PetscCall(PetscSectionSetFieldDof(gs, p, f, off < 0 ? -(dof + 1) : dof));
1391:       PetscCall(PetscSectionSetFieldOffset(gs, p, f, foff));
1392:       PetscCall(PetscSectionGetFieldConstraintDof(gs, p, f, &cdof));
1393:       foff = off < 0 ? foff - (dof - cdof) : foff + (dof - cdof);
1394:     }
1395:   }
1396:   for (f = 0; f < numFields; ++f) {
1397:     PetscSection gfs = gs->field[f];

1399:     PetscCall(PetscSectionSetUpBC(gfs));
1400:     if (gfs->bcIndices) PetscCall(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]));
1401:   }
1402:   gs->setup = PETSC_TRUE;
1403:   PetscCall(PetscSectionViewFromOptions(gs, NULL, "-global_section_view"));
1404:   *gsection = gs;
1405:   PetscFunctionReturn(PETSC_SUCCESS);
1406: }

1408: /*@
1409:   PetscSectionCreateGlobalSectionCensored - Create a `PetscSection` describing the global field layout using
1410:   the local section and an `PetscSF` describing the section point overlap.

1412:   Input Parameters:
1413: + s - The `PetscSection` for the local field layout
1414: . sf - The `PetscSF` describing parallel layout of the section points
1415: . includeConstraints - By default this is `PETSC_FALSE`, meaning that the global field vector will not possess constrained dofs
1416: . numExcludes - The number of exclusion ranges
1417: - excludes - An array [start_0, end_0, start_1, end_1, ...] where there are numExcludes pairs

1419:   Output Parameter:
1420: . gsection - The `PetscSection` for the global field layout

1422:   Level: advanced

1424:   Note:
1425:   This routine augments `PetscSectionCreateGlobalSection()` by allowing one to exclude certain ranges in the chart of the `PetscSection`

1427:   This gives negative sizes and offsets to points not owned by this process

1429:   Developer Note:
1430:   This is a terrible function name

1432: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionCreateGlobalSectionCensored()`
1433: @*/
1434: PetscErrorCode PetscSectionCreateGlobalSectionCensored(PetscSection s, PetscSF sf, PetscBool includeConstraints, PetscInt numExcludes, const PetscInt excludes[], PetscSection *gsection)
1435: {
1436:   const PetscInt *pind = NULL;
1437:   PetscInt       *neg = NULL, *tmpOff = NULL;
1438:   PetscInt        pStart, pEnd, p, e, dof, cdof, off, globalOff = 0, nroots;

1440:   PetscFunctionBegin;
1444:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), gsection));
1445:   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
1446:   PetscCall(PetscSectionSetChart(*gsection, pStart, pEnd));
1447:   PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL));
1448:   if (nroots >= 0) {
1449:     PetscCheck(nroots >= pEnd - pStart, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %" PetscInt_FMT " < %" PetscInt_FMT " section size", nroots, pEnd - pStart);
1450:     PetscCall(PetscCalloc1(nroots, &neg));
1451:     if (nroots > pEnd - pStart) {
1452:       PetscCall(PetscCalloc1(nroots, &tmpOff));
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:         PetscCall(PetscSectionSetDof(*gsection, p, 0));
1462:         break;
1463:       }
1464:     }
1465:     if (e < numExcludes) continue;
1466:     PetscCall(PetscSectionGetDof(s, p, &dof));
1467:     PetscCall(PetscSectionSetDof(*gsection, p, dof));
1468:     PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
1469:     if (!includeConstraints && cdof > 0) PetscCall(PetscSectionSetConstraintDof(*gsection, p, cdof));
1470:     if (neg) neg[p] = -(dof + 1);
1471:   }
1472:   PetscCall(PetscSectionSetUpBC(*gsection));
1473:   if (nroots >= 0) {
1474:     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
1475:     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
1476:     if (nroots > pEnd - pStart) {
1477:       for (p = pStart; p < pEnd; ++p) {
1478:         if (tmpOff[p] < 0) (*gsection)->atlasDof[p - pStart] = tmpOff[p];
1479:       }
1480:     }
1481:   }
1482:   /* Calculate new sizes, get process offset, and calculate point offsets */
1483:   if (s->perm) PetscCall(ISGetIndices(s->perm, &pind));
1484:   for (p = 0, off = 0; p < pEnd - pStart; ++p) {
1485:     const PetscInt q = pind ? pind[p] : p;

1487:     cdof                     = (!includeConstraints && s->bc) ? s->bc->atlasDof[q] : 0;
1488:     (*gsection)->atlasOff[q] = off;
1489:     off += (*gsection)->atlasDof[q] > 0 ? (*gsection)->atlasDof[q] - cdof : 0;
1490:   }
1491:   PetscCallMPI(MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)s)));
1492:   globalOff -= off;
1493:   for (p = 0, off = 0; p < pEnd - pStart; ++p) {
1494:     (*gsection)->atlasOff[p] += globalOff;
1495:     if (neg) neg[p + pStart] = -((*gsection)->atlasOff[p] + 1);
1496:   }
1497:   if (s->perm) PetscCall(ISRestoreIndices(s->perm, &pind));
1498:   /* Put in negative offsets for ghost points */
1499:   if (nroots >= 0) {
1500:     if (nroots == pEnd - pStart) tmpOff = &(*gsection)->atlasOff[-pStart];
1501:     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
1502:     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
1503:     if (nroots > pEnd - pStart) {
1504:       for (p = pStart; p < pEnd; ++p) {
1505:         if (tmpOff[p] < 0) (*gsection)->atlasOff[p - pStart] = tmpOff[p];
1506:       }
1507:     }
1508:   }
1509:   if (nroots >= 0 && nroots > pEnd - pStart) PetscCall(PetscFree(tmpOff));
1510:   PetscCall(PetscFree(neg));
1511:   PetscFunctionReturn(PETSC_SUCCESS);
1512: }

1514: /*@
1515:   PetscSectionGetPointLayout - Get the `PetscLayout` associated with a `PetscSection`

1517:   Collective

1519:   Input Parameters:
1520: + comm - The `MPI_Comm`
1521: - s    - The `PetscSection`

1523:   Output Parameter:
1524: . layout - The point layout for the data that defines the section

1526:   Level: advanced

1528:   Notes:
1529:   `PetscSectionGetValueLayout()` provides the `layout` for an array of data associated with the `PetscSection`. `PetscSectionGetPointLayout()`
1530:   provides the `layout` for the data that
1531:   defines the `PetscSection`

1533:   This is usually called for the default global section.

1535: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetValueLayout()`, `PetscSectionCreate()`
1536: @*/
1537: PetscErrorCode PetscSectionGetPointLayout(MPI_Comm comm, PetscSection s, PetscLayout *layout)
1538: {
1539:   PetscInt pStart, pEnd, p, localSize = 0;

1541:   PetscFunctionBegin;
1542:   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
1543:   for (p = pStart; p < pEnd; ++p) {
1544:     PetscInt dof;

1546:     PetscCall(PetscSectionGetDof(s, p, &dof));
1547:     if (dof >= 0) ++localSize;
1548:   }
1549:   PetscCall(PetscLayoutCreate(comm, layout));
1550:   PetscCall(PetscLayoutSetLocalSize(*layout, localSize));
1551:   PetscCall(PetscLayoutSetBlockSize(*layout, 1));
1552:   PetscCall(PetscLayoutSetUp(*layout));
1553:   PetscFunctionReturn(PETSC_SUCCESS);
1554: }

1556: /*@
1557:   PetscSectionGetValueLayout - Get the `PetscLayout` associated with the section dofs of a `PetscSection`

1559:   Collective

1561:   Input Parameters:
1562: + comm - The `MPI_Comm`
1563: - s    - The `PetscSection`

1565:   Output Parameter:
1566: . layout - The dof layout for the section

1568:   Level: advanced

1570:   Notes:
1571:   `PetscSectionGetValueLayout()` provides the `layout` for an array of data associated with the `PetscSection`. `PetscSectionGetPointLayout()`
1572:   provides the `layout` for the data that
1573:   defines the `PetscSection`

1575:   This is usually called for the default global section.

1577: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetPointLayout()`, `PetscSectionCreate()`
1578: @*/
1579: PetscErrorCode PetscSectionGetValueLayout(MPI_Comm comm, PetscSection s, PetscLayout *layout)
1580: {
1581:   PetscInt pStart, pEnd, p, localSize = 0;

1583:   PetscFunctionBegin;
1586:   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
1587:   for (p = pStart; p < pEnd; ++p) {
1588:     PetscInt dof, cdof;

1590:     PetscCall(PetscSectionGetDof(s, p, &dof));
1591:     PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
1592:     if (dof - cdof > 0) localSize += dof - cdof;
1593:   }
1594:   PetscCall(PetscLayoutCreate(comm, layout));
1595:   PetscCall(PetscLayoutSetLocalSize(*layout, localSize));
1596:   PetscCall(PetscLayoutSetBlockSize(*layout, 1));
1597:   PetscCall(PetscLayoutSetUp(*layout));
1598:   PetscFunctionReturn(PETSC_SUCCESS);
1599: }

1601: /*@
1602:   PetscSectionGetOffset - Return the offset into an array or `Vec` for the dof associated with the given point.

1604:   Not Collective

1606:   Input Parameters:
1607: + s - the `PetscSection`
1608: - point - the point

1610:   Output Parameter:
1611: . offset - the offset

1613:   Note:
1614:   In a global section, this offset will be negative for points not owned by this process.

1616:   Level: intermediate

1618: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetFieldOffset()`, `PetscSectionCreate()`
1619: @*/
1620: PetscErrorCode PetscSectionGetOffset(PetscSection s, PetscInt point, PetscInt *offset)
1621: {
1622:   PetscFunctionBegin;
1625:   if (PetscDefined(USE_DEBUG)) PetscCheck(!(point < s->pStart) && !(point >= s->pEnd), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section point %" PetscInt_FMT " should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, s->pStart, s->pEnd);
1626:   *offset = s->atlasOff[point - s->pStart];
1627:   PetscFunctionReturn(PETSC_SUCCESS);
1628: }

1630: /*@
1631:   PetscSectionSetOffset - Set the offset into an array or `Vec` for the dof associated with the given point.

1633:   Not Collective

1635:   Input Parameters:
1636: + s - the `PetscSection`
1637: . point - the point
1638: - offset - the offset

1640:   Level: intermediate

1642:   Note:
1643:   The user usually does not call this function, but uses `PetscSectionSetUp()`

1645: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetFieldOffset()`, `PetscSectionCreate()`, `PetscSectionSetUp()`
1646: @*/
1647: PetscErrorCode PetscSectionSetOffset(PetscSection s, PetscInt point, PetscInt offset)
1648: {
1649:   PetscFunctionBegin;
1651:   PetscCheck(!(point < s->pStart) && !(point >= s->pEnd), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section point %" PetscInt_FMT " should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, s->pStart, s->pEnd);
1652:   s->atlasOff[point - s->pStart] = offset;
1653:   PetscFunctionReturn(PETSC_SUCCESS);
1654: }

1656: /*@
1657:   PetscSectionGetFieldOffset - Return the offset into an array or `Vec` for the field dof associated with the given point.

1659:   Not Collective

1661:   Input Parameters:
1662: + s - the `PetscSection`
1663: . point - the point
1664: - field - the field

1666:   Output Parameter:
1667: . offset - the offset

1669:   Note:
1670:   In a global section, this offset will be negative for points not owned by this process.

1672:   Level: intermediate

1674: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionCreate()`
1675: @*/
1676: PetscErrorCode PetscSectionGetFieldOffset(PetscSection s, PetscInt point, PetscInt field, PetscInt *offset)
1677: {
1678:   PetscFunctionBegin;
1681:   PetscSectionCheckValidField(field, s->numFields);
1682:   PetscCall(PetscSectionGetOffset(s->field[field], point, offset));
1683:   PetscFunctionReturn(PETSC_SUCCESS);
1684: }

1686: /*@
1687:   PetscSectionSetFieldOffset - Set the offset into an array or `Vec` for the dof associated with the given field at a point.

1689:   Not Collective

1691:   Input Parameters:
1692: + s - the `PetscSection`
1693: . point - the point
1694: . field - the field
1695: - offset - the offset

1697:   Level: developer

1699:   Note:
1700:   The user usually does not call this function, but uses `PetscSectionSetUp()`

1702: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetFieldOffset()`, `PetscSectionSetOffset()`, `PetscSectionCreate()`, `PetscSectionSetUp()`
1703: @*/
1704: PetscErrorCode PetscSectionSetFieldOffset(PetscSection s, PetscInt point, PetscInt field, PetscInt offset)
1705: {
1706:   PetscFunctionBegin;
1708:   PetscSectionCheckValidField(field, s->numFields);
1709:   PetscCall(PetscSectionSetOffset(s->field[field], point, offset));
1710:   PetscFunctionReturn(PETSC_SUCCESS);
1711: }

1713: /*@
1714:   PetscSectionGetFieldPointOffset - Return the offset on the given point for the dof associated with the given point.

1716:   Not Collective

1718:   Input Parameters:
1719: + s - the `PetscSection`
1720: . point - the point
1721: - field - the field

1723:   Output Parameter:
1724: . offset - the offset

1726:   Level: advanced

1728:   Note:
1729:   This gives the offset on a point of the field, ignoring constraints, meaning starting at the first dof for
1730:   this point, what number is the first dof with this field.

1732: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionCreate()`
1733: @*/
1734: PetscErrorCode PetscSectionGetFieldPointOffset(PetscSection s, PetscInt point, PetscInt field, PetscInt *offset)
1735: {
1736:   PetscInt off, foff;

1738:   PetscFunctionBegin;
1741:   PetscSectionCheckValidField(field, s->numFields);
1742:   PetscCall(PetscSectionGetOffset(s, point, &off));
1743:   PetscCall(PetscSectionGetOffset(s->field[field], point, &foff));
1744:   *offset = foff - off;
1745:   PetscFunctionReturn(PETSC_SUCCESS);
1746: }

1748: /*@
1749:   PetscSectionGetOffsetRange - Return the full range of offsets [`start`, `end`) for a `PetscSection`

1751:   Not Collective

1753:   Input Parameter:
1754: . s - the `PetscSection`

1756:   Output Parameters:
1757: + start - the minimum offset
1758: - end   - one more than the maximum offset

1760:   Level: intermediate

1762: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionCreate()`
1763: @*/
1764: PetscErrorCode PetscSectionGetOffsetRange(PetscSection s, PetscInt *start, PetscInt *end)
1765: {
1766:   PetscInt os = 0, oe = 0, pStart, pEnd, p;

1768:   PetscFunctionBegin;
1770:   if (s->atlasOff) {
1771:     os = s->atlasOff[0];
1772:     oe = s->atlasOff[0];
1773:   }
1774:   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
1775:   for (p = 0; p < pEnd - pStart; ++p) {
1776:     PetscInt dof = s->atlasDof[p], off = s->atlasOff[p];

1778:     if (off >= 0) {
1779:       os = PetscMin(os, off);
1780:       oe = PetscMax(oe, off + dof);
1781:     }
1782:   }
1783:   if (start) *start = os;
1784:   if (end) *end = oe;
1785:   PetscFunctionReturn(PETSC_SUCCESS);
1786: }

1788: /*@
1789:   PetscSectionCreateSubsection - Create a new, smaller `PetscSection` composed of only the selected fields

1791:   Collective

1793:   Input Parameters:
1794: + s      - the `PetscSection`
1795: . len    - the number of subfields
1796: - fields - the subfield numbers

1798:   Output Parameter:
1799: . subs   - the subsection

1801:   Level: advanced

1803:   Notes:
1804:   The section offsets now refer to a new, smaller vector.

1806:   This will error if a fieldnumber is out of range

1808: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreateSupersection()`, `PetscSectionCreate()`
1809: @*/
1810: PetscErrorCode PetscSectionCreateSubsection(PetscSection s, PetscInt len, const PetscInt fields[], PetscSection *subs)
1811: {
1812:   PetscInt nF, f, c, pStart, pEnd, p, maxCdof = 0;

1814:   PetscFunctionBegin;
1815:   if (!len) PetscFunctionReturn(PETSC_SUCCESS);
1819:   PetscCall(PetscSectionGetNumFields(s, &nF));
1820:   PetscCheck(len <= nF, PetscObjectComm((PetscObject)s), PETSC_ERR_ARG_WRONG, "Number of requested fields %" PetscInt_FMT " greater than number of fields %" PetscInt_FMT, len, nF);
1821:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), subs));
1822:   PetscCall(PetscSectionSetNumFields(*subs, len));
1823:   for (f = 0; f < len; ++f) {
1824:     const char *name    = NULL;
1825:     PetscInt    numComp = 0;

1827:     PetscCall(PetscSectionGetFieldName(s, fields[f], &name));
1828:     PetscCall(PetscSectionSetFieldName(*subs, f, name));
1829:     PetscCall(PetscSectionGetFieldComponents(s, fields[f], &numComp));
1830:     PetscCall(PetscSectionSetFieldComponents(*subs, f, numComp));
1831:     for (c = 0; c < s->numFieldComponents[fields[f]]; ++c) {
1832:       PetscCall(PetscSectionGetComponentName(s, fields[f], c, &name));
1833:       PetscCall(PetscSectionSetComponentName(*subs, f, c, name));
1834:     }
1835:   }
1836:   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
1837:   PetscCall(PetscSectionSetChart(*subs, pStart, pEnd));
1838:   for (p = pStart; p < pEnd; ++p) {
1839:     PetscInt dof = 0, cdof = 0, fdof = 0, cfdof = 0;

1841:     for (f = 0; f < len; ++f) {
1842:       PetscCall(PetscSectionGetFieldDof(s, p, fields[f], &fdof));
1843:       PetscCall(PetscSectionSetFieldDof(*subs, p, f, fdof));
1844:       PetscCall(PetscSectionGetFieldConstraintDof(s, p, fields[f], &cfdof));
1845:       if (cfdof) PetscCall(PetscSectionSetFieldConstraintDof(*subs, p, f, cfdof));
1846:       dof += fdof;
1847:       cdof += cfdof;
1848:     }
1849:     PetscCall(PetscSectionSetDof(*subs, p, dof));
1850:     if (cdof) PetscCall(PetscSectionSetConstraintDof(*subs, p, cdof));
1851:     maxCdof = PetscMax(cdof, maxCdof);
1852:   }
1853:   PetscCall(PetscSectionSetUp(*subs));
1854:   if (maxCdof) {
1855:     PetscInt *indices;

1857:     PetscCall(PetscMalloc1(maxCdof, &indices));
1858:     for (p = pStart; p < pEnd; ++p) {
1859:       PetscInt cdof;

1861:       PetscCall(PetscSectionGetConstraintDof(*subs, p, &cdof));
1862:       if (cdof) {
1863:         const PetscInt *oldIndices = NULL;
1864:         PetscInt        fdof = 0, cfdof = 0, fc, numConst = 0, fOff = 0;

1866:         for (f = 0; f < len; ++f) {
1867:           PetscCall(PetscSectionGetFieldDof(s, p, fields[f], &fdof));
1868:           PetscCall(PetscSectionGetFieldConstraintDof(s, p, fields[f], &cfdof));
1869:           PetscCall(PetscSectionGetFieldConstraintIndices(s, p, fields[f], &oldIndices));
1870:           PetscCall(PetscSectionSetFieldConstraintIndices(*subs, p, f, oldIndices));
1871:           for (fc = 0; fc < cfdof; ++fc) indices[numConst + fc] = oldIndices[fc] + fOff;
1872:           numConst += cfdof;
1873:           fOff += fdof;
1874:         }
1875:         PetscCall(PetscSectionSetConstraintIndices(*subs, p, indices));
1876:       }
1877:     }
1878:     PetscCall(PetscFree(indices));
1879:   }
1880:   PetscFunctionReturn(PETSC_SUCCESS);
1881: }

1883: /*@
1884:   PetscSectionCreateSupersection - Create a new, larger section composed of multiple input `PetscSection`s

1886:   Collective

1888:   Input Parameters:
1889: + s     - the input sections
1890: - len   - the number of input sections

1892:   Output Parameter:
1893: . supers - the supersection

1895:   Level: advanced

1897:   Note:
1898:   The section offsets now refer to a new, larger vector.

1900:   Developer Note:
1901:   Needs to explain how the sections are composed

1903: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreateSubsection()`, `PetscSectionCreate()`
1904: @*/
1905: PetscErrorCode PetscSectionCreateSupersection(PetscSection s[], PetscInt len, PetscSection *supers)
1906: {
1907:   PetscInt Nf = 0, f, pStart = PETSC_MAX_INT, pEnd = 0, p, maxCdof = 0, i;

1909:   PetscFunctionBegin;
1910:   if (!len) PetscFunctionReturn(PETSC_SUCCESS);
1911:   for (i = 0; i < len; ++i) {
1912:     PetscInt nf, pStarti, pEndi;

1914:     PetscCall(PetscSectionGetNumFields(s[i], &nf));
1915:     PetscCall(PetscSectionGetChart(s[i], &pStarti, &pEndi));
1916:     pStart = PetscMin(pStart, pStarti);
1917:     pEnd   = PetscMax(pEnd, pEndi);
1918:     Nf += nf;
1919:   }
1920:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s[0]), supers));
1921:   PetscCall(PetscSectionSetNumFields(*supers, Nf));
1922:   for (i = 0, f = 0; i < len; ++i) {
1923:     PetscInt nf, fi, ci;

1925:     PetscCall(PetscSectionGetNumFields(s[i], &nf));
1926:     for (fi = 0; fi < nf; ++fi, ++f) {
1927:       const char *name    = NULL;
1928:       PetscInt    numComp = 0;

1930:       PetscCall(PetscSectionGetFieldName(s[i], fi, &name));
1931:       PetscCall(PetscSectionSetFieldName(*supers, f, name));
1932:       PetscCall(PetscSectionGetFieldComponents(s[i], fi, &numComp));
1933:       PetscCall(PetscSectionSetFieldComponents(*supers, f, numComp));
1934:       for (ci = 0; ci < s[i]->numFieldComponents[fi]; ++ci) {
1935:         PetscCall(PetscSectionGetComponentName(s[i], fi, ci, &name));
1936:         PetscCall(PetscSectionSetComponentName(*supers, f, ci, name));
1937:       }
1938:     }
1939:   }
1940:   PetscCall(PetscSectionSetChart(*supers, pStart, pEnd));
1941:   for (p = pStart; p < pEnd; ++p) {
1942:     PetscInt dof = 0, cdof = 0;

1944:     for (i = 0, f = 0; i < len; ++i) {
1945:       PetscInt nf, fi, pStarti, pEndi;
1946:       PetscInt fdof = 0, cfdof = 0;

1948:       PetscCall(PetscSectionGetNumFields(s[i], &nf));
1949:       PetscCall(PetscSectionGetChart(s[i], &pStarti, &pEndi));
1950:       if ((p < pStarti) || (p >= pEndi)) continue;
1951:       for (fi = 0; fi < nf; ++fi, ++f) {
1952:         PetscCall(PetscSectionGetFieldDof(s[i], p, fi, &fdof));
1953:         PetscCall(PetscSectionAddFieldDof(*supers, p, f, fdof));
1954:         PetscCall(PetscSectionGetFieldConstraintDof(s[i], p, fi, &cfdof));
1955:         if (cfdof) PetscCall(PetscSectionAddFieldConstraintDof(*supers, p, f, cfdof));
1956:         dof += fdof;
1957:         cdof += cfdof;
1958:       }
1959:     }
1960:     PetscCall(PetscSectionSetDof(*supers, p, dof));
1961:     if (cdof) PetscCall(PetscSectionSetConstraintDof(*supers, p, cdof));
1962:     maxCdof = PetscMax(cdof, maxCdof);
1963:   }
1964:   PetscCall(PetscSectionSetUp(*supers));
1965:   if (maxCdof) {
1966:     PetscInt *indices;

1968:     PetscCall(PetscMalloc1(maxCdof, &indices));
1969:     for (p = pStart; p < pEnd; ++p) {
1970:       PetscInt cdof;

1972:       PetscCall(PetscSectionGetConstraintDof(*supers, p, &cdof));
1973:       if (cdof) {
1974:         PetscInt dof, numConst = 0, fOff = 0;

1976:         for (i = 0, f = 0; i < len; ++i) {
1977:           const PetscInt *oldIndices = NULL;
1978:           PetscInt        nf, fi, pStarti, pEndi, fdof, cfdof, fc;

1980:           PetscCall(PetscSectionGetNumFields(s[i], &nf));
1981:           PetscCall(PetscSectionGetChart(s[i], &pStarti, &pEndi));
1982:           if ((p < pStarti) || (p >= pEndi)) continue;
1983:           for (fi = 0; fi < nf; ++fi, ++f) {
1984:             PetscCall(PetscSectionGetFieldDof(s[i], p, fi, &fdof));
1985:             PetscCall(PetscSectionGetFieldConstraintDof(s[i], p, fi, &cfdof));
1986:             PetscCall(PetscSectionGetFieldConstraintIndices(s[i], p, fi, &oldIndices));
1987:             for (fc = 0; fc < cfdof; ++fc) indices[numConst + fc] = oldIndices[fc];
1988:             PetscCall(PetscSectionSetFieldConstraintIndices(*supers, p, f, &indices[numConst]));
1989:             for (fc = 0; fc < cfdof; ++fc) indices[numConst + fc] += fOff;
1990:             numConst += cfdof;
1991:           }
1992:           PetscCall(PetscSectionGetDof(s[i], p, &dof));
1993:           fOff += dof;
1994:         }
1995:         PetscCall(PetscSectionSetConstraintIndices(*supers, p, indices));
1996:       }
1997:     }
1998:     PetscCall(PetscFree(indices));
1999:   }
2000:   PetscFunctionReturn(PETSC_SUCCESS);
2001: }

2003: PetscErrorCode PetscSectionCreateSubplexSection_Internal(PetscSection s, IS subpointMap, PetscBool renumberPoints, PetscSection *subs)
2004: {
2005:   const PetscInt *points = NULL, *indices = NULL;
2006:   PetscInt        numFields, f, c, numSubpoints = 0, pStart, pEnd, p, spStart, spEnd, subp;

2008:   PetscFunctionBegin;
2012:   PetscCall(PetscSectionGetNumFields(s, &numFields));
2013:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), subs));
2014:   if (numFields) PetscCall(PetscSectionSetNumFields(*subs, numFields));
2015:   for (f = 0; f < numFields; ++f) {
2016:     const char *name    = NULL;
2017:     PetscInt    numComp = 0;

2019:     PetscCall(PetscSectionGetFieldName(s, f, &name));
2020:     PetscCall(PetscSectionSetFieldName(*subs, f, name));
2021:     PetscCall(PetscSectionGetFieldComponents(s, f, &numComp));
2022:     PetscCall(PetscSectionSetFieldComponents(*subs, f, numComp));
2023:     for (c = 0; c < s->numFieldComponents[f]; ++c) {
2024:       PetscCall(PetscSectionGetComponentName(s, f, c, &name));
2025:       PetscCall(PetscSectionSetComponentName(*subs, f, c, name));
2026:     }
2027:   }
2028:   /* For right now, we do not try to squeeze the subchart */
2029:   if (subpointMap) {
2030:     PetscCall(ISGetSize(subpointMap, &numSubpoints));
2031:     PetscCall(ISGetIndices(subpointMap, &points));
2032:   }
2033:   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
2034:   if (renumberPoints) {
2035:     spStart = 0;
2036:     spEnd   = numSubpoints;
2037:   } else {
2038:     PetscCall(ISGetMinMax(subpointMap, &spStart, &spEnd));
2039:     ++spEnd;
2040:   }
2041:   PetscCall(PetscSectionSetChart(*subs, spStart, spEnd));
2042:   for (p = pStart; p < pEnd; ++p) {
2043:     PetscInt dof, cdof, fdof = 0, cfdof = 0;

2045:     PetscCall(PetscFindInt(p, numSubpoints, points, &subp));
2046:     if (subp < 0) continue;
2047:     if (!renumberPoints) subp = p;
2048:     for (f = 0; f < numFields; ++f) {
2049:       PetscCall(PetscSectionGetFieldDof(s, p, f, &fdof));
2050:       PetscCall(PetscSectionSetFieldDof(*subs, subp, f, fdof));
2051:       PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cfdof));
2052:       if (cfdof) PetscCall(PetscSectionSetFieldConstraintDof(*subs, subp, f, cfdof));
2053:     }
2054:     PetscCall(PetscSectionGetDof(s, p, &dof));
2055:     PetscCall(PetscSectionSetDof(*subs, subp, dof));
2056:     PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
2057:     if (cdof) PetscCall(PetscSectionSetConstraintDof(*subs, subp, cdof));
2058:   }
2059:   PetscCall(PetscSectionSetUp(*subs));
2060:   /* Change offsets to original offsets */
2061:   for (p = pStart; p < pEnd; ++p) {
2062:     PetscInt off, foff = 0;

2064:     PetscCall(PetscFindInt(p, numSubpoints, points, &subp));
2065:     if (subp < 0) continue;
2066:     if (!renumberPoints) subp = p;
2067:     for (f = 0; f < numFields; ++f) {
2068:       PetscCall(PetscSectionGetFieldOffset(s, p, f, &foff));
2069:       PetscCall(PetscSectionSetFieldOffset(*subs, subp, f, foff));
2070:     }
2071:     PetscCall(PetscSectionGetOffset(s, p, &off));
2072:     PetscCall(PetscSectionSetOffset(*subs, subp, off));
2073:   }
2074:   /* Copy constraint indices */
2075:   for (subp = spStart; subp < spEnd; ++subp) {
2076:     PetscInt cdof;

2078:     PetscCall(PetscSectionGetConstraintDof(*subs, subp, &cdof));
2079:     if (cdof) {
2080:       for (f = 0; f < numFields; ++f) {
2081:         PetscCall(PetscSectionGetFieldConstraintIndices(s, points[subp - spStart], f, &indices));
2082:         PetscCall(PetscSectionSetFieldConstraintIndices(*subs, subp, f, indices));
2083:       }
2084:       PetscCall(PetscSectionGetConstraintIndices(s, points[subp - spStart], &indices));
2085:       PetscCall(PetscSectionSetConstraintIndices(*subs, subp, indices));
2086:     }
2087:   }
2088:   if (subpointMap) PetscCall(ISRestoreIndices(subpointMap, &points));
2089:   PetscFunctionReturn(PETSC_SUCCESS);
2090: }

2092: /*@
2093:   PetscSectionCreateSubmeshSection - Create a new, smaller section with support on the submesh

2095:   Collective

2097:   Input Parameters:
2098: + s           - the `PetscSection`
2099: - subpointMap - a sorted list of points in the original mesh which are in the submesh

2101:   Output Parameter:
2102: . subs - the subsection

2104:   Level: advanced

2106:   Note:
2107:   The points are renumbered from 0, and the section offsets now refer to a new, smaller vector.
2108:   Compare this with `PetscSectionCreateSubdomainSection()` that does not map the points numbers to start at zero but leaves them as before

2110:   Developer Note:
2111:   The use of the term Submesh is confusing and needs clarification, it is not specific to meshes. It appears to be just a subset of the chart of the original `PetscSection`

2113: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreateSubdomainSection()`, `PetscSectionCreateSubsection()`, `DMPlexGetSubpointMap()`, `PetscSectionCreate()`
2114: @*/
2115: PetscErrorCode PetscSectionCreateSubmeshSection(PetscSection s, IS subpointMap, PetscSection *subs)
2116: {
2117:   PetscFunctionBegin;
2118:   PetscCall(PetscSectionCreateSubplexSection_Internal(s, subpointMap, PETSC_TRUE, subs));
2119:   PetscFunctionReturn(PETSC_SUCCESS);
2120: }

2122: /*@
2123:   PetscSectionCreateSubdomainSection - Create a new, smaller section with support on a subdomain of the mesh

2125:   Collective

2127:   Input Parameters:
2128: + s           - the `PetscSection`
2129: - subpointMap - a sorted list of points in the original mesh which are in the subdomain

2131:   Output Parameter:
2132: . subs - the subsection

2134:   Level: advanced

2136:   Note:
2137:   The point numbers remain the same as in the larger `PetscSection`, but the section offsets now refer to a new, smaller vector.
2138:   Compare this with `PetscSectionCreateSubmeshSection()` that maps the point numbers to start at zero

2140:   Developer Notes:
2141:   The use of the term Subdomain is unneeded and needs clarification, it is not specific to meshes. It appears to be just a subset of the chart of the original `PetscSection`

2143: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreateSubmeshSection()`, `PetscSectionCreateSubsection()`, `DMPlexGetSubpointMap()`, `PetscSectionCreate()`
2144: @*/
2145: PetscErrorCode PetscSectionCreateSubdomainSection(PetscSection s, IS subpointMap, PetscSection *subs)
2146: {
2147:   PetscFunctionBegin;
2148:   PetscCall(PetscSectionCreateSubplexSection_Internal(s, subpointMap, PETSC_FALSE, subs));
2149:   PetscFunctionReturn(PETSC_SUCCESS);
2150: }

2152: static PetscErrorCode PetscSectionView_ASCII(PetscSection s, PetscViewer viewer)
2153: {
2154:   PetscInt    p;
2155:   PetscMPIInt rank;

2157:   PetscFunctionBegin;
2158:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
2159:   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
2160:   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank));
2161:   for (p = 0; p < s->pEnd - s->pStart; ++p) {
2162:     if ((s->bc) && (s->bc->atlasDof[p] > 0)) {
2163:       PetscInt b;

2165:       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT " constrained", p + s->pStart, s->atlasDof[p], s->atlasOff[p]));
2166:       if (s->bcIndices) {
2167:         for (b = 0; b < s->bc->atlasDof[p]; ++b) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, s->bcIndices[s->bc->atlasOff[p] + b]));
2168:       }
2169:       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
2170:     } else {
2171:       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT "\n", p + s->pStart, s->atlasDof[p], s->atlasOff[p]));
2172:     }
2173:   }
2174:   PetscCall(PetscViewerFlush(viewer));
2175:   PetscCall(PetscViewerASCIIPopSynchronized(viewer));
2176:   if (s->sym) {
2177:     PetscCall(PetscViewerASCIIPushTab(viewer));
2178:     PetscCall(PetscSectionSymView(s->sym, viewer));
2179:     PetscCall(PetscViewerASCIIPopTab(viewer));
2180:   }
2181:   PetscFunctionReturn(PETSC_SUCCESS);
2182: }

2184: /*@C
2185:    PetscSectionViewFromOptions - View the `PetscSection` based on values in the options database

2187:    Collective

2189:    Input Parameters:
2190: +  A - the `PetscSection` object to view
2191: .  obj - Optional object that provides the options prefix used for the options
2192: -  name - command line option

2194:    Level: intermediate

2196:    Note:
2197:    See `PetscObjectViewFromOptions()` for available values of `PetscViewer` and `PetscViewerFormat`

2199: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionView`, `PetscObjectViewFromOptions()`, `PetscSectionCreate()`, `PetscSectionView()`
2200: @*/
2201: PetscErrorCode PetscSectionViewFromOptions(PetscSection A, PetscObject obj, const char name[])
2202: {
2203:   PetscFunctionBegin;
2205:   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
2206:   PetscFunctionReturn(PETSC_SUCCESS);
2207: }

2209: /*@C
2210:   PetscSectionView - Views a `PetscSection`

2212:   Collective

2214:   Input Parameters:
2215: + s - the `PetscSection` object to view
2216: - v - the viewer

2218:   Level: beginner

2220:   Note:
2221:   `PetscSectionView()`, when viewer is of type `PETSCVIEWERHDF5`, only saves
2222:   distribution independent data, such as dofs, offsets, constraint dofs,
2223:   and constraint indices. Points that have negative dofs, for instance,
2224:   are not saved as they represent points owned by other processes.
2225:   Point numbering and rank assignment is currently not stored.
2226:   The saved section can be loaded with `PetscSectionLoad()`.

2228: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()`, `PetscSectionLoad()`, `PetscViewer`
2229: @*/
2230: PetscErrorCode PetscSectionView(PetscSection s, PetscViewer viewer)
2231: {
2232:   PetscBool isascii, ishdf5;
2233:   PetscInt  f;

2235:   PetscFunctionBegin;
2237:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)s), &viewer));
2239:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
2240:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2241:   if (isascii) {
2242:     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)s, viewer));
2243:     if (s->numFields) {
2244:       PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " fields\n", s->numFields));
2245:       for (f = 0; f < s->numFields; ++f) {
2246:         PetscCall(PetscViewerASCIIPrintf(viewer, "  field %" PetscInt_FMT " with %" PetscInt_FMT " components\n", f, s->numFieldComponents[f]));
2247:         PetscCall(PetscSectionView_ASCII(s->field[f], viewer));
2248:       }
2249:     } else {
2250:       PetscCall(PetscSectionView_ASCII(s, viewer));
2251:     }
2252:   } else if (ishdf5) {
2253: #if PetscDefined(HAVE_HDF5)
2254:     PetscCall(PetscSectionView_HDF5_Internal(s, viewer));
2255: #else
2256:     SETERRQ(PetscObjectComm((PetscObject)s), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2257: #endif
2258:   }
2259:   PetscFunctionReturn(PETSC_SUCCESS);
2260: }

2262: /*@C
2263:   PetscSectionLoad - Loads a `PetscSection`

2265:   Collective

2267:   Input Parameters:
2268: + s - the `PetscSection` object to load
2269: - v - the viewer

2271:   Level: beginner

2273:   Note:
2274:   `PetscSectionLoad()`, when viewer is of type `PETSCVIEWERHDF5`, loads
2275:   a section saved with `PetscSectionView()`. The number of processes
2276:   used here (N) does not need to be the same as that used when saving.
2277:   After calling this function, the chart of s on rank i will be set
2278:   to [0, E_i), where \sum_{i=0}^{N-1}E_i equals to the total number of
2279:   saved section points.

2281: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()`, `PetscSectionView()`
2282: @*/
2283: PetscErrorCode PetscSectionLoad(PetscSection s, PetscViewer viewer)
2284: {
2285:   PetscBool ishdf5;

2287:   PetscFunctionBegin;
2290:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2291:   if (ishdf5) {
2292: #if PetscDefined(HAVE_HDF5)
2293:     PetscCall(PetscSectionLoad_HDF5_Internal(s, viewer));
2294:     PetscFunctionReturn(PETSC_SUCCESS);
2295: #else
2296:     SETERRQ(PetscObjectComm((PetscObject)s), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2297: #endif
2298:   } else SETERRQ(PetscObjectComm((PetscObject)s), PETSC_ERR_SUP, "Viewer type %s not yet supported for PetscSection loading", ((PetscObject)viewer)->type_name);
2299: }

2301: static PetscErrorCode PetscSectionResetClosurePermutation(PetscSection section)
2302: {
2303:   PetscSectionClosurePermVal clVal;

2305:   PetscFunctionBegin;
2306:   if (!section->clHash) PetscFunctionReturn(PETSC_SUCCESS);
2307:   kh_foreach_value(section->clHash, clVal, {
2308:     PetscCall(PetscFree(clVal.perm));
2309:     PetscCall(PetscFree(clVal.invPerm));
2310:   });
2311:   kh_destroy(ClPerm, section->clHash);
2312:   section->clHash = NULL;
2313:   PetscFunctionReturn(PETSC_SUCCESS);
2314: }

2316: /*@
2317:   PetscSectionReset - Frees all section data.

2319:   Not Collective

2321:   Input Parameter:
2322: . s - the `PetscSection`

2324:   Level: beginner

2326: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`
2327: @*/
2328: PetscErrorCode PetscSectionReset(PetscSection s)
2329: {
2330:   PetscInt f, c;

2332:   PetscFunctionBegin;
2334:   for (f = 0; f < s->numFields; ++f) {
2335:     PetscCall(PetscSectionDestroy(&s->field[f]));
2336:     PetscCall(PetscFree(s->fieldNames[f]));
2337:     for (c = 0; c < s->numFieldComponents[f]; ++c) PetscCall(PetscFree(s->compNames[f][c]));
2338:     PetscCall(PetscFree(s->compNames[f]));
2339:   }
2340:   PetscCall(PetscFree(s->numFieldComponents));
2341:   PetscCall(PetscFree(s->fieldNames));
2342:   PetscCall(PetscFree(s->compNames));
2343:   PetscCall(PetscFree(s->field));
2344:   PetscCall(PetscSectionDestroy(&s->bc));
2345:   PetscCall(PetscFree(s->bcIndices));
2346:   PetscCall(PetscFree2(s->atlasDof, s->atlasOff));
2347:   PetscCall(PetscSectionDestroy(&s->clSection));
2348:   PetscCall(ISDestroy(&s->clPoints));
2349:   PetscCall(ISDestroy(&s->perm));
2350:   PetscCall(PetscSectionResetClosurePermutation(s));
2351:   PetscCall(PetscSectionSymDestroy(&s->sym));
2352:   PetscCall(PetscSectionDestroy(&s->clSection));
2353:   PetscCall(ISDestroy(&s->clPoints));
2354:   PetscCall(PetscSectionInvalidateMaxDof_Internal(s));
2355:   s->pStart    = -1;
2356:   s->pEnd      = -1;
2357:   s->maxDof    = 0;
2358:   s->setup     = PETSC_FALSE;
2359:   s->numFields = 0;
2360:   s->clObj     = NULL;
2361:   PetscFunctionReturn(PETSC_SUCCESS);
2362: }

2364: /*@
2365:   PetscSectionDestroy - Frees a section object and frees its range if that exists.

2367:   Not Collective

2369:   Input Parameter:
2370: . s - the `PetscSection`

2372:   Level: beginner

2374: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionReset()`
2375: @*/
2376: PetscErrorCode PetscSectionDestroy(PetscSection *s)
2377: {
2378:   PetscFunctionBegin;
2379:   if (!*s) PetscFunctionReturn(PETSC_SUCCESS);
2381:   if (--((PetscObject)(*s))->refct > 0) {
2382:     *s = NULL;
2383:     PetscFunctionReturn(PETSC_SUCCESS);
2384:   }
2385:   PetscCall(PetscSectionReset(*s));
2386:   PetscCall(PetscHeaderDestroy(s));
2387:   PetscFunctionReturn(PETSC_SUCCESS);
2388: }

2390: PetscErrorCode VecIntGetValuesSection(PetscInt *baseArray, PetscSection s, PetscInt point, const PetscInt **values)
2391: {
2392:   const PetscInt p = point - s->pStart;

2394:   PetscFunctionBegin;
2396:   *values = &baseArray[s->atlasOff[p]];
2397:   PetscFunctionReturn(PETSC_SUCCESS);
2398: }

2400: PetscErrorCode VecIntSetValuesSection(PetscInt *baseArray, PetscSection s, PetscInt point, const PetscInt values[], InsertMode mode)
2401: {
2402:   PetscInt      *array;
2403:   const PetscInt p           = point - s->pStart;
2404:   const PetscInt orientation = 0; /* Needs to be included for use in closure operations */
2405:   PetscInt       cDim        = 0;

2407:   PetscFunctionBegin;
2409:   PetscCall(PetscSectionGetConstraintDof(s, p, &cDim));
2410:   array = &baseArray[s->atlasOff[p]];
2411:   if (!cDim) {
2412:     if (orientation >= 0) {
2413:       const PetscInt dim = s->atlasDof[p];
2414:       PetscInt       i;

2416:       if (mode == INSERT_VALUES) {
2417:         for (i = 0; i < dim; ++i) array[i] = values[i];
2418:       } else {
2419:         for (i = 0; i < dim; ++i) array[i] += values[i];
2420:       }
2421:     } else {
2422:       PetscInt offset = 0;
2423:       PetscInt j      = -1, field, i;

2425:       for (field = 0; field < s->numFields; ++field) {
2426:         const PetscInt dim = s->field[field]->atlasDof[p];

2428:         for (i = dim - 1; i >= 0; --i) array[++j] = values[i + offset];
2429:         offset += dim;
2430:       }
2431:     }
2432:   } else {
2433:     if (orientation >= 0) {
2434:       const PetscInt  dim  = s->atlasDof[p];
2435:       PetscInt        cInd = 0, i;
2436:       const PetscInt *cDof;

2438:       PetscCall(PetscSectionGetConstraintIndices(s, point, &cDof));
2439:       if (mode == INSERT_VALUES) {
2440:         for (i = 0; i < dim; ++i) {
2441:           if ((cInd < cDim) && (i == cDof[cInd])) {
2442:             ++cInd;
2443:             continue;
2444:           }
2445:           array[i] = values[i];
2446:         }
2447:       } else {
2448:         for (i = 0; i < dim; ++i) {
2449:           if ((cInd < cDim) && (i == cDof[cInd])) {
2450:             ++cInd;
2451:             continue;
2452:           }
2453:           array[i] += values[i];
2454:         }
2455:       }
2456:     } else {
2457:       const PetscInt *cDof;
2458:       PetscInt        offset  = 0;
2459:       PetscInt        cOffset = 0;
2460:       PetscInt        j       = 0, field;

2462:       PetscCall(PetscSectionGetConstraintIndices(s, point, &cDof));
2463:       for (field = 0; field < s->numFields; ++field) {
2464:         const PetscInt dim  = s->field[field]->atlasDof[p];     /* PetscSectionGetFieldDof() */
2465:         const PetscInt tDim = s->field[field]->bc->atlasDof[p]; /* PetscSectionGetFieldConstraintDof() */
2466:         const PetscInt sDim = dim - tDim;
2467:         PetscInt       cInd = 0, i, k;

2469:         for (i = 0, k = dim + offset - 1; i < dim; ++i, ++j, --k) {
2470:           if ((cInd < sDim) && (j == cDof[cInd + cOffset])) {
2471:             ++cInd;
2472:             continue;
2473:           }
2474:           array[j] = values[k];
2475:         }
2476:         offset += dim;
2477:         cOffset += dim - tDim;
2478:       }
2479:     }
2480:   }
2481:   PetscFunctionReturn(PETSC_SUCCESS);
2482: }

2484: /*@C
2485:   PetscSectionHasConstraints - Determine whether a `PetscSection` has constrained dofs

2487:   Not Collective

2489:   Input Parameter:
2490: . s - The `PetscSection`

2492:   Output Parameter:
2493: . hasConstraints - flag indicating that the section has constrained dofs

2495:   Level: intermediate

2497: .seealso: [PetscSection](sec_petscsection), `PetscSectionSetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection`
2498: @*/
2499: PetscErrorCode PetscSectionHasConstraints(PetscSection s, PetscBool *hasConstraints)
2500: {
2501:   PetscFunctionBegin;
2504:   *hasConstraints = s->bc ? PETSC_TRUE : PETSC_FALSE;
2505:   PetscFunctionReturn(PETSC_SUCCESS);
2506: }

2508: /*@C
2509:   PetscSectionGetConstraintIndices - Get the point dof numbers, in [0, dof), which are constrained for a given point

2511:   Not Collective

2513:   Input Parameters:
2514: + s     - The `PetscSection`
2515: - point - The point

2517:   Output Parameter:
2518: . indices - The constrained dofs

2520:   Level: intermediate

2522:   Fortran Note:
2523:   Use `PetscSectionGetConstraintIndicesF90()` and `PetscSectionRestoreConstraintIndicesF90()`

2525: .seealso: [PetscSection](sec_petscsection), `PetscSectionSetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection`
2526: @*/
2527: PetscErrorCode PetscSectionGetConstraintIndices(PetscSection s, PetscInt point, const PetscInt **indices)
2528: {
2529:   PetscFunctionBegin;
2531:   if (s->bc) {
2532:     PetscCall(VecIntGetValuesSection(s->bcIndices, s->bc, point, indices));
2533:   } else *indices = NULL;
2534:   PetscFunctionReturn(PETSC_SUCCESS);
2535: }

2537: /*@C
2538:   PetscSectionSetConstraintIndices - Set the point dof numbers, in [0, dof), which are constrained

2540:   Not Collective

2542:   Input Parameters:
2543: + s     - The `PetscSection`
2544: . point - The point
2545: - indices - The constrained dofs

2547:   Level: intermediate

2549:   Fortran Note:
2550:   Use `PetscSectionSetConstraintIndicesF90()`

2552: .seealso: [PetscSection](sec_petscsection), `PetscSectionGetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection`
2553: @*/
2554: PetscErrorCode PetscSectionSetConstraintIndices(PetscSection s, PetscInt point, const PetscInt indices[])
2555: {
2556:   PetscFunctionBegin;
2558:   if (s->bc) {
2559:     const PetscInt dof  = s->atlasDof[point];
2560:     const PetscInt cdof = s->bc->atlasDof[point];
2561:     PetscInt       d;

2563:     for (d = 0; d < cdof; ++d) PetscCheck(indices[d] < dof, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " dof %" PetscInt_FMT ", invalid constraint index[%" PetscInt_FMT "]: %" PetscInt_FMT, point, dof, d, indices[d]);
2564:     PetscCall(VecIntSetValuesSection(s->bcIndices, s->bc, point, indices, INSERT_VALUES));
2565:   }
2566:   PetscFunctionReturn(PETSC_SUCCESS);
2567: }

2569: /*@C
2570:   PetscSectionGetFieldConstraintIndices - Get the field dof numbers, in [0, fdof), which are constrained

2572:   Not Collective

2574:   Input Parameters:
2575: + s     - The `PetscSection`
2576: . field  - The field number
2577: - point - The point

2579:   Output Parameter:
2580: . indices - The constrained dofs sorted in ascending order

2582:   Level: intermediate

2584:   Note:
2585:   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()`.

2587:   Fortran Note:
2588:   Use `PetscSectionGetFieldConstraintIndicesF90()` and `PetscSectionRestoreFieldConstraintIndicesF90()`

2590: .seealso: [PetscSection](sec_petscsection), `PetscSectionSetFieldConstraintIndices()`, `PetscSectionGetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection`
2591: @*/
2592: PetscErrorCode PetscSectionGetFieldConstraintIndices(PetscSection s, PetscInt point, PetscInt field, const PetscInt **indices)
2593: {
2594:   PetscFunctionBegin;
2597:   PetscSectionCheckValidField(field, s->numFields);
2598:   PetscCall(PetscSectionGetConstraintIndices(s->field[field], point, indices));
2599:   PetscFunctionReturn(PETSC_SUCCESS);
2600: }

2602: /*@C
2603:   PetscSectionSetFieldConstraintIndices - Set the field dof numbers, in [0, fdof), which are constrained

2605:   Not Collective

2607:   Input Parameters:
2608: + s       - The `PetscSection`
2609: . point   - The point
2610: . field   - The field number
2611: - indices - The constrained dofs

2613:   Level: intermediate

2615:   Fortran Note:
2616:   Use `PetscSectionSetFieldConstraintIndicesF90()`

2618: .seealso: [PetscSection](sec_petscsection), `PetscSectionSetConstraintIndices()`, `PetscSectionGetFieldConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection`
2619: @*/
2620: PetscErrorCode PetscSectionSetFieldConstraintIndices(PetscSection s, PetscInt point, PetscInt field, const PetscInt indices[])
2621: {
2622:   PetscFunctionBegin;
2624:   if (PetscDefined(USE_DEBUG)) {
2625:     PetscInt nfdof;

2627:     PetscCall(PetscSectionGetFieldConstraintDof(s, point, field, &nfdof));
2629:   }
2630:   PetscSectionCheckValidField(field, s->numFields);
2631:   PetscCall(PetscSectionSetConstraintIndices(s->field[field], point, indices));
2632:   PetscFunctionReturn(PETSC_SUCCESS);
2633: }

2635: /*@
2636:   PetscSectionPermute - Reorder the section according to the input point permutation

2638:   Collective

2640:   Input Parameters:
2641: + section - The `PetscSection` object
2642: - perm - The point permutation, old point p becomes new point perm[p]

2644:   Output Parameter:
2645: . sectionNew - The permuted `PetscSection`

2647:   Level: intermediate

2649: .seealso: [PetscSection](sec_petscsection), `IS`, `PetscSection`, `MatPermute()`
2650: @*/
2651: PetscErrorCode PetscSectionPermute(PetscSection section, IS permutation, PetscSection *sectionNew)
2652: {
2653:   PetscSection    s = section, sNew;
2654:   const PetscInt *perm;
2655:   PetscInt        numFields, f, c, numPoints, pStart, pEnd, p;

2657:   PetscFunctionBegin;
2661:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), &sNew));
2662:   PetscCall(PetscSectionGetNumFields(s, &numFields));
2663:   if (numFields) PetscCall(PetscSectionSetNumFields(sNew, numFields));
2664:   for (f = 0; f < numFields; ++f) {
2665:     const char *name;
2666:     PetscInt    numComp;

2668:     PetscCall(PetscSectionGetFieldName(s, f, &name));
2669:     PetscCall(PetscSectionSetFieldName(sNew, f, name));
2670:     PetscCall(PetscSectionGetFieldComponents(s, f, &numComp));
2671:     PetscCall(PetscSectionSetFieldComponents(sNew, f, numComp));
2672:     for (c = 0; c < s->numFieldComponents[f]; ++c) {
2673:       PetscCall(PetscSectionGetComponentName(s, f, c, &name));
2674:       PetscCall(PetscSectionSetComponentName(sNew, f, c, name));
2675:     }
2676:   }
2677:   PetscCall(ISGetLocalSize(permutation, &numPoints));
2678:   PetscCall(ISGetIndices(permutation, &perm));
2679:   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
2680:   PetscCall(PetscSectionSetChart(sNew, pStart, pEnd));
2681:   PetscCheck(numPoints >= pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Permutation size %" PetscInt_FMT " is less than largest Section point %" PetscInt_FMT, numPoints, pEnd);
2682:   for (p = pStart; p < pEnd; ++p) {
2683:     PetscInt dof, cdof;

2685:     PetscCall(PetscSectionGetDof(s, p, &dof));
2686:     PetscCall(PetscSectionSetDof(sNew, perm[p], dof));
2687:     PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
2688:     if (cdof) PetscCall(PetscSectionSetConstraintDof(sNew, perm[p], cdof));
2689:     for (f = 0; f < numFields; ++f) {
2690:       PetscCall(PetscSectionGetFieldDof(s, p, f, &dof));
2691:       PetscCall(PetscSectionSetFieldDof(sNew, perm[p], f, dof));
2692:       PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cdof));
2693:       if (cdof) PetscCall(PetscSectionSetFieldConstraintDof(sNew, perm[p], f, cdof));
2694:     }
2695:   }
2696:   PetscCall(PetscSectionSetUp(sNew));
2697:   for (p = pStart; p < pEnd; ++p) {
2698:     const PetscInt *cind;
2699:     PetscInt        cdof;

2701:     PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
2702:     if (cdof) {
2703:       PetscCall(PetscSectionGetConstraintIndices(s, p, &cind));
2704:       PetscCall(PetscSectionSetConstraintIndices(sNew, perm[p], cind));
2705:     }
2706:     for (f = 0; f < numFields; ++f) {
2707:       PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cdof));
2708:       if (cdof) {
2709:         PetscCall(PetscSectionGetFieldConstraintIndices(s, p, f, &cind));
2710:         PetscCall(PetscSectionSetFieldConstraintIndices(sNew, perm[p], f, cind));
2711:       }
2712:     }
2713:   }
2714:   PetscCall(ISRestoreIndices(permutation, &perm));
2715:   *sectionNew = sNew;
2716:   PetscFunctionReturn(PETSC_SUCCESS);
2717: }

2719: /*@
2720:   PetscSectionSetClosureIndex - Create an internal data structure to speed up closure queries.

2722:   Collective

2724:   Input Parameters:
2725: + section   - The `PetscSection`
2726: . obj       - A `PetscObject` which serves as the key for this index
2727: . clSection - `PetscSection` giving the size of the closure of each point
2728: - clPoints  - `IS` giving the points in each closure

2730:   Level: advanced

2732:   Note:
2733:   This function creates an internal map from each point to its closure. We compress out closure points with no dofs in this section.

2735:   Developer Note:
2736:   The information provided here is completely opaque

2738: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetClosureIndex()`, `DMPlexCreateClosureIndex()`
2739: @*/
2740: PetscErrorCode PetscSectionSetClosureIndex(PetscSection section, PetscObject obj, PetscSection clSection, IS clPoints)
2741: {
2742:   PetscFunctionBegin;
2746:   if (section->clObj != obj) PetscCall(PetscSectionResetClosurePermutation(section));
2747:   section->clObj = obj;
2748:   PetscCall(PetscObjectReference((PetscObject)clSection));
2749:   PetscCall(PetscObjectReference((PetscObject)clPoints));
2750:   PetscCall(PetscSectionDestroy(&section->clSection));
2751:   PetscCall(ISDestroy(&section->clPoints));
2752:   section->clSection = clSection;
2753:   section->clPoints  = clPoints;
2754:   PetscFunctionReturn(PETSC_SUCCESS);
2755: }

2757: /*@
2758:   PetscSectionGetClosureIndex - Get the cache of points in the closure of each point in the section set with `PetscSectionSetClosureIndex()`

2760:   Collective

2762:   Input Parameters:
2763: + section   - The `PetscSection`
2764: - obj       - A `PetscObject` which serves as the key for this index

2766:   Output Parameters:
2767: + clSection - `PetscSection` giving the size of the closure of each point
2768: - clPoints  - `IS` giving the points in each closure

2770:   Level: advanced

2772: .seealso: [PetscSection](sec_petscsection), `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()`
2773: @*/
2774: PetscErrorCode PetscSectionGetClosureIndex(PetscSection section, PetscObject obj, PetscSection *clSection, IS *clPoints)
2775: {
2776:   PetscFunctionBegin;
2777:   if (section->clObj == obj) {
2778:     if (clSection) *clSection = section->clSection;
2779:     if (clPoints) *clPoints = section->clPoints;
2780:   } else {
2781:     if (clSection) *clSection = NULL;
2782:     if (clPoints) *clPoints = NULL;
2783:   }
2784:   PetscFunctionReturn(PETSC_SUCCESS);
2785: }

2787: PetscErrorCode PetscSectionSetClosurePermutation_Internal(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, PetscCopyMode mode, PetscInt *clPerm)
2788: {
2789:   PetscInt                    i;
2790:   khiter_t                    iter;
2791:   int                         new_entry;
2792:   PetscSectionClosurePermKey  key = {depth, clSize};
2793:   PetscSectionClosurePermVal *val;

2795:   PetscFunctionBegin;
2796:   if (section->clObj != obj) {
2797:     PetscCall(PetscSectionDestroy(&section->clSection));
2798:     PetscCall(ISDestroy(&section->clPoints));
2799:   }
2800:   section->clObj = obj;
2801:   if (!section->clHash) PetscCall(PetscClPermCreate(&section->clHash));
2802:   iter = kh_put(ClPerm, section->clHash, key, &new_entry);
2803:   val  = &kh_val(section->clHash, iter);
2804:   if (!new_entry) {
2805:     PetscCall(PetscFree(val->perm));
2806:     PetscCall(PetscFree(val->invPerm));
2807:   }
2808:   if (mode == PETSC_COPY_VALUES) {
2809:     PetscCall(PetscMalloc1(clSize, &val->perm));
2810:     PetscCall(PetscArraycpy(val->perm, clPerm, clSize));
2811:   } else if (mode == PETSC_OWN_POINTER) {
2812:     val->perm = clPerm;
2813:   } else SETERRQ(PetscObjectComm(obj), PETSC_ERR_SUP, "Do not support borrowed arrays");
2814:   PetscCall(PetscMalloc1(clSize, &val->invPerm));
2815:   for (i = 0; i < clSize; ++i) val->invPerm[clPerm[i]] = i;
2816:   PetscFunctionReturn(PETSC_SUCCESS);
2817: }

2819: /*@
2820:   PetscSectionSetClosurePermutation - Set the dof permutation for the closure of each cell in the section, meaning clPerm[newIndex] = oldIndex.

2822:   Not Collective

2824:   Input Parameters:
2825: + section - The `PetscSection`
2826: . obj     - A `PetscObject` which serves as the key for this index (usually a `DM`)
2827: . depth   - Depth of points on which to apply the given permutation
2828: - perm    - Permutation of the cell dof closure

2830:   Level: intermediate

2832:   Notes:
2833:   The specified permutation will only be applied to points at depth whose closure size matches the length of perm.  In a
2834:   mixed-topology or variable-degree finite element space, this function can be called multiple times at each depth for
2835:   each topology and degree.

2837:   This approach assumes that (depth, len(perm)) uniquely identifies the desired permutation; this might not be true for
2838:   exotic/enriched spaces on mixed topology meshes.

2840: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `IS`, `PetscSectionGetClosurePermutation()`, `PetscSectionGetClosureIndex()`, `DMPlexCreateClosureIndex()`, `PetscCopyMode`
2841: @*/
2842: PetscErrorCode PetscSectionSetClosurePermutation(PetscSection section, PetscObject obj, PetscInt depth, IS perm)
2843: {
2844:   const PetscInt *clPerm = NULL;
2845:   PetscInt        clSize = 0;

2847:   PetscFunctionBegin;
2848:   if (perm) {
2849:     PetscCall(ISGetLocalSize(perm, &clSize));
2850:     PetscCall(ISGetIndices(perm, &clPerm));
2851:   }
2852:   PetscCall(PetscSectionSetClosurePermutation_Internal(section, obj, depth, clSize, PETSC_COPY_VALUES, (PetscInt *)clPerm));
2853:   if (perm) PetscCall(ISRestoreIndices(perm, &clPerm));
2854:   PetscFunctionReturn(PETSC_SUCCESS);
2855: }

2857: PetscErrorCode PetscSectionGetClosurePermutation_Internal(PetscSection section, PetscObject obj, PetscInt depth, PetscInt size, const PetscInt *perm[])
2858: {
2859:   PetscFunctionBegin;
2860:   if (section->clObj == obj) {
2861:     PetscSectionClosurePermKey k = {depth, size};
2862:     PetscSectionClosurePermVal v;
2863:     PetscCall(PetscClPermGet(section->clHash, k, &v));
2864:     if (perm) *perm = v.perm;
2865:   } else {
2866:     if (perm) *perm = NULL;
2867:   }
2868:   PetscFunctionReturn(PETSC_SUCCESS);
2869: }

2871: /*@
2872:   PetscSectionGetClosurePermutation - Get the dof permutation for the closure of each cell in the section, meaning clPerm[newIndex] = oldIndex.

2874:   Not Collective

2876:   Input Parameters:
2877: + section   - The `PetscSection`
2878: . obj       - A `PetscObject` which serves as the key for this index (usually a DM)
2879: . depth     - Depth stratum on which to obtain closure permutation
2880: - clSize    - Closure size to be permuted (e.g., may vary with element topology and degree)

2882:   Output Parameter:
2883: . perm - The dof closure permutation

2885:   Level: intermediate

2887:   Note:
2888:   The user must destroy the `IS` that is returned.

2890: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `IS`, `PetscSectionSetClosurePermutation()`, `PetscSectionGetClosureInversePermutation()`, `PetscSectionGetClosureIndex()`, `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()`
2891: @*/
2892: PetscErrorCode PetscSectionGetClosurePermutation(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, IS *perm)
2893: {
2894:   const PetscInt *clPerm;

2896:   PetscFunctionBegin;
2897:   PetscCall(PetscSectionGetClosurePermutation_Internal(section, obj, depth, clSize, &clPerm));
2898:   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, clSize, clPerm, PETSC_USE_POINTER, perm));
2899:   PetscFunctionReturn(PETSC_SUCCESS);
2900: }

2902: PetscErrorCode PetscSectionGetClosureInversePermutation_Internal(PetscSection section, PetscObject obj, PetscInt depth, PetscInt size, const PetscInt *perm[])
2903: {
2904:   PetscFunctionBegin;
2905:   if (section->clObj == obj && section->clHash) {
2906:     PetscSectionClosurePermKey k = {depth, size};
2907:     PetscSectionClosurePermVal v;
2908:     PetscCall(PetscClPermGet(section->clHash, k, &v));
2909:     if (perm) *perm = v.invPerm;
2910:   } else {
2911:     if (perm) *perm = NULL;
2912:   }
2913:   PetscFunctionReturn(PETSC_SUCCESS);
2914: }

2916: /*@
2917:   PetscSectionGetClosureInversePermutation - Get the inverse dof permutation for the closure of each cell in the section, meaning clPerm[oldIndex] = newIndex.

2919:   Not Collective

2921:   Input Parameters:
2922: + section   - The `PetscSection`
2923: . obj       - A `PetscObject` which serves as the key for this index (usually a `DM`)
2924: . depth     - Depth stratum on which to obtain closure permutation
2925: - clSize    - Closure size to be permuted (e.g., may vary with element topology and degree)

2927:   Output Parameter:
2928: . perm - The dof closure permutation

2930:   Level: intermediate

2932:   Note:
2933:   The user must destroy the `IS` that is returned.

2935: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `IS`, `PetscSectionSetClosurePermutation()`, `PetscSectionGetClosureIndex()`, `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()`
2936: @*/
2937: PetscErrorCode PetscSectionGetClosureInversePermutation(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, IS *perm)
2938: {
2939:   const PetscInt *clPerm;

2941:   PetscFunctionBegin;
2942:   PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, obj, depth, clSize, &clPerm));
2943:   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, clSize, clPerm, PETSC_USE_POINTER, perm));
2944:   PetscFunctionReturn(PETSC_SUCCESS);
2945: }

2947: /*@
2948:   PetscSectionGetField - Get the subsection associated with a single field

2950:   Input Parameters:
2951: + s     - The `PetscSection`
2952: - field - The field number

2954:   Output Parameter:
2955: . subs  - The subsection for the given field

2957:   Level: intermediate

2959:   Note:
2960:   Does not increase the reference count of the selected sub-section. There is no matching `PetscSectionRestoreField()`

2962: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `IS`, `PetscSectionSetNumFields()`
2963: @*/
2964: PetscErrorCode PetscSectionGetField(PetscSection s, PetscInt field, PetscSection *subs)
2965: {
2966:   PetscFunctionBegin;
2969:   PetscSectionCheckValidField(field, s->numFields);
2970:   *subs = s->field[field];
2971:   PetscFunctionReturn(PETSC_SUCCESS);
2972: }

2974: PetscClassId      PETSC_SECTION_SYM_CLASSID;
2975: PetscFunctionList PetscSectionSymList = NULL;

2977: /*@
2978:   PetscSectionSymCreate - Creates an empty `PetscSectionSym` object.

2980:   Collective

2982:   Input Parameter:
2983: . comm - the MPI communicator

2985:   Output Parameter:
2986: . sym - pointer to the new set of symmetries

2988:   Level: developer

2990: .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSym`, `PetscSectionSymDestroy()`
2991: @*/
2992: PetscErrorCode PetscSectionSymCreate(MPI_Comm comm, PetscSectionSym *sym)
2993: {
2994:   PetscFunctionBegin;
2996:   PetscCall(ISInitializePackage());
2997:   PetscCall(PetscHeaderCreate(*sym, PETSC_SECTION_SYM_CLASSID, "PetscSectionSym", "Section Symmetry", "IS", comm, PetscSectionSymDestroy, PetscSectionSymView));
2998:   PetscFunctionReturn(PETSC_SUCCESS);
2999: }

3001: /*@C
3002:   PetscSectionSymSetType - Builds a `PetscSectionSym`, for a particular implementation.

3004:   Collective

3006:   Input Parameters:
3007: + sym    - The section symmetry object
3008: - method - The name of the section symmetry type

3010:   Level: developer

3012: .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymGetType()`, `PetscSectionSymCreate()`
3013: @*/
3014: PetscErrorCode PetscSectionSymSetType(PetscSectionSym sym, PetscSectionSymType method)
3015: {
3016:   PetscErrorCode (*r)(PetscSectionSym);
3017:   PetscBool match;

3019:   PetscFunctionBegin;
3021:   PetscCall(PetscObjectTypeCompare((PetscObject)sym, method, &match));
3022:   if (match) PetscFunctionReturn(PETSC_SUCCESS);

3024:   PetscCall(PetscFunctionListFind(PetscSectionSymList, method, &r));
3025:   PetscCheck(r, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscSectionSym type: %s", method);
3026:   PetscTryTypeMethod(sym, destroy);
3027:   sym->ops->destroy = NULL;

3029:   PetscCall((*r)(sym));
3030:   PetscCall(PetscObjectChangeTypeName((PetscObject)sym, method));
3031:   PetscFunctionReturn(PETSC_SUCCESS);
3032: }

3034: /*@C
3035:   PetscSectionSymGetType - Gets the section symmetry type name (as a string) from the `PetscSectionSym`.

3037:   Not Collective

3039:   Input Parameter:
3040: . sym  - The section symmetry

3042:   Output Parameter:
3043: . type - The index set type name

3045:   Level: developer

3047: .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymSetType()`, `PetscSectionSymCreate()`
3048: @*/
3049: PetscErrorCode PetscSectionSymGetType(PetscSectionSym sym, PetscSectionSymType *type)
3050: {
3051:   PetscFunctionBegin;
3054:   *type = ((PetscObject)sym)->type_name;
3055:   PetscFunctionReturn(PETSC_SUCCESS);
3056: }

3058: /*@C
3059:   PetscSectionSymRegister - Registers a new section symmetry implementation

3061:   Not Collective

3063:   Input Parameters:
3064: + sname        - The name of a new user-defined creation routine
3065: - function - The creation routine itself

3067:   Level: developer

3069:   Notes:
3070:   `PetscSectionSymRegister()` may be called multiple times to add several user-defined vectors

3072: .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymCreate()`, `PetscSectionSymSetType()`
3073: @*/
3074: PetscErrorCode PetscSectionSymRegister(const char sname[], PetscErrorCode (*function)(PetscSectionSym))
3075: {
3076:   PetscFunctionBegin;
3077:   PetscCall(ISInitializePackage());
3078:   PetscCall(PetscFunctionListAdd(&PetscSectionSymList, sname, function));
3079:   PetscFunctionReturn(PETSC_SUCCESS);
3080: }

3082: /*@
3083:    PetscSectionSymDestroy - Destroys a section symmetry.

3085:    Collective

3087:    Input Parameter:
3088: .  sym - the section symmetry

3090:    Level: developer

3092: .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()`, `PetscSectionSymDestroy()`
3093: @*/
3094: PetscErrorCode PetscSectionSymDestroy(PetscSectionSym *sym)
3095: {
3096:   SymWorkLink link, next;

3098:   PetscFunctionBegin;
3099:   if (!*sym) PetscFunctionReturn(PETSC_SUCCESS);
3101:   if (--((PetscObject)(*sym))->refct > 0) {
3102:     *sym = NULL;
3103:     PetscFunctionReturn(PETSC_SUCCESS);
3104:   }
3105:   if ((*sym)->ops->destroy) PetscCall((*(*sym)->ops->destroy)(*sym));
3106:   PetscCheck(!(*sym)->workout, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Work array still checked out");
3107:   for (link = (*sym)->workin; link; link = next) {
3108:     PetscInt    **perms = (PetscInt **)link->perms;
3109:     PetscScalar **rots  = (PetscScalar **)link->rots;
3110:     PetscCall(PetscFree2(perms, rots));
3111:     next = link->next;
3112:     PetscCall(PetscFree(link));
3113:   }
3114:   (*sym)->workin = NULL;
3115:   PetscCall(PetscHeaderDestroy(sym));
3116:   PetscFunctionReturn(PETSC_SUCCESS);
3117: }

3119: /*@C
3120:    PetscSectionSymView - Displays a section symmetry

3122:    Collective

3124:    Input Parameters:
3125: +  sym - the index set
3126: -  viewer - viewer used to display the set, for example `PETSC_VIEWER_STDOUT_SELF`.

3128:    Level: developer

3130: .seealso:  `PetscSectionSym`, `PetscViewer`, `PetscViewerASCIIOpen()`
3131: @*/
3132: PetscErrorCode PetscSectionSymView(PetscSectionSym sym, PetscViewer viewer)
3133: {
3134:   PetscFunctionBegin;
3136:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sym), &viewer));
3138:   PetscCheckSameComm(sym, 1, viewer, 2);
3139:   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)sym, viewer));
3140:   PetscTryTypeMethod(sym, view, viewer);
3141:   PetscFunctionReturn(PETSC_SUCCESS);
3142: }

3144: /*@
3145:   PetscSectionSetSym - Set the symmetries for the data referred to by the section

3147:   Collective

3149:   Input Parameters:
3150: + section - the section describing data layout
3151: - sym - the symmetry describing the affect of orientation on the access of the data

3153:   Level: developer

3155: .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetSym()`, `PetscSectionSymCreate()`
3156: @*/
3157: PetscErrorCode PetscSectionSetSym(PetscSection section, PetscSectionSym sym)
3158: {
3159:   PetscFunctionBegin;
3161:   PetscCall(PetscSectionSymDestroy(&(section->sym)));
3162:   if (sym) {
3164:     PetscCheckSameComm(section, 1, sym, 2);
3165:     PetscCall(PetscObjectReference((PetscObject)sym));
3166:   }
3167:   section->sym = sym;
3168:   PetscFunctionReturn(PETSC_SUCCESS);
3169: }

3171: /*@
3172:   PetscSectionGetSym - Get the symmetries for the data referred to by the section

3174:   Not Collective

3176:   Input Parameter:
3177: . section - the section describing data layout

3179:   Output Parameter:
3180: . sym - the symmetry describing the affect of orientation on the access of the data, provided previously by `PetscSectionSetSym()`

3182:   Level: developer

3184: .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSetSym()`, `PetscSectionSymCreate()`
3185: @*/
3186: PetscErrorCode PetscSectionGetSym(PetscSection section, PetscSectionSym *sym)
3187: {
3188:   PetscFunctionBegin;
3190:   *sym = section->sym;
3191:   PetscFunctionReturn(PETSC_SUCCESS);
3192: }

3194: /*@
3195:   PetscSectionSetFieldSym - Set the symmetries for the data referred to by a field of the section

3197:   Collective

3199:   Input Parameters:
3200: + section - the section describing data layout
3201: . field - the field number
3202: - sym - the symmetry describing the affect of orientation on the access of the data

3204:   Level: developer

3206: .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetFieldSym()`, `PetscSectionSymCreate()`
3207: @*/
3208: PetscErrorCode PetscSectionSetFieldSym(PetscSection section, PetscInt field, PetscSectionSym sym)
3209: {
3210:   PetscFunctionBegin;
3212:   PetscSectionCheckValidField(field, section->numFields);
3213:   PetscCall(PetscSectionSetSym(section->field[field], sym));
3214:   PetscFunctionReturn(PETSC_SUCCESS);
3215: }

3217: /*@
3218:   PetscSectionGetFieldSym - Get the symmetries for the data referred to by a field of the section

3220:   Collective

3222:   Input Parameters:
3223: + section - the section describing data layout
3224: - field - the field number

3226:   Output Parameter:
3227: . sym - the symmetry describing the affect of orientation on the access of the data

3229:   Level: developer

3231: .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSetFieldSym()`, `PetscSectionSymCreate()`
3232: @*/
3233: PetscErrorCode PetscSectionGetFieldSym(PetscSection section, PetscInt field, PetscSectionSym *sym)
3234: {
3235:   PetscFunctionBegin;
3237:   PetscSectionCheckValidField(field, section->numFields);
3238:   *sym = section->field[field]->sym;
3239:   PetscFunctionReturn(PETSC_SUCCESS);
3240: }

3242: /*@C
3243:   PetscSectionGetPointSyms - Get the symmetries for a set of points in a `PetscSection` under specific orientations.

3245:   Not Collective

3247:   Input Parameters:
3248: + section - the section
3249: . numPoints - the number of points
3250: - points - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an
3251:     arbitrary integer: its interpretation is up to sym.  Orientations are used by `DM`: for their interpretation in that
3252:     context, see `DMPlexGetConeOrientation()`).

3254:   Output Parameters:
3255: + perms - The permutations for the given orientations (or `NULL` if there is no symmetry or the permutation is the identity).
3256: - rots - The field rotations symmetries for the given orientations (or `NULL` if there is no symmetry or the rotations are all
3257:     identity).

3259:   Example of usage, gathering dofs into a local array (lArray) from a section array (sArray):
3260: .vb
3261:      const PetscInt    **perms;
3262:      const PetscScalar **rots;
3263:      PetscInt            lOffset;

3265:      PetscSectionGetPointSyms(section,numPoints,points,&perms,&rots);
3266:      for (i = 0, lOffset = 0; i < numPoints; i++) {
3267:        PetscInt           point = points[2*i], dof, sOffset;
3268:        const PetscInt    *perm  = perms ? perms[i] : NULL;
3269:        const PetscScalar *rot   = rots  ? rots[i]  : NULL;

3271:        PetscSectionGetDof(section,point,&dof);
3272:        PetscSectionGetOffset(section,point,&sOffset);

3274:        if (perm) {for (j = 0; j < dof; j++) {lArray[lOffset + perm[j]]  = sArray[sOffset + j];}}
3275:        else      {for (j = 0; j < dof; j++) {lArray[lOffset +      j ]  = sArray[sOffset + j];}}
3276:        if (rot)  {for (j = 0; j < dof; j++) {lArray[lOffset +      j ] *= rot[j];             }}
3277:        lOffset += dof;
3278:      }
3279:      PetscSectionRestorePointSyms(section,numPoints,points,&perms,&rots);
3280: .ve

3282:   Example of usage, adding dofs into a section array (sArray) from a local array (lArray):
3283: .vb
3284:      const PetscInt    **perms;
3285:      const PetscScalar **rots;
3286:      PetscInt            lOffset;

3288:      PetscSectionGetPointSyms(section,numPoints,points,&perms,&rots);
3289:      for (i = 0, lOffset = 0; i < numPoints; i++) {
3290:        PetscInt           point = points[2*i], dof, sOffset;
3291:        const PetscInt    *perm  = perms ? perms[i] : NULL;
3292:        const PetscScalar *rot   = rots  ? rots[i]  : NULL;

3294:        PetscSectionGetDof(section,point,&dof);
3295:        PetscSectionGetOffset(section,point,&sOff);

3297:        if (perm) {for (j = 0; j < dof; j++) {sArray[sOffset + j] += lArray[lOffset + perm[j]] * (rot ? PetscConj(rot[perm[j]]) : 1.);}}
3298:        else      {for (j = 0; j < dof; j++) {sArray[sOffset + j] += lArray[lOffset +      j ] * (rot ? PetscConj(rot[     j ]) : 1.);}}
3299:        offset += dof;
3300:      }
3301:      PetscSectionRestorePointSyms(section,numPoints,points,&perms,&rots);
3302: .ve

3304:   Level: developer

3306:   Note:
3307:   `PetscSectionSetSym()` must have been previously called to provide the symmetries to the `PetscSection`

3309:   Use `PetscSectionRestorePointSyms()` when finished with the data

3311: .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionRestorePointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`
3312: @*/
3313: PetscErrorCode PetscSectionGetPointSyms(PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3314: {
3315:   PetscSectionSym sym;

3317:   PetscFunctionBegin;
3320:   if (perms) *perms = NULL;
3321:   if (rots) *rots = NULL;
3322:   sym = section->sym;
3323:   if (sym && (perms || rots)) {
3324:     SymWorkLink link;

3326:     if (sym->workin) {
3327:       link        = sym->workin;
3328:       sym->workin = sym->workin->next;
3329:     } else {
3330:       PetscCall(PetscNew(&link));
3331:     }
3332:     if (numPoints > link->numPoints) {
3333:       PetscInt    **perms = (PetscInt **)link->perms;
3334:       PetscScalar **rots  = (PetscScalar **)link->rots;
3335:       PetscCall(PetscFree2(perms, rots));
3336:       PetscCall(PetscMalloc2(numPoints, (PetscInt ***)&link->perms, numPoints, (PetscScalar ***)&link->rots));
3337:       link->numPoints = numPoints;
3338:     }
3339:     link->next   = sym->workout;
3340:     sym->workout = link;
3341:     PetscCall(PetscArrayzero((PetscInt **)link->perms, numPoints));
3342:     PetscCall(PetscArrayzero((PetscInt **)link->rots, numPoints));
3343:     PetscCall((*sym->ops->getpoints)(sym, section, numPoints, points, link->perms, link->rots));
3344:     if (perms) *perms = link->perms;
3345:     if (rots) *rots = link->rots;
3346:   }
3347:   PetscFunctionReturn(PETSC_SUCCESS);
3348: }

3350: /*@C
3351:   PetscSectionRestorePointSyms - Restore the symmetries returned by `PetscSectionGetPointSyms()`

3353:   Not Collective

3355:   Input Parameters:
3356: + section - the section
3357: . numPoints - the number of points
3358: - points - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an
3359:     arbitrary integer: its interpretation is up to sym.  Orientations are used by `DM`: for their interpretation in that
3360:     context, see `DMPlexGetConeOrientation()`).
3361: . perms - The permutations for the given orientations: set to `NULL` at conclusion
3362: - rots - The field rotations symmetries for the given orientations: set to `NULL` at conclusion

3364:   Level: developer

3366: .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetPointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`
3367: @*/
3368: PetscErrorCode PetscSectionRestorePointSyms(PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3369: {
3370:   PetscSectionSym sym;

3372:   PetscFunctionBegin;
3374:   sym = section->sym;
3375:   if (sym && (perms || rots)) {
3376:     SymWorkLink *p, link;

3378:     for (p = &sym->workout; (link = *p); p = &link->next) {
3379:       if ((perms && link->perms == *perms) || (rots && link->rots == *rots)) {
3380:         *p          = link->next;
3381:         link->next  = sym->workin;
3382:         sym->workin = link;
3383:         if (perms) *perms = NULL;
3384:         if (rots) *rots = NULL;
3385:         PetscFunctionReturn(PETSC_SUCCESS);
3386:       }
3387:     }
3388:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Array was not checked out");
3389:   }
3390:   PetscFunctionReturn(PETSC_SUCCESS);
3391: }

3393: /*@C
3394:   PetscSectionGetFieldPointSyms - Get the symmetries for a set of points in a field of a `PetscSection` under specific orientations.

3396:   Not Collective

3398:   Input Parameters:
3399: + section - the section
3400: . field - the field of the section
3401: . numPoints - the number of points
3402: - points - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an
3403:     arbitrary integer: its interpretation is up to sym.  Orientations are used by `DM`: for their interpretation in that
3404:     context, see `DMPlexGetConeOrientation()`).

3406:   Output Parameters:
3407: + perms - The permutations for the given orientations (or `NULL` if there is no symmetry or the permutation is the identity).
3408: - rots - The field rotations symmetries for the given orientations (or `NULL` if there is no symmetry or the rotations are all
3409:     identity).

3411:   Level: developer

3413:   Notes:
3414:   `PetscSectionSetFieldSym()` must have been previously called to provide the symmetries to the `PetscSection`

3416:   Use `PetscSectionRestoreFieldPointSyms()` when finished with the data

3418: .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetPointSyms()`, `PetscSectionRestoreFieldPointSyms()`
3419: @*/
3420: PetscErrorCode PetscSectionGetFieldPointSyms(PetscSection section, PetscInt field, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3421: {
3422:   PetscFunctionBegin;
3424:   PetscCheck(field <= section->numFields, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "field %" PetscInt_FMT " greater than number of fields (%" PetscInt_FMT ") in section", field, section->numFields);
3425:   PetscCall(PetscSectionGetPointSyms(section->field[field], numPoints, points, perms, rots));
3426:   PetscFunctionReturn(PETSC_SUCCESS);
3427: }

3429: /*@C
3430:   PetscSectionRestoreFieldPointSyms - Restore the symmetries returned by `PetscSectionGetFieldPointSyms()`

3432:   Not Collective

3434:   Input Parameters:
3435: + section - the section
3436: . field - the field number
3437: . numPoints - the number of points
3438: - points - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an
3439:     arbitrary integer: its interpretation is up to sym.  Orientations are used by `DM`: for their interpretation in that
3440:     context, see `DMPlexGetConeOrientation()`).
3441: . perms - The permutations for the given orientations: set to NULL at conclusion
3442: - rots - The field rotations symmetries for the given orientations: set to NULL at conclusion

3444:   Level: developer

3446: .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionRestorePointSyms()`, `petscSectionGetFieldPointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`
3447: @*/
3448: PetscErrorCode PetscSectionRestoreFieldPointSyms(PetscSection section, PetscInt field, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots)
3449: {
3450:   PetscFunctionBegin;
3452:   PetscCheck(field <= section->numFields, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "field %" PetscInt_FMT " greater than number of fields (%" PetscInt_FMT ") in section", field, section->numFields);
3453:   PetscCall(PetscSectionRestorePointSyms(section->field[field], numPoints, points, perms, rots));
3454:   PetscFunctionReturn(PETSC_SUCCESS);
3455: }

3457: /*@
3458:   PetscSectionSymCopy - Copy the symmetries, assuming that the point structure is compatible

3460:   Not Collective

3462:   Input Parameter:
3463: . sym - the `PetscSectionSym`

3465:   Output Parameter:
3466: . nsym - the equivalent symmetries

3468:   Level: developer

3470: .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`, `PetscSectionSymLabelSetStratum()`, `PetscSectionGetPointSyms()`
3471: @*/
3472: PetscErrorCode PetscSectionSymCopy(PetscSectionSym sym, PetscSectionSym nsym)
3473: {
3474:   PetscFunctionBegin;
3477:   PetscTryTypeMethod(sym, copy, nsym);
3478:   PetscFunctionReturn(PETSC_SUCCESS);
3479: }

3481: /*@
3482:   PetscSectionSymDistribute - Distribute the symmetries in accordance with the input `PetscSF`

3484:   Collective

3486:   Input Parameters:
3487: + sym - the `PetscSectionSym`
3488: - migrationSF - the distribution map from roots to leaves

3490:   Output Parameter:
3491: . dsym - the redistributed symmetries

3493:   Level: developer

3495: .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`, `PetscSectionSymLabelSetStratum()`, `PetscSectionGetPointSyms()`
3496: @*/
3497: PetscErrorCode PetscSectionSymDistribute(PetscSectionSym sym, PetscSF migrationSF, PetscSectionSym *dsym)
3498: {
3499:   PetscFunctionBegin;
3503:   PetscTryTypeMethod(sym, distribute, migrationSF, dsym);
3504:   PetscFunctionReturn(PETSC_SUCCESS);
3505: }

3507: /*@
3508:   PetscSectionGetUseFieldOffsets - Get the flag indicating if field offsets are used directly in a global section, rather than just the point offset

3510:   Not Collective

3512:   Input Parameter:
3513: . s - the global `PetscSection`

3515:   Output Parameter:
3516: . flg - the flag

3518:   Level: developer

3520: .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSetChart()`, `PetscSectionCreate()`
3521: @*/
3522: PetscErrorCode PetscSectionGetUseFieldOffsets(PetscSection s, PetscBool *flg)
3523: {
3524:   PetscFunctionBegin;
3526:   *flg = s->useFieldOff;
3527:   PetscFunctionReturn(PETSC_SUCCESS);
3528: }

3530: /*@
3531:   PetscSectionSetUseFieldOffsets - Set the flag to use field offsets directly in a global section, rather than just the point offset

3533:   Not Collective

3535:   Input Parameters:
3536: + s   - the global `PetscSection`
3537: - flg - the flag

3539:   Level: developer

3541: .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetUseFieldOffsets()`, `PetscSectionSetChart()`, `PetscSectionCreate()`
3542: @*/
3543: PetscErrorCode PetscSectionSetUseFieldOffsets(PetscSection s, PetscBool flg)
3544: {
3545:   PetscFunctionBegin;
3547:   s->useFieldOff = flg;
3548:   PetscFunctionReturn(PETSC_SUCCESS);
3549: }

3551: #define PetscSectionExpandPoints_Loop(TYPE) \
3552:   { \
3553:     PetscInt i, n, o0, o1, size; \
3554:     TYPE    *a0 = (TYPE *)origArray, *a1; \
3555:     PetscCall(PetscSectionGetStorageSize(s, &size)); \
3556:     PetscCall(PetscMalloc1(size, &a1)); \
3557:     for (i = 0; i < npoints; i++) { \
3558:       PetscCall(PetscSectionGetOffset(origSection, points_[i], &o0)); \
3559:       PetscCall(PetscSectionGetOffset(s, i, &o1)); \
3560:       PetscCall(PetscSectionGetDof(s, i, &n)); \
3561:       PetscCall(PetscMemcpy(&a1[o1], &a0[o0], n *unitsize)); \
3562:     } \
3563:     *newArray = (void *)a1; \
3564:   }

3566: /*@
3567:   PetscSectionExtractDofsFromArray - Extracts elements of an array corresponding to DOFs of specified points.

3569:   Not Collective

3571:   Input Parameters:
3572: + origSection - the `PetscSection` describing the layout of the array
3573: . dataType - `MPI_Datatype` describing the data type of the array (currently only `MPIU_INT`, `MPIU_SCALAR`, `MPIU_REAL`)
3574: . origArray - the array; its size must be equal to the storage size of `origSection`
3575: - points - `IS` with points to extract; its indices must lie in the chart of `origSection`

3577:   Output Parameters:
3578: + newSection - the new `PetscSection` describing the layout of the new array (with points renumbered 0,1,... but preserving numbers of DOFs)
3579: - newArray - the array of the extracted DOFs; its size is the storage size of `newSection`

3581:   Level: developer

3583: .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetChart()`, `PetscSectionGetDof()`, `PetscSectionGetStorageSize()`, `PetscSectionCreate()`
3584: @*/
3585: PetscErrorCode PetscSectionExtractDofsFromArray(PetscSection origSection, MPI_Datatype dataType, const void *origArray, IS points, PetscSection *newSection, void *newArray[])
3586: {
3587:   PetscSection    s;
3588:   const PetscInt *points_;
3589:   PetscInt        i, n, npoints, pStart, pEnd;
3590:   PetscMPIInt     unitsize;

3592:   PetscFunctionBegin;
3598:   PetscCallMPI(MPI_Type_size(dataType, &unitsize));
3599:   PetscCall(ISGetLocalSize(points, &npoints));
3600:   PetscCall(ISGetIndices(points, &points_));
3601:   PetscCall(PetscSectionGetChart(origSection, &pStart, &pEnd));
3602:   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s));
3603:   PetscCall(PetscSectionSetChart(s, 0, npoints));
3604:   for (i = 0; i < npoints; i++) {
3605:     PetscCheck(points_[i] >= pStart && points_[i] < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "point %" PetscInt_FMT " (index %" PetscInt_FMT ") in input IS out of input section's chart", points_[i], i);
3606:     PetscCall(PetscSectionGetDof(origSection, points_[i], &n));
3607:     PetscCall(PetscSectionSetDof(s, i, n));
3608:   }
3609:   PetscCall(PetscSectionSetUp(s));
3610:   if (newArray) {
3611:     if (dataType == MPIU_INT) {
3612:       PetscSectionExpandPoints_Loop(PetscInt);
3613:     } else if (dataType == MPIU_SCALAR) {
3614:       PetscSectionExpandPoints_Loop(PetscScalar);
3615:     } else if (dataType == MPIU_REAL) {
3616:       PetscSectionExpandPoints_Loop(PetscReal);
3617:     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "not implemented for this MPI_Datatype");
3618:   }
3619:   if (newSection) {
3620:     *newSection = s;
3621:   } else {
3622:     PetscCall(PetscSectionDestroy(&s));
3623:   }
3624:   PetscCall(ISRestoreIndices(points, &points_));
3625:   PetscFunctionReturn(PETSC_SUCCESS);
3626: }