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