1 #include <petscvec.h>
2 #include <petsc/private/dmimpl.h> /*I "petscdm.h" I*/
3 #include <petsc/private/dmlabelimpl.h> /*I "petscdmlabel.h" I*/
4 #include <petsc/private/petscdsimpl.h> /*I "petscds.h" I*/
5 #include <petscdmplex.h>
6 #include <petscdmceed.h>
7 #include <petscdmfield.h>
8 #include <petscsf.h>
9 #include <petscds.h>
10
11 #ifdef PETSC_HAVE_LIBCEED
12 #include <petscfeceed.h>
13 #endif
14
15 PetscClassId DM_CLASSID;
16 PetscClassId DMLABEL_CLASSID;
17 PetscLogEvent DM_Convert, DM_GlobalToLocal, DM_LocalToGlobal, DM_LocalToLocal, DM_LocatePoints, DM_Coarsen, DM_Refine, DM_CreateInterpolation, DM_CreateRestriction, DM_CreateInjection, DM_CreateMatrix, DM_CreateMassMatrix, DM_Load, DM_View, DM_AdaptInterpolator, DM_ProjectFunction;
18
19 const char *const DMBoundaryTypes[] = {"NONE", "GHOSTED", "MIRROR", "PERIODIC", "TWIST", "DMBoundaryType", "DM_BOUNDARY_", NULL};
20 const char *const DMBoundaryConditionTypes[] = {"INVALID", "ESSENTIAL", "NATURAL", "INVALID", "LOWER_BOUND", "ESSENTIAL_FIELD", "NATURAL_FIELD", "INVALID", "UPPER_BOUND", "ESSENTIAL_BD_FIELD", "NATURAL_RIEMANN", "DMBoundaryConditionType",
21 "DM_BC_", NULL};
22 const char *const DMBlockingTypes[] = {"TOPOLOGICAL_POINT", "FIELD_NODE", "DMBlockingType", "DM_BLOCKING_", NULL};
23 const char *const DMPolytopeTypes[] =
24 {"vertex", "segment", "tensor_segment", "triangle", "quadrilateral", "tensor_quad", "tetrahedron", "hexahedron", "triangular_prism", "tensor_triangular_prism", "tensor_quadrilateral_prism", "pyramid", "FV_ghost_cell", "interior_ghost_cell",
25 "unknown", "unknown_cell", "unknown_face", "invalid", "DMPolytopeType", "DM_POLYTOPE_", NULL};
26 const char *const DMCopyLabelsModes[] = {"replace", "keep", "fail", "DMCopyLabelsMode", "DM_COPY_LABELS_", NULL};
27
28 /*@
29 DMCreate - Creates an empty `DM` object. `DM`s are the abstract objects in PETSc that mediate between meshes and discretizations and the
30 algebraic solvers, time integrators, and optimization algorithms in PETSc.
31
32 Collective
33
34 Input Parameter:
35 . comm - The communicator for the `DM` object
36
37 Output Parameter:
38 . dm - The `DM` object
39
40 Level: beginner
41
42 Notes:
43 See `DMType` for a brief summary of available `DM`.
44
45 The type must then be set with `DMSetType()`. If you never call `DMSetType()` it will generate an
46 error when you try to use the `dm`.
47
48 `DM` is an orphan initialism or orphan acronym, the letters have no meaning and never did.
49
50 .seealso: [](ch_dmbase), `DM`, `DMSetType()`, `DMType`, `DMDACreate()`, `DMDA`, `DMSLICED`, `DMCOMPOSITE`, `DMPLEX`, `DMMOAB`, `DMNETWORK`
51 @*/
DMCreate(MPI_Comm comm,DM * dm)52 PetscErrorCode DMCreate(MPI_Comm comm, DM *dm)
53 {
54 DM v;
55 PetscDS ds;
56
57 PetscFunctionBegin;
58 PetscAssertPointer(dm, 2);
59
60 PetscCall(DMInitializePackage());
61 PetscCall(PetscHeaderCreate(v, DM_CLASSID, "DM", "Distribution Manager", "DM", comm, DMDestroy, DMView));
62 ((PetscObject)v)->non_cyclic_references = &DMCountNonCyclicReferences;
63 v->setupcalled = PETSC_FALSE;
64 v->setfromoptionscalled = PETSC_FALSE;
65 v->ltogmap = NULL;
66 v->bind_below = 0;
67 v->bs = 1;
68 v->coloringtype = IS_COLORING_GLOBAL;
69 PetscCall(PetscSFCreate(comm, &v->sf));
70 PetscCall(PetscSFCreate(comm, &v->sectionSF));
71 v->labels = NULL;
72 v->adjacency[0] = PETSC_FALSE;
73 v->adjacency[1] = PETSC_TRUE;
74 v->depthLabel = NULL;
75 v->celltypeLabel = NULL;
76 v->localSection = NULL;
77 v->globalSection = NULL;
78 v->defaultConstraint.section = NULL;
79 v->defaultConstraint.mat = NULL;
80 v->defaultConstraint.bias = NULL;
81 v->coordinates[0].dim = PETSC_DEFAULT;
82 v->coordinates[1].dim = PETSC_DEFAULT;
83 v->sparseLocalize = PETSC_TRUE;
84 v->dim = PETSC_DETERMINE;
85 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds));
86 PetscCall(DMSetRegionDS(v, NULL, NULL, ds, NULL));
87 PetscCall(PetscDSDestroy(&ds));
88 PetscCall(PetscHMapAuxCreate(&v->auxData));
89 v->dmBC = NULL;
90 v->coarseMesh = NULL;
91 v->outputSequenceNum = -1;
92 v->outputSequenceVal = 0.0;
93 PetscCall(DMSetVecType(v, VECSTANDARD));
94 PetscCall(DMSetMatType(v, MATAIJ));
95
96 *dm = v;
97 PetscFunctionReturn(PETSC_SUCCESS);
98 }
99
100 /*@
101 DMClone - Creates a `DM` object with the same topology as the original.
102
103 Collective
104
105 Input Parameter:
106 . dm - The original `DM` object
107
108 Output Parameter:
109 . newdm - The new `DM` object
110
111 Level: beginner
112
113 Notes:
114 For some `DM` implementations this is a shallow clone, the result of which may share (reference counted) information with its parent. For example,
115 `DMClone()` applied to a `DMPLEX` object will result in a new `DMPLEX` that shares the topology with the original `DMPLEX`. It does not
116 share the `PetscSection` of the original `DM`.
117
118 The clone is considered set up if the original has been set up.
119
120 Use `DMConvert()` for a general way to create new `DM` from a given `DM`
121
122 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMCreate()`, `DMSetType()`, `DMSetLocalSection()`, `DMSetGlobalSection()`, `DMPLEX`, `DMConvert()`
123 @*/
DMClone(DM dm,DM * newdm)124 PetscErrorCode DMClone(DM dm, DM *newdm)
125 {
126 PetscSF sf;
127 Vec coords;
128 void *ctx;
129 MatOrderingType otype;
130 DMReorderDefaultFlag flg;
131 PetscInt dim, cdim, i;
132
133 PetscFunctionBegin;
134 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
135 PetscAssertPointer(newdm, 2);
136 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), newdm));
137 PetscCall(DMCopyLabels(dm, *newdm, PETSC_COPY_VALUES, PETSC_TRUE, DM_COPY_LABELS_FAIL));
138 (*newdm)->leveldown = dm->leveldown;
139 (*newdm)->levelup = dm->levelup;
140 (*newdm)->prealloc_only = dm->prealloc_only;
141 (*newdm)->prealloc_skip = dm->prealloc_skip;
142 PetscCall(PetscFree((*newdm)->vectype));
143 PetscCall(PetscStrallocpy(dm->vectype, (char **)&(*newdm)->vectype));
144 PetscCall(PetscFree((*newdm)->mattype));
145 PetscCall(PetscStrallocpy(dm->mattype, (char **)&(*newdm)->mattype));
146 PetscCall(DMGetDimension(dm, &dim));
147 PetscCall(DMSetDimension(*newdm, dim));
148 PetscTryTypeMethod(dm, clone, newdm);
149 (*newdm)->setupcalled = dm->setupcalled;
150 PetscCall(DMGetPointSF(dm, &sf));
151 PetscCall(DMSetPointSF(*newdm, sf));
152 PetscCall(DMGetApplicationContext(dm, &ctx));
153 PetscCall(DMSetApplicationContext(*newdm, ctx));
154 PetscCall(DMReorderSectionGetDefault(dm, &flg));
155 PetscCall(DMReorderSectionSetDefault(*newdm, flg));
156 PetscCall(DMReorderSectionGetType(dm, &otype));
157 PetscCall(DMReorderSectionSetType(*newdm, otype));
158 for (i = 0; i < 2; ++i) {
159 if (dm->coordinates[i].dm) {
160 DM ncdm;
161 PetscSection cs;
162 PetscInt pEnd = -1, pEndMax = -1;
163
164 PetscCall(DMGetLocalSection(dm->coordinates[i].dm, &cs));
165 if (cs) PetscCall(PetscSectionGetChart(cs, NULL, &pEnd));
166 PetscCallMPI(MPIU_Allreduce(&pEnd, &pEndMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
167 if (pEndMax >= 0) {
168 PetscCall(DMClone(dm->coordinates[i].dm, &ncdm));
169 PetscCall(DMCopyDisc(dm->coordinates[i].dm, ncdm));
170 PetscCall(DMSetLocalSection(ncdm, cs));
171 if (dm->coordinates[i].dm->periodic.setup) {
172 ncdm->periodic.setup = dm->coordinates[i].dm->periodic.setup;
173 PetscCall(ncdm->periodic.setup(ncdm));
174 }
175 if (i) PetscCall(DMSetCellCoordinateDM(*newdm, ncdm));
176 else PetscCall(DMSetCoordinateDM(*newdm, ncdm));
177 PetscCall(DMDestroy(&ncdm));
178 }
179 }
180 }
181 PetscCall(DMGetCoordinateDim(dm, &cdim));
182 PetscCall(DMSetCoordinateDim(*newdm, cdim));
183 PetscCall(DMGetCoordinatesLocal(dm, &coords));
184 if (coords) {
185 PetscCall(DMSetCoordinatesLocal(*newdm, coords));
186 } else {
187 PetscCall(DMGetCoordinates(dm, &coords));
188 if (coords) PetscCall(DMSetCoordinates(*newdm, coords));
189 }
190 PetscCall(DMGetCellCoordinatesLocal(dm, &coords));
191 if (coords) {
192 PetscCall(DMSetCellCoordinatesLocal(*newdm, coords));
193 } else {
194 PetscCall(DMGetCellCoordinates(dm, &coords));
195 if (coords) PetscCall(DMSetCellCoordinates(*newdm, coords));
196 }
197 {
198 const PetscReal *maxCell, *Lstart, *L;
199
200 PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
201 PetscCall(DMSetPeriodicity(*newdm, maxCell, Lstart, L));
202 }
203 {
204 PetscBool useCone, useClosure;
205
206 PetscCall(DMGetAdjacency(dm, PETSC_DEFAULT, &useCone, &useClosure));
207 PetscCall(DMSetAdjacency(*newdm, PETSC_DEFAULT, useCone, useClosure));
208 }
209 PetscFunctionReturn(PETSC_SUCCESS);
210 }
211
212 /*@
213 DMSetVecType - Sets the type of vector to be created with `DMCreateLocalVector()` and `DMCreateGlobalVector()`
214
215 Logically Collective
216
217 Input Parameters:
218 + dm - initial distributed array
219 - ctype - the vector type, for example `VECSTANDARD`, `VECCUDA`, or `VECVIENNACL`
220
221 Options Database Key:
222 . -dm_vec_type ctype - the type of vector to create
223
224 Level: intermediate
225
226 .seealso: [](ch_dmbase), `DM`, `DMCreate()`, `DMDestroy()`, `DMDAInterpolationType`, `VecType`, `DMGetVecType()`, `DMSetMatType()`, `DMGetMatType()`,
227 `VECSTANDARD`, `VECCUDA`, `VECVIENNACL`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`
228 @*/
DMSetVecType(DM dm,VecType ctype)229 PetscErrorCode DMSetVecType(DM dm, VecType ctype)
230 {
231 char *tmp;
232
233 PetscFunctionBegin;
234 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
235 PetscAssertPointer(ctype, 2);
236 tmp = (char *)dm->vectype;
237 PetscCall(PetscStrallocpy(ctype, (char **)&dm->vectype));
238 PetscCall(PetscFree(tmp));
239 PetscFunctionReturn(PETSC_SUCCESS);
240 }
241
242 /*@
243 DMGetVecType - Gets the type of vector created with `DMCreateLocalVector()` and `DMCreateGlobalVector()`
244
245 Logically Collective
246
247 Input Parameter:
248 . da - initial distributed array
249
250 Output Parameter:
251 . ctype - the vector type
252
253 Level: intermediate
254
255 .seealso: [](ch_dmbase), `DM`, `DMCreate()`, `DMDestroy()`, `DMDAInterpolationType`, `VecType`, `DMSetMatType()`, `DMGetMatType()`, `DMSetVecType()`
256 @*/
DMGetVecType(DM da,VecType * ctype)257 PetscErrorCode DMGetVecType(DM da, VecType *ctype)
258 {
259 PetscFunctionBegin;
260 PetscValidHeaderSpecific(da, DM_CLASSID, 1);
261 *ctype = da->vectype;
262 PetscFunctionReturn(PETSC_SUCCESS);
263 }
264
265 /*@
266 VecGetDM - Gets the `DM` defining the data layout of the vector
267
268 Not Collective
269
270 Input Parameter:
271 . v - The `Vec`
272
273 Output Parameter:
274 . dm - The `DM`
275
276 Level: intermediate
277
278 Note:
279 A `Vec` may not have a `DM` associated with it.
280
281 .seealso: [](ch_dmbase), `DM`, `VecSetDM()`, `DMGetLocalVector()`, `DMGetGlobalVector()`, `DMSetVecType()`
282 @*/
VecGetDM(Vec v,DM * dm)283 PetscErrorCode VecGetDM(Vec v, DM *dm)
284 {
285 PetscFunctionBegin;
286 PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
287 PetscAssertPointer(dm, 2);
288 PetscCall(PetscObjectQuery((PetscObject)v, "__PETSc_dm", (PetscObject *)dm));
289 PetscFunctionReturn(PETSC_SUCCESS);
290 }
291
292 /*@
293 VecSetDM - Sets the `DM` defining the data layout of the vector.
294
295 Not Collective
296
297 Input Parameters:
298 + v - The `Vec`
299 - dm - The `DM`
300
301 Level: developer
302
303 Notes:
304 This is rarely used, generally one uses `DMGetLocalVector()` or `DMGetGlobalVector()` to create a vector associated with a given `DM`
305
306 This is NOT the same as `DMCreateGlobalVector()` since it does not change the view methods or perform other customization, but merely sets the `DM` member.
307
308 .seealso: [](ch_dmbase), `DM`, `VecGetDM()`, `DMGetLocalVector()`, `DMGetGlobalVector()`, `DMSetVecType()`
309 @*/
VecSetDM(Vec v,DM dm)310 PetscErrorCode VecSetDM(Vec v, DM dm)
311 {
312 PetscFunctionBegin;
313 PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
314 if (dm) PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
315 PetscCall(PetscObjectCompose((PetscObject)v, "__PETSc_dm", (PetscObject)dm));
316 PetscFunctionReturn(PETSC_SUCCESS);
317 }
318
319 /*@
320 DMSetISColoringType - Sets the type of coloring, `IS_COLORING_GLOBAL` or `IS_COLORING_LOCAL` that is created by the `DM`
321
322 Logically Collective
323
324 Input Parameters:
325 + dm - the `DM` context
326 - ctype - the matrix type
327
328 Options Database Key:
329 . -dm_is_coloring_type - global or local
330
331 Level: intermediate
332
333 .seealso: [](ch_dmbase), `DM`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMGetMatType()`,
334 `DMGetISColoringType()`, `ISColoringType`, `IS_COLORING_GLOBAL`, `IS_COLORING_LOCAL`
335 @*/
DMSetISColoringType(DM dm,ISColoringType ctype)336 PetscErrorCode DMSetISColoringType(DM dm, ISColoringType ctype)
337 {
338 PetscFunctionBegin;
339 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
340 dm->coloringtype = ctype;
341 PetscFunctionReturn(PETSC_SUCCESS);
342 }
343
344 /*@
345 DMGetISColoringType - Gets the type of coloring, `IS_COLORING_GLOBAL` or `IS_COLORING_LOCAL` that is created by the `DM`
346
347 Logically Collective
348
349 Input Parameter:
350 . dm - the `DM` context
351
352 Output Parameter:
353 . ctype - the matrix type
354
355 Options Database Key:
356 . -dm_is_coloring_type - global or local
357
358 Level: intermediate
359
360 .seealso: [](ch_dmbase), `DM`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMGetMatType()`,
361 `ISColoringType`, `IS_COLORING_GLOBAL`, `IS_COLORING_LOCAL`
362 @*/
DMGetISColoringType(DM dm,ISColoringType * ctype)363 PetscErrorCode DMGetISColoringType(DM dm, ISColoringType *ctype)
364 {
365 PetscFunctionBegin;
366 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
367 *ctype = dm->coloringtype;
368 PetscFunctionReturn(PETSC_SUCCESS);
369 }
370
371 /*@
372 DMSetMatType - Sets the type of matrix created with `DMCreateMatrix()`
373
374 Logically Collective
375
376 Input Parameters:
377 + dm - the `DM` context
378 - ctype - the matrix type, for example `MATMPIAIJ`
379
380 Options Database Key:
381 . -dm_mat_type ctype - the type of the matrix to create, for example mpiaij
382
383 Level: intermediate
384
385 .seealso: [](ch_dmbase), `DM`, `MatType`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `DMGetMatType()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`
386 @*/
DMSetMatType(DM dm,MatType ctype)387 PetscErrorCode DMSetMatType(DM dm, MatType ctype)
388 {
389 char *tmp;
390
391 PetscFunctionBegin;
392 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
393 PetscAssertPointer(ctype, 2);
394 tmp = (char *)dm->mattype;
395 PetscCall(PetscStrallocpy(ctype, (char **)&dm->mattype));
396 PetscCall(PetscFree(tmp));
397 PetscFunctionReturn(PETSC_SUCCESS);
398 }
399
400 /*@
401 DMGetMatType - Gets the type of matrix that would be created with `DMCreateMatrix()`
402
403 Logically Collective
404
405 Input Parameter:
406 . dm - the `DM` context
407
408 Output Parameter:
409 . ctype - the matrix type
410
411 Level: intermediate
412
413 .seealso: [](ch_dmbase), `DM`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMSetMatType()`
414 @*/
DMGetMatType(DM dm,MatType * ctype)415 PetscErrorCode DMGetMatType(DM dm, MatType *ctype)
416 {
417 PetscFunctionBegin;
418 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
419 *ctype = dm->mattype;
420 PetscFunctionReturn(PETSC_SUCCESS);
421 }
422
423 /*@
424 MatGetDM - Gets the `DM` defining the data layout of the matrix
425
426 Not Collective
427
428 Input Parameter:
429 . A - The `Mat`
430
431 Output Parameter:
432 . dm - The `DM`
433
434 Level: intermediate
435
436 Note:
437 A matrix may not have a `DM` associated with it
438
439 Developer Note:
440 Since the `Mat` class doesn't know about the `DM` class the `DM` object is associated with the `Mat` through a `PetscObjectCompose()` operation
441
442 .seealso: [](ch_dmbase), `DM`, `MatSetDM()`, `DMCreateMatrix()`, `DMSetMatType()`
443 @*/
MatGetDM(Mat A,DM * dm)444 PetscErrorCode MatGetDM(Mat A, DM *dm)
445 {
446 PetscFunctionBegin;
447 PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
448 PetscAssertPointer(dm, 2);
449 PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_dm", (PetscObject *)dm));
450 PetscFunctionReturn(PETSC_SUCCESS);
451 }
452
453 /*@
454 MatSetDM - Sets the `DM` defining the data layout of the matrix
455
456 Not Collective
457
458 Input Parameters:
459 + A - The `Mat`
460 - dm - The `DM`
461
462 Level: developer
463
464 Note:
465 This is rarely used in practice, rather `DMCreateMatrix()` is used to create a matrix associated with a particular `DM`
466
467 Developer Note:
468 Since the `Mat` class doesn't know about the `DM` class the `DM` object is associated with
469 the `Mat` through a `PetscObjectCompose()` operation
470
471 .seealso: [](ch_dmbase), `DM`, `MatGetDM()`, `DMCreateMatrix()`, `DMSetMatType()`
472 @*/
MatSetDM(Mat A,DM dm)473 PetscErrorCode MatSetDM(Mat A, DM dm)
474 {
475 PetscFunctionBegin;
476 PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
477 if (dm) PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
478 PetscCall(PetscObjectCompose((PetscObject)A, "__PETSc_dm", (PetscObject)dm));
479 PetscFunctionReturn(PETSC_SUCCESS);
480 }
481
482 /*@
483 DMSetOptionsPrefix - Sets the prefix prepended to all option names when searching through the options database
484
485 Logically Collective
486
487 Input Parameters:
488 + dm - the `DM` context
489 - prefix - the prefix to prepend
490
491 Level: advanced
492
493 Note:
494 A hyphen (-) must NOT be given at the beginning of the prefix name.
495 The first character of all runtime options is AUTOMATICALLY the hyphen.
496
497 .seealso: [](ch_dmbase), `DM`, `PetscObjectSetOptionsPrefix()`, `DMSetFromOptions()`
498 @*/
DMSetOptionsPrefix(DM dm,const char prefix[])499 PetscErrorCode DMSetOptionsPrefix(DM dm, const char prefix[])
500 {
501 PetscFunctionBegin;
502 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
503 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, prefix));
504 if (dm->sf) PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm->sf, prefix));
505 if (dm->sectionSF) PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm->sectionSF, prefix));
506 PetscFunctionReturn(PETSC_SUCCESS);
507 }
508
509 /*@
510 DMAppendOptionsPrefix - Appends an additional string to an already existing prefix used for searching for
511 `DM` options in the options database.
512
513 Logically Collective
514
515 Input Parameters:
516 + dm - the `DM` context
517 - prefix - the string to append to the current prefix
518
519 Level: advanced
520
521 Note:
522 If the `DM` does not currently have an options prefix then this value is used alone as the prefix as if `DMSetOptionsPrefix()` had been called.
523 A hyphen (-) must NOT be given at the beginning of the prefix name.
524 The first character of all runtime options is AUTOMATICALLY the hyphen.
525
526 .seealso: [](ch_dmbase), `DM`, `DMSetOptionsPrefix()`, `DMGetOptionsPrefix()`, `PetscObjectAppendOptionsPrefix()`, `DMSetFromOptions()`
527 @*/
DMAppendOptionsPrefix(DM dm,const char prefix[])528 PetscErrorCode DMAppendOptionsPrefix(DM dm, const char prefix[])
529 {
530 PetscFunctionBegin;
531 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
532 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)dm, prefix));
533 PetscFunctionReturn(PETSC_SUCCESS);
534 }
535
536 /*@
537 DMGetOptionsPrefix - Gets the prefix used for searching for all
538 DM options in the options database.
539
540 Not Collective
541
542 Input Parameter:
543 . dm - the `DM` context
544
545 Output Parameter:
546 . prefix - pointer to the prefix string used is returned
547
548 Level: advanced
549
550 .seealso: [](ch_dmbase), `DM`, `DMSetOptionsPrefix()`, `DMAppendOptionsPrefix()`, `DMSetFromOptions()`
551 @*/
DMGetOptionsPrefix(DM dm,const char * prefix[])552 PetscErrorCode DMGetOptionsPrefix(DM dm, const char *prefix[])
553 {
554 PetscFunctionBegin;
555 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
556 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, prefix));
557 PetscFunctionReturn(PETSC_SUCCESS);
558 }
559
DMCountNonCyclicReferences_Internal(DM dm,PetscBool recurseCoarse,PetscBool recurseFine,PetscInt * ncrefct)560 static PetscErrorCode DMCountNonCyclicReferences_Internal(DM dm, PetscBool recurseCoarse, PetscBool recurseFine, PetscInt *ncrefct)
561 {
562 PetscInt refct = ((PetscObject)dm)->refct;
563
564 PetscFunctionBegin;
565 *ncrefct = 0;
566 if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
567 refct--;
568 if (recurseCoarse) {
569 PetscInt coarseCount;
570
571 PetscCall(DMCountNonCyclicReferences_Internal(dm->coarseMesh, PETSC_TRUE, PETSC_FALSE, &coarseCount));
572 refct += coarseCount;
573 }
574 }
575 if (dm->fineMesh && dm->fineMesh->coarseMesh == dm) {
576 refct--;
577 if (recurseFine) {
578 PetscInt fineCount;
579
580 PetscCall(DMCountNonCyclicReferences_Internal(dm->fineMesh, PETSC_FALSE, PETSC_TRUE, &fineCount));
581 refct += fineCount;
582 }
583 }
584 *ncrefct = refct;
585 PetscFunctionReturn(PETSC_SUCCESS);
586 }
587
588 /* Generic wrapper for DMCountNonCyclicReferences_Internal() */
DMCountNonCyclicReferences(PetscObject dm,PetscInt * ncrefct)589 PetscErrorCode DMCountNonCyclicReferences(PetscObject dm, PetscInt *ncrefct)
590 {
591 PetscFunctionBegin;
592 PetscCall(DMCountNonCyclicReferences_Internal((DM)dm, PETSC_TRUE, PETSC_TRUE, ncrefct));
593 PetscFunctionReturn(PETSC_SUCCESS);
594 }
595
DMDestroyLabelLinkList_Internal(DM dm)596 PetscErrorCode DMDestroyLabelLinkList_Internal(DM dm)
597 {
598 DMLabelLink next = dm->labels;
599
600 PetscFunctionBegin;
601 /* destroy the labels */
602 while (next) {
603 DMLabelLink tmp = next->next;
604
605 if (next->label == dm->depthLabel) dm->depthLabel = NULL;
606 if (next->label == dm->celltypeLabel) dm->celltypeLabel = NULL;
607 PetscCall(DMLabelDestroy(&next->label));
608 PetscCall(PetscFree(next));
609 next = tmp;
610 }
611 dm->labels = NULL;
612 PetscFunctionReturn(PETSC_SUCCESS);
613 }
614
DMDestroyCoordinates_Private(DMCoordinates * c)615 static PetscErrorCode DMDestroyCoordinates_Private(DMCoordinates *c)
616 {
617 PetscFunctionBegin;
618 c->dim = PETSC_DEFAULT;
619 PetscCall(DMDestroy(&c->dm));
620 PetscCall(VecDestroy(&c->x));
621 PetscCall(VecDestroy(&c->xl));
622 PetscCall(DMFieldDestroy(&c->field));
623 PetscFunctionReturn(PETSC_SUCCESS);
624 }
625
626 /*@
627 DMDestroy - Destroys a `DM`.
628
629 Collective
630
631 Input Parameter:
632 . dm - the `DM` object to destroy
633
634 Level: developer
635
636 .seealso: [](ch_dmbase), `DM`, `DMCreate()`, `DMType`, `DMSetType()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`
637 @*/
DMDestroy(DM * dm)638 PetscErrorCode DMDestroy(DM *dm)
639 {
640 PetscInt cnt;
641
642 PetscFunctionBegin;
643 if (!*dm) PetscFunctionReturn(PETSC_SUCCESS);
644 PetscValidHeaderSpecific(*dm, DM_CLASSID, 1);
645
646 /* count all non-cyclic references in the doubly-linked list of coarse<->fine meshes */
647 PetscCall(DMCountNonCyclicReferences_Internal(*dm, PETSC_TRUE, PETSC_TRUE, &cnt));
648 --((PetscObject)*dm)->refct;
649 if (--cnt > 0) {
650 *dm = NULL;
651 PetscFunctionReturn(PETSC_SUCCESS);
652 }
653 if (((PetscObject)*dm)->refct < 0) PetscFunctionReturn(PETSC_SUCCESS);
654 ((PetscObject)*dm)->refct = 0;
655
656 PetscCall(DMClearGlobalVectors(*dm));
657 PetscCall(DMClearLocalVectors(*dm));
658 PetscCall(DMClearNamedGlobalVectors(*dm));
659 PetscCall(DMClearNamedLocalVectors(*dm));
660
661 /* Destroy the list of hooks */
662 {
663 DMCoarsenHookLink link, next;
664 for (link = (*dm)->coarsenhook; link; link = next) {
665 next = link->next;
666 PetscCall(PetscFree(link));
667 }
668 (*dm)->coarsenhook = NULL;
669 }
670 {
671 DMRefineHookLink link, next;
672 for (link = (*dm)->refinehook; link; link = next) {
673 next = link->next;
674 PetscCall(PetscFree(link));
675 }
676 (*dm)->refinehook = NULL;
677 }
678 {
679 DMSubDomainHookLink link, next;
680 for (link = (*dm)->subdomainhook; link; link = next) {
681 next = link->next;
682 PetscCall(PetscFree(link));
683 }
684 (*dm)->subdomainhook = NULL;
685 }
686 {
687 DMGlobalToLocalHookLink link, next;
688 for (link = (*dm)->gtolhook; link; link = next) {
689 next = link->next;
690 PetscCall(PetscFree(link));
691 }
692 (*dm)->gtolhook = NULL;
693 }
694 {
695 DMLocalToGlobalHookLink link, next;
696 for (link = (*dm)->ltoghook; link; link = next) {
697 next = link->next;
698 PetscCall(PetscFree(link));
699 }
700 (*dm)->ltoghook = NULL;
701 }
702 /* Destroy the work arrays */
703 {
704 DMWorkLink link, next;
705 PetscCheck(!(*dm)->workout, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Work array still checked out %p %p", (void *)(*dm)->workout, (*dm)->workout->mem);
706 for (link = (*dm)->workin; link; link = next) {
707 next = link->next;
708 PetscCall(PetscFree(link->mem));
709 PetscCall(PetscFree(link));
710 }
711 (*dm)->workin = NULL;
712 }
713 /* destroy the labels */
714 PetscCall(DMDestroyLabelLinkList_Internal(*dm));
715 /* destroy the fields */
716 PetscCall(DMClearFields(*dm));
717 /* destroy the boundaries */
718 {
719 DMBoundary next = (*dm)->boundary;
720 while (next) {
721 DMBoundary b = next;
722
723 next = b->next;
724 PetscCall(PetscFree(b));
725 }
726 }
727
728 PetscCall(PetscObjectDestroy(&(*dm)->dmksp));
729 PetscCall(PetscObjectDestroy(&(*dm)->dmsnes));
730 PetscCall(PetscObjectDestroy(&(*dm)->dmts));
731
732 if ((*dm)->ctx && (*dm)->ctxdestroy) PetscCall((*(*dm)->ctxdestroy)(&(*dm)->ctx));
733 PetscCall(MatFDColoringDestroy(&(*dm)->fd));
734 PetscCall(ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap));
735 PetscCall(PetscFree((*dm)->vectype));
736 PetscCall(PetscFree((*dm)->mattype));
737
738 PetscCall(PetscSectionDestroy(&(*dm)->localSection));
739 PetscCall(PetscSectionDestroy(&(*dm)->globalSection));
740 PetscCall(PetscFree((*dm)->reorderSectionType));
741 PetscCall(PetscLayoutDestroy(&(*dm)->map));
742 PetscCall(PetscSectionDestroy(&(*dm)->defaultConstraint.section));
743 PetscCall(MatDestroy(&(*dm)->defaultConstraint.mat));
744 PetscCall(PetscSFDestroy(&(*dm)->sf));
745 PetscCall(PetscSFDestroy(&(*dm)->sectionSF));
746 if ((*dm)->sfNatural) PetscCall(PetscSFDestroy(&(*dm)->sfNatural));
747 PetscCall(PetscObjectDereference((PetscObject)(*dm)->sfMigration));
748 PetscCall(DMClearAuxiliaryVec(*dm));
749 PetscCall(PetscHMapAuxDestroy(&(*dm)->auxData));
750 if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) PetscCall(DMSetFineDM((*dm)->coarseMesh, NULL));
751
752 PetscCall(DMDestroy(&(*dm)->coarseMesh));
753 if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) PetscCall(DMSetCoarseDM((*dm)->fineMesh, NULL));
754 PetscCall(DMDestroy(&(*dm)->fineMesh));
755 PetscCall(PetscFree((*dm)->Lstart));
756 PetscCall(PetscFree((*dm)->L));
757 PetscCall(PetscFree((*dm)->maxCell));
758 PetscCall(PetscFree2((*dm)->nullspaceConstructors, (*dm)->nearnullspaceConstructors));
759 PetscCall(DMDestroyCoordinates_Private(&(*dm)->coordinates[0]));
760 PetscCall(DMDestroyCoordinates_Private(&(*dm)->coordinates[1]));
761 if ((*dm)->transformDestroy) PetscCall((*(*dm)->transformDestroy)(*dm, (*dm)->transformCtx));
762 PetscCall(DMDestroy(&(*dm)->transformDM));
763 PetscCall(VecDestroy(&(*dm)->transform));
764 for (PetscInt i = 0; i < (*dm)->periodic.num_affines; i++) {
765 PetscCall(VecScatterDestroy(&(*dm)->periodic.affine_to_local[i]));
766 PetscCall(VecDestroy(&(*dm)->periodic.affine[i]));
767 }
768 if ((*dm)->periodic.num_affines > 0) PetscCall(PetscFree2((*dm)->periodic.affine_to_local, (*dm)->periodic.affine));
769
770 PetscCall(DMClearDS(*dm));
771 PetscCall(DMDestroy(&(*dm)->dmBC));
772 /* if memory was published with SAWs then destroy it */
773 PetscCall(PetscObjectSAWsViewOff((PetscObject)*dm));
774
775 PetscTryTypeMethod(*dm, destroy);
776 PetscCall(DMMonitorCancel(*dm));
777 PetscCall(DMCeedDestroy(&(*dm)->dmceed));
778 #ifdef PETSC_HAVE_LIBCEED
779 PetscCallCEED(CeedElemRestrictionDestroy(&(*dm)->ceedERestrict));
780 PetscCallCEED(CeedDestroy(&(*dm)->ceed));
781 #endif
782 /* We do not destroy (*dm)->data here so that we can reference count backend objects */
783 PetscCall(PetscHeaderDestroy(dm));
784 PetscFunctionReturn(PETSC_SUCCESS);
785 }
786
787 /*@
788 DMSetUp - sets up the data structures inside a `DM` object
789
790 Collective
791
792 Input Parameter:
793 . dm - the `DM` object to setup
794
795 Level: intermediate
796
797 Note:
798 This is usually called after various parameter setting operations and `DMSetFromOptions()` are called on the `DM`
799
800 .seealso: [](ch_dmbase), `DM`, `DMCreate()`, `DMSetType()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`
801 @*/
DMSetUp(DM dm)802 PetscErrorCode DMSetUp(DM dm)
803 {
804 PetscFunctionBegin;
805 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
806 if (dm->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
807 PetscTryTypeMethod(dm, setup);
808 dm->setupcalled = PETSC_TRUE;
809 PetscFunctionReturn(PETSC_SUCCESS);
810 }
811
812 /*@
813 DMSetFromOptions - sets parameters in a `DM` from the options database
814
815 Collective
816
817 Input Parameter:
818 . dm - the `DM` object to set options for
819
820 Options Database Keys:
821 + -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()` and `DMCreateMassMatrix()`, but do not fill it with zeros
822 . -dm_vec_type <type> - type of vector to create inside `DM`
823 . -dm_mat_type <type> - type of matrix to create inside `DM`
824 . -dm_is_coloring_type - <global or local>
825 . -dm_bind_below <n> - bind (force execution on CPU) for `Vec` and `Mat` objects with local size (number of vector entries or matrix rows) below n; currently only supported for `DMDA`
826 . -dm_plex_option_phases <ph0_, ph1_, ...> - List of prefixes for option processing phases
827 . -dm_plex_filename <str> - File containing a mesh
828 . -dm_plex_boundary_filename <str> - File containing a mesh boundary
829 . -dm_plex_name <str> - Name of the mesh in the file
830 . -dm_plex_shape <shape> - The domain shape, such as `BOX`, `SPHERE`, etc.
831 . -dm_plex_cell <ct> - Cell shape
832 . -dm_plex_reference_cell_domain <bool> - Use a reference cell domain
833 . -dm_plex_dim <dim> - Set the topological dimension
834 . -dm_plex_simplex <bool> - `PETSC_TRUE` for simplex elements, `PETSC_FALSE` for tensor elements
835 . -dm_plex_interpolate <bool> - `PETSC_TRUE` turns on topological interpolation (creating edges and faces)
836 . -dm_plex_orient <bool> - `PETSC_TRUE` turns on topological orientation (flipping edges and faces)
837 . -dm_plex_scale <sc> - Scale factor for mesh coordinates
838 . -dm_coord_remap <bool> - Map coordinates using a function
839 . -dm_plex_coordinate_dim <dim> - Change the coordinate dimension of a mesh (usually given with cdm_ prefix)
840 . -dm_coord_map <mapname> - Select a builtin coordinate map
841 . -dm_coord_map_params <p0,p1,p2,...> - Set coordinate mapping parameters
842 . -dm_plex_box_faces <m,n,p> - Number of faces along each dimension
843 . -dm_plex_box_lower <x,y,z> - Specify lower-left-bottom coordinates for the box
844 . -dm_plex_box_upper <x,y,z> - Specify upper-right-top coordinates for the box
845 . -dm_plex_box_bd <bx,by,bz> - Specify the `DMBoundaryType` for each direction
846 . -dm_plex_sphere_radius <r> - The sphere radius
847 . -dm_plex_ball_radius <r> - Radius of the ball
848 . -dm_plex_cylinder_bd <bz> - Boundary type in the z direction
849 . -dm_plex_cylinder_num_wedges <n> - Number of wedges around the cylinder
850 . -dm_plex_reorder <order> - Reorder the mesh using the specified algorithm
851 . -dm_refine_pre <n> - The number of refinements before distribution
852 . -dm_refine_uniform_pre <bool> - Flag for uniform refinement before distribution
853 . -dm_refine_volume_limit_pre <v> - The maximum cell volume after refinement before distribution
854 . -dm_refine <n> - The number of refinements after distribution
855 . -dm_extrude <l> - Activate extrusion and specify the number of layers to extrude
856 . -dm_plex_save_transform <bool> - Save the `DMPlexTransform` that produced this mesh
857 . -dm_plex_transform_extrude_thickness <t> - The total thickness of extruded layers
858 . -dm_plex_transform_extrude_use_tensor <bool> - Use tensor cells when extruding
859 . -dm_plex_transform_extrude_symmetric <bool> - Extrude layers symmetrically about the surface
860 . -dm_plex_transform_extrude_normal <n0,...,nd> - Specify the extrusion direction
861 . -dm_plex_transform_extrude_thicknesses <t0,...,tl> - Specify thickness of each layer
862 . -dm_plex_create_fv_ghost_cells - Flag to create finite volume ghost cells on the boundary
863 . -dm_plex_fv_ghost_cells_label <name> - Label name for ghost cells boundary
864 . -dm_distribute <bool> - Flag to redistribute a mesh among processes
865 . -dm_distribute_overlap <n> - The size of the overlap halo
866 . -dm_plex_adj_cone <bool> - Set adjacency direction
867 . -dm_plex_adj_closure <bool> - Set adjacency size
868 . -dm_plex_use_ceed <bool> - Use LibCEED as the FEM backend
869 . -dm_plex_check_symmetry - Check that the adjacency information in the mesh is symmetric - `DMPlexCheckSymmetry()`
870 . -dm_plex_check_skeleton - Check that each cell has the correct number of vertices (only for homogeneous simplex or tensor meshes) - `DMPlexCheckSkeleton()`
871 . -dm_plex_check_faces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type - `DMPlexCheckFaces()`
872 . -dm_plex_check_geometry - Check that cells have positive volume - `DMPlexCheckGeometry()`
873 . -dm_plex_check_pointsf - Check some necessary conditions for `PointSF` - `DMPlexCheckPointSF()`
874 . -dm_plex_check_interface_cones - Check points on inter-partition interfaces have conforming order of cone points - `DMPlexCheckInterfaceCones()`
875 - -dm_plex_check_all - Perform all the checks above
876
877 Level: intermediate
878
879 Note:
880 For some `DMType` such as `DMDA` this cannot be called after `DMSetUp()` has been called.
881
882 .seealso: [](ch_dmbase), `DM`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`,
883 `DMPlexCheckSymmetry()`, `DMPlexCheckSkeleton()`, `DMPlexCheckFaces()`, `DMPlexCheckGeometry()`, `DMPlexCheckPointSF()`, `DMPlexCheckInterfaceCones()`,
884 `DMSetOptionsPrefix()`, `DMType`, `DMPLEX`, `DMDA`, `DMSetUp()`
885 @*/
DMSetFromOptions(DM dm)886 PetscErrorCode DMSetFromOptions(DM dm)
887 {
888 char typeName[256];
889 PetscBool flg;
890
891 PetscFunctionBegin;
892 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
893 dm->setfromoptionscalled = PETSC_TRUE;
894 if (dm->sf) PetscCall(PetscSFSetFromOptions(dm->sf));
895 if (dm->sectionSF) PetscCall(PetscSFSetFromOptions(dm->sectionSF));
896 if (dm->coordinates[0].dm) PetscCall(DMSetFromOptions(dm->coordinates[0].dm));
897 PetscObjectOptionsBegin((PetscObject)dm);
898 PetscCall(PetscOptionsBool("-dm_preallocate_only", "only preallocate matrix, but do not set column indices", "DMSetMatrixPreallocateOnly", dm->prealloc_only, &dm->prealloc_only, NULL));
899 PetscCall(PetscOptionsFList("-dm_vec_type", "Vector type used for created vectors", "DMSetVecType", VecList, dm->vectype, typeName, 256, &flg));
900 if (flg) PetscCall(DMSetVecType(dm, typeName));
901 PetscCall(PetscOptionsFList("-dm_mat_type", "Matrix type used for created matrices", "DMSetMatType", MatList, dm->mattype ? dm->mattype : typeName, typeName, sizeof(typeName), &flg));
902 if (flg) PetscCall(DMSetMatType(dm, typeName));
903 PetscCall(PetscOptionsEnum("-dm_blocking_type", "Topological point or field node blocking", "DMSetBlockingType", DMBlockingTypes, (PetscEnum)dm->blocking_type, (PetscEnum *)&dm->blocking_type, NULL));
904 PetscCall(PetscOptionsEnum("-dm_is_coloring_type", "Global or local coloring of Jacobian", "DMSetISColoringType", ISColoringTypes, (PetscEnum)dm->coloringtype, (PetscEnum *)&dm->coloringtype, NULL));
905 PetscCall(PetscOptionsInt("-dm_bind_below", "Set the size threshold (in entries) below which the Vec is bound to the CPU", "VecBindToCPU", dm->bind_below, &dm->bind_below, &flg));
906 PetscCall(PetscOptionsBool("-dm_ignore_perm_output", "Ignore the local section permutation on output", "DMGetOutputDM", dm->ignorePermOutput, &dm->ignorePermOutput, NULL));
907 PetscTryTypeMethod(dm, setfromoptions, PetscOptionsObject);
908 /* process any options handlers added with PetscObjectAddOptionsHandler() */
909 PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)dm, PetscOptionsObject));
910 PetscOptionsEnd();
911 PetscFunctionReturn(PETSC_SUCCESS);
912 }
913
914 /*@
915 DMViewFromOptions - View a `DM` in a particular way based on a request in the options database
916
917 Collective
918
919 Input Parameters:
920 + dm - the `DM` object
921 . obj - optional object that provides the prefix for the options database (if `NULL` then the prefix in `obj` is used)
922 - name - option string that is used to activate viewing
923
924 Level: intermediate
925
926 Note:
927 See `PetscObjectViewFromOptions()` for a list of values that can be provided in the options database to determine how the `DM` is viewed
928
929 .seealso: [](ch_dmbase), `DM`, `DMView()`, `PetscObjectViewFromOptions()`, `DMCreate()`
930 @*/
DMViewFromOptions(DM dm,PeOp PetscObject obj,const char name[])931 PetscErrorCode DMViewFromOptions(DM dm, PeOp PetscObject obj, const char name[])
932 {
933 PetscFunctionBegin;
934 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
935 PetscCall(PetscObjectViewFromOptions((PetscObject)dm, obj, name));
936 PetscFunctionReturn(PETSC_SUCCESS);
937 }
938
939 /*@
940 DMView - Views a `DM`. Depending on the `PetscViewer` and its `PetscViewerFormat` it may print some ASCII information about the `DM` to the screen or a file or
941 save the `DM` in a binary file to be loaded later or create a visualization of the `DM`
942
943 Collective
944
945 Input Parameters:
946 + dm - the `DM` object to view
947 - v - the viewer
948
949 Options Database Keys:
950 + -view_pyvista_warp <f> - Warps the mesh by the active scalar with factor f
951 . -view_pyvista_clip <xl,xu,yl,yu,zl,zu> - Defines the clipping box
952 . -dm_view_draw_line_color <int> - Specify the X-window color for cell borders
953 . -dm_view_draw_cell_color <int> - Specify the X-window color for cells
954 - -dm_view_draw_affine <bool> - Flag to ignore high-order edges
955
956 Level: beginner
957
958 Notes:
959
960 `PetscViewer` = `PETSCVIEWERHDF5` i.e. HDF5 format can be used with `PETSC_VIEWER_HDF5_PETSC` as the `PetscViewerFormat` to save multiple `DMPLEX`
961 meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()`
962 before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object.
963
964 `PetscViewer` = `PETSCVIEWEREXODUSII` i.e. ExodusII format assumes that element blocks (mapped to "Cell sets" labels)
965 consists of sequentially numbered cells.
966
967 If `dm` has been distributed, only the part of the `DM` on MPI rank 0 (including "ghost" cells and vertices) will be written.
968
969 Only TRI, TET, QUAD, and HEX cells are supported in ExodusII.
970
971 `DMPLEX` only represents geometry while most post-processing software expect that a mesh also provides information on the discretization space. This function assumes that the file represents Lagrange finite elements of order 1 or 2.
972 The order of the mesh shall be set using `PetscViewerExodusIISetOrder()`
973
974 Variable names can be set and queried using `PetscViewerExodusII[Set/Get][Nodal/Zonal]VariableNames[s]`.
975
976 .seealso: [](ch_dmbase), `DM`, `PetscViewer`, `PetscViewerFormat`, `PetscViewerSetFormat()`, `DMDestroy()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMLoad()`, `PetscObjectSetName()`
977 @*/
DMView(DM dm,PetscViewer v)978 PetscErrorCode DMView(DM dm, PetscViewer v)
979 {
980 PetscBool isbinary;
981 PetscMPIInt size;
982 PetscViewerFormat format;
983
984 PetscFunctionBegin;
985 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
986 if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm), &v));
987 PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 2);
988 /* Ideally, we would like to have this test on.
989 However, it currently breaks socket viz via GLVis.
990 During DMView(parallel_mesh,glvis_viewer), each
991 process opens a sequential ASCII socket to visualize
992 the local mesh, and PetscObjectView(dm,local_socket)
993 is internally called inside VecView_GLVis, incurring
994 in an error here */
995 /* PetscCheckSameComm(dm,1,v,2); */
996 PetscCall(PetscViewerCheckWritable(v));
997
998 PetscCall(PetscLogEventBegin(DM_View, v, 0, 0, 0));
999 PetscCall(PetscViewerGetFormat(v, &format));
1000 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
1001 if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) PetscFunctionReturn(PETSC_SUCCESS);
1002 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)dm, v));
1003 PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERBINARY, &isbinary));
1004 if (isbinary) {
1005 PetscInt classid = DM_FILE_CLASSID;
1006 char type[256];
1007
1008 PetscCall(PetscViewerBinaryWrite(v, &classid, 1, PETSC_INT));
1009 PetscCall(PetscStrncpy(type, ((PetscObject)dm)->type_name, sizeof(type)));
1010 PetscCall(PetscViewerBinaryWrite(v, type, 256, PETSC_CHAR));
1011 }
1012 PetscTryTypeMethod(dm, view, v);
1013 PetscCall(PetscLogEventEnd(DM_View, v, 0, 0, 0));
1014 PetscFunctionReturn(PETSC_SUCCESS);
1015 }
1016
1017 /*@
1018 DMCreateGlobalVector - Creates a global vector from a `DM` object. A global vector is a parallel vector that has no duplicate values shared between MPI ranks,
1019 that is it has no ghost locations.
1020
1021 Collective
1022
1023 Input Parameter:
1024 . dm - the `DM` object
1025
1026 Output Parameter:
1027 . vec - the global vector
1028
1029 Level: beginner
1030
1031 .seealso: [](ch_dmbase), `DM`, `Vec`, `DMCreateLocalVector()`, `DMGetGlobalVector()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`,
1032 `DMGlobalToLocalBegin()`, `DMGlobalToLocalEnd()`
1033 @*/
DMCreateGlobalVector(DM dm,Vec * vec)1034 PetscErrorCode DMCreateGlobalVector(DM dm, Vec *vec)
1035 {
1036 PetscFunctionBegin;
1037 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1038 PetscAssertPointer(vec, 2);
1039 PetscUseTypeMethod(dm, createglobalvector, vec);
1040 if (PetscDefined(USE_DEBUG)) {
1041 DM vdm;
1042
1043 PetscCall(VecGetDM(*vec, &vdm));
1044 PetscCheck(vdm, PETSC_COMM_SELF, PETSC_ERR_PLIB, "DM type '%s' did not attach the DM to the vector", ((PetscObject)dm)->type_name);
1045 }
1046 PetscFunctionReturn(PETSC_SUCCESS);
1047 }
1048
1049 /*@
1050 DMCreateLocalVector - Creates a local vector from a `DM` object.
1051
1052 Not Collective
1053
1054 Input Parameter:
1055 . dm - the `DM` object
1056
1057 Output Parameter:
1058 . vec - the local vector
1059
1060 Level: beginner
1061
1062 Note:
1063 A local vector usually has ghost locations that contain values that are owned by different MPI ranks. A global vector has no ghost locations.
1064
1065 .seealso: [](ch_dmbase), `DM`, `Vec`, `DMCreateGlobalVector()`, `DMGetLocalVector()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`
1066 `DMGlobalToLocalBegin()`, `DMGlobalToLocalEnd()`
1067 @*/
DMCreateLocalVector(DM dm,Vec * vec)1068 PetscErrorCode DMCreateLocalVector(DM dm, Vec *vec)
1069 {
1070 PetscFunctionBegin;
1071 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1072 PetscAssertPointer(vec, 2);
1073 PetscUseTypeMethod(dm, createlocalvector, vec);
1074 if (PetscDefined(USE_DEBUG)) {
1075 DM vdm;
1076
1077 PetscCall(VecGetDM(*vec, &vdm));
1078 PetscCheck(vdm, PETSC_COMM_SELF, PETSC_ERR_LIB, "DM type '%s' did not attach the DM to the vector", ((PetscObject)dm)->type_name);
1079 }
1080 PetscFunctionReturn(PETSC_SUCCESS);
1081 }
1082
1083 /*@
1084 DMGetLocalToGlobalMapping - Accesses the local-to-global mapping in a `DM`.
1085
1086 Collective
1087
1088 Input Parameter:
1089 . dm - the `DM` that provides the mapping
1090
1091 Output Parameter:
1092 . ltog - the mapping
1093
1094 Level: advanced
1095
1096 Notes:
1097 The global to local mapping allows one to set values into the global vector or matrix using `VecSetValuesLocal()` and `MatSetValuesLocal()`
1098
1099 Vectors obtained with `DMCreateGlobalVector()` and matrices obtained with `DMCreateMatrix()` already contain the global mapping so you do
1100 need to use this function with those objects.
1101
1102 This mapping can then be used by `VecSetLocalToGlobalMapping()` or `MatSetLocalToGlobalMapping()`.
1103
1104 .seealso: [](ch_dmbase), `DM`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `VecSetLocalToGlobalMapping()`, `MatSetLocalToGlobalMapping()`,
1105 `DMCreateMatrix()`
1106 @*/
DMGetLocalToGlobalMapping(DM dm,ISLocalToGlobalMapping * ltog)1107 PetscErrorCode DMGetLocalToGlobalMapping(DM dm, ISLocalToGlobalMapping *ltog)
1108 {
1109 PetscInt bs = -1, bsLocal[2], bsMinMax[2];
1110
1111 PetscFunctionBegin;
1112 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1113 PetscAssertPointer(ltog, 2);
1114 if (!dm->ltogmap) {
1115 PetscSection section, sectionGlobal;
1116
1117 PetscCall(DMGetLocalSection(dm, §ion));
1118 if (section) {
1119 const PetscInt *cdofs;
1120 PetscInt *ltog;
1121 PetscInt pStart, pEnd, n, p, k, l;
1122
1123 PetscCall(DMGetGlobalSection(dm, §ionGlobal));
1124 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
1125 PetscCall(PetscSectionGetStorageSize(section, &n));
1126 PetscCall(PetscMalloc1(n, <og)); /* We want the local+overlap size */
1127 for (p = pStart, l = 0; p < pEnd; ++p) {
1128 PetscInt bdof, cdof, dof, off, c, cind;
1129
1130 /* Should probably use constrained dofs */
1131 PetscCall(PetscSectionGetDof(section, p, &dof));
1132 PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
1133 PetscCall(PetscSectionGetConstraintIndices(section, p, &cdofs));
1134 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &off));
1135 /* If you have dofs, and constraints, and they are unequal, we set the blocksize to 1 */
1136 bdof = cdof && (dof - cdof) ? 1 : dof;
1137 if (dof) bs = bs < 0 ? bdof : PetscGCD(bs, bdof);
1138
1139 for (c = 0, cind = 0; c < dof; ++c, ++l) {
1140 if (cind < cdof && c == cdofs[cind]) {
1141 ltog[l] = off < 0 ? off - c : -(off + c + 1);
1142 cind++;
1143 } else {
1144 ltog[l] = (off < 0 ? -(off + 1) : off) + c - cind;
1145 }
1146 }
1147 }
1148 /* Must have same blocksize on all procs (some might have no points) */
1149 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs;
1150 bsLocal[1] = bs;
1151 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
1152 if (bsMinMax[0] != bsMinMax[1]) {
1153 bs = 1;
1154 } else {
1155 bs = bsMinMax[0];
1156 }
1157 bs = bs < 0 ? 1 : bs;
1158 /* Must reduce indices by blocksize */
1159 if (bs > 1) {
1160 for (l = 0, k = 0; l < n; l += bs, ++k) {
1161 // Integer division of negative values truncates toward zero(!), not toward negative infinity
1162 ltog[k] = ltog[l] >= 0 ? ltog[l] / bs : -(-(ltog[l] + 1) / bs + 1);
1163 }
1164 n /= bs;
1165 }
1166 PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap));
1167 } else PetscUseTypeMethod(dm, getlocaltoglobalmapping);
1168 }
1169 *ltog = dm->ltogmap;
1170 PetscFunctionReturn(PETSC_SUCCESS);
1171 }
1172
1173 /*@
1174 DMGetBlockSize - Gets the inherent block size associated with a `DM`
1175
1176 Not Collective
1177
1178 Input Parameter:
1179 . dm - the `DM` with block structure
1180
1181 Output Parameter:
1182 . bs - the block size, 1 implies no exploitable block structure
1183
1184 Level: intermediate
1185
1186 Notes:
1187 This might be the number of degrees of freedom at each grid point for a structured grid.
1188
1189 Complex `DM` that represent multiphysics or staggered grids or mixed-methods do not generally have a single inherent block size, but
1190 rather different locations in the vectors may have a different block size.
1191
1192 .seealso: [](ch_dmbase), `DM`, `ISCreateBlock()`, `VecSetBlockSize()`, `MatSetBlockSize()`, `DMGetLocalToGlobalMapping()`
1193 @*/
DMGetBlockSize(DM dm,PetscInt * bs)1194 PetscErrorCode DMGetBlockSize(DM dm, PetscInt *bs)
1195 {
1196 PetscFunctionBegin;
1197 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1198 PetscAssertPointer(bs, 2);
1199 PetscCheck(dm->bs >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM does not have enough information to provide a block size yet");
1200 *bs = dm->bs;
1201 PetscFunctionReturn(PETSC_SUCCESS);
1202 }
1203
1204 /*@
1205 DMCreateInterpolation - Gets the interpolation matrix between two `DM` objects. The resulting matrix map degrees of freedom in the vector obtained by
1206 `DMCreateGlobalVector()` on the coarse `DM` to similar vectors on the fine grid `DM`.
1207
1208 Collective
1209
1210 Input Parameters:
1211 + dmc - the `DM` object
1212 - dmf - the second, finer `DM` object
1213
1214 Output Parameters:
1215 + mat - the interpolation
1216 - vec - the scaling (optional, pass `NULL` if not needed), see `DMCreateInterpolationScale()`
1217
1218 Level: developer
1219
1220 Notes:
1221 For `DMDA` objects this only works for "uniform refinement", that is the refined mesh was obtained `DMRefine()` or the coarse mesh was obtained by
1222 DMCoarsen(). The coordinates set into the `DMDA` are completely ignored in computing the interpolation.
1223
1224 For `DMDA` objects you can use this interpolation (more precisely the interpolation from the `DMGetCoordinateDM()`) to interpolate the mesh coordinate
1225 vectors EXCEPT in the periodic case where it does not make sense since the coordinate vectors are not periodic.
1226
1227 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolationScale()`
1228 @*/
DMCreateInterpolation(DM dmc,DM dmf,Mat * mat,Vec * vec)1229 PetscErrorCode DMCreateInterpolation(DM dmc, DM dmf, Mat *mat, Vec *vec)
1230 {
1231 PetscFunctionBegin;
1232 PetscValidHeaderSpecific(dmc, DM_CLASSID, 1);
1233 PetscValidHeaderSpecific(dmf, DM_CLASSID, 2);
1234 PetscAssertPointer(mat, 3);
1235 PetscCall(PetscLogEventBegin(DM_CreateInterpolation, dmc, dmf, 0, 0));
1236 PetscUseTypeMethod(dmc, createinterpolation, dmf, mat, vec);
1237 PetscCall(PetscLogEventEnd(DM_CreateInterpolation, dmc, dmf, 0, 0));
1238 PetscFunctionReturn(PETSC_SUCCESS);
1239 }
1240
1241 /*@
1242 DMCreateInterpolationScale - Forms L = 1/(R*1) where 1 is the vector of all ones, and R is
1243 the transpose of the interpolation between the `DM`.
1244
1245 Input Parameters:
1246 + dac - `DM` that defines a coarse mesh
1247 . daf - `DM` that defines a fine mesh
1248 - mat - the restriction (or interpolation operator) from fine to coarse
1249
1250 Output Parameter:
1251 . scale - the scaled vector
1252
1253 Level: advanced
1254
1255 Note:
1256 xcoarse = diag(L)*R*xfine preserves scale and is thus suitable for state (versus residual)
1257 restriction. In other words xcoarse is the coarse representation of xfine.
1258
1259 Developer Note:
1260 If the fine-scale `DMDA` has the -dm_bind_below option set to true, then `DMCreateInterpolationScale()` calls `MatSetBindingPropagates()`
1261 on the restriction/interpolation operator to set the bindingpropagates flag to true.
1262
1263 .seealso: [](ch_dmbase), `DM`, `MatRestrict()`, `MatInterpolate()`, `DMCreateInterpolation()`, `DMCreateRestriction()`, `DMCreateGlobalVector()`
1264 @*/
DMCreateInterpolationScale(DM dac,DM daf,Mat mat,Vec * scale)1265 PetscErrorCode DMCreateInterpolationScale(DM dac, DM daf, Mat mat, Vec *scale)
1266 {
1267 Vec fine;
1268 PetscScalar one = 1.0;
1269 #if defined(PETSC_HAVE_CUDA)
1270 PetscBool bindingpropagates, isbound;
1271 #endif
1272
1273 PetscFunctionBegin;
1274 PetscCall(DMCreateGlobalVector(daf, &fine));
1275 PetscCall(DMCreateGlobalVector(dac, scale));
1276 PetscCall(VecSet(fine, one));
1277 #if defined(PETSC_HAVE_CUDA)
1278 /* If the 'fine' Vec is bound to the CPU, it makes sense to bind 'mat' as well.
1279 * Note that we only do this for the CUDA case, right now, but if we add support for MatMultTranspose() via ViennaCL,
1280 * we'll need to do it for that case, too.*/
1281 PetscCall(VecGetBindingPropagates(fine, &bindingpropagates));
1282 if (bindingpropagates) {
1283 PetscCall(MatSetBindingPropagates(mat, PETSC_TRUE));
1284 PetscCall(VecBoundToCPU(fine, &isbound));
1285 PetscCall(MatBindToCPU(mat, isbound));
1286 }
1287 #endif
1288 PetscCall(MatRestrict(mat, fine, *scale));
1289 PetscCall(VecDestroy(&fine));
1290 PetscCall(VecReciprocal(*scale));
1291 PetscFunctionReturn(PETSC_SUCCESS);
1292 }
1293
1294 /*@
1295 DMCreateRestriction - Gets restriction matrix between two `DM` objects. The resulting matrix map degrees of freedom in the vector obtained by
1296 `DMCreateGlobalVector()` on the fine `DM` to similar vectors on the coarse grid `DM`.
1297
1298 Collective
1299
1300 Input Parameters:
1301 + dmc - the `DM` object
1302 - dmf - the second, finer `DM` object
1303
1304 Output Parameter:
1305 . mat - the restriction
1306
1307 Level: developer
1308
1309 Note:
1310 This only works for `DMSTAG`. For many situations either the transpose of the operator obtained with `DMCreateInterpolation()` or that
1311 matrix multiplied by the vector obtained with `DMCreateInterpolationScale()` provides the desired object.
1312
1313 .seealso: [](ch_dmbase), `DM`, `DMRestrict()`, `DMInterpolate()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateInterpolation()`
1314 @*/
DMCreateRestriction(DM dmc,DM dmf,Mat * mat)1315 PetscErrorCode DMCreateRestriction(DM dmc, DM dmf, Mat *mat)
1316 {
1317 PetscFunctionBegin;
1318 PetscValidHeaderSpecific(dmc, DM_CLASSID, 1);
1319 PetscValidHeaderSpecific(dmf, DM_CLASSID, 2);
1320 PetscAssertPointer(mat, 3);
1321 PetscCall(PetscLogEventBegin(DM_CreateRestriction, dmc, dmf, 0, 0));
1322 PetscUseTypeMethod(dmc, createrestriction, dmf, mat);
1323 PetscCall(PetscLogEventEnd(DM_CreateRestriction, dmc, dmf, 0, 0));
1324 PetscFunctionReturn(PETSC_SUCCESS);
1325 }
1326
1327 /*@
1328 DMCreateInjection - Gets injection matrix between two `DM` objects.
1329
1330 Collective
1331
1332 Input Parameters:
1333 + dac - the `DM` object
1334 - daf - the second, finer `DM` object
1335
1336 Output Parameter:
1337 . mat - the injection
1338
1339 Level: developer
1340
1341 Notes:
1342 This is an operator that applied to a vector obtained with `DMCreateGlobalVector()` on the
1343 fine grid maps the values to a vector on the vector on the coarse `DM` by simply selecting
1344 the values on the coarse grid points. This compares to the operator obtained by
1345 `DMCreateRestriction()` or the transpose of the operator obtained by
1346 `DMCreateInterpolation()` that uses a "local weighted average" of the values around the
1347 coarse grid point as the coarse grid value.
1348
1349 For `DMDA` objects this only works for "uniform refinement", that is the refined mesh was obtained `DMRefine()` or the coarse mesh was obtained by
1350 `DMCoarsen()`. The coordinates set into the `DMDA` are completely ignored in computing the injection.
1351
1352 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateInterpolation()`,
1353 `DMCreateRestriction()`, `MatRestrict()`, `MatInterpolate()`
1354 @*/
DMCreateInjection(DM dac,DM daf,Mat * mat)1355 PetscErrorCode DMCreateInjection(DM dac, DM daf, Mat *mat)
1356 {
1357 PetscFunctionBegin;
1358 PetscValidHeaderSpecific(dac, DM_CLASSID, 1);
1359 PetscValidHeaderSpecific(daf, DM_CLASSID, 2);
1360 PetscAssertPointer(mat, 3);
1361 PetscCall(PetscLogEventBegin(DM_CreateInjection, dac, daf, 0, 0));
1362 PetscUseTypeMethod(dac, createinjection, daf, mat);
1363 PetscCall(PetscLogEventEnd(DM_CreateInjection, dac, daf, 0, 0));
1364 PetscFunctionReturn(PETSC_SUCCESS);
1365 }
1366
1367 /*@
1368 DMCreateMassMatrix - Gets the mass matrix between two `DM` objects, M_ij = \int \phi_i \psi_j where the \phi are Galerkin basis functions for a
1369 a Galerkin finite element model on the `DM`
1370
1371 Collective
1372
1373 Input Parameters:
1374 + dmc - the target `DM` object
1375 - dmf - the source `DM` object, can be `NULL`
1376
1377 Output Parameter:
1378 . mat - the mass matrix
1379
1380 Level: developer
1381
1382 Notes:
1383 For `DMPLEX` the finite element model for the `DM` must have been already provided.
1384
1385 if `dmc` is `dmf` or `NULL`, then x^t M x is an approximation to the L2 norm of the vector x which is obtained by `DMCreateGlobalVector()`
1386
1387 .seealso: [](ch_dmbase), `DM`, `DMCreateMassMatrixLumped()`, `DMCreateMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolation()`, `DMCreateInjection()`
1388 @*/
DMCreateMassMatrix(DM dmc,DM dmf,Mat * mat)1389 PetscErrorCode DMCreateMassMatrix(DM dmc, DM dmf, Mat *mat)
1390 {
1391 PetscFunctionBegin;
1392 PetscValidHeaderSpecific(dmc, DM_CLASSID, 1);
1393 if (!dmf) dmf = dmc;
1394 PetscValidHeaderSpecific(dmf, DM_CLASSID, 2);
1395 PetscAssertPointer(mat, 3);
1396 PetscCall(PetscLogEventBegin(DM_CreateMassMatrix, dmc, dmf, 0, 0));
1397 PetscUseTypeMethod(dmc, createmassmatrix, dmf, mat);
1398 PetscCall(PetscLogEventEnd(DM_CreateMassMatrix, dmc, dmf, 0, 0));
1399 PetscFunctionReturn(PETSC_SUCCESS);
1400 }
1401
1402 /*@
1403 DMCreateMassMatrixLumped - Gets the lumped mass matrix for a given `DM`
1404
1405 Collective
1406
1407 Input Parameter:
1408 . dm - the `DM` object
1409
1410 Output Parameters:
1411 + llm - the local lumped mass matrix, which is a diagonal matrix, represented as a vector
1412 - lm - the global lumped mass matrix, which is a diagonal matrix, represented as a vector
1413
1414 Level: developer
1415
1416 Note:
1417 See `DMCreateMassMatrix()` for how to create the non-lumped version of the mass matrix.
1418
1419 .seealso: [](ch_dmbase), `DM`, `DMCreateMassMatrix()`, `DMCreateMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolation()`, `DMCreateInjection()`
1420 @*/
DMCreateMassMatrixLumped(DM dm,Vec * llm,Vec * lm)1421 PetscErrorCode DMCreateMassMatrixLumped(DM dm, Vec *llm, Vec *lm)
1422 {
1423 PetscFunctionBegin;
1424 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1425 if (llm) PetscAssertPointer(llm, 2);
1426 if (lm) PetscAssertPointer(lm, 3);
1427 if (llm || lm) PetscUseTypeMethod(dm, createmassmatrixlumped, llm, lm);
1428 PetscFunctionReturn(PETSC_SUCCESS);
1429 }
1430
1431 /*@
1432 DMCreateGradientMatrix - Gets the gradient matrix between two `DM` objects, M_(ic)j = \int \partial_c \phi_i \psi_j where the \phi are Galerkin basis functions for a Galerkin finite element model on the `DM`
1433
1434 Collective
1435
1436 Input Parameters:
1437 + dmc - the target `DM` object
1438 - dmf - the source `DM` object, can be `NULL`
1439
1440 Output Parameter:
1441 . mat - the gradient matrix
1442
1443 Level: developer
1444
1445 Notes:
1446 For `DMPLEX` the finite element model for the `DM` must have been already provided.
1447
1448 .seealso: [](ch_dmbase), `DM`, `DMCreateMassMatrix()`, `DMCreateMassMatrixLumped()`, `DMCreateMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolation()`, `DMCreateInjection()`
1449 @*/
DMCreateGradientMatrix(DM dmc,DM dmf,Mat * mat)1450 PetscErrorCode DMCreateGradientMatrix(DM dmc, DM dmf, Mat *mat)
1451 {
1452 PetscFunctionBegin;
1453 PetscValidHeaderSpecific(dmc, DM_CLASSID, 1);
1454 if (!dmf) dmf = dmc;
1455 PetscValidHeaderSpecific(dmf, DM_CLASSID, 2);
1456 PetscAssertPointer(mat, 3);
1457 PetscUseTypeMethod(dmc, creategradientmatrix, dmf, mat);
1458 PetscFunctionReturn(PETSC_SUCCESS);
1459 }
1460
1461 /*@
1462 DMCreateColoring - Gets coloring of a graph associated with the `DM`. Often the graph represents the operator matrix associated with the discretization
1463 of a PDE on the `DM`.
1464
1465 Collective
1466
1467 Input Parameters:
1468 + dm - the `DM` object
1469 - ctype - `IS_COLORING_LOCAL` or `IS_COLORING_GLOBAL`
1470
1471 Output Parameter:
1472 . coloring - the coloring
1473
1474 Level: developer
1475
1476 Notes:
1477 Coloring of matrices can also be computed directly from the sparse matrix nonzero structure via the `MatColoring` object or from the mesh from which the
1478 matrix comes from (what this function provides). In general using the mesh produces a more optimal coloring (fewer colors).
1479
1480 This produces a coloring with the distance of 2, see `MatSetColoringDistance()` which can be used for efficiently computing Jacobians with `MatFDColoringCreate()`
1481 For `DMDA` in three dimensions with periodic boundary conditions the number of grid points in each dimension must be divisible by 2*stencil_width + 1,
1482 otherwise an error will be generated.
1483
1484 .seealso: [](ch_dmbase), `DM`, `ISColoring`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatType()`, `MatColoring`, `MatFDColoringCreate()`
1485 @*/
DMCreateColoring(DM dm,ISColoringType ctype,ISColoring * coloring)1486 PetscErrorCode DMCreateColoring(DM dm, ISColoringType ctype, ISColoring *coloring)
1487 {
1488 PetscFunctionBegin;
1489 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1490 PetscAssertPointer(coloring, 3);
1491 PetscUseTypeMethod(dm, getcoloring, ctype, coloring);
1492 PetscFunctionReturn(PETSC_SUCCESS);
1493 }
1494
1495 /*@
1496 DMCreateMatrix - Gets an empty matrix for a `DM` that is most commonly used to store the Jacobian of a discrete PDE operator.
1497
1498 Collective
1499
1500 Input Parameter:
1501 . dm - the `DM` object
1502
1503 Output Parameter:
1504 . mat - the empty Jacobian
1505
1506 Options Database Key:
1507 . -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()` and `DMCreateMassMatrix()`, but do not fill it with zeros
1508
1509 Level: beginner
1510
1511 Notes:
1512 This properly preallocates the number of nonzeros in the sparse matrix so you
1513 do not need to do it yourself.
1514
1515 By default it also sets the nonzero structure and puts in the zero entries. To prevent setting
1516 the nonzero pattern call `DMSetMatrixPreallocateOnly()`
1517
1518 For `DMDA`, when you call `MatView()` on this matrix it is displayed using the global natural ordering, NOT in the ordering used
1519 internally by PETSc.
1520
1521 For `DMDA`, in general it is easiest to use `MatSetValuesStencil()` or `MatSetValuesLocal()` to put values into the matrix because
1522 `MatSetValues()` requires the indices for the global numbering for the `DMDA` which is complic`ated to compute
1523
1524 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMSetMatType()`, `DMCreateMassMatrix()`
1525 @*/
DMCreateMatrix(DM dm,Mat * mat)1526 PetscErrorCode DMCreateMatrix(DM dm, Mat *mat)
1527 {
1528 PetscFunctionBegin;
1529 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1530 PetscAssertPointer(mat, 2);
1531 PetscCall(MatInitializePackage());
1532 PetscCall(PetscLogEventBegin(DM_CreateMatrix, 0, 0, 0, 0));
1533 PetscUseTypeMethod(dm, creatematrix, mat);
1534 if (PetscDefined(USE_DEBUG)) {
1535 DM mdm;
1536
1537 PetscCall(MatGetDM(*mat, &mdm));
1538 PetscCheck(mdm, PETSC_COMM_SELF, PETSC_ERR_PLIB, "DM type '%s' did not attach the DM to the matrix", ((PetscObject)dm)->type_name);
1539 }
1540 /* Handle nullspace and near nullspace */
1541 if (dm->Nf) {
1542 MatNullSpace nullSpace;
1543 PetscInt Nf, f;
1544
1545 PetscCall(DMGetNumFields(dm, &Nf));
1546 for (f = 0; f < Nf; ++f) {
1547 if (dm->nullspaceConstructors && dm->nullspaceConstructors[f]) {
1548 PetscCall((*dm->nullspaceConstructors[f])(dm, f, f, &nullSpace));
1549 PetscCall(MatSetNullSpace(*mat, nullSpace));
1550 PetscCall(MatNullSpaceDestroy(&nullSpace));
1551 break;
1552 }
1553 }
1554 for (f = 0; f < Nf; ++f) {
1555 if (dm->nearnullspaceConstructors && dm->nearnullspaceConstructors[f]) {
1556 PetscCall((*dm->nearnullspaceConstructors[f])(dm, f, f, &nullSpace));
1557 PetscCall(MatSetNearNullSpace(*mat, nullSpace));
1558 PetscCall(MatNullSpaceDestroy(&nullSpace));
1559 }
1560 }
1561 }
1562 PetscCall(PetscLogEventEnd(DM_CreateMatrix, 0, 0, 0, 0));
1563 PetscFunctionReturn(PETSC_SUCCESS);
1564 }
1565
1566 /*@
1567 DMSetMatrixPreallocateSkip - When `DMCreateMatrix()` is called the matrix sizes and
1568 `ISLocalToGlobalMapping` will be properly set, but the data structures to store values in the
1569 matrices will not be preallocated.
1570
1571 Logically Collective
1572
1573 Input Parameters:
1574 + dm - the `DM`
1575 - skip - `PETSC_TRUE` to skip preallocation
1576
1577 Level: developer
1578
1579 Note:
1580 This is most useful to reduce initialization costs when `MatSetPreallocationCOO()` and
1581 `MatSetValuesCOO()` will be used.
1582
1583 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `DMSetMatrixStructureOnly()`, `DMSetMatrixPreallocateOnly()`
1584 @*/
DMSetMatrixPreallocateSkip(DM dm,PetscBool skip)1585 PetscErrorCode DMSetMatrixPreallocateSkip(DM dm, PetscBool skip)
1586 {
1587 PetscFunctionBegin;
1588 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1589 dm->prealloc_skip = skip;
1590 PetscFunctionReturn(PETSC_SUCCESS);
1591 }
1592
1593 /*@
1594 DMSetMatrixPreallocateOnly - When `DMCreateMatrix()` is called the matrix will be properly
1595 preallocated but the nonzero structure and zero values will not be set.
1596
1597 Logically Collective
1598
1599 Input Parameters:
1600 + dm - the `DM`
1601 - only - `PETSC_TRUE` if only want preallocation
1602
1603 Options Database Key:
1604 . -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()`, `DMCreateMassMatrix()`, but do not fill it with zeros
1605
1606 Level: developer
1607
1608 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixStructureOnly()`, `DMSetMatrixPreallocateSkip()`
1609 @*/
DMSetMatrixPreallocateOnly(DM dm,PetscBool only)1610 PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1611 {
1612 PetscFunctionBegin;
1613 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1614 dm->prealloc_only = only;
1615 PetscFunctionReturn(PETSC_SUCCESS);
1616 }
1617
1618 /*@
1619 DMSetMatrixStructureOnly - When `DMCreateMatrix()` is called, the matrix nonzero structure will be created
1620 but the array for numerical values will not be allocated.
1621
1622 Logically Collective
1623
1624 Input Parameters:
1625 + dm - the `DM`
1626 - only - `PETSC_TRUE` if you only want matrix nonzero structure
1627
1628 Level: developer
1629
1630 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `DMSetMatrixPreallocateOnly()`, `DMSetMatrixPreallocateSkip()`
1631 @*/
DMSetMatrixStructureOnly(DM dm,PetscBool only)1632 PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1633 {
1634 PetscFunctionBegin;
1635 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1636 dm->structure_only = only;
1637 PetscFunctionReturn(PETSC_SUCCESS);
1638 }
1639
1640 /*@
1641 DMSetBlockingType - set the blocking granularity to be used for variable block size `DMCreateMatrix()` is called
1642
1643 Logically Collective
1644
1645 Input Parameters:
1646 + dm - the `DM`
1647 - btype - block by topological point or field node
1648
1649 Options Database Key:
1650 . -dm_blocking_type [topological_point, field_node] - use topological point blocking or field node blocking
1651
1652 Level: advanced
1653
1654 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `MatSetVariableBlockSizes()`
1655 @*/
DMSetBlockingType(DM dm,DMBlockingType btype)1656 PetscErrorCode DMSetBlockingType(DM dm, DMBlockingType btype)
1657 {
1658 PetscFunctionBegin;
1659 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1660 dm->blocking_type = btype;
1661 PetscFunctionReturn(PETSC_SUCCESS);
1662 }
1663
1664 /*@
1665 DMGetBlockingType - get the blocking granularity to be used for variable block size `DMCreateMatrix()` is called
1666
1667 Not Collective
1668
1669 Input Parameter:
1670 . dm - the `DM`
1671
1672 Output Parameter:
1673 . btype - block by topological point or field node
1674
1675 Level: advanced
1676
1677 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `MatSetVariableBlockSizes()`
1678 @*/
DMGetBlockingType(DM dm,DMBlockingType * btype)1679 PetscErrorCode DMGetBlockingType(DM dm, DMBlockingType *btype)
1680 {
1681 PetscFunctionBegin;
1682 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1683 PetscAssertPointer(btype, 2);
1684 *btype = dm->blocking_type;
1685 PetscFunctionReturn(PETSC_SUCCESS);
1686 }
1687
1688 /*@C
1689 DMGetWorkArray - Gets a work array guaranteed to be at least the input size, restore with `DMRestoreWorkArray()`
1690
1691 Not Collective
1692
1693 Input Parameters:
1694 + dm - the `DM` object
1695 . count - The minimum size
1696 - dtype - MPI data type, often `MPIU_REAL`, `MPIU_SCALAR`, or `MPIU_INT`)
1697
1698 Output Parameter:
1699 . mem - the work array
1700
1701 Level: developer
1702
1703 Notes:
1704 A `DM` may stash the array between instantiations so using this routine may be more efficient than calling `PetscMalloc()`
1705
1706 The array may contain nonzero values
1707
1708 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMCreate()`, `DMRestoreWorkArray()`, `PetscMalloc()`
1709 @*/
DMGetWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void * mem)1710 PetscErrorCode DMGetWorkArray(DM dm, PetscInt count, MPI_Datatype dtype, void *mem)
1711 {
1712 DMWorkLink link;
1713 PetscMPIInt dsize;
1714
1715 PetscFunctionBegin;
1716 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1717 PetscAssertPointer(mem, 4);
1718 if (!count) {
1719 *(void **)mem = NULL;
1720 PetscFunctionReturn(PETSC_SUCCESS);
1721 }
1722 if (dm->workin) {
1723 link = dm->workin;
1724 dm->workin = dm->workin->next;
1725 } else {
1726 PetscCall(PetscNew(&link));
1727 }
1728 /* Avoid MPI_Type_size for most used datatypes
1729 Get size directly */
1730 if (dtype == MPIU_INT) dsize = sizeof(PetscInt);
1731 else if (dtype == MPIU_REAL) dsize = sizeof(PetscReal);
1732 #if defined(PETSC_USE_64BIT_INDICES)
1733 else if (dtype == MPI_INT) dsize = sizeof(int);
1734 #endif
1735 #if defined(PETSC_USE_COMPLEX)
1736 else if (dtype == MPIU_SCALAR) dsize = sizeof(PetscScalar);
1737 #endif
1738 else PetscCallMPI(MPI_Type_size(dtype, &dsize));
1739
1740 if (((size_t)dsize * count) > link->bytes) {
1741 PetscCall(PetscFree(link->mem));
1742 PetscCall(PetscMalloc(dsize * count, &link->mem));
1743 link->bytes = dsize * count;
1744 }
1745 link->next = dm->workout;
1746 dm->workout = link;
1747 *(void **)mem = link->mem;
1748 PetscFunctionReturn(PETSC_SUCCESS);
1749 }
1750
1751 /*@C
1752 DMRestoreWorkArray - Restores a work array obtained with `DMCreateWorkArray()`
1753
1754 Not Collective
1755
1756 Input Parameters:
1757 + dm - the `DM` object
1758 . count - The minimum size
1759 - dtype - MPI data type, often `MPIU_REAL`, `MPIU_SCALAR`, `MPIU_INT`
1760
1761 Output Parameter:
1762 . mem - the work array
1763
1764 Level: developer
1765
1766 Developer Note:
1767 count and dtype are ignored, they are only needed for `DMGetWorkArray()`
1768
1769 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMCreate()`, `DMGetWorkArray()`
1770 @*/
DMRestoreWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void * mem)1771 PetscErrorCode DMRestoreWorkArray(DM dm, PetscInt count, MPI_Datatype dtype, void *mem)
1772 {
1773 DMWorkLink *p, link;
1774
1775 PetscFunctionBegin;
1776 PetscAssertPointer(mem, 4);
1777 (void)count;
1778 (void)dtype;
1779 if (!*(void **)mem) PetscFunctionReturn(PETSC_SUCCESS);
1780 for (p = &dm->workout; (link = *p); p = &link->next) {
1781 if (link->mem == *(void **)mem) {
1782 *p = link->next;
1783 link->next = dm->workin;
1784 dm->workin = link;
1785 *(void **)mem = NULL;
1786 PetscFunctionReturn(PETSC_SUCCESS);
1787 }
1788 }
1789 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Array was not checked out");
1790 }
1791
1792 /*@C
1793 DMSetNullSpaceConstructor - Provide a callback function which constructs the nullspace for a given field, defined with `DMAddField()`, when function spaces
1794 are joined or split, such as in `DMCreateSubDM()`
1795
1796 Logically Collective; No Fortran Support
1797
1798 Input Parameters:
1799 + dm - The `DM`
1800 . field - The field number for the nullspace
1801 - nullsp - A callback to create the nullspace
1802
1803 Calling sequence of `nullsp`:
1804 + dm - The present `DM`
1805 . origField - The field number given above, in the original `DM`
1806 . field - The field number in dm
1807 - nullSpace - The nullspace for the given field
1808
1809 Level: intermediate
1810
1811 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetNullSpaceConstructor()`, `DMSetNearNullSpaceConstructor()`, `DMGetNearNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
1812 @*/
DMSetNullSpaceConstructor(DM dm,PetscInt field,PetscErrorCode (* nullsp)(DM dm,PetscInt origField,PetscInt field,MatNullSpace * nullSpace))1813 PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1814 {
1815 PetscFunctionBegin;
1816 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1817 PetscCheck(field < dm->Nf, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= %" PetscInt_FMT " fields", field, dm->Nf);
1818 PetscCheck(dm->nullspaceConstructors, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must call DMCreateDS() to setup nullspaces");
1819 dm->nullspaceConstructors[field] = nullsp;
1820 PetscFunctionReturn(PETSC_SUCCESS);
1821 }
1822
1823 /*@C
1824 DMGetNullSpaceConstructor - Return the callback function which constructs the nullspace for a given field, defined with `DMAddField()`
1825
1826 Not Collective; No Fortran Support
1827
1828 Input Parameters:
1829 + dm - The `DM`
1830 - field - The field number for the nullspace
1831
1832 Output Parameter:
1833 . nullsp - A callback to create the nullspace
1834
1835 Calling sequence of `nullsp`:
1836 + dm - The present DM
1837 . origField - The field number given above, in the original DM
1838 . field - The field number in dm
1839 - nullSpace - The nullspace for the given field
1840
1841 Level: intermediate
1842
1843 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`, `DMSetNullSpaceConstructor()`, `DMSetNearNullSpaceConstructor()`, `DMGetNearNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
1844 @*/
DMGetNullSpaceConstructor(DM dm,PetscInt field,PetscErrorCode (** nullsp)(DM dm,PetscInt origField,PetscInt field,MatNullSpace * nullSpace))1845 PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1846 {
1847 PetscFunctionBegin;
1848 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1849 PetscAssertPointer(nullsp, 3);
1850 PetscCheck(field < dm->Nf, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= %" PetscInt_FMT " fields", field, dm->Nf);
1851 PetscCheck(dm->nullspaceConstructors, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must call DMCreateDS() to setup nullspaces");
1852 *nullsp = dm->nullspaceConstructors[field];
1853 PetscFunctionReturn(PETSC_SUCCESS);
1854 }
1855
1856 /*@C
1857 DMSetNearNullSpaceConstructor - Provide a callback function which constructs the near-nullspace for a given field, defined with `DMAddField()`
1858
1859 Logically Collective; No Fortran Support
1860
1861 Input Parameters:
1862 + dm - The `DM`
1863 . field - The field number for the nullspace
1864 - nullsp - A callback to create the near-nullspace
1865
1866 Calling sequence of `nullsp`:
1867 + dm - The present `DM`
1868 . origField - The field number given above, in the original `DM`
1869 . field - The field number in dm
1870 - nullSpace - The nullspace for the given field
1871
1872 Level: intermediate
1873
1874 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetNearNullSpaceConstructor()`, `DMSetNullSpaceConstructor()`, `DMGetNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`,
1875 `MatNullSpace`
1876 @*/
DMSetNearNullSpaceConstructor(DM dm,PetscInt field,PetscErrorCode (* nullsp)(DM dm,PetscInt origField,PetscInt field,MatNullSpace * nullSpace))1877 PetscErrorCode DMSetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1878 {
1879 PetscFunctionBegin;
1880 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1881 PetscCheck(field < dm->Nf, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= %" PetscInt_FMT " fields", field, dm->Nf);
1882 PetscCheck(dm->nearnullspaceConstructors, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must call DMCreateDS() to setup nullspaces");
1883 dm->nearnullspaceConstructors[field] = nullsp;
1884 PetscFunctionReturn(PETSC_SUCCESS);
1885 }
1886
1887 /*@C
1888 DMGetNearNullSpaceConstructor - Return the callback function which constructs the near-nullspace for a given field, defined with `DMAddField()`
1889
1890 Not Collective; No Fortran Support
1891
1892 Input Parameters:
1893 + dm - The `DM`
1894 - field - The field number for the nullspace
1895
1896 Output Parameter:
1897 . nullsp - A callback to create the near-nullspace
1898
1899 Calling sequence of `nullsp`:
1900 + dm - The present `DM`
1901 . origField - The field number given above, in the original `DM`
1902 . field - The field number in dm
1903 - nullSpace - The nullspace for the given field
1904
1905 Level: intermediate
1906
1907 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`, `DMSetNearNullSpaceConstructor()`, `DMSetNullSpaceConstructor()`, `DMGetNullSpaceConstructor()`, `DMCreateSubDM()`,
1908 `MatNullSpace`, `DMCreateSuperDM()`
1909 @*/
DMGetNearNullSpaceConstructor(DM dm,PetscInt field,PetscErrorCode (** nullsp)(DM dm,PetscInt origField,PetscInt field,MatNullSpace * nullSpace))1910 PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1911 {
1912 PetscFunctionBegin;
1913 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1914 PetscAssertPointer(nullsp, 3);
1915 PetscCheck(field < dm->Nf, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= %" PetscInt_FMT " fields", field, dm->Nf);
1916 PetscCheck(dm->nearnullspaceConstructors, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must call DMCreateDS() to setup nullspaces");
1917 *nullsp = dm->nearnullspaceConstructors[field];
1918 PetscFunctionReturn(PETSC_SUCCESS);
1919 }
1920
1921 /*@C
1922 DMCreateFieldIS - Creates a set of `IS` objects with the global indices of dofs for each field defined with `DMAddField()`
1923
1924 Not Collective; No Fortran Support
1925
1926 Input Parameter:
1927 . dm - the `DM` object
1928
1929 Output Parameters:
1930 + numFields - The number of fields (or `NULL` if not requested)
1931 . fieldNames - The name of each field (or `NULL` if not requested)
1932 - fields - The global indices for each field (or `NULL` if not requested)
1933
1934 Level: intermediate
1935
1936 Note:
1937 The user is responsible for freeing all requested arrays. In particular, every entry of `fieldNames` should be freed with
1938 `PetscFree()`, every entry of `fields` should be destroyed with `ISDestroy()`, and both arrays should be freed with
1939 `PetscFree()`.
1940
1941 Developer Note:
1942 It is not clear why both this function and `DMCreateFieldDecomposition()` exist. Having two seems redundant and confusing. This function should
1943 likely be removed.
1944
1945 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`,
1946 `DMCreateFieldDecomposition()`
1947 @*/
DMCreateFieldIS(DM dm,PetscInt * numFields,char *** fieldNames,IS * fields[])1948 PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS *fields[])
1949 {
1950 PetscSection section, sectionGlobal;
1951
1952 PetscFunctionBegin;
1953 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1954 if (numFields) {
1955 PetscAssertPointer(numFields, 2);
1956 *numFields = 0;
1957 }
1958 if (fieldNames) {
1959 PetscAssertPointer(fieldNames, 3);
1960 *fieldNames = NULL;
1961 }
1962 if (fields) {
1963 PetscAssertPointer(fields, 4);
1964 *fields = NULL;
1965 }
1966 PetscCall(DMGetLocalSection(dm, §ion));
1967 if (section) {
1968 PetscInt *fieldSizes, *fieldNc, **fieldIndices;
1969 PetscInt nF, f, pStart, pEnd, p;
1970
1971 PetscCall(DMGetGlobalSection(dm, §ionGlobal));
1972 PetscCall(PetscSectionGetNumFields(section, &nF));
1973 PetscCall(PetscMalloc3(nF, &fieldSizes, nF, &fieldNc, nF, &fieldIndices));
1974 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd));
1975 for (f = 0; f < nF; ++f) {
1976 fieldSizes[f] = 0;
1977 PetscCall(PetscSectionGetFieldComponents(section, f, &fieldNc[f]));
1978 }
1979 for (p = pStart; p < pEnd; ++p) {
1980 PetscInt gdof;
1981
1982 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
1983 if (gdof > 0) {
1984 for (f = 0; f < nF; ++f) {
1985 PetscInt fdof, fcdof, fpdof;
1986
1987 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof));
1988 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof));
1989 fpdof = fdof - fcdof;
1990 if (fpdof && fpdof != fieldNc[f]) {
1991 /* Layout does not admit a pointwise block size */
1992 fieldNc[f] = 1;
1993 }
1994 fieldSizes[f] += fpdof;
1995 }
1996 }
1997 }
1998 for (f = 0; f < nF; ++f) {
1999 PetscCall(PetscMalloc1(fieldSizes[f], &fieldIndices[f]));
2000 fieldSizes[f] = 0;
2001 }
2002 for (p = pStart; p < pEnd; ++p) {
2003 PetscInt gdof, goff;
2004
2005 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
2006 if (gdof > 0) {
2007 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &goff));
2008 for (f = 0; f < nF; ++f) {
2009 PetscInt fdof, fcdof, fc;
2010
2011 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof));
2012 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof));
2013 for (fc = 0; fc < fdof - fcdof; ++fc, ++fieldSizes[f]) fieldIndices[f][fieldSizes[f]] = goff++;
2014 }
2015 }
2016 }
2017 if (numFields) *numFields = nF;
2018 if (fieldNames) {
2019 PetscCall(PetscMalloc1(nF, fieldNames));
2020 for (f = 0; f < nF; ++f) {
2021 const char *fieldName;
2022
2023 PetscCall(PetscSectionGetFieldName(section, f, &fieldName));
2024 PetscCall(PetscStrallocpy(fieldName, &(*fieldNames)[f]));
2025 }
2026 }
2027 if (fields) {
2028 PetscCall(PetscMalloc1(nF, fields));
2029 for (f = 0; f < nF; ++f) {
2030 PetscInt bs, in[2], out[2];
2031
2032 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]));
2033 in[0] = -fieldNc[f];
2034 in[1] = fieldNc[f];
2035 PetscCallMPI(MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
2036 bs = (-out[0] == out[1]) ? out[1] : 1;
2037 PetscCall(ISSetBlockSize((*fields)[f], bs));
2038 }
2039 }
2040 PetscCall(PetscFree3(fieldSizes, fieldNc, fieldIndices));
2041 } else PetscTryTypeMethod(dm, createfieldis, numFields, fieldNames, fields);
2042 PetscFunctionReturn(PETSC_SUCCESS);
2043 }
2044
2045 /*@C
2046 DMCreateFieldDecomposition - Returns a list of `IS` objects defining a decomposition of a problem into subproblems
2047 corresponding to different fields.
2048
2049 Not Collective; No Fortran Support
2050
2051 Input Parameter:
2052 . dm - the `DM` object
2053
2054 Output Parameters:
2055 + len - The number of fields (or `NULL` if not requested)
2056 . namelist - The name for each field (or `NULL` if not requested)
2057 . islist - The global indices for each field (or `NULL` if not requested)
2058 - dmlist - The `DM`s for each field subproblem (or `NULL`, if not requested; if `NULL` is returned, no `DM`s are defined)
2059
2060 Level: intermediate
2061
2062 Notes:
2063 Each `IS` contains the global indices of the dofs of the corresponding field, defined by
2064 `DMAddField()`. The optional list of `DM`s define the `DM` for each subproblem.
2065
2066 The same as `DMCreateFieldIS()` but also returns a `DM` for each field.
2067
2068 The user is responsible for freeing all requested arrays. In particular, every entry of `namelist` should be freed with
2069 `PetscFree()`, every entry of `islist` should be destroyed with `ISDestroy()`, every entry of `dmlist` should be destroyed with `DMDestroy()`,
2070 and all of the arrays should be freed with `PetscFree()`.
2071
2072 Fortran Notes:
2073 Use the declarations
2074 .vb
2075 character(80), pointer :: namelist(:)
2076 IS, pointer :: islist(:)
2077 DM, pointer :: dmlist(:)
2078 .ve
2079
2080 `namelist` must be provided, `islist` may be `PETSC_NULL_IS_POINTER` and `dmlist` may be `PETSC_NULL_DM_POINTER`
2081
2082 Use `DMDestroyFieldDecomposition()` to free the returned objects
2083
2084 Developer Notes:
2085 It is not clear why this function and `DMCreateFieldIS()` exist. Having two seems redundant and confusing.
2086
2087 Unlike `DMRefine()`, `DMCoarsen()`, and `DMCreateDomainDecomposition()` this provides no mechanism to provide hooks that are called after the
2088 decomposition is computed.
2089
2090 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMCreateFieldIS()`, `DMCreateSubDM()`, `DMCreateDomainDecomposition()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`
2091 @*/
DMCreateFieldDecomposition(DM dm,PetscInt * len,char *** namelist,IS * islist[],DM * dmlist[])2092 PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS *islist[], DM *dmlist[])
2093 {
2094 PetscFunctionBegin;
2095 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2096 if (len) {
2097 PetscAssertPointer(len, 2);
2098 *len = 0;
2099 }
2100 if (namelist) {
2101 PetscAssertPointer(namelist, 3);
2102 *namelist = NULL;
2103 }
2104 if (islist) {
2105 PetscAssertPointer(islist, 4);
2106 *islist = NULL;
2107 }
2108 if (dmlist) {
2109 PetscAssertPointer(dmlist, 5);
2110 *dmlist = NULL;
2111 }
2112 /*
2113 Is it a good idea to apply the following check across all impls?
2114 Perhaps some impls can have a well-defined decomposition before DMSetUp?
2115 This, however, follows the general principle that accessors are not well-behaved until the object is set up.
2116 */
2117 PetscCheck(dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
2118 if (!dm->ops->createfielddecomposition) {
2119 PetscSection section;
2120 PetscInt numFields, f;
2121
2122 PetscCall(DMGetLocalSection(dm, §ion));
2123 if (section) PetscCall(PetscSectionGetNumFields(section, &numFields));
2124 if (section && numFields && dm->ops->createsubdm) {
2125 if (len) *len = numFields;
2126 if (namelist) PetscCall(PetscMalloc1(numFields, namelist));
2127 if (islist) PetscCall(PetscMalloc1(numFields, islist));
2128 if (dmlist) PetscCall(PetscMalloc1(numFields, dmlist));
2129 for (f = 0; f < numFields; ++f) {
2130 const char *fieldName;
2131
2132 PetscCall(DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL));
2133 if (namelist) {
2134 PetscCall(PetscSectionGetFieldName(section, f, &fieldName));
2135 PetscCall(PetscStrallocpy(fieldName, &(*namelist)[f]));
2136 }
2137 }
2138 } else {
2139 PetscCall(DMCreateFieldIS(dm, len, namelist, islist));
2140 /* By default there are no DMs associated with subproblems. */
2141 if (dmlist) *dmlist = NULL;
2142 }
2143 } else PetscUseTypeMethod(dm, createfielddecomposition, len, namelist, islist, dmlist);
2144 PetscFunctionReturn(PETSC_SUCCESS);
2145 }
2146
2147 /*@
2148 DMCreateSubDM - Returns an `IS` and `DM` encapsulating a subproblem defined by the fields passed in.
2149 The fields are defined by `DMCreateFieldIS()`.
2150
2151 Not collective
2152
2153 Input Parameters:
2154 + dm - The `DM` object
2155 . numFields - The number of fields to select
2156 - fields - The field numbers of the selected fields
2157
2158 Output Parameters:
2159 + is - The global indices for all the degrees of freedom in the new sub `DM`, use `NULL` if not needed
2160 - subdm - The `DM` for the subproblem, use `NULL` if not needed
2161
2162 Level: intermediate
2163
2164 Note:
2165 You need to call `DMPlexSetMigrationSF()` on the original `DM` if you want the Global-To-Natural map to be automatically constructed
2166
2167 .seealso: [](ch_dmbase), `DM`, `DMCreateFieldIS()`, `DMCreateFieldDecomposition()`, `DMAddField()`, `DMCreateSuperDM()`, `IS`, `VecISCopy()`, `DMPlexSetMigrationSF()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`
2168 @*/
DMCreateSubDM(DM dm,PetscInt numFields,const PetscInt fields[],IS * is,DM * subdm)2169 PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
2170 {
2171 PetscFunctionBegin;
2172 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2173 PetscAssertPointer(fields, 3);
2174 if (is) PetscAssertPointer(is, 4);
2175 if (subdm) PetscAssertPointer(subdm, 5);
2176 PetscUseTypeMethod(dm, createsubdm, numFields, fields, is, subdm);
2177 PetscFunctionReturn(PETSC_SUCCESS);
2178 }
2179
2180 /*@C
2181 DMCreateSuperDM - Returns an arrays of `IS` and a single `DM` encapsulating a superproblem defined by multiple `DM`s passed in.
2182
2183 Not collective
2184
2185 Input Parameters:
2186 + dms - The `DM` objects
2187 - n - The number of `DM`s
2188
2189 Output Parameters:
2190 + is - The global indices for each of subproblem within the super `DM`, or `NULL`, its length is `n`
2191 - superdm - The `DM` for the superproblem
2192
2193 Level: intermediate
2194
2195 Note:
2196 You need to call `DMPlexSetMigrationSF()` on the original `DM` if you want the Global-To-Natural map to be automatically constructed
2197
2198 .seealso: [](ch_dmbase), `DM`, `DMCreateSubDM()`, `DMPlexSetMigrationSF()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()`, `DMCreateDomainDecomposition()`
2199 @*/
DMCreateSuperDM(DM dms[],PetscInt n,IS * is[],DM * superdm)2200 PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt n, IS *is[], DM *superdm)
2201 {
2202 PetscInt i;
2203
2204 PetscFunctionBegin;
2205 PetscAssertPointer(dms, 1);
2206 for (i = 0; i < n; ++i) PetscValidHeaderSpecific(dms[i], DM_CLASSID, 1);
2207 if (is) PetscAssertPointer(is, 3);
2208 PetscAssertPointer(superdm, 4);
2209 PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of DMs must be nonnegative: %" PetscInt_FMT, n);
2210 if (n) {
2211 DM dm = dms[0];
2212 PetscCheck(dm->ops->createsuperdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No method createsuperdm for DM of type %s", ((PetscObject)dm)->type_name);
2213 PetscCall((*dm->ops->createsuperdm)(dms, n, is, superdm));
2214 }
2215 PetscFunctionReturn(PETSC_SUCCESS);
2216 }
2217
2218 /*@C
2219 DMCreateDomainDecomposition - Returns lists of `IS` objects defining a decomposition of a
2220 problem into subproblems corresponding to restrictions to pairs of nested subdomains.
2221
2222 Not Collective
2223
2224 Input Parameter:
2225 . dm - the `DM` object
2226
2227 Output Parameters:
2228 + n - The number of subproblems in the domain decomposition (or `NULL` if not requested), also the length of the four arrays below
2229 . namelist - The name for each subdomain (or `NULL` if not requested)
2230 . innerislist - The global indices for each inner subdomain (or `NULL`, if not requested)
2231 . outerislist - The global indices for each outer subdomain (or `NULL`, if not requested)
2232 - dmlist - The `DM`s for each subdomain subproblem (or `NULL`, if not requested; if `NULL` is returned, no `DM`s are defined)
2233
2234 Level: intermediate
2235
2236 Notes:
2237 Each `IS` contains the global indices of the dofs of the corresponding subdomains with in the
2238 dofs of the original `DM`. The inner subdomains conceptually define a nonoverlapping
2239 covering, while outer subdomains can overlap.
2240
2241 The optional list of `DM`s define a `DM` for each subproblem.
2242
2243 The user is responsible for freeing all requested arrays. In particular, every entry of `namelist` should be freed with
2244 `PetscFree()`, every entry of `innerislist` and `outerislist` should be destroyed with `ISDestroy()`, every entry of `dmlist` should be destroyed with `DMDestroy()`,
2245 and all of the arrays should be freed with `PetscFree()`.
2246
2247 Developer Notes:
2248 The `dmlist` is for the inner subdomains or the outer subdomains or all subdomains?
2249
2250 The names are inconsistent, the hooks use `DMSubDomainHook` which is nothing like `DMCreateDomainDecomposition()` while `DMRefineHook` is used for `DMRefine()`.
2251
2252 .seealso: [](ch_dmbase), `DM`, `DMCreateFieldDecomposition()`, `DMDestroy()`, `DMCreateDomainDecompositionScatters()`, `DMView()`, `DMCreateInterpolation()`,
2253 `DMSubDomainHookAdd()`, `DMSubDomainHookRemove()`,`DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`
2254 @*/
DMCreateDomainDecomposition(DM dm,PetscInt * n,char *** namelist,IS * innerislist[],IS * outerislist[],DM * dmlist[])2255 PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *n, char ***namelist, IS *innerislist[], IS *outerislist[], DM *dmlist[])
2256 {
2257 DMSubDomainHookLink link;
2258 PetscInt i, l;
2259
2260 PetscFunctionBegin;
2261 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2262 if (n) {
2263 PetscAssertPointer(n, 2);
2264 *n = 0;
2265 }
2266 if (namelist) {
2267 PetscAssertPointer(namelist, 3);
2268 *namelist = NULL;
2269 }
2270 if (innerislist) {
2271 PetscAssertPointer(innerislist, 4);
2272 *innerislist = NULL;
2273 }
2274 if (outerislist) {
2275 PetscAssertPointer(outerislist, 5);
2276 *outerislist = NULL;
2277 }
2278 if (dmlist) {
2279 PetscAssertPointer(dmlist, 6);
2280 *dmlist = NULL;
2281 }
2282 /*
2283 Is it a good idea to apply the following check across all impls?
2284 Perhaps some impls can have a well-defined decomposition before DMSetUp?
2285 This, however, follows the general principle that accessors are not well-behaved until the object is set up.
2286 */
2287 PetscCheck(dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
2288 if (dm->ops->createdomaindecomposition) {
2289 PetscUseTypeMethod(dm, createdomaindecomposition, &l, namelist, innerislist, outerislist, dmlist);
2290 /* copy subdomain hooks and context over to the subdomain DMs */
2291 if (dmlist && *dmlist) {
2292 for (i = 0; i < l; i++) {
2293 for (link = dm->subdomainhook; link; link = link->next) {
2294 if (link->ddhook) PetscCall((*link->ddhook)(dm, (*dmlist)[i], link->ctx));
2295 }
2296 if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx;
2297 }
2298 }
2299 if (n) *n = l;
2300 }
2301 PetscFunctionReturn(PETSC_SUCCESS);
2302 }
2303
2304 /*@C
2305 DMCreateDomainDecompositionScatters - Returns scatters to the subdomain vectors from the global vector for subdomains created with
2306 `DMCreateDomainDecomposition()`
2307
2308 Not Collective
2309
2310 Input Parameters:
2311 + dm - the `DM` object
2312 . n - the number of subdomains
2313 - subdms - the local subdomains
2314
2315 Output Parameters:
2316 + iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
2317 . oscat - scatter from global vector to overlapping global vector entries on subdomain
2318 - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)
2319
2320 Level: developer
2321
2322 Note:
2323 This is an alternative to the iis and ois arguments in `DMCreateDomainDecomposition()` that allow for the solution
2324 of general nonlinear problems with overlapping subdomain methods. While merely having index sets that enable subsets
2325 of the residual equations to be created is fine for linear problems, nonlinear problems require local assembly of
2326 solution and residual data.
2327
2328 Developer Note:
2329 Can the subdms input be anything or are they exactly the `DM` obtained from
2330 `DMCreateDomainDecomposition()`?
2331
2332 .seealso: [](ch_dmbase), `DM`, `DMCreateDomainDecomposition()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()`
2333 @*/
DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM * subdms,VecScatter * iscat[],VecScatter * oscat[],VecScatter * gscat[])2334 PetscErrorCode DMCreateDomainDecompositionScatters(DM dm, PetscInt n, DM *subdms, VecScatter *iscat[], VecScatter *oscat[], VecScatter *gscat[])
2335 {
2336 PetscFunctionBegin;
2337 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2338 PetscAssertPointer(subdms, 3);
2339 PetscUseTypeMethod(dm, createddscatters, n, subdms, iscat, oscat, gscat);
2340 PetscFunctionReturn(PETSC_SUCCESS);
2341 }
2342
2343 /*@
2344 DMRefine - Refines a `DM` object using a standard nonadaptive refinement of the underlying mesh
2345
2346 Collective
2347
2348 Input Parameters:
2349 + dm - the `DM` object
2350 - comm - the communicator to contain the new `DM` object (or `MPI_COMM_NULL`)
2351
2352 Output Parameter:
2353 . dmf - the refined `DM`, or `NULL`
2354
2355 Options Database Key:
2356 . -dm_plex_cell_refiner <strategy> - chooses the refinement strategy, e.g. regular, tohex
2357
2358 Level: developer
2359
2360 Note:
2361 If no refinement was done, the return value is `NULL`
2362
2363 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateDomainDecomposition()`,
2364 `DMRefineHookAdd()`, `DMRefineHookRemove()`
2365 @*/
DMRefine(DM dm,MPI_Comm comm,DM * dmf)2366 PetscErrorCode DMRefine(DM dm, MPI_Comm comm, DM *dmf)
2367 {
2368 DMRefineHookLink link;
2369
2370 PetscFunctionBegin;
2371 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2372 PetscCall(PetscLogEventBegin(DM_Refine, dm, 0, 0, 0));
2373 PetscUseTypeMethod(dm, refine, comm, dmf);
2374 if (*dmf) {
2375 (*dmf)->ops->creatematrix = dm->ops->creatematrix;
2376
2377 PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dmf));
2378
2379 (*dmf)->ctx = dm->ctx;
2380 (*dmf)->leveldown = dm->leveldown;
2381 (*dmf)->levelup = dm->levelup + 1;
2382
2383 PetscCall(DMSetMatType(*dmf, dm->mattype));
2384 for (link = dm->refinehook; link; link = link->next) {
2385 if (link->refinehook) PetscCall((*link->refinehook)(dm, *dmf, link->ctx));
2386 }
2387 }
2388 PetscCall(PetscLogEventEnd(DM_Refine, dm, 0, 0, 0));
2389 PetscFunctionReturn(PETSC_SUCCESS);
2390 }
2391
2392 /*@C
2393 DMRefineHookAdd - adds a callback to be run when interpolating a nonlinear problem to a finer grid
2394
2395 Logically Collective; No Fortran Support
2396
2397 Input Parameters:
2398 + coarse - `DM` on which to run a hook when interpolating to a finer level
2399 . refinehook - function to run when setting up the finer level
2400 . interphook - function to run to update data on finer levels (once per `SNESSolve()`)
2401 - ctx - [optional] user-defined context for provide data for the hooks (may be `NULL`)
2402
2403 Calling sequence of `refinehook`:
2404 + coarse - coarse level `DM`
2405 . fine - fine level `DM` to interpolate problem to
2406 - ctx - optional user-defined function context
2407
2408 Calling sequence of `interphook`:
2409 + coarse - coarse level `DM`
2410 . interp - matrix interpolating a coarse-level solution to the finer grid
2411 . fine - fine level `DM` to update
2412 - ctx - optional user-defined function context
2413
2414 Level: advanced
2415
2416 Notes:
2417 This function is only needed if auxiliary data that is attached to the `DM`s via, for example, `PetscObjectCompose()`, needs to be
2418 passed to fine grids while grid sequencing.
2419
2420 The actual interpolation is done when `DMInterpolate()` is called.
2421
2422 If this function is called multiple times, the hooks will be run in the order they are added.
2423
2424 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookAdd()`, `DMInterpolate()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2425 @*/
DMRefineHookAdd(DM coarse,PetscErrorCode (* refinehook)(DM coarse,DM fine,PetscCtx ctx),PetscErrorCode (* interphook)(DM coarse,Mat interp,DM fine,PetscCtx ctx),PetscCtx ctx)2426 PetscErrorCode DMRefineHookAdd(DM coarse, PetscErrorCode (*refinehook)(DM coarse, DM fine, PetscCtx ctx), PetscErrorCode (*interphook)(DM coarse, Mat interp, DM fine, PetscCtx ctx), PetscCtx ctx)
2427 {
2428 DMRefineHookLink link, *p;
2429
2430 PetscFunctionBegin;
2431 PetscValidHeaderSpecific(coarse, DM_CLASSID, 1);
2432 for (p = &coarse->refinehook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */
2433 if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) PetscFunctionReturn(PETSC_SUCCESS);
2434 }
2435 PetscCall(PetscNew(&link));
2436 link->refinehook = refinehook;
2437 link->interphook = interphook;
2438 link->ctx = ctx;
2439 link->next = NULL;
2440 *p = link;
2441 PetscFunctionReturn(PETSC_SUCCESS);
2442 }
2443
2444 /*@C
2445 DMRefineHookRemove - remove a callback from the list of hooks, that have been set with `DMRefineHookAdd()`, to be run when interpolating
2446 a nonlinear problem to a finer grid
2447
2448 Logically Collective; No Fortran Support
2449
2450 Input Parameters:
2451 + coarse - the `DM` on which to run a hook when restricting to a coarser level
2452 . refinehook - function to run when setting up a finer level
2453 . interphook - function to run to update data on finer levels
2454 - ctx - [optional] user-defined context for provide data for the hooks (may be `NULL`)
2455
2456 Level: advanced
2457
2458 Note:
2459 This function does nothing if the hook is not in the list.
2460
2461 .seealso: [](ch_dmbase), `DM`, `DMRefineHookAdd()`, `DMCoarsenHookRemove()`, `DMInterpolate()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2462 @*/
DMRefineHookRemove(DM coarse,PetscErrorCode (* refinehook)(DM,DM,void *),PetscErrorCode (* interphook)(DM,Mat,DM,void *),PetscCtx ctx)2463 PetscErrorCode DMRefineHookRemove(DM coarse, PetscErrorCode (*refinehook)(DM, DM, void *), PetscErrorCode (*interphook)(DM, Mat, DM, void *), PetscCtx ctx)
2464 {
2465 DMRefineHookLink link, *p;
2466
2467 PetscFunctionBegin;
2468 PetscValidHeaderSpecific(coarse, DM_CLASSID, 1);
2469 for (p = &coarse->refinehook; *p; p = &(*p)->next) { /* Search the list of current hooks */
2470 if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
2471 link = *p;
2472 *p = link->next;
2473 PetscCall(PetscFree(link));
2474 break;
2475 }
2476 }
2477 PetscFunctionReturn(PETSC_SUCCESS);
2478 }
2479
2480 /*@
2481 DMInterpolate - interpolates user-defined problem data attached to a `DM` to a finer `DM` by running hooks registered by `DMRefineHookAdd()`
2482
2483 Collective if any hooks are
2484
2485 Input Parameters:
2486 + coarse - coarser `DM` to use as a base
2487 . interp - interpolation matrix, apply using `MatInterpolate()`
2488 - fine - finer `DM` to update
2489
2490 Level: developer
2491
2492 Developer Note:
2493 This routine is called `DMInterpolate()` while the hook is called `DMRefineHookAdd()`. It would be better to have an
2494 an API with consistent terminology.
2495
2496 .seealso: [](ch_dmbase), `DM`, `DMRefineHookAdd()`, `MatInterpolate()`
2497 @*/
DMInterpolate(DM coarse,Mat interp,DM fine)2498 PetscErrorCode DMInterpolate(DM coarse, Mat interp, DM fine)
2499 {
2500 DMRefineHookLink link;
2501
2502 PetscFunctionBegin;
2503 for (link = fine->refinehook; link; link = link->next) {
2504 if (link->interphook) PetscCall((*link->interphook)(coarse, interp, fine, link->ctx));
2505 }
2506 PetscFunctionReturn(PETSC_SUCCESS);
2507 }
2508
2509 /*@
2510 DMInterpolateSolution - Interpolates a solution from a coarse mesh to a fine mesh.
2511
2512 Collective
2513
2514 Input Parameters:
2515 + coarse - coarse `DM`
2516 . fine - fine `DM`
2517 . interp - (optional) the matrix computed by `DMCreateInterpolation()`. Implementations may not need this, but if it
2518 is available it can avoid some recomputation. If it is provided, `MatInterpolate()` will be used if
2519 the coarse `DM` does not have a specialized implementation.
2520 - coarseSol - solution on the coarse mesh
2521
2522 Output Parameter:
2523 . fineSol - the interpolation of coarseSol to the fine mesh
2524
2525 Level: developer
2526
2527 Note:
2528 This function exists because the interpolation of a solution vector between meshes is not always a linear
2529 map. For example, if a boundary value problem has an inhomogeneous Dirichlet boundary condition that is compressed
2530 out of the solution vector. Or if interpolation is inherently a nonlinear operation, such as a method using
2531 slope-limiting reconstruction.
2532
2533 Developer Note:
2534 This doesn't just interpolate "solutions" so its API name is questionable.
2535
2536 .seealso: [](ch_dmbase), `DM`, `DMInterpolate()`, `DMCreateInterpolation()`
2537 @*/
DMInterpolateSolution(DM coarse,DM fine,Mat interp,Vec coarseSol,Vec fineSol)2538 PetscErrorCode DMInterpolateSolution(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
2539 {
2540 PetscErrorCode (*interpsol)(DM, DM, Mat, Vec, Vec) = NULL;
2541
2542 PetscFunctionBegin;
2543 PetscValidHeaderSpecific(coarse, DM_CLASSID, 1);
2544 if (interp) PetscValidHeaderSpecific(interp, MAT_CLASSID, 3);
2545 PetscValidHeaderSpecific(coarseSol, VEC_CLASSID, 4);
2546 PetscValidHeaderSpecific(fineSol, VEC_CLASSID, 5);
2547
2548 PetscCall(PetscObjectQueryFunction((PetscObject)coarse, "DMInterpolateSolution_C", &interpsol));
2549 if (interpsol) {
2550 PetscCall((*interpsol)(coarse, fine, interp, coarseSol, fineSol));
2551 } else if (interp) {
2552 PetscCall(MatInterpolate(interp, coarseSol, fineSol));
2553 } else SETERRQ(PetscObjectComm((PetscObject)coarse), PETSC_ERR_SUP, "DM %s does not implement DMInterpolateSolution()", ((PetscObject)coarse)->type_name);
2554 PetscFunctionReturn(PETSC_SUCCESS);
2555 }
2556
2557 /*@
2558 DMGetRefineLevel - Gets the number of refinements that have generated this `DM` from some initial `DM`.
2559
2560 Not Collective
2561
2562 Input Parameter:
2563 . dm - the `DM` object
2564
2565 Output Parameter:
2566 . level - number of refinements
2567
2568 Level: developer
2569
2570 Note:
2571 This can be used, by example, to set the number of coarser levels associated with this `DM` for a multigrid solver.
2572
2573 .seealso: [](ch_dmbase), `DM`, `DMRefine()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
2574 @*/
DMGetRefineLevel(DM dm,PetscInt * level)2575 PetscErrorCode DMGetRefineLevel(DM dm, PetscInt *level)
2576 {
2577 PetscFunctionBegin;
2578 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2579 *level = dm->levelup;
2580 PetscFunctionReturn(PETSC_SUCCESS);
2581 }
2582
2583 /*@
2584 DMSetRefineLevel - Sets the number of refinements that have generated this `DM`.
2585
2586 Not Collective
2587
2588 Input Parameters:
2589 + dm - the `DM` object
2590 - level - number of refinements
2591
2592 Level: advanced
2593
2594 Notes:
2595 This value is used by `PCMG` to determine how many multigrid levels to use
2596
2597 The values are usually set automatically by the process that is causing the refinements of an initial `DM` by calling this routine.
2598
2599 .seealso: [](ch_dmbase), `DM`, `DMGetRefineLevel()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
2600 @*/
DMSetRefineLevel(DM dm,PetscInt level)2601 PetscErrorCode DMSetRefineLevel(DM dm, PetscInt level)
2602 {
2603 PetscFunctionBegin;
2604 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2605 dm->levelup = level;
2606 PetscFunctionReturn(PETSC_SUCCESS);
2607 }
2608
2609 /*@
2610 DMExtrude - Extrude a `DM` object from a surface
2611
2612 Collective
2613
2614 Input Parameters:
2615 + dm - the `DM` object
2616 - layers - the number of extruded cell layers
2617
2618 Output Parameter:
2619 . dme - the extruded `DM`, or `NULL`
2620
2621 Level: developer
2622
2623 Note:
2624 If no extrusion was done, the return value is `NULL`
2625
2626 .seealso: [](ch_dmbase), `DM`, `DMRefine()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`
2627 @*/
DMExtrude(DM dm,PetscInt layers,DM * dme)2628 PetscErrorCode DMExtrude(DM dm, PetscInt layers, DM *dme)
2629 {
2630 PetscFunctionBegin;
2631 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2632 PetscUseTypeMethod(dm, extrude, layers, dme);
2633 if (*dme) {
2634 (*dme)->ops->creatematrix = dm->ops->creatematrix;
2635 PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dme));
2636 (*dme)->ctx = dm->ctx;
2637 PetscCall(DMSetMatType(*dme, dm->mattype));
2638 }
2639 PetscFunctionReturn(PETSC_SUCCESS);
2640 }
2641
DMGetBasisTransformDM_Internal(DM dm,DM * tdm)2642 PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2643 {
2644 PetscFunctionBegin;
2645 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2646 PetscAssertPointer(tdm, 2);
2647 *tdm = dm->transformDM;
2648 PetscFunctionReturn(PETSC_SUCCESS);
2649 }
2650
DMGetBasisTransformVec_Internal(DM dm,Vec * tv)2651 PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2652 {
2653 PetscFunctionBegin;
2654 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2655 PetscAssertPointer(tv, 2);
2656 *tv = dm->transform;
2657 PetscFunctionReturn(PETSC_SUCCESS);
2658 }
2659
2660 /*@
2661 DMHasBasisTransform - Whether the `DM` employs a basis transformation from functions in global vectors to functions in local vectors
2662
2663 Input Parameter:
2664 . dm - The `DM`
2665
2666 Output Parameter:
2667 . flg - `PETSC_TRUE` if a basis transformation should be done
2668
2669 Level: developer
2670
2671 .seealso: [](ch_dmbase), `DM`, `DMPlexGlobalToLocalBasis()`, `DMPlexLocalToGlobalBasis()`, `DMPlexCreateBasisRotation()`
2672 @*/
DMHasBasisTransform(DM dm,PetscBool * flg)2673 PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
2674 {
2675 Vec tv;
2676
2677 PetscFunctionBegin;
2678 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2679 PetscAssertPointer(flg, 2);
2680 PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
2681 *flg = tv ? PETSC_TRUE : PETSC_FALSE;
2682 PetscFunctionReturn(PETSC_SUCCESS);
2683 }
2684
DMConstructBasisTransform_Internal(DM dm)2685 PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
2686 {
2687 PetscSection s, ts;
2688 PetscScalar *ta;
2689 PetscInt cdim, pStart, pEnd, p, Nf, f, Nc, dof;
2690
2691 PetscFunctionBegin;
2692 PetscCall(DMGetCoordinateDim(dm, &cdim));
2693 PetscCall(DMGetLocalSection(dm, &s));
2694 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
2695 PetscCall(PetscSectionGetNumFields(s, &Nf));
2696 PetscCall(DMClone(dm, &dm->transformDM));
2697 PetscCall(DMGetLocalSection(dm->transformDM, &ts));
2698 PetscCall(PetscSectionSetNumFields(ts, Nf));
2699 PetscCall(PetscSectionSetChart(ts, pStart, pEnd));
2700 for (f = 0; f < Nf; ++f) {
2701 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc));
2702 /* We could start to label fields by their transformation properties */
2703 if (Nc != cdim) continue;
2704 for (p = pStart; p < pEnd; ++p) {
2705 PetscCall(PetscSectionGetFieldDof(s, p, f, &dof));
2706 if (!dof) continue;
2707 PetscCall(PetscSectionSetFieldDof(ts, p, f, PetscSqr(cdim)));
2708 PetscCall(PetscSectionAddDof(ts, p, PetscSqr(cdim)));
2709 }
2710 }
2711 PetscCall(PetscSectionSetUp(ts));
2712 PetscCall(DMCreateLocalVector(dm->transformDM, &dm->transform));
2713 PetscCall(VecGetArray(dm->transform, &ta));
2714 for (p = pStart; p < pEnd; ++p) {
2715 for (f = 0; f < Nf; ++f) {
2716 PetscCall(PetscSectionGetFieldDof(ts, p, f, &dof));
2717 if (dof) {
2718 PetscReal x[3] = {0.0, 0.0, 0.0};
2719 PetscScalar *tva;
2720 const PetscScalar *A;
2721
2722 /* TODO Get quadrature point for this dual basis vector for coordinate */
2723 PetscCall((*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx));
2724 PetscCall(DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *)&tva));
2725 PetscCall(PetscArraycpy(tva, A, PetscSqr(cdim)));
2726 }
2727 }
2728 }
2729 PetscCall(VecRestoreArray(dm->transform, &ta));
2730 PetscFunctionReturn(PETSC_SUCCESS);
2731 }
2732
DMCopyTransform(DM dm,DM newdm)2733 PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2734 {
2735 PetscFunctionBegin;
2736 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2737 PetscValidHeaderSpecific(newdm, DM_CLASSID, 2);
2738 newdm->transformCtx = dm->transformCtx;
2739 newdm->transformSetUp = dm->transformSetUp;
2740 newdm->transformDestroy = NULL;
2741 newdm->transformGetMatrix = dm->transformGetMatrix;
2742 if (newdm->transformSetUp) PetscCall(DMConstructBasisTransform_Internal(newdm));
2743 PetscFunctionReturn(PETSC_SUCCESS);
2744 }
2745
2746 /*@C
2747 DMGlobalToLocalHookAdd - adds a callback to be run when `DMGlobalToLocal()` is called
2748
2749 Logically Collective
2750
2751 Input Parameters:
2752 + dm - the `DM`
2753 . beginhook - function to run at the beginning of `DMGlobalToLocalBegin()`
2754 . endhook - function to run after `DMGlobalToLocalEnd()` has completed
2755 - ctx - [optional] user-defined context for provide data for the hooks (may be `NULL`)
2756
2757 Calling sequence of `beginhook`:
2758 + dm - global `DM`
2759 . g - global vector
2760 . mode - mode
2761 . l - local vector
2762 - ctx - optional user-defined function context
2763
2764 Calling sequence of `endhook`:
2765 + dm - global `DM`
2766 . g - global vector
2767 . mode - mode
2768 . l - local vector
2769 - ctx - optional user-defined function context
2770
2771 Level: advanced
2772
2773 Note:
2774 The hook may be used to provide, for example, values that represent boundary conditions in the local vectors that do not exist on the global vector.
2775
2776 .seealso: [](ch_dmbase), `DM`, `DMGlobalToLocal()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2777 @*/
DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (* beginhook)(DM dm,Vec g,InsertMode mode,Vec l,PetscCtx ctx),PetscErrorCode (* endhook)(DM dm,Vec g,InsertMode mode,Vec l,PetscCtx ctx),PetscCtx ctx)2778 PetscErrorCode DMGlobalToLocalHookAdd(DM dm, PetscErrorCode (*beginhook)(DM dm, Vec g, InsertMode mode, Vec l, PetscCtx ctx), PetscErrorCode (*endhook)(DM dm, Vec g, InsertMode mode, Vec l, PetscCtx ctx), PetscCtx ctx)
2779 {
2780 DMGlobalToLocalHookLink link, *p;
2781
2782 PetscFunctionBegin;
2783 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2784 for (p = &dm->gtolhook; *p; p = &(*p)->next) { } /* Scan to the end of the current list of hooks */
2785 PetscCall(PetscNew(&link));
2786 link->beginhook = beginhook;
2787 link->endhook = endhook;
2788 link->ctx = ctx;
2789 link->next = NULL;
2790 *p = link;
2791 PetscFunctionReturn(PETSC_SUCCESS);
2792 }
2793
DMGlobalToLocalHook_Constraints(DM dm,Vec g,InsertMode mode,Vec l,PetscCtx ctx)2794 static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, PetscCtx ctx)
2795 {
2796 Mat cMat;
2797 Vec cVec, cBias;
2798 PetscSection section, cSec;
2799 PetscInt pStart, pEnd, p, dof;
2800
2801 PetscFunctionBegin;
2802 (void)g;
2803 (void)ctx;
2804 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2805 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, &cBias));
2806 if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2807 PetscInt nRows;
2808
2809 PetscCall(MatGetSize(cMat, &nRows, NULL));
2810 if (nRows <= 0) PetscFunctionReturn(PETSC_SUCCESS);
2811 PetscCall(DMGetLocalSection(dm, §ion));
2812 PetscCall(MatCreateVecs(cMat, NULL, &cVec));
2813 PetscCall(MatMult(cMat, l, cVec));
2814 if (cBias) PetscCall(VecAXPY(cVec, 1., cBias));
2815 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd));
2816 for (p = pStart; p < pEnd; p++) {
2817 PetscCall(PetscSectionGetDof(cSec, p, &dof));
2818 if (dof) {
2819 PetscScalar *vals;
2820 PetscCall(VecGetValuesSection(cVec, cSec, p, &vals));
2821 PetscCall(VecSetValuesSection(l, section, p, vals, INSERT_ALL_VALUES));
2822 }
2823 }
2824 PetscCall(VecDestroy(&cVec));
2825 }
2826 PetscFunctionReturn(PETSC_SUCCESS);
2827 }
2828
2829 /*@
2830 DMGlobalToLocal - update local vectors from global vector
2831
2832 Neighbor-wise Collective
2833
2834 Input Parameters:
2835 + dm - the `DM` object
2836 . g - the global vector
2837 . mode - `INSERT_VALUES` or `ADD_VALUES`
2838 - l - the local vector
2839
2840 Level: beginner
2841
2842 Notes:
2843 The communication involved in this update can be overlapped with computation by instead using
2844 `DMGlobalToLocalBegin()` and `DMGlobalToLocalEnd()`.
2845
2846 `DMGlobalToLocalHookAdd()` may be used to provide additional operations that are performed during the update process.
2847
2848 .seealso: [](ch_dmbase), `DM`, `DMGlobalToLocalHookAdd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`,
2849 `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalEnd()`,
2850 `DMGlobalToLocalBegin()` `DMGlobalToLocalEnd()`
2851 @*/
DMGlobalToLocal(DM dm,Vec g,InsertMode mode,Vec l)2852 PetscErrorCode DMGlobalToLocal(DM dm, Vec g, InsertMode mode, Vec l)
2853 {
2854 PetscFunctionBegin;
2855 PetscCall(DMGlobalToLocalBegin(dm, g, mode, l));
2856 PetscCall(DMGlobalToLocalEnd(dm, g, mode, l));
2857 PetscFunctionReturn(PETSC_SUCCESS);
2858 }
2859
2860 /*@
2861 DMGlobalToLocalBegin - Begins updating local vectors from global vector
2862
2863 Neighbor-wise Collective
2864
2865 Input Parameters:
2866 + dm - the `DM` object
2867 . g - the global vector
2868 . mode - `INSERT_VALUES` or `ADD_VALUES`
2869 - l - the local vector
2870
2871 Level: intermediate
2872
2873 Notes:
2874 The operation is completed with `DMGlobalToLocalEnd()`
2875
2876 One can perform local computations between the `DMGlobalToLocalBegin()` and `DMGlobalToLocalEnd()` to overlap communication and computation
2877
2878 `DMGlobalToLocal()` is a short form of `DMGlobalToLocalBegin()` and `DMGlobalToLocalEnd()`
2879
2880 `DMGlobalToLocalHookAdd()` may be used to provide additional operations that are performed during the update process.
2881
2882 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalEnd()`
2883 @*/
DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)2884 PetscErrorCode DMGlobalToLocalBegin(DM dm, Vec g, InsertMode mode, Vec l)
2885 {
2886 PetscSF sf;
2887 DMGlobalToLocalHookLink link;
2888
2889 PetscFunctionBegin;
2890 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2891 for (link = dm->gtolhook; link; link = link->next) {
2892 if (link->beginhook) PetscCall((*link->beginhook)(dm, g, mode, l, link->ctx));
2893 }
2894 PetscCall(DMGetSectionSF(dm, &sf));
2895 if (sf) {
2896 const PetscScalar *gArray;
2897 PetscScalar *lArray;
2898 PetscMemType lmtype, gmtype;
2899
2900 PetscCheck(mode != ADD_VALUES, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", (int)mode);
2901 PetscCall(VecGetArrayAndMemType(l, &lArray, &lmtype));
2902 PetscCall(VecGetArrayReadAndMemType(g, &gArray, &gmtype));
2903 PetscCall(PetscSFBcastWithMemTypeBegin(sf, MPIU_SCALAR, gmtype, gArray, lmtype, lArray, MPI_REPLACE));
2904 PetscCall(VecRestoreArrayAndMemType(l, &lArray));
2905 PetscCall(VecRestoreArrayReadAndMemType(g, &gArray));
2906 } else {
2907 PetscUseTypeMethod(dm, globaltolocalbegin, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
2908 }
2909 PetscFunctionReturn(PETSC_SUCCESS);
2910 }
2911
2912 /*@
2913 DMGlobalToLocalEnd - Ends updating local vectors from global vector
2914
2915 Neighbor-wise Collective
2916
2917 Input Parameters:
2918 + dm - the `DM` object
2919 . g - the global vector
2920 . mode - `INSERT_VALUES` or `ADD_VALUES`
2921 - l - the local vector
2922
2923 Level: intermediate
2924
2925 Note:
2926 See `DMGlobalToLocalBegin()` for details.
2927
2928 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalEnd()`
2929 @*/
DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)2930 PetscErrorCode DMGlobalToLocalEnd(DM dm, Vec g, InsertMode mode, Vec l)
2931 {
2932 PetscSF sf;
2933 const PetscScalar *gArray;
2934 PetscScalar *lArray;
2935 PetscBool transform;
2936 DMGlobalToLocalHookLink link;
2937 PetscMemType lmtype, gmtype;
2938
2939 PetscFunctionBegin;
2940 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2941 PetscCall(DMGetSectionSF(dm, &sf));
2942 PetscCall(DMHasBasisTransform(dm, &transform));
2943 if (sf) {
2944 PetscCheck(mode != ADD_VALUES, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", (int)mode);
2945
2946 PetscCall(VecGetArrayAndMemType(l, &lArray, &lmtype));
2947 PetscCall(VecGetArrayReadAndMemType(g, &gArray, &gmtype));
2948 PetscCall(PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray, MPI_REPLACE));
2949 PetscCall(VecRestoreArrayAndMemType(l, &lArray));
2950 PetscCall(VecRestoreArrayReadAndMemType(g, &gArray));
2951 if (transform) PetscCall(DMPlexGlobalToLocalBasis(dm, l));
2952 } else {
2953 PetscUseTypeMethod(dm, globaltolocalend, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
2954 }
2955 PetscCall(DMGlobalToLocalHook_Constraints(dm, g, mode, l, NULL));
2956 for (link = dm->gtolhook; link; link = link->next) {
2957 if (link->endhook) PetscCall((*link->endhook)(dm, g, mode, l, link->ctx));
2958 }
2959 PetscFunctionReturn(PETSC_SUCCESS);
2960 }
2961
2962 /*@C
2963 DMLocalToGlobalHookAdd - adds a callback to be run when a local to global is called
2964
2965 Logically Collective
2966
2967 Input Parameters:
2968 + dm - the `DM`
2969 . beginhook - function to run at the beginning of `DMLocalToGlobalBegin()`
2970 . endhook - function to run after `DMLocalToGlobalEnd()` has completed
2971 - ctx - [optional] user-defined context for provide data for the hooks (may be `NULL`)
2972
2973 Calling sequence of `beginhook`:
2974 + global - global `DM`
2975 . l - local vector
2976 . mode - mode
2977 . g - global vector
2978 - ctx - optional user-defined function context
2979
2980 Calling sequence of `endhook`:
2981 + global - global `DM`
2982 . l - local vector
2983 . mode - mode
2984 . g - global vector
2985 - ctx - optional user-defined function context
2986
2987 Level: advanced
2988
2989 .seealso: [](ch_dmbase), `DM`, `DMLocalToGlobal()`, `DMRefineHookAdd()`, `DMGlobalToLocalHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2990 @*/
DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (* beginhook)(DM global,Vec l,InsertMode mode,Vec g,PetscCtx ctx),PetscErrorCode (* endhook)(DM global,Vec l,InsertMode mode,Vec g,PetscCtx ctx),PetscCtx ctx)2991 PetscErrorCode DMLocalToGlobalHookAdd(DM dm, PetscErrorCode (*beginhook)(DM global, Vec l, InsertMode mode, Vec g, PetscCtx ctx), PetscErrorCode (*endhook)(DM global, Vec l, InsertMode mode, Vec g, PetscCtx ctx), PetscCtx ctx)
2992 {
2993 DMLocalToGlobalHookLink link, *p;
2994
2995 PetscFunctionBegin;
2996 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2997 for (p = &dm->ltoghook; *p; p = &(*p)->next) { } /* Scan to the end of the current list of hooks */
2998 PetscCall(PetscNew(&link));
2999 link->beginhook = beginhook;
3000 link->endhook = endhook;
3001 link->ctx = ctx;
3002 link->next = NULL;
3003 *p = link;
3004 PetscFunctionReturn(PETSC_SUCCESS);
3005 }
3006
DMLocalToGlobalHook_Constraints(DM dm,Vec l,InsertMode mode,Vec g,PetscCtx ctx)3007 static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, PetscCtx ctx)
3008 {
3009 PetscFunctionBegin;
3010 (void)g;
3011 (void)ctx;
3012 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3013 if (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES) {
3014 Mat cMat;
3015 Vec cVec;
3016 PetscInt nRows;
3017 PetscSection section, cSec;
3018 PetscInt pStart, pEnd, p, dof;
3019
3020 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL));
3021 if (!cMat) PetscFunctionReturn(PETSC_SUCCESS);
3022
3023 PetscCall(MatGetSize(cMat, &nRows, NULL));
3024 if (nRows <= 0) PetscFunctionReturn(PETSC_SUCCESS);
3025 PetscCall(DMGetLocalSection(dm, §ion));
3026 PetscCall(MatCreateVecs(cMat, NULL, &cVec));
3027 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd));
3028 for (p = pStart; p < pEnd; p++) {
3029 PetscCall(PetscSectionGetDof(cSec, p, &dof));
3030 if (dof) {
3031 PetscInt d;
3032 PetscScalar *vals;
3033 PetscCall(VecGetValuesSection(l, section, p, &vals));
3034 PetscCall(VecSetValuesSection(cVec, cSec, p, vals, mode));
3035 /* for this to be the true transpose, we have to zero the values that
3036 * we just extracted */
3037 for (d = 0; d < dof; d++) vals[d] = 0.;
3038 }
3039 }
3040 PetscCall(MatMultTransposeAdd(cMat, cVec, l, l));
3041 PetscCall(VecDestroy(&cVec));
3042 }
3043 PetscFunctionReturn(PETSC_SUCCESS);
3044 }
3045 /*@
3046 DMLocalToGlobal - updates global vectors from local vectors
3047
3048 Neighbor-wise Collective
3049
3050 Input Parameters:
3051 + dm - the `DM` object
3052 . l - the local vector
3053 . mode - if `INSERT_VALUES` then no parallel communication is used, if `ADD_VALUES` then all ghost points from the same base point accumulate into that base point.
3054 - g - the global vector
3055
3056 Level: beginner
3057
3058 Notes:
3059 The communication involved in this update can be overlapped with computation by using
3060 `DMLocalToGlobalBegin()` and `DMLocalToGlobalEnd()`.
3061
3062 In the `ADD_VALUES` case you normally would zero the receiving vector before beginning this operation.
3063
3064 `INSERT_VALUES` is not supported for `DMDA`; in that case simply compute the values directly into a global vector instead of a local one.
3065
3066 Use `DMLocalToGlobalHookAdd()` to add additional operations that are performed on the data during the update process
3067
3068 .seealso: [](ch_dmbase), `DM`, `DMLocalToGlobalBegin()`, `DMLocalToGlobalEnd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMGlobalToLocalBegin()`, `DMLocalToGlobalHookAdd()`, `DMGlobaToLocallHookAdd()`
3069 @*/
DMLocalToGlobal(DM dm,Vec l,InsertMode mode,Vec g)3070 PetscErrorCode DMLocalToGlobal(DM dm, Vec l, InsertMode mode, Vec g)
3071 {
3072 PetscFunctionBegin;
3073 PetscCall(DMLocalToGlobalBegin(dm, l, mode, g));
3074 PetscCall(DMLocalToGlobalEnd(dm, l, mode, g));
3075 PetscFunctionReturn(PETSC_SUCCESS);
3076 }
3077
3078 /*@
3079 DMLocalToGlobalBegin - begins updating global vectors from local vectors
3080
3081 Neighbor-wise Collective
3082
3083 Input Parameters:
3084 + dm - the `DM` object
3085 . l - the local vector
3086 . mode - if `INSERT_VALUES` then no parallel communication is used, if `ADD_VALUES` then all ghost points from the same base point accumulate into that base point.
3087 - g - the global vector
3088
3089 Level: intermediate
3090
3091 Notes:
3092 In the `ADD_VALUES` case you normally would zero the receiving vector before beginning this operation.
3093
3094 `INSERT_VALUES is` not supported for `DMDA`, in that case simply compute the values directly into a global vector instead of a local one.
3095
3096 Use `DMLocalToGlobalEnd()` to complete the communication process.
3097
3098 `DMLocalToGlobal()` is a short form of `DMLocalToGlobalBegin()` and `DMLocalToGlobalEnd()`
3099
3100 `DMLocalToGlobalHookAdd()` may be used to provide additional operations that are performed during the update process.
3101
3102 .seealso: [](ch_dmbase), `DM`, `DMLocalToGlobal()`, `DMLocalToGlobalEnd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMGlobalToLocalBegin()`
3103 @*/
DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)3104 PetscErrorCode DMLocalToGlobalBegin(DM dm, Vec l, InsertMode mode, Vec g)
3105 {
3106 PetscSF sf;
3107 PetscSection s, gs;
3108 DMLocalToGlobalHookLink link;
3109 Vec tmpl;
3110 const PetscScalar *lArray;
3111 PetscScalar *gArray;
3112 PetscBool isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE;
3113 PetscMemType lmtype = PETSC_MEMTYPE_HOST, gmtype = PETSC_MEMTYPE_HOST;
3114
3115 PetscFunctionBegin;
3116 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3117 for (link = dm->ltoghook; link; link = link->next) {
3118 if (link->beginhook) PetscCall((*link->beginhook)(dm, l, mode, g, link->ctx));
3119 }
3120 PetscCall(DMLocalToGlobalHook_Constraints(dm, l, mode, g, NULL));
3121 PetscCall(DMGetSectionSF(dm, &sf));
3122 PetscCall(DMGetLocalSection(dm, &s));
3123 switch (mode) {
3124 case INSERT_VALUES:
3125 case INSERT_ALL_VALUES:
3126 case INSERT_BC_VALUES:
3127 isInsert = PETSC_TRUE;
3128 break;
3129 case ADD_VALUES:
3130 case ADD_ALL_VALUES:
3131 case ADD_BC_VALUES:
3132 isInsert = PETSC_FALSE;
3133 break;
3134 default:
3135 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", mode);
3136 }
3137 if ((sf && !isInsert) || (s && isInsert)) {
3138 PetscCall(DMHasBasisTransform(dm, &transform));
3139 if (transform) {
3140 PetscCall(DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl));
3141 PetscCall(VecCopy(l, tmpl));
3142 PetscCall(DMPlexLocalToGlobalBasis(dm, tmpl));
3143 PetscCall(VecGetArrayRead(tmpl, &lArray));
3144 } else if (isInsert) {
3145 PetscCall(VecGetArrayRead(l, &lArray));
3146 } else {
3147 PetscCall(VecGetArrayReadAndMemType(l, &lArray, &lmtype));
3148 l_inplace = PETSC_TRUE;
3149 }
3150 if (s && isInsert) {
3151 PetscCall(VecGetArray(g, &gArray));
3152 } else {
3153 PetscCall(VecGetArrayAndMemType(g, &gArray, &gmtype));
3154 g_inplace = PETSC_TRUE;
3155 }
3156 if (sf && !isInsert) {
3157 PetscCall(PetscSFReduceWithMemTypeBegin(sf, MPIU_SCALAR, lmtype, lArray, gmtype, gArray, MPIU_SUM));
3158 } else if (s && isInsert) {
3159 PetscInt gStart, pStart, pEnd, p;
3160
3161 PetscCall(DMGetGlobalSection(dm, &gs));
3162 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
3163 PetscCall(VecGetOwnershipRange(g, &gStart, NULL));
3164 for (p = pStart; p < pEnd; ++p) {
3165 PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;
3166
3167 PetscCall(PetscSectionGetDof(s, p, &dof));
3168 PetscCall(PetscSectionGetDof(gs, p, &gdof));
3169 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
3170 PetscCall(PetscSectionGetConstraintDof(gs, p, &gcdof));
3171 PetscCall(PetscSectionGetOffset(s, p, &off));
3172 PetscCall(PetscSectionGetOffset(gs, p, &goff));
3173 /* Ignore off-process data and points with no global data */
3174 if (!gdof || goff < 0) continue;
3175 PetscCheck(dof == gdof, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Inconsistent sizes, p: %" PetscInt_FMT " dof: %" PetscInt_FMT " gdof: %" PetscInt_FMT " cdof: %" PetscInt_FMT " gcdof: %" PetscInt_FMT, p, dof, gdof, cdof, gcdof);
3176 /* If no constraints are enforced in the global vector */
3177 if (!gcdof) {
3178 for (d = 0; d < dof; ++d) gArray[goff - gStart + d] = lArray[off + d];
3179 /* If constraints are enforced in the global vector */
3180 } else if (cdof == gcdof) {
3181 const PetscInt *cdofs;
3182 PetscInt cind = 0;
3183
3184 PetscCall(PetscSectionGetConstraintIndices(s, p, &cdofs));
3185 for (d = 0, e = 0; d < dof; ++d) {
3186 if ((cind < cdof) && (d == cdofs[cind])) {
3187 ++cind;
3188 continue;
3189 }
3190 gArray[goff - gStart + e++] = lArray[off + d];
3191 }
3192 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Inconsistent sizes, p: %" PetscInt_FMT " dof: %" PetscInt_FMT " gdof: %" PetscInt_FMT " cdof: %" PetscInt_FMT " gcdof: %" PetscInt_FMT, p, dof, gdof, cdof, gcdof);
3193 }
3194 }
3195 if (g_inplace) {
3196 PetscCall(VecRestoreArrayAndMemType(g, &gArray));
3197 } else {
3198 PetscCall(VecRestoreArray(g, &gArray));
3199 }
3200 if (transform) {
3201 PetscCall(VecRestoreArrayRead(tmpl, &lArray));
3202 PetscCall(DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl));
3203 } else if (l_inplace) {
3204 PetscCall(VecRestoreArrayReadAndMemType(l, &lArray));
3205 } else {
3206 PetscCall(VecRestoreArrayRead(l, &lArray));
3207 }
3208 } else {
3209 PetscUseTypeMethod(dm, localtoglobalbegin, l, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), g);
3210 }
3211 PetscFunctionReturn(PETSC_SUCCESS);
3212 }
3213
3214 /*@
3215 DMLocalToGlobalEnd - updates global vectors from local vectors
3216
3217 Neighbor-wise Collective
3218
3219 Input Parameters:
3220 + dm - the `DM` object
3221 . l - the local vector
3222 . mode - `INSERT_VALUES` or `ADD_VALUES`
3223 - g - the global vector
3224
3225 Level: intermediate
3226
3227 Note:
3228 See `DMLocalToGlobalBegin()` for full details
3229
3230 .seealso: [](ch_dmbase), `DM`, `DMLocalToGlobalBegin()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocalEnd()`
3231 @*/
DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)3232 PetscErrorCode DMLocalToGlobalEnd(DM dm, Vec l, InsertMode mode, Vec g)
3233 {
3234 PetscSF sf;
3235 PetscSection s;
3236 DMLocalToGlobalHookLink link;
3237 PetscBool isInsert, transform;
3238
3239 PetscFunctionBegin;
3240 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3241 PetscCall(DMGetSectionSF(dm, &sf));
3242 PetscCall(DMGetLocalSection(dm, &s));
3243 switch (mode) {
3244 case INSERT_VALUES:
3245 case INSERT_ALL_VALUES:
3246 isInsert = PETSC_TRUE;
3247 break;
3248 case ADD_VALUES:
3249 case ADD_ALL_VALUES:
3250 isInsert = PETSC_FALSE;
3251 break;
3252 default:
3253 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", mode);
3254 }
3255 if (sf && !isInsert) {
3256 const PetscScalar *lArray;
3257 PetscScalar *gArray;
3258 Vec tmpl;
3259
3260 PetscCall(DMHasBasisTransform(dm, &transform));
3261 if (transform) {
3262 PetscCall(DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl));
3263 PetscCall(VecGetArrayRead(tmpl, &lArray));
3264 } else {
3265 PetscCall(VecGetArrayReadAndMemType(l, &lArray, NULL));
3266 }
3267 PetscCall(VecGetArrayAndMemType(g, &gArray, NULL));
3268 PetscCall(PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM));
3269 if (transform) {
3270 PetscCall(VecRestoreArrayRead(tmpl, &lArray));
3271 PetscCall(DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl));
3272 } else {
3273 PetscCall(VecRestoreArrayReadAndMemType(l, &lArray));
3274 }
3275 PetscCall(VecRestoreArrayAndMemType(g, &gArray));
3276 } else if (s && isInsert) {
3277 } else {
3278 PetscUseTypeMethod(dm, localtoglobalend, l, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), g);
3279 }
3280 for (link = dm->ltoghook; link; link = link->next) {
3281 if (link->endhook) PetscCall((*link->endhook)(dm, g, mode, l, link->ctx));
3282 }
3283 PetscFunctionReturn(PETSC_SUCCESS);
3284 }
3285
3286 /*@
3287 DMLocalToLocalBegin - Begins the process of mapping values from a local vector (that include
3288 ghost points that contain irrelevant values) to another local vector where the ghost points
3289 in the second are set correctly from values on other MPI ranks.
3290
3291 Neighbor-wise Collective
3292
3293 Input Parameters:
3294 + dm - the `DM` object
3295 . g - the original local vector
3296 - mode - one of `INSERT_VALUES` or `ADD_VALUES`
3297
3298 Output Parameter:
3299 . l - the local vector with correct ghost values
3300
3301 Level: intermediate
3302
3303 Note:
3304 Must be followed by `DMLocalToLocalEnd()`.
3305
3306 .seealso: [](ch_dmbase), `DM`, `DMLocalToLocalEnd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`
3307 @*/
DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)3308 PetscErrorCode DMLocalToLocalBegin(DM dm, Vec g, InsertMode mode, Vec l)
3309 {
3310 PetscFunctionBegin;
3311 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3312 PetscValidHeaderSpecific(g, VEC_CLASSID, 2);
3313 PetscValidHeaderSpecific(l, VEC_CLASSID, 4);
3314 PetscUseTypeMethod(dm, localtolocalbegin, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
3315 PetscFunctionReturn(PETSC_SUCCESS);
3316 }
3317
3318 /*@
3319 DMLocalToLocalEnd - Maps from a local vector to another local vector where the ghost
3320 points in the second are set correctly. Must be preceded by `DMLocalToLocalBegin()`.
3321
3322 Neighbor-wise Collective
3323
3324 Input Parameters:
3325 + dm - the `DM` object
3326 . g - the original local vector
3327 - mode - one of `INSERT_VALUES` or `ADD_VALUES`
3328
3329 Output Parameter:
3330 . l - the local vector with correct ghost values
3331
3332 Level: intermediate
3333
3334 .seealso: [](ch_dmbase), `DM`, `DMLocalToLocalBegin()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`
3335 @*/
DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)3336 PetscErrorCode DMLocalToLocalEnd(DM dm, Vec g, InsertMode mode, Vec l)
3337 {
3338 PetscFunctionBegin;
3339 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3340 PetscValidHeaderSpecific(g, VEC_CLASSID, 2);
3341 PetscValidHeaderSpecific(l, VEC_CLASSID, 4);
3342 PetscUseTypeMethod(dm, localtolocalend, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
3343 PetscFunctionReturn(PETSC_SUCCESS);
3344 }
3345
3346 /*@
3347 DMCoarsen - Coarsens a `DM` object using a standard, non-adaptive coarsening of the underlying mesh
3348
3349 Collective
3350
3351 Input Parameters:
3352 + dm - the `DM` object
3353 - comm - the communicator to contain the new `DM` object (or `MPI_COMM_NULL`)
3354
3355 Output Parameter:
3356 . dmc - the coarsened `DM`
3357
3358 Level: developer
3359
3360 .seealso: [](ch_dmbase), `DM`, `DMRefine()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateDomainDecomposition()`,
3361 `DMCoarsenHookAdd()`, `DMCoarsenHookRemove()`
3362 @*/
DMCoarsen(DM dm,MPI_Comm comm,DM * dmc)3363 PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
3364 {
3365 DMCoarsenHookLink link;
3366
3367 PetscFunctionBegin;
3368 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3369 PetscCall(PetscLogEventBegin(DM_Coarsen, dm, 0, 0, 0));
3370 PetscUseTypeMethod(dm, coarsen, comm, dmc);
3371 if (*dmc) {
3372 (*dmc)->bind_below = dm->bind_below; /* Propagate this from parent DM; otherwise -dm_bind_below will be useless for multigrid cases. */
3373 PetscCall(DMSetCoarseDM(dm, *dmc));
3374 (*dmc)->ops->creatematrix = dm->ops->creatematrix;
3375 PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dmc));
3376 (*dmc)->ctx = dm->ctx;
3377 (*dmc)->levelup = dm->levelup;
3378 (*dmc)->leveldown = dm->leveldown + 1;
3379 PetscCall(DMSetMatType(*dmc, dm->mattype));
3380 for (link = dm->coarsenhook; link; link = link->next) {
3381 if (link->coarsenhook) PetscCall((*link->coarsenhook)(dm, *dmc, link->ctx));
3382 }
3383 }
3384 PetscCall(PetscLogEventEnd(DM_Coarsen, dm, 0, 0, 0));
3385 PetscCheck(*dmc, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced");
3386 PetscFunctionReturn(PETSC_SUCCESS);
3387 }
3388
3389 /*@C
3390 DMCoarsenHookAdd - adds a callback to be run when restricting a nonlinear problem to the coarse grid
3391
3392 Logically Collective; No Fortran Support
3393
3394 Input Parameters:
3395 + fine - `DM` on which to run a hook when restricting to a coarser level
3396 . coarsenhook - function to run when setting up a coarser level
3397 . restricthook - function to run to update data on coarser levels (called once per `SNESSolve()`)
3398 - ctx - [optional] user-defined context for provide data for the hooks (may be `NULL`)
3399
3400 Calling sequence of `coarsenhook`:
3401 + fine - fine level `DM`
3402 . coarse - coarse level `DM` to restrict problem to
3403 - ctx - optional user-defined function context
3404
3405 Calling sequence of `restricthook`:
3406 + fine - fine level `DM`
3407 . mrestrict - matrix restricting a fine-level solution to the coarse grid, usually the transpose of the interpolation
3408 . rscale - scaling vector for restriction
3409 . inject - matrix restricting by injection
3410 . coarse - coarse level DM to update
3411 - ctx - optional user-defined function context
3412
3413 Level: advanced
3414
3415 Notes:
3416 This function is only needed if auxiliary data, attached to the `DM` with `PetscObjectCompose()`, needs to be set up or passed from the fine `DM` to the coarse `DM`.
3417
3418 If this function is called multiple times, the hooks will be run in the order they are added.
3419
3420 In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3421 extract the finest level information from its context (instead of from the `SNES`).
3422
3423 The hooks are automatically called by `DMRestrict()`
3424
3425 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookRemove()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3426 @*/
DMCoarsenHookAdd(DM fine,PetscErrorCode (* coarsenhook)(DM fine,DM coarse,PetscCtx ctx),PetscErrorCode (* restricthook)(DM fine,Mat mrestrict,Vec rscale,Mat inject,DM coarse,PetscCtx ctx),PetscCtx ctx)3427 PetscErrorCode DMCoarsenHookAdd(DM fine, PetscErrorCode (*coarsenhook)(DM fine, DM coarse, PetscCtx ctx), PetscErrorCode (*restricthook)(DM fine, Mat mrestrict, Vec rscale, Mat inject, DM coarse, PetscCtx ctx), PetscCtx ctx)
3428 {
3429 DMCoarsenHookLink link, *p;
3430
3431 PetscFunctionBegin;
3432 PetscValidHeaderSpecific(fine, DM_CLASSID, 1);
3433 for (p = &fine->coarsenhook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */
3434 if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) PetscFunctionReturn(PETSC_SUCCESS);
3435 }
3436 PetscCall(PetscNew(&link));
3437 link->coarsenhook = coarsenhook;
3438 link->restricthook = restricthook;
3439 link->ctx = ctx;
3440 link->next = NULL;
3441 *p = link;
3442 PetscFunctionReturn(PETSC_SUCCESS);
3443 }
3444
3445 /*@C
3446 DMCoarsenHookRemove - remove a callback set with `DMCoarsenHookAdd()`
3447
3448 Logically Collective; No Fortran Support
3449
3450 Input Parameters:
3451 + fine - `DM` on which to run a hook when restricting to a coarser level
3452 . coarsenhook - function to run when setting up a coarser level
3453 . restricthook - function to run to update data on coarser levels
3454 - ctx - [optional] user-defined context for provide data for the hooks (may be `NULL`)
3455
3456 Level: advanced
3457
3458 Notes:
3459 This function does nothing if the `coarsenhook` is not in the list.
3460
3461 See `DMCoarsenHookAdd()` for the calling sequence of `coarsenhook` and `restricthook`
3462
3463 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookAdd()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3464 @*/
DMCoarsenHookRemove(DM fine,PetscErrorCode (* coarsenhook)(DM,DM,void *),PetscErrorCode (* restricthook)(DM,Mat,Vec,Mat,DM,void *),PetscCtx ctx)3465 PetscErrorCode DMCoarsenHookRemove(DM fine, PetscErrorCode (*coarsenhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, Mat, Vec, Mat, DM, void *), PetscCtx ctx)
3466 {
3467 DMCoarsenHookLink link, *p;
3468
3469 PetscFunctionBegin;
3470 PetscValidHeaderSpecific(fine, DM_CLASSID, 1);
3471 for (p = &fine->coarsenhook; *p; p = &(*p)->next) { /* Search the list of current hooks */
3472 if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3473 link = *p;
3474 *p = link->next;
3475 PetscCall(PetscFree(link));
3476 break;
3477 }
3478 }
3479 PetscFunctionReturn(PETSC_SUCCESS);
3480 }
3481
3482 /*@
3483 DMRestrict - restricts user-defined problem data to a coarser `DM` by running hooks registered by `DMCoarsenHookAdd()`
3484
3485 Collective if any hooks are
3486
3487 Input Parameters:
3488 + fine - finer `DM` from which the data is obtained
3489 . restrct - restriction matrix, apply using `MatRestrict()`, usually the transpose of the interpolation
3490 . rscale - scaling vector for restriction
3491 . inject - injection matrix, also use `MatRestrict()`
3492 - coarse - coarser `DM` to update
3493
3494 Level: developer
3495
3496 Developer Note:
3497 Though this routine is called `DMRestrict()` the hooks are added with `DMCoarsenHookAdd()`, a consistent terminology would be better
3498
3499 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookAdd()`, `MatRestrict()`, `DMInterpolate()`, `DMRefineHookAdd()`
3500 @*/
DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)3501 PetscErrorCode DMRestrict(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse)
3502 {
3503 DMCoarsenHookLink link;
3504
3505 PetscFunctionBegin;
3506 for (link = fine->coarsenhook; link; link = link->next) {
3507 if (link->restricthook) PetscCall((*link->restricthook)(fine, restrct, rscale, inject, coarse, link->ctx));
3508 }
3509 PetscFunctionReturn(PETSC_SUCCESS);
3510 }
3511
3512 /*@C
3513 DMSubDomainHookAdd - adds a callback to be run when restricting a problem to subdomain `DM`s with `DMCreateDomainDecomposition()`
3514
3515 Logically Collective; No Fortran Support
3516
3517 Input Parameters:
3518 + global - global `DM`
3519 . ddhook - function to run to pass data to the decomposition `DM` upon its creation
3520 . restricthook - function to run to update data on block solve (at the beginning of the block solve)
3521 - ctx - [optional] user-defined context for provide data for the hooks (may be `NULL`)
3522
3523 Calling sequence of `ddhook`:
3524 + global - global `DM`
3525 . block - subdomain `DM`
3526 - ctx - optional user-defined function context
3527
3528 Calling sequence of `restricthook`:
3529 + global - global `DM`
3530 . out - scatter to the outer (with ghost and overlap points) sub vector
3531 . in - scatter to sub vector values only owned locally
3532 . block - subdomain `DM`
3533 - ctx - optional user-defined function context
3534
3535 Level: advanced
3536
3537 Notes:
3538 This function can be used if auxiliary data needs to be set up on subdomain `DM`s.
3539
3540 If this function is called multiple times, the hooks will be run in the order they are added.
3541
3542 In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3543 extract the global information from its context (instead of from the `SNES`).
3544
3545 Developer Note:
3546 It is unclear what "block solve" means within the definition of `restricthook`
3547
3548 .seealso: [](ch_dmbase), `DM`, `DMSubDomainHookRemove()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`, `DMCreateDomainDecomposition()`
3549 @*/
DMSubDomainHookAdd(DM global,PetscErrorCode (* ddhook)(DM global,DM block,PetscCtx ctx),PetscErrorCode (* restricthook)(DM global,VecScatter out,VecScatter in,DM block,PetscCtx ctx),PetscCtx ctx)3550 PetscErrorCode DMSubDomainHookAdd(DM global, PetscErrorCode (*ddhook)(DM global, DM block, PetscCtx ctx), PetscErrorCode (*restricthook)(DM global, VecScatter out, VecScatter in, DM block, PetscCtx ctx), PetscCtx ctx)
3551 {
3552 DMSubDomainHookLink link, *p;
3553
3554 PetscFunctionBegin;
3555 PetscValidHeaderSpecific(global, DM_CLASSID, 1);
3556 for (p = &global->subdomainhook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */
3557 if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) PetscFunctionReturn(PETSC_SUCCESS);
3558 }
3559 PetscCall(PetscNew(&link));
3560 link->restricthook = restricthook;
3561 link->ddhook = ddhook;
3562 link->ctx = ctx;
3563 link->next = NULL;
3564 *p = link;
3565 PetscFunctionReturn(PETSC_SUCCESS);
3566 }
3567
3568 /*@C
3569 DMSubDomainHookRemove - remove a callback from the list to be run when restricting a problem to subdomain `DM`s with `DMCreateDomainDecomposition()`
3570
3571 Logically Collective; No Fortran Support
3572
3573 Input Parameters:
3574 + global - global `DM`
3575 . ddhook - function to run to pass data to the decomposition `DM` upon its creation
3576 . restricthook - function to run to update data on block solve (at the beginning of the block solve)
3577 - ctx - [optional] user-defined context for provide data for the hooks (may be `NULL`)
3578
3579 Level: advanced
3580
3581 Note:
3582 See `DMSubDomainHookAdd()` for the calling sequences of `ddhook` and `restricthook`
3583
3584 .seealso: [](ch_dmbase), `DM`, `DMSubDomainHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`,
3585 `DMCreateDomainDecomposition()`
3586 @*/
DMSubDomainHookRemove(DM global,PetscErrorCode (* ddhook)(DM,DM,void *),PetscErrorCode (* restricthook)(DM,VecScatter,VecScatter,DM,void *),PetscCtx ctx)3587 PetscErrorCode DMSubDomainHookRemove(DM global, PetscErrorCode (*ddhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, VecScatter, VecScatter, DM, void *), PetscCtx ctx)
3588 {
3589 DMSubDomainHookLink link, *p;
3590
3591 PetscFunctionBegin;
3592 PetscValidHeaderSpecific(global, DM_CLASSID, 1);
3593 for (p = &global->subdomainhook; *p; p = &(*p)->next) { /* Search the list of current hooks */
3594 if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3595 link = *p;
3596 *p = link->next;
3597 PetscCall(PetscFree(link));
3598 break;
3599 }
3600 }
3601 PetscFunctionReturn(PETSC_SUCCESS);
3602 }
3603
3604 /*@
3605 DMSubDomainRestrict - restricts user-defined problem data to a subdomain `DM` by running hooks registered by `DMSubDomainHookAdd()`
3606
3607 Collective if any hooks are
3608
3609 Input Parameters:
3610 + global - The global `DM` to use as a base
3611 . oscatter - The scatter from domain global vector filling subdomain global vector with overlap
3612 . gscatter - The scatter from domain global vector filling subdomain local vector with ghosts
3613 - subdm - The subdomain `DM` to update
3614
3615 Level: developer
3616
3617 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookAdd()`, `MatRestrict()`, `DMCreateDomainDecomposition()`
3618 @*/
DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)3619 PetscErrorCode DMSubDomainRestrict(DM global, VecScatter oscatter, VecScatter gscatter, DM subdm)
3620 {
3621 DMSubDomainHookLink link;
3622
3623 PetscFunctionBegin;
3624 for (link = global->subdomainhook; link; link = link->next) {
3625 if (link->restricthook) PetscCall((*link->restricthook)(global, oscatter, gscatter, subdm, link->ctx));
3626 }
3627 PetscFunctionReturn(PETSC_SUCCESS);
3628 }
3629
3630 /*@
3631 DMGetCoarsenLevel - Gets the number of coarsenings that have generated this `DM`.
3632
3633 Not Collective
3634
3635 Input Parameter:
3636 . dm - the `DM` object
3637
3638 Output Parameter:
3639 . level - number of coarsenings
3640
3641 Level: developer
3642
3643 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMSetCoarsenLevel()`, `DMGetRefineLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3644 @*/
DMGetCoarsenLevel(DM dm,PetscInt * level)3645 PetscErrorCode DMGetCoarsenLevel(DM dm, PetscInt *level)
3646 {
3647 PetscFunctionBegin;
3648 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3649 PetscAssertPointer(level, 2);
3650 *level = dm->leveldown;
3651 PetscFunctionReturn(PETSC_SUCCESS);
3652 }
3653
3654 /*@
3655 DMSetCoarsenLevel - Sets the number of coarsenings that have generated this `DM`.
3656
3657 Collective
3658
3659 Input Parameters:
3660 + dm - the `DM` object
3661 - level - number of coarsenings
3662
3663 Level: developer
3664
3665 Note:
3666 This is rarely used directly, the information is automatically set when a `DM` is created with `DMCoarsen()`
3667
3668 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMGetRefineLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3669 @*/
DMSetCoarsenLevel(DM dm,PetscInt level)3670 PetscErrorCode DMSetCoarsenLevel(DM dm, PetscInt level)
3671 {
3672 PetscFunctionBegin;
3673 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3674 dm->leveldown = level;
3675 PetscFunctionReturn(PETSC_SUCCESS);
3676 }
3677
3678 /*@
3679 DMRefineHierarchy - Refines a `DM` object, all levels at once
3680
3681 Collective
3682
3683 Input Parameters:
3684 + dm - the `DM` object
3685 - nlevels - the number of levels of refinement
3686
3687 Output Parameter:
3688 . dmf - the refined `DM` hierarchy
3689
3690 Level: developer
3691
3692 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMCoarsenHierarchy()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3693 @*/
DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])3694 PetscErrorCode DMRefineHierarchy(DM dm, PetscInt nlevels, DM dmf[])
3695 {
3696 PetscFunctionBegin;
3697 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3698 PetscCheck(nlevels >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "nlevels cannot be negative");
3699 if (nlevels == 0) PetscFunctionReturn(PETSC_SUCCESS);
3700 PetscAssertPointer(dmf, 3);
3701 if (dm->ops->refine && !dm->ops->refinehierarchy) {
3702 PetscInt i;
3703
3704 PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &dmf[0]));
3705 for (i = 1; i < nlevels; i++) PetscCall(DMRefine(dmf[i - 1], PetscObjectComm((PetscObject)dm), &dmf[i]));
3706 } else PetscUseTypeMethod(dm, refinehierarchy, nlevels, dmf);
3707 PetscFunctionReturn(PETSC_SUCCESS);
3708 }
3709
3710 /*@
3711 DMCoarsenHierarchy - Coarsens a `DM` object, all levels at once
3712
3713 Collective
3714
3715 Input Parameters:
3716 + dm - the `DM` object
3717 - nlevels - the number of levels of coarsening
3718
3719 Output Parameter:
3720 . dmc - the coarsened `DM` hierarchy
3721
3722 Level: developer
3723
3724 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMRefineHierarchy()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3725 @*/
DMCoarsenHierarchy(DM dm,PetscInt nlevels,DM dmc[])3726 PetscErrorCode DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3727 {
3728 PetscFunctionBegin;
3729 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3730 PetscCheck(nlevels >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "nlevels cannot be negative");
3731 if (nlevels == 0) PetscFunctionReturn(PETSC_SUCCESS);
3732 PetscAssertPointer(dmc, 3);
3733 if (dm->ops->coarsen && !dm->ops->coarsenhierarchy) {
3734 PetscInt i;
3735
3736 PetscCall(DMCoarsen(dm, PetscObjectComm((PetscObject)dm), &dmc[0]));
3737 for (i = 1; i < nlevels; i++) PetscCall(DMCoarsen(dmc[i - 1], PetscObjectComm((PetscObject)dm), &dmc[i]));
3738 } else PetscUseTypeMethod(dm, coarsenhierarchy, nlevels, dmc);
3739 PetscFunctionReturn(PETSC_SUCCESS);
3740 }
3741
3742 /*@C
3743 DMSetApplicationContextDestroy - Sets a user function that will be called to destroy the application context when the `DM` is destroyed
3744
3745 Logically Collective if the function is collective
3746
3747 Input Parameters:
3748 + dm - the `DM` object
3749 - destroy - the destroy function, see `PetscCtxDestroyFn` for the calling sequence
3750
3751 Level: intermediate
3752
3753 .seealso: [](ch_dmbase), `DM`, `DMSetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`,
3754 `DMGetApplicationContext()`, `PetscCtxDestroyFn`
3755 @*/
DMSetApplicationContextDestroy(DM dm,PetscCtxDestroyFn * destroy)3756 PetscErrorCode DMSetApplicationContextDestroy(DM dm, PetscCtxDestroyFn *destroy)
3757 {
3758 PetscFunctionBegin;
3759 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3760 dm->ctxdestroy = destroy;
3761 PetscFunctionReturn(PETSC_SUCCESS);
3762 }
3763
3764 /*@
3765 DMSetApplicationContext - Set a user context into a `DM` object
3766
3767 Not Collective
3768
3769 Input Parameters:
3770 + dm - the `DM` object
3771 - ctx - the user context
3772
3773 Level: intermediate
3774
3775 Note:
3776 A user context is a way to pass problem specific information that is accessible whenever the `DM` is available
3777 In a multilevel solver, the user context is shared by all the `DM` in the hierarchy; it is thus not advisable
3778 to store objects that represent discretized quantities inside the context.
3779
3780 Fortran Notes:
3781 This only works when the context is a Fortran derived type or a `PetscObject`. Declare `ctx` with
3782 .vb
3783 type(tUsertype), pointer :: ctx
3784 .ve
3785
3786 .seealso: [](ch_dmbase), `DM`, `DMGetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`
3787 @*/
DMSetApplicationContext(DM dm,PetscCtx ctx)3788 PetscErrorCode DMSetApplicationContext(DM dm, PetscCtx ctx)
3789 {
3790 PetscFunctionBegin;
3791 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3792 dm->ctx = ctx;
3793 PetscFunctionReturn(PETSC_SUCCESS);
3794 }
3795
3796 /*@
3797 DMGetApplicationContext - Gets a user context from a `DM` object provided with `DMSetApplicationContext()`
3798
3799 Not Collective
3800
3801 Input Parameter:
3802 . dm - the `DM` object
3803
3804 Output Parameter:
3805 . ctx - a pointer to the user context
3806
3807 Level: intermediate
3808
3809 Note:
3810 A user context is a way to pass problem specific information that is accessible whenever the `DM` is available
3811
3812 Fortran Notes:
3813 This only works when the context is a Fortran derived type (it cannot be a `PetscObject`) and you **must** write a Fortran interface definition for this
3814 function that tells the Fortran compiler the derived data type that is returned as the `ctx` argument. For example,
3815 .vb
3816 Interface DMGetApplicationContext
3817 Subroutine DMGetApplicationContext(dm,ctx,ierr)
3818 #include <petsc/finclude/petscdm.h>
3819 use petscdm
3820 DM dm
3821 type(tUsertype), pointer :: ctx
3822 PetscErrorCode ierr
3823 End Subroutine
3824 End Interface DMGetApplicationContext
3825 .ve
3826
3827 The prototype for `ctx` must be
3828 .vb
3829 type(tUsertype), pointer :: ctx
3830 .ve
3831
3832 .seealso: [](ch_dmbase), `DM`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`
3833 @*/
DMGetApplicationContext(DM dm,PetscCtxRt ctx)3834 PetscErrorCode DMGetApplicationContext(DM dm, PetscCtxRt ctx)
3835 {
3836 PetscFunctionBegin;
3837 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3838 *(void **)ctx = dm->ctx;
3839 PetscFunctionReturn(PETSC_SUCCESS);
3840 }
3841
3842 /*@C
3843 DMSetVariableBounds - sets a function to compute the lower and upper bound vectors for `SNESVI`.
3844
3845 Logically Collective
3846
3847 Input Parameters:
3848 + dm - the DM object
3849 - f - the function that computes variable bounds used by `SNESVI` (use `NULL` to cancel a previous function that was set)
3850
3851 Level: intermediate
3852
3853 Developer Note:
3854 Should be called `DMSetComputeVIBounds()` or something similar
3855
3856 .seealso: [](ch_dmbase), `DM`, `DMComputeVariableBounds()`, `DMHasVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`,
3857 `DMSetJacobian()`
3858 @*/
DMSetVariableBounds(DM dm,PetscErrorCode (* f)(DM,Vec,Vec))3859 PetscErrorCode DMSetVariableBounds(DM dm, PetscErrorCode (*f)(DM, Vec, Vec))
3860 {
3861 PetscFunctionBegin;
3862 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3863 dm->ops->computevariablebounds = f;
3864 PetscFunctionReturn(PETSC_SUCCESS);
3865 }
3866
3867 /*@
3868 DMHasVariableBounds - does the `DM` object have a variable bounds function?
3869
3870 Not Collective
3871
3872 Input Parameter:
3873 . dm - the `DM` object to destroy
3874
3875 Output Parameter:
3876 . flg - `PETSC_TRUE` if the variable bounds function exists
3877
3878 Level: developer
3879
3880 .seealso: [](ch_dmbase), `DM`, `DMComputeVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3881 @*/
DMHasVariableBounds(DM dm,PetscBool * flg)3882 PetscErrorCode DMHasVariableBounds(DM dm, PetscBool *flg)
3883 {
3884 PetscFunctionBegin;
3885 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3886 PetscAssertPointer(flg, 2);
3887 *flg = (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3888 PetscFunctionReturn(PETSC_SUCCESS);
3889 }
3890
3891 /*@
3892 DMComputeVariableBounds - compute variable bounds used by `SNESVI`.
3893
3894 Logically Collective
3895
3896 Input Parameter:
3897 . dm - the `DM` object
3898
3899 Output Parameters:
3900 + xl - lower bound
3901 - xu - upper bound
3902
3903 Level: advanced
3904
3905 Note:
3906 This is generally not called by users. It calls the function provided by the user with DMSetVariableBounds()
3907
3908 .seealso: [](ch_dmbase), `DM`, `DMHasVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3909 @*/
DMComputeVariableBounds(DM dm,Vec xl,Vec xu)3910 PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3911 {
3912 PetscFunctionBegin;
3913 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3914 PetscValidHeaderSpecific(xl, VEC_CLASSID, 2);
3915 PetscValidHeaderSpecific(xu, VEC_CLASSID, 3);
3916 PetscUseTypeMethod(dm, computevariablebounds, xl, xu);
3917 PetscFunctionReturn(PETSC_SUCCESS);
3918 }
3919
3920 /*@
3921 DMHasColoring - does the `DM` object have a method of providing a coloring?
3922
3923 Not Collective
3924
3925 Input Parameter:
3926 . dm - the DM object
3927
3928 Output Parameter:
3929 . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateColoring()`.
3930
3931 Level: developer
3932
3933 .seealso: [](ch_dmbase), `DM`, `DMCreateColoring()`
3934 @*/
DMHasColoring(DM dm,PetscBool * flg)3935 PetscErrorCode DMHasColoring(DM dm, PetscBool *flg)
3936 {
3937 PetscFunctionBegin;
3938 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3939 PetscAssertPointer(flg, 2);
3940 *flg = (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3941 PetscFunctionReturn(PETSC_SUCCESS);
3942 }
3943
3944 /*@
3945 DMHasCreateRestriction - does the `DM` object have a method of providing a restriction?
3946
3947 Not Collective
3948
3949 Input Parameter:
3950 . dm - the `DM` object
3951
3952 Output Parameter:
3953 . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateRestriction()`.
3954
3955 Level: developer
3956
3957 .seealso: [](ch_dmbase), `DM`, `DMCreateRestriction()`, `DMHasCreateInterpolation()`, `DMHasCreateInjection()`
3958 @*/
DMHasCreateRestriction(DM dm,PetscBool * flg)3959 PetscErrorCode DMHasCreateRestriction(DM dm, PetscBool *flg)
3960 {
3961 PetscFunctionBegin;
3962 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3963 PetscAssertPointer(flg, 2);
3964 *flg = (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3965 PetscFunctionReturn(PETSC_SUCCESS);
3966 }
3967
3968 /*@
3969 DMHasCreateInjection - does the `DM` object have a method of providing an injection?
3970
3971 Not Collective
3972
3973 Input Parameter:
3974 . dm - the `DM` object
3975
3976 Output Parameter:
3977 . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateInjection()`.
3978
3979 Level: developer
3980
3981 .seealso: [](ch_dmbase), `DM`, `DMCreateInjection()`, `DMHasCreateRestriction()`, `DMHasCreateInterpolation()`
3982 @*/
DMHasCreateInjection(DM dm,PetscBool * flg)3983 PetscErrorCode DMHasCreateInjection(DM dm, PetscBool *flg)
3984 {
3985 PetscFunctionBegin;
3986 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3987 PetscAssertPointer(flg, 2);
3988 if (dm->ops->hascreateinjection) PetscUseTypeMethod(dm, hascreateinjection, flg);
3989 else *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3990 PetscFunctionReturn(PETSC_SUCCESS);
3991 }
3992
3993 PetscFunctionList DMList = NULL;
3994 PetscBool DMRegisterAllCalled = PETSC_FALSE;
3995
3996 /*@
3997 DMSetType - Builds a `DM`, for a particular `DM` implementation.
3998
3999 Collective
4000
4001 Input Parameters:
4002 + dm - The `DM` object
4003 - method - The name of the `DMType`, for example `DMDA`, `DMPLEX`
4004
4005 Options Database Key:
4006 . -dm_type <type> - Sets the `DM` type; use -help for a list of available types
4007
4008 Level: intermediate
4009
4010 Note:
4011 Of the `DM` is constructed by directly calling a function to construct a particular `DM`, for example, `DMDACreate2d()` or `DMPlexCreateBoxMesh()`
4012
4013 .seealso: [](ch_dmbase), `DM`, `DMType`, `DMDA`, `DMPLEX`, `DMGetType()`, `DMCreate()`, `DMDACreate2d()`
4014 @*/
DMSetType(DM dm,DMType method)4015 PetscErrorCode DMSetType(DM dm, DMType method)
4016 {
4017 PetscErrorCode (*r)(DM);
4018 PetscBool match;
4019
4020 PetscFunctionBegin;
4021 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4022 PetscCall(PetscObjectTypeCompare((PetscObject)dm, method, &match));
4023 if (match) PetscFunctionReturn(PETSC_SUCCESS);
4024
4025 PetscCall(DMRegisterAll());
4026 PetscCall(PetscFunctionListFind(DMList, method, &r));
4027 PetscCheck(r, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DM type: %s", method);
4028
4029 PetscTryTypeMethod(dm, destroy);
4030 PetscCall(PetscMemzero(dm->ops, sizeof(*dm->ops)));
4031 PetscCall(PetscObjectChangeTypeName((PetscObject)dm, method));
4032 PetscCall((*r)(dm));
4033 PetscFunctionReturn(PETSC_SUCCESS);
4034 }
4035
4036 /*@
4037 DMGetType - Gets the `DM` type name (as a string) from the `DM`.
4038
4039 Not Collective
4040
4041 Input Parameter:
4042 . dm - The `DM`
4043
4044 Output Parameter:
4045 . type - The `DMType` name
4046
4047 Level: intermediate
4048
4049 .seealso: [](ch_dmbase), `DM`, `DMType`, `DMDA`, `DMPLEX`, `DMSetType()`, `DMCreate()`
4050 @*/
DMGetType(DM dm,DMType * type)4051 PetscErrorCode DMGetType(DM dm, DMType *type)
4052 {
4053 PetscFunctionBegin;
4054 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4055 PetscAssertPointer(type, 2);
4056 PetscCall(DMRegisterAll());
4057 *type = ((PetscObject)dm)->type_name;
4058 PetscFunctionReturn(PETSC_SUCCESS);
4059 }
4060
4061 /*@
4062 DMConvert - Converts a `DM` to another `DM`, either of the same or different type.
4063
4064 Collective
4065
4066 Input Parameters:
4067 + dm - the `DM`
4068 - newtype - new `DM` type (use "same" for the same type)
4069
4070 Output Parameter:
4071 . M - pointer to new `DM`
4072
4073 Level: intermediate
4074
4075 Note:
4076 Cannot be used to convert a sequential `DM` to a parallel or a parallel to sequential,
4077 the MPI communicator of the generated `DM` is always the same as the communicator
4078 of the input `DM`.
4079
4080 .seealso: [](ch_dmbase), `DM`, `DMSetType()`, `DMCreate()`, `DMClone()`
4081 @*/
DMConvert(DM dm,DMType newtype,DM * M)4082 PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
4083 {
4084 DM B;
4085 char convname[256];
4086 PetscBool sametype /*, issame */;
4087
4088 PetscFunctionBegin;
4089 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4090 PetscValidType(dm, 1);
4091 PetscAssertPointer(M, 3);
4092 PetscCall(PetscObjectTypeCompare((PetscObject)dm, newtype, &sametype));
4093 /* PetscCall(PetscStrcmp(newtype, "same", &issame)); */
4094 if (sametype) {
4095 *M = dm;
4096 PetscCall(PetscObjectReference((PetscObject)dm));
4097 PetscFunctionReturn(PETSC_SUCCESS);
4098 } else {
4099 PetscErrorCode (*conv)(DM, DMType, DM *) = NULL;
4100
4101 /*
4102 Order of precedence:
4103 1) See if a specialized converter is known to the current DM.
4104 2) See if a specialized converter is known to the desired DM class.
4105 3) See if a good general converter is registered for the desired class
4106 4) See if a good general converter is known for the current matrix.
4107 5) Use a really basic converter.
4108 */
4109
4110 /* 1) See if a specialized converter is known to the current DM and the desired class */
4111 PetscCall(PetscStrncpy(convname, "DMConvert_", sizeof(convname)));
4112 PetscCall(PetscStrlcat(convname, ((PetscObject)dm)->type_name, sizeof(convname)));
4113 PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4114 PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4115 PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4116 PetscCall(PetscObjectQueryFunction((PetscObject)dm, convname, &conv));
4117 if (conv) goto foundconv;
4118
4119 /* 2) See if a specialized converter is known to the desired DM class. */
4120 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &B));
4121 PetscCall(DMSetType(B, newtype));
4122 PetscCall(PetscStrncpy(convname, "DMConvert_", sizeof(convname)));
4123 PetscCall(PetscStrlcat(convname, ((PetscObject)dm)->type_name, sizeof(convname)));
4124 PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4125 PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4126 PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4127 PetscCall(PetscObjectQueryFunction((PetscObject)B, convname, &conv));
4128 if (conv) {
4129 PetscCall(DMDestroy(&B));
4130 goto foundconv;
4131 }
4132
4133 #if 0
4134 /* 3) See if a good general converter is registered for the desired class */
4135 conv = B->ops->convertfrom;
4136 PetscCall(DMDestroy(&B));
4137 if (conv) goto foundconv;
4138
4139 /* 4) See if a good general converter is known for the current matrix */
4140 if (dm->ops->convert) conv = dm->ops->convert;
4141 if (conv) goto foundconv;
4142 #endif
4143
4144 /* 5) Use a really basic converter. */
4145 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject)dm)->type_name, newtype);
4146
4147 foundconv:
4148 PetscCall(PetscLogEventBegin(DM_Convert, dm, 0, 0, 0));
4149 PetscCall((*conv)(dm, newtype, M));
4150 /* Things that are independent of DM type: We should consult DMClone() here */
4151 {
4152 const PetscReal *maxCell, *Lstart, *L;
4153
4154 PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
4155 PetscCall(DMSetPeriodicity(*M, maxCell, Lstart, L));
4156 (*M)->prealloc_only = dm->prealloc_only;
4157 PetscCall(PetscFree((*M)->vectype));
4158 PetscCall(PetscStrallocpy(dm->vectype, (char **)&(*M)->vectype));
4159 PetscCall(PetscFree((*M)->mattype));
4160 PetscCall(PetscStrallocpy(dm->mattype, (char **)&(*M)->mattype));
4161 }
4162 PetscCall(PetscLogEventEnd(DM_Convert, dm, 0, 0, 0));
4163 }
4164 PetscCall(PetscObjectStateIncrease((PetscObject)*M));
4165 PetscFunctionReturn(PETSC_SUCCESS);
4166 }
4167
4168 /*@C
4169 DMRegister - Adds a new `DM` type implementation
4170
4171 Not Collective, No Fortran Support
4172
4173 Input Parameters:
4174 + sname - The name of a new user-defined creation routine
4175 - function - The creation routine itself
4176
4177 Level: advanced
4178
4179 Note:
4180 `DMRegister()` may be called multiple times to add several user-defined `DM`s
4181
4182 Example Usage:
4183 .vb
4184 DMRegister("my_da", MyDMCreate);
4185 .ve
4186
4187 Then, your `DM` type can be chosen with the procedural interface via
4188 .vb
4189 DMCreate(MPI_Comm, DM *);
4190 DMSetType(DM,"my_da");
4191 .ve
4192 or at runtime via the option
4193 .vb
4194 -da_type my_da
4195 .ve
4196
4197 .seealso: [](ch_dmbase), `DM`, `DMType`, `DMSetType()`, `DMRegisterAll()`, `DMRegisterDestroy()`
4198 @*/
DMRegister(const char sname[],PetscErrorCode (* function)(DM))4199 PetscErrorCode DMRegister(const char sname[], PetscErrorCode (*function)(DM))
4200 {
4201 PetscFunctionBegin;
4202 PetscCall(DMInitializePackage());
4203 PetscCall(PetscFunctionListAdd(&DMList, sname, function));
4204 PetscFunctionReturn(PETSC_SUCCESS);
4205 }
4206
4207 /*@
4208 DMLoad - Loads a DM that has been stored in binary with `DMView()`.
4209
4210 Collective
4211
4212 Input Parameters:
4213 + newdm - the newly loaded `DM`, this needs to have been created with `DMCreate()` or
4214 some related function before a call to `DMLoad()`.
4215 - viewer - binary file viewer, obtained from `PetscViewerBinaryOpen()` or
4216 `PETSCVIEWERHDF5` file viewer, obtained from `PetscViewerHDF5Open()`
4217
4218 Level: intermediate
4219
4220 Notes:
4221 The type is determined by the data in the file, any type set into the DM before this call is ignored.
4222
4223 Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` format, one can save multiple `DMPLEX`
4224 meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()`
4225 before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object.
4226
4227 .seealso: [](ch_dmbase), `DM`, `PetscViewerBinaryOpen()`, `DMView()`, `MatLoad()`, `VecLoad()`
4228 @*/
DMLoad(DM newdm,PetscViewer viewer)4229 PetscErrorCode DMLoad(DM newdm, PetscViewer viewer)
4230 {
4231 PetscBool isbinary, ishdf5;
4232
4233 PetscFunctionBegin;
4234 PetscValidHeaderSpecific(newdm, DM_CLASSID, 1);
4235 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
4236 PetscCall(PetscViewerCheckReadable(viewer));
4237 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
4238 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
4239 PetscCall(PetscLogEventBegin(DM_Load, viewer, 0, 0, 0));
4240 if (isbinary) {
4241 PetscInt classid;
4242 char type[256];
4243
4244 PetscCall(PetscViewerBinaryRead(viewer, &classid, 1, NULL, PETSC_INT));
4245 PetscCheck(classid == DM_FILE_CLASSID, PetscObjectComm((PetscObject)newdm), PETSC_ERR_ARG_WRONG, "Not DM next in file, classid found %" PetscInt_FMT, classid);
4246 PetscCall(PetscViewerBinaryRead(viewer, type, 256, NULL, PETSC_CHAR));
4247 PetscCall(DMSetType(newdm, type));
4248 PetscTryTypeMethod(newdm, load, viewer);
4249 } else if (ishdf5) {
4250 PetscTryTypeMethod(newdm, load, viewer);
4251 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
4252 PetscCall(PetscLogEventEnd(DM_Load, viewer, 0, 0, 0));
4253 PetscFunctionReturn(PETSC_SUCCESS);
4254 }
4255
4256 /* FEM Support */
4257
DMPrintCellIndices(PetscInt c,const char name[],PetscInt len,const PetscInt x[])4258 PetscErrorCode DMPrintCellIndices(PetscInt c, const char name[], PetscInt len, const PetscInt x[])
4259 {
4260 PetscInt f;
4261
4262 PetscFunctionBegin;
4263 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4264 for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, " | %" PetscInt_FMT " |\n", x[f]));
4265 PetscFunctionReturn(PETSC_SUCCESS);
4266 }
4267
DMPrintCellVector(PetscInt c,const char name[],PetscInt len,const PetscScalar x[])4268 PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
4269 {
4270 PetscInt f;
4271
4272 PetscFunctionBegin;
4273 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4274 for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, " | %g |\n", (double)PetscRealPart(x[f])));
4275 PetscFunctionReturn(PETSC_SUCCESS);
4276 }
4277
DMPrintCellVectorReal(PetscInt c,const char name[],PetscInt len,const PetscReal x[])4278 PetscErrorCode DMPrintCellVectorReal(PetscInt c, const char name[], PetscInt len, const PetscReal x[])
4279 {
4280 PetscInt f;
4281
4282 PetscFunctionBegin;
4283 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4284 for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, " | %g |\n", (double)x[f]));
4285 PetscFunctionReturn(PETSC_SUCCESS);
4286 }
4287
DMPrintCellMatrix(PetscInt c,const char name[],PetscInt rows,PetscInt cols,const PetscScalar A[])4288 PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4289 {
4290 PetscInt f, g;
4291
4292 PetscFunctionBegin;
4293 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4294 for (f = 0; f < rows; ++f) {
4295 PetscCall(PetscPrintf(PETSC_COMM_SELF, " |"));
4296 for (g = 0; g < cols; ++g) PetscCall(PetscPrintf(PETSC_COMM_SELF, " % 9.5g", (double)PetscRealPart(A[f * cols + g])));
4297 PetscCall(PetscPrintf(PETSC_COMM_SELF, " |\n"));
4298 }
4299 PetscFunctionReturn(PETSC_SUCCESS);
4300 }
4301
DMPrintLocalVec(DM dm,const char name[],PetscReal tol,Vec X)4302 PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
4303 {
4304 PetscInt localSize, bs;
4305 PetscMPIInt size;
4306 Vec x, xglob;
4307 const PetscScalar *xarray;
4308
4309 PetscFunctionBegin;
4310 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
4311 PetscCall(VecDuplicate(X, &x));
4312 PetscCall(VecCopy(X, x));
4313 PetscCall(VecFilter(x, tol));
4314 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "%s:\n", name));
4315 if (size > 1) {
4316 PetscCall(VecGetLocalSize(x, &localSize));
4317 PetscCall(VecGetArrayRead(x, &xarray));
4318 PetscCall(VecGetBlockSize(x, &bs));
4319 PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)dm), bs, localSize, PETSC_DETERMINE, xarray, &xglob));
4320 } else {
4321 xglob = x;
4322 }
4323 PetscCall(VecView(xglob, PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)dm))));
4324 if (size > 1) {
4325 PetscCall(VecDestroy(&xglob));
4326 PetscCall(VecRestoreArrayRead(x, &xarray));
4327 }
4328 PetscCall(VecDestroy(&x));
4329 PetscFunctionReturn(PETSC_SUCCESS);
4330 }
4331
4332 /*@
4333 DMGetLocalSection - Get the `PetscSection` encoding the local data layout for the `DM`.
4334
4335 Input Parameter:
4336 . dm - The `DM`
4337
4338 Output Parameter:
4339 . section - The `PetscSection`
4340
4341 Options Database Key:
4342 . -dm_petscsection_view - View the section created by the `DM`
4343
4344 Level: intermediate
4345
4346 Note:
4347 This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4348
4349 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetGlobalSection()`
4350 @*/
DMGetLocalSection(DM dm,PetscSection * section)4351 PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4352 {
4353 PetscFunctionBegin;
4354 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4355 PetscAssertPointer(section, 2);
4356 if (!dm->localSection && dm->ops->createlocalsection) {
4357 PetscInt d;
4358
4359 if (dm->setfromoptionscalled) {
4360 PetscObject obj = (PetscObject)dm;
4361 PetscViewer viewer;
4362 PetscViewerFormat format;
4363 PetscBool flg;
4364
4365 PetscCall(PetscOptionsCreateViewer(PetscObjectComm(obj), obj->options, obj->prefix, "-dm_petscds_view", &viewer, &format, &flg));
4366 if (flg) PetscCall(PetscViewerPushFormat(viewer, format));
4367 for (d = 0; d < dm->Nds; ++d) {
4368 PetscCall(PetscDSSetFromOptions(dm->probs[d].ds));
4369 if (flg) PetscCall(PetscDSView(dm->probs[d].ds, viewer));
4370 }
4371 if (flg) {
4372 PetscCall(PetscViewerFlush(viewer));
4373 PetscCall(PetscViewerPopFormat(viewer));
4374 PetscCall(PetscViewerDestroy(&viewer));
4375 }
4376 }
4377 PetscUseTypeMethod(dm, createlocalsection);
4378 if (dm->localSection) PetscCall(PetscObjectViewFromOptions((PetscObject)dm->localSection, NULL, "-dm_petscsection_view"));
4379 }
4380 *section = dm->localSection;
4381 PetscFunctionReturn(PETSC_SUCCESS);
4382 }
4383
4384 /*@
4385 DMSetLocalSection - Set the `PetscSection` encoding the local data layout for the `DM`.
4386
4387 Input Parameters:
4388 + dm - The `DM`
4389 - section - The `PetscSection`
4390
4391 Level: intermediate
4392
4393 Note:
4394 Any existing Section will be destroyed
4395
4396 .seealso: [](ch_dmbase), `DM`, `PetscSection`, `DMGetLocalSection()`, `DMSetGlobalSection()`
4397 @*/
DMSetLocalSection(DM dm,PetscSection section)4398 PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4399 {
4400 PetscInt numFields = 0;
4401 PetscInt f;
4402
4403 PetscFunctionBegin;
4404 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4405 if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4406 PetscCall(PetscObjectReference((PetscObject)section));
4407 PetscCall(PetscSectionDestroy(&dm->localSection));
4408 dm->localSection = section;
4409 if (section) PetscCall(PetscSectionGetNumFields(dm->localSection, &numFields));
4410 if (numFields) {
4411 PetscCall(DMSetNumFields(dm, numFields));
4412 for (f = 0; f < numFields; ++f) {
4413 PetscObject disc;
4414 const char *name;
4415
4416 PetscCall(PetscSectionGetFieldName(dm->localSection, f, &name));
4417 PetscCall(DMGetField(dm, f, NULL, &disc));
4418 PetscCall(PetscObjectSetName(disc, name));
4419 }
4420 }
4421 /* The global section and the SectionSF will be rebuilt
4422 in the next call to DMGetGlobalSection() and DMGetSectionSF(). */
4423 PetscCall(PetscSectionDestroy(&dm->globalSection));
4424 PetscCall(PetscSFDestroy(&dm->sectionSF));
4425 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4426
4427 /* Clear scratch vectors */
4428 PetscCall(DMClearGlobalVectors(dm));
4429 PetscCall(DMClearLocalVectors(dm));
4430 PetscCall(DMClearNamedGlobalVectors(dm));
4431 PetscCall(DMClearNamedLocalVectors(dm));
4432 PetscFunctionReturn(PETSC_SUCCESS);
4433 }
4434
4435 /*@C
4436 DMCreateSectionPermutation - Create a permutation of the `PetscSection` chart and optionally a block structure.
4437
4438 Input Parameter:
4439 . dm - The `DM`
4440
4441 Output Parameters:
4442 + perm - A permutation of the mesh points in the chart
4443 - blockStarts - A high bit is set for the point that begins every block, or `NULL` for default blocking
4444
4445 Level: developer
4446
4447 .seealso: [](ch_dmbase), `DM`, `PetscSection`, `DMGetLocalSection()`, `DMGetGlobalSection()`
4448 @*/
DMCreateSectionPermutation(DM dm,IS * perm,PetscBT * blockStarts)4449 PetscErrorCode DMCreateSectionPermutation(DM dm, IS *perm, PetscBT *blockStarts)
4450 {
4451 PetscFunctionBegin;
4452 *perm = NULL;
4453 *blockStarts = NULL;
4454 PetscTryTypeMethod(dm, createsectionpermutation, perm, blockStarts);
4455 PetscFunctionReturn(PETSC_SUCCESS);
4456 }
4457
4458 /*@
4459 DMGetDefaultConstraints - Get the `PetscSection` and `Mat` that specify the local constraint interpolation. See `DMSetDefaultConstraints()` for a description of the purpose of constraint interpolation.
4460
4461 not Collective
4462
4463 Input Parameter:
4464 . dm - The `DM`
4465
4466 Output Parameters:
4467 + section - The `PetscSection` describing the range of the constraint matrix: relates rows of the constraint matrix to dofs of the default section. Returns `NULL` if there are no local constraints.
4468 . mat - The `Mat` that interpolates local constraints: its width should be the layout size of the default section. Returns `NULL` if there are no local constraints.
4469 - bias - Vector containing bias to be added to constrained dofs
4470
4471 Level: advanced
4472
4473 Note:
4474 This gets borrowed references, so the user should not destroy the `PetscSection`, `Mat`, or `Vec`.
4475
4476 .seealso: [](ch_dmbase), `DM`, `DMSetDefaultConstraints()`
4477 @*/
DMGetDefaultConstraints(DM dm,PetscSection * section,Mat * mat,Vec * bias)4478 PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat, Vec *bias)
4479 {
4480 PetscFunctionBegin;
4481 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4482 if (!dm->defaultConstraint.section && !dm->defaultConstraint.mat && dm->ops->createdefaultconstraints) PetscUseTypeMethod(dm, createdefaultconstraints);
4483 if (section) *section = dm->defaultConstraint.section;
4484 if (mat) *mat = dm->defaultConstraint.mat;
4485 if (bias) *bias = dm->defaultConstraint.bias;
4486 PetscFunctionReturn(PETSC_SUCCESS);
4487 }
4488
4489 /*@
4490 DMSetDefaultConstraints - Set the `PetscSection` and `Mat` that specify the local constraint interpolation.
4491
4492 Collective
4493
4494 Input Parameters:
4495 + dm - The `DM`
4496 . section - The `PetscSection` describing the range of the constraint matrix: relates rows of the constraint matrix to dofs of the default section. Must have a local communicator (`PETSC_COMM_SELF` or derivative).
4497 . mat - The `Mat` that interpolates local constraints: its width should be the layout size of the default section: `NULL` indicates no constraints. Must have a local communicator (`PETSC_COMM_SELF` or derivative).
4498 - bias - A bias vector to be added to constrained values in the local vector. `NULL` indicates no bias. Must have a local communicator (`PETSC_COMM_SELF` or derivative).
4499
4500 Level: advanced
4501
4502 Notes:
4503 If a constraint matrix is specified, then it is applied during `DMGlobalToLocalEnd()` when mode is `INSERT_VALUES`, `INSERT_BC_VALUES`, or `INSERT_ALL_VALUES`. Without a constraint matrix, the local vector l returned by `DMGlobalToLocalEnd()` contains values that have been scattered from a global vector without modification; with a constraint matrix A, l is modified by computing c = A * l + bias, l[s[i]] = c[i], where the scatter s is defined by the `PetscSection` returned by `DMGetDefaultConstraints()`.
4504
4505 If a constraint matrix is specified, then its adjoint is applied during `DMLocalToGlobalBegin()` when mode is `ADD_VALUES`, `ADD_BC_VALUES`, or `ADD_ALL_VALUES`. Without a constraint matrix, the local vector l is accumulated into a global vector without modification; with a constraint matrix A, l is first modified by computing c[i] = l[s[i]], l[s[i]] = 0, l = l + A'*c, which is the adjoint of the operation described above. Any bias, if specified, is ignored when accumulating.
4506
4507 This increments the references of the `PetscSection`, `Mat`, and `Vec`, so they user can destroy them.
4508
4509 .seealso: [](ch_dmbase), `DM`, `DMGetDefaultConstraints()`
4510 @*/
DMSetDefaultConstraints(DM dm,PetscSection section,Mat mat,Vec bias)4511 PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat, Vec bias)
4512 {
4513 PetscMPIInt result;
4514
4515 PetscFunctionBegin;
4516 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4517 if (section) {
4518 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4519 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)section), &result));
4520 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint section must have local communicator");
4521 }
4522 if (mat) {
4523 PetscValidHeaderSpecific(mat, MAT_CLASSID, 3);
4524 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)mat), &result));
4525 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint matrix must have local communicator");
4526 }
4527 if (bias) {
4528 PetscValidHeaderSpecific(bias, VEC_CLASSID, 4);
4529 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)bias), &result));
4530 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint bias must have local communicator");
4531 }
4532 PetscCall(PetscObjectReference((PetscObject)section));
4533 PetscCall(PetscSectionDestroy(&dm->defaultConstraint.section));
4534 dm->defaultConstraint.section = section;
4535 PetscCall(PetscObjectReference((PetscObject)mat));
4536 PetscCall(MatDestroy(&dm->defaultConstraint.mat));
4537 dm->defaultConstraint.mat = mat;
4538 PetscCall(PetscObjectReference((PetscObject)bias));
4539 PetscCall(VecDestroy(&dm->defaultConstraint.bias));
4540 dm->defaultConstraint.bias = bias;
4541 PetscFunctionReturn(PETSC_SUCCESS);
4542 }
4543
4544 #if defined(PETSC_USE_DEBUG)
4545 /*
4546 DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections. Generates and error if they are not consistent.
4547
4548 Input Parameters:
4549 + dm - The `DM`
4550 . localSection - `PetscSection` describing the local data layout
4551 - globalSection - `PetscSection` describing the global data layout
4552
4553 Level: intermediate
4554
4555 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMSetSectionSF()`
4556 */
DMDefaultSectionCheckConsistency_Internal(DM dm,PetscSection localSection,PetscSection globalSection)4557 static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4558 {
4559 MPI_Comm comm;
4560 PetscLayout layout;
4561 const PetscInt *ranges;
4562 PetscInt pStart, pEnd, p, nroots;
4563 PetscMPIInt size, rank;
4564 PetscBool valid = PETSC_TRUE, gvalid;
4565
4566 PetscFunctionBegin;
4567 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
4568 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4569 PetscCallMPI(MPI_Comm_size(comm, &size));
4570 PetscCallMPI(MPI_Comm_rank(comm, &rank));
4571 PetscCall(PetscSectionGetChart(globalSection, &pStart, &pEnd));
4572 PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &nroots));
4573 PetscCall(PetscLayoutCreate(comm, &layout));
4574 PetscCall(PetscLayoutSetBlockSize(layout, 1));
4575 PetscCall(PetscLayoutSetLocalSize(layout, nroots));
4576 PetscCall(PetscLayoutSetUp(layout));
4577 PetscCall(PetscLayoutGetRanges(layout, &ranges));
4578 for (p = pStart; p < pEnd; ++p) {
4579 PetscInt dof, cdof, off, gdof, gcdof, goff, gsize, d;
4580
4581 PetscCall(PetscSectionGetDof(localSection, p, &dof));
4582 PetscCall(PetscSectionGetOffset(localSection, p, &off));
4583 PetscCall(PetscSectionGetConstraintDof(localSection, p, &cdof));
4584 PetscCall(PetscSectionGetDof(globalSection, p, &gdof));
4585 PetscCall(PetscSectionGetConstraintDof(globalSection, p, &gcdof));
4586 PetscCall(PetscSectionGetOffset(globalSection, p, &goff));
4587 if (!gdof) continue; /* Censored point */
4588 if ((gdof < 0 ? -(gdof + 1) : gdof) != dof) {
4589 PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global dof %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local dof %" PetscInt_FMT "\n", rank, gdof, p, dof));
4590 valid = PETSC_FALSE;
4591 }
4592 if (gcdof && (gcdof != cdof)) {
4593 PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global constraints %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local constraints %" PetscInt_FMT "\n", rank, gcdof, p, cdof));
4594 valid = PETSC_FALSE;
4595 }
4596 if (gdof < 0) {
4597 gsize = gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof;
4598 for (d = 0; d < gsize; ++d) {
4599 PetscInt offset = -(goff + 1) + d, r;
4600
4601 PetscCall(PetscFindInt(offset, size + 1, ranges, &r));
4602 if (r < 0) r = -(r + 2);
4603 if ((r < 0) || (r >= size)) {
4604 PetscCall(PetscSynchronizedPrintf(comm, "[%d]Point %" PetscInt_FMT " mapped to invalid process %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, p, r, gdof, goff));
4605 valid = PETSC_FALSE;
4606 break;
4607 }
4608 }
4609 }
4610 }
4611 PetscCall(PetscLayoutDestroy(&layout));
4612 PetscCall(PetscSynchronizedFlush(comm, NULL));
4613 PetscCallMPI(MPIU_Allreduce(&valid, &gvalid, 1, MPI_C_BOOL, MPI_LAND, comm));
4614 if (!gvalid) {
4615 PetscCall(DMView(dm, NULL));
4616 SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4617 }
4618 PetscFunctionReturn(PETSC_SUCCESS);
4619 }
4620 #endif
4621
DMGetIsoperiodicPointSF_Internal(DM dm,PetscSF * sf)4622 PetscErrorCode DMGetIsoperiodicPointSF_Internal(DM dm, PetscSF *sf)
4623 {
4624 PetscErrorCode (*f)(DM, PetscSF *);
4625
4626 PetscFunctionBegin;
4627 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4628 PetscAssertPointer(sf, 2);
4629 PetscCall(PetscObjectQueryFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", &f));
4630 if (f) PetscCall(f(dm, sf));
4631 else *sf = dm->sf;
4632 PetscFunctionReturn(PETSC_SUCCESS);
4633 }
4634
4635 /*@
4636 DMGetGlobalSection - Get the `PetscSection` encoding the global data layout for the `DM`.
4637
4638 Collective
4639
4640 Input Parameter:
4641 . dm - The `DM`
4642
4643 Output Parameter:
4644 . section - The `PetscSection`
4645
4646 Level: intermediate
4647
4648 Note:
4649 This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4650
4651 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetLocalSection()`
4652 @*/
DMGetGlobalSection(DM dm,PetscSection * section)4653 PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4654 {
4655 PetscFunctionBegin;
4656 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4657 PetscAssertPointer(section, 2);
4658 if (!dm->globalSection) {
4659 PetscSection s;
4660 PetscSF sf;
4661
4662 PetscCall(DMGetLocalSection(dm, &s));
4663 PetscCheck(s, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4664 PetscCheck(dm->sf, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4665 PetscCall(DMGetIsoperiodicPointSF_Internal(dm, &sf));
4666 PetscCall(PetscSectionCreateGlobalSection(s, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &dm->globalSection));
4667 PetscCall(PetscLayoutDestroy(&dm->map));
4668 PetscCall(PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map));
4669 PetscCall(PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view"));
4670 }
4671 *section = dm->globalSection;
4672 PetscFunctionReturn(PETSC_SUCCESS);
4673 }
4674
4675 /*@
4676 DMSetGlobalSection - Set the `PetscSection` encoding the global data layout for the `DM`.
4677
4678 Input Parameters:
4679 + dm - The `DM`
4680 - section - The PetscSection, or `NULL`
4681
4682 Level: intermediate
4683
4684 Note:
4685 Any existing `PetscSection` will be destroyed
4686
4687 .seealso: [](ch_dmbase), `DM`, `DMGetGlobalSection()`, `DMSetLocalSection()`
4688 @*/
DMSetGlobalSection(DM dm,PetscSection section)4689 PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4690 {
4691 PetscFunctionBegin;
4692 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4693 if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4694 PetscCall(PetscObjectReference((PetscObject)section));
4695 PetscCall(PetscSectionDestroy(&dm->globalSection));
4696 dm->globalSection = section;
4697 #if defined(PETSC_USE_DEBUG)
4698 if (section) PetscCall(DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section));
4699 #endif
4700 /* Clear global scratch vectors and sectionSF */
4701 PetscCall(PetscSFDestroy(&dm->sectionSF));
4702 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4703 PetscCall(DMClearGlobalVectors(dm));
4704 PetscCall(DMClearNamedGlobalVectors(dm));
4705 PetscFunctionReturn(PETSC_SUCCESS);
4706 }
4707
4708 /*@
4709 DMGetSectionSF - Get the `PetscSF` encoding the parallel dof overlap for the `DM`. If it has not been set,
4710 it is created from the default `PetscSection` layouts in the `DM`.
4711
4712 Input Parameter:
4713 . dm - The `DM`
4714
4715 Output Parameter:
4716 . sf - The `PetscSF`
4717
4718 Level: intermediate
4719
4720 Note:
4721 This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4722
4723 .seealso: [](ch_dmbase), `DM`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4724 @*/
DMGetSectionSF(DM dm,PetscSF * sf)4725 PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4726 {
4727 PetscInt nroots;
4728
4729 PetscFunctionBegin;
4730 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4731 PetscAssertPointer(sf, 2);
4732 if (!dm->sectionSF) PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4733 PetscCall(PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL));
4734 if (nroots < 0) {
4735 PetscSection section, gSection;
4736
4737 PetscCall(DMGetLocalSection(dm, §ion));
4738 if (section) {
4739 PetscCall(DMGetGlobalSection(dm, &gSection));
4740 PetscCall(DMCreateSectionSF(dm, section, gSection));
4741 } else {
4742 *sf = NULL;
4743 PetscFunctionReturn(PETSC_SUCCESS);
4744 }
4745 }
4746 *sf = dm->sectionSF;
4747 PetscFunctionReturn(PETSC_SUCCESS);
4748 }
4749
4750 /*@
4751 DMSetSectionSF - Set the `PetscSF` encoding the parallel dof overlap for the `DM`
4752
4753 Input Parameters:
4754 + dm - The `DM`
4755 - sf - The `PetscSF`
4756
4757 Level: intermediate
4758
4759 Note:
4760 Any previous `PetscSF` is destroyed
4761
4762 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMCreateSectionSF()`
4763 @*/
DMSetSectionSF(DM dm,PetscSF sf)4764 PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4765 {
4766 PetscFunctionBegin;
4767 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4768 if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4769 PetscCall(PetscObjectReference((PetscObject)sf));
4770 PetscCall(PetscSFDestroy(&dm->sectionSF));
4771 dm->sectionSF = sf;
4772 PetscFunctionReturn(PETSC_SUCCESS);
4773 }
4774
4775 /*@
4776 DMCreateSectionSF - Create the `PetscSF` encoding the parallel dof overlap for the `DM` based upon the `PetscSection`s
4777 describing the data layout.
4778
4779 Input Parameters:
4780 + dm - The `DM`
4781 . localSection - `PetscSection` describing the local data layout
4782 - globalSection - `PetscSection` describing the global data layout
4783
4784 Level: developer
4785
4786 Note:
4787 One usually uses `DMGetSectionSF()` to obtain the `PetscSF`
4788
4789 Developer Note:
4790 Since this routine has for arguments the two sections from the `DM` and puts the resulting `PetscSF`
4791 directly into the `DM`, perhaps this function should not take the local and global sections as
4792 input and should just obtain them from the `DM`? Plus PETSc creation functions return the thing
4793 they create, this returns nothing
4794
4795 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
4796 @*/
DMCreateSectionSF(DM dm,PetscSection localSection,PetscSection globalSection)4797 PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4798 {
4799 PetscFunctionBegin;
4800 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4801 PetscCall(PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection));
4802 PetscFunctionReturn(PETSC_SUCCESS);
4803 }
4804
4805 /*@
4806 DMGetPointSF - Get the `PetscSF` encoding the parallel section point overlap for the `DM`.
4807
4808 Not collective but the resulting `PetscSF` is collective
4809
4810 Input Parameter:
4811 . dm - The `DM`
4812
4813 Output Parameter:
4814 . sf - The `PetscSF`
4815
4816 Level: intermediate
4817
4818 Note:
4819 This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4820
4821 .seealso: [](ch_dmbase), `DM`, `DMSetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4822 @*/
DMGetPointSF(DM dm,PetscSF * sf)4823 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4824 {
4825 PetscFunctionBegin;
4826 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4827 PetscAssertPointer(sf, 2);
4828 *sf = dm->sf;
4829 PetscFunctionReturn(PETSC_SUCCESS);
4830 }
4831
4832 /*@
4833 DMSetPointSF - Set the `PetscSF` encoding the parallel section point overlap for the `DM`.
4834
4835 Collective
4836
4837 Input Parameters:
4838 + dm - The `DM`
4839 - sf - The `PetscSF`
4840
4841 Level: intermediate
4842
4843 .seealso: [](ch_dmbase), `DM`, `DMGetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4844 @*/
DMSetPointSF(DM dm,PetscSF sf)4845 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4846 {
4847 PetscFunctionBegin;
4848 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4849 if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4850 PetscCall(PetscObjectReference((PetscObject)sf));
4851 PetscCall(PetscSFDestroy(&dm->sf));
4852 dm->sf = sf;
4853 PetscFunctionReturn(PETSC_SUCCESS);
4854 }
4855
4856 /*@
4857 DMGetNaturalSF - Get the `PetscSF` encoding the map back to the original mesh ordering
4858
4859 Input Parameter:
4860 . dm - The `DM`
4861
4862 Output Parameter:
4863 . sf - The `PetscSF`
4864
4865 Level: intermediate
4866
4867 Note:
4868 This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4869
4870 .seealso: [](ch_dmbase), `DM`, `DMSetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4871 @*/
DMGetNaturalSF(DM dm,PetscSF * sf)4872 PetscErrorCode DMGetNaturalSF(DM dm, PetscSF *sf)
4873 {
4874 PetscFunctionBegin;
4875 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4876 PetscAssertPointer(sf, 2);
4877 *sf = dm->sfNatural;
4878 PetscFunctionReturn(PETSC_SUCCESS);
4879 }
4880
4881 /*@
4882 DMSetNaturalSF - Set the PetscSF encoding the map back to the original mesh ordering
4883
4884 Input Parameters:
4885 + dm - The DM
4886 - sf - The PetscSF
4887
4888 Level: intermediate
4889
4890 .seealso: [](ch_dmbase), `DM`, `DMGetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4891 @*/
DMSetNaturalSF(DM dm,PetscSF sf)4892 PetscErrorCode DMSetNaturalSF(DM dm, PetscSF sf)
4893 {
4894 PetscFunctionBegin;
4895 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4896 if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4897 PetscCall(PetscObjectReference((PetscObject)sf));
4898 PetscCall(PetscSFDestroy(&dm->sfNatural));
4899 dm->sfNatural = sf;
4900 PetscFunctionReturn(PETSC_SUCCESS);
4901 }
4902
DMSetDefaultAdjacency_Private(DM dm,PetscInt f,PetscObject disc)4903 static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4904 {
4905 PetscClassId id;
4906
4907 PetscFunctionBegin;
4908 PetscCall(PetscObjectGetClassId(disc, &id));
4909 if (id == PETSCFE_CLASSID) {
4910 PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE));
4911 } else if (id == PETSCFV_CLASSID) {
4912 PetscCall(DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE));
4913 } else {
4914 PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE));
4915 }
4916 PetscFunctionReturn(PETSC_SUCCESS);
4917 }
4918
DMFieldEnlarge_Static(DM dm,PetscInt NfNew)4919 static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4920 {
4921 RegionField *tmpr;
4922 PetscInt Nf = dm->Nf, f;
4923
4924 PetscFunctionBegin;
4925 if (Nf >= NfNew) PetscFunctionReturn(PETSC_SUCCESS);
4926 PetscCall(PetscMalloc1(NfNew, &tmpr));
4927 for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4928 for (f = Nf; f < NfNew; ++f) {
4929 tmpr[f].disc = NULL;
4930 tmpr[f].label = NULL;
4931 tmpr[f].avoidTensor = PETSC_FALSE;
4932 }
4933 PetscCall(PetscFree(dm->fields));
4934 dm->Nf = NfNew;
4935 dm->fields = tmpr;
4936 PetscFunctionReturn(PETSC_SUCCESS);
4937 }
4938
4939 /*@
4940 DMClearFields - Remove all fields from the `DM`
4941
4942 Logically Collective
4943
4944 Input Parameter:
4945 . dm - The `DM`
4946
4947 Level: intermediate
4948
4949 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetNumFields()`, `DMSetField()`
4950 @*/
DMClearFields(DM dm)4951 PetscErrorCode DMClearFields(DM dm)
4952 {
4953 PetscInt f;
4954
4955 PetscFunctionBegin;
4956 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4957 if (!dm->fields) PetscFunctionReturn(PETSC_SUCCESS); // DMDA does not use fields field in DM
4958 for (f = 0; f < dm->Nf; ++f) {
4959 PetscCall(PetscObjectDestroy(&dm->fields[f].disc));
4960 PetscCall(DMLabelDestroy(&dm->fields[f].label));
4961 }
4962 PetscCall(PetscFree(dm->fields));
4963 dm->fields = NULL;
4964 dm->Nf = 0;
4965 PetscFunctionReturn(PETSC_SUCCESS);
4966 }
4967
4968 /*@
4969 DMGetNumFields - Get the number of fields in the `DM`
4970
4971 Not Collective
4972
4973 Input Parameter:
4974 . dm - The `DM`
4975
4976 Output Parameter:
4977 . numFields - The number of fields
4978
4979 Level: intermediate
4980
4981 .seealso: [](ch_dmbase), `DM`, `DMSetNumFields()`, `DMSetField()`
4982 @*/
DMGetNumFields(DM dm,PetscInt * numFields)4983 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4984 {
4985 PetscFunctionBegin;
4986 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4987 PetscAssertPointer(numFields, 2);
4988 *numFields = dm->Nf;
4989 PetscFunctionReturn(PETSC_SUCCESS);
4990 }
4991
4992 /*@
4993 DMSetNumFields - Set the number of fields in the `DM`
4994
4995 Logically Collective
4996
4997 Input Parameters:
4998 + dm - The `DM`
4999 - numFields - The number of fields
5000
5001 Level: intermediate
5002
5003 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetField()`
5004 @*/
DMSetNumFields(DM dm,PetscInt numFields)5005 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
5006 {
5007 PetscInt Nf, f;
5008
5009 PetscFunctionBegin;
5010 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5011 PetscCall(DMGetNumFields(dm, &Nf));
5012 for (f = Nf; f < numFields; ++f) {
5013 PetscContainer obj;
5014
5015 PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)dm), &obj));
5016 PetscCall(DMAddField(dm, NULL, (PetscObject)obj));
5017 PetscCall(PetscContainerDestroy(&obj));
5018 }
5019 PetscFunctionReturn(PETSC_SUCCESS);
5020 }
5021
5022 /*@
5023 DMGetField - Return the `DMLabel` and discretization object for a given `DM` field
5024
5025 Not Collective
5026
5027 Input Parameters:
5028 + dm - The `DM`
5029 - f - The field number
5030
5031 Output Parameters:
5032 + label - The label indicating the support of the field, or `NULL` for the entire mesh (pass in `NULL` if not needed)
5033 - disc - The discretization object (pass in `NULL` if not needed)
5034
5035 Level: intermediate
5036
5037 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()`
5038 @*/
DMGetField(DM dm,PetscInt f,DMLabel * label,PetscObject * disc)5039 PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *disc)
5040 {
5041 PetscFunctionBegin;
5042 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5043 PetscAssertPointer(disc, 4);
5044 PetscCheck((f >= 0) && (f < dm->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, dm->Nf);
5045 if (!dm->fields) {
5046 if (label) *label = NULL;
5047 if (disc) *disc = NULL;
5048 } else { // some DM such as DMDA do not have dm->fields
5049 if (label) *label = dm->fields[f].label;
5050 if (disc) *disc = dm->fields[f].disc;
5051 }
5052 PetscFunctionReturn(PETSC_SUCCESS);
5053 }
5054
5055 /* Does not clear the DS */
DMSetField_Internal(DM dm,PetscInt f,DMLabel label,PetscObject disc)5056 PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject disc)
5057 {
5058 PetscFunctionBegin;
5059 PetscCall(DMFieldEnlarge_Static(dm, f + 1));
5060 PetscCall(DMLabelDestroy(&dm->fields[f].label));
5061 PetscCall(PetscObjectDestroy(&dm->fields[f].disc));
5062 dm->fields[f].label = label;
5063 dm->fields[f].disc = disc;
5064 PetscCall(PetscObjectReference((PetscObject)label));
5065 PetscCall(PetscObjectReference(disc));
5066 PetscFunctionReturn(PETSC_SUCCESS);
5067 }
5068
5069 /*@
5070 DMSetField - Set the discretization object for a given `DM` field. Usually one would call `DMAddField()` which automatically handles
5071 the field numbering.
5072
5073 Logically Collective
5074
5075 Input Parameters:
5076 + dm - The `DM`
5077 . f - The field number
5078 . label - The label indicating the support of the field, or `NULL` for the entire mesh
5079 - disc - The discretization object
5080
5081 Level: intermediate
5082
5083 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`
5084 @*/
DMSetField(DM dm,PetscInt f,DMLabel label,PetscObject disc)5085 PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject disc)
5086 {
5087 PetscFunctionBegin;
5088 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5089 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
5090 PetscValidHeader(disc, 4);
5091 PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
5092 PetscCall(DMSetField_Internal(dm, f, label, disc));
5093 PetscCall(DMSetDefaultAdjacency_Private(dm, f, disc));
5094 PetscCall(DMClearDS(dm));
5095 PetscFunctionReturn(PETSC_SUCCESS);
5096 }
5097
5098 /*@
5099 DMAddField - Add a field to a `DM` object. A field is a function space defined by of a set of discretization points (geometric entities)
5100 and a discretization object that defines the function space associated with those points.
5101
5102 Logically Collective
5103
5104 Input Parameters:
5105 + dm - The `DM`
5106 . label - The label indicating the support of the field, or `NULL` for the entire mesh
5107 - disc - The discretization object
5108
5109 Level: intermediate
5110
5111 Notes:
5112 The label already exists or will be added to the `DM` with `DMSetLabel()`.
5113
5114 For example, a piecewise continuous pressure field can be defined by coefficients at the cell centers of a mesh and piecewise constant functions
5115 within each cell. Thus a specific function in the space is defined by the combination of a `Vec` containing the coefficients, a `DM` defining the
5116 geometry entities, a `DMLabel` indicating a subset of those geometric entities, and a discretization object, such as a `PetscFE`.
5117
5118 Fortran Note:
5119 Use the argument `PetscObjectCast(disc)` as the second argument
5120
5121 .seealso: [](ch_dmbase), `DM`, `DMSetLabel()`, `DMSetField()`, `DMGetField()`, `PetscFE`
5122 @*/
DMAddField(DM dm,DMLabel label,PetscObject disc)5123 PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject disc)
5124 {
5125 PetscInt Nf = dm->Nf;
5126
5127 PetscFunctionBegin;
5128 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5129 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5130 PetscValidHeader(disc, 3);
5131 PetscCall(DMFieldEnlarge_Static(dm, Nf + 1));
5132 dm->fields[Nf].label = label;
5133 dm->fields[Nf].disc = disc;
5134 PetscCall(PetscObjectReference((PetscObject)label));
5135 PetscCall(PetscObjectReference(disc));
5136 PetscCall(DMSetDefaultAdjacency_Private(dm, Nf, disc));
5137 PetscCall(DMClearDS(dm));
5138 PetscFunctionReturn(PETSC_SUCCESS);
5139 }
5140
5141 /*@
5142 DMSetFieldAvoidTensor - Set flag to avoid defining the field on tensor cells
5143
5144 Logically Collective
5145
5146 Input Parameters:
5147 + dm - The `DM`
5148 . f - The field index
5149 - avoidTensor - `PETSC_TRUE` to skip defining the field on tensor cells
5150
5151 Level: intermediate
5152
5153 .seealso: [](ch_dmbase), `DM`, `DMGetFieldAvoidTensor()`, `DMSetField()`, `DMGetField()`
5154 @*/
DMSetFieldAvoidTensor(DM dm,PetscInt f,PetscBool avoidTensor)5155 PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
5156 {
5157 PetscFunctionBegin;
5158 PetscCheck((f >= 0) && (f < dm->Nf), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", f, dm->Nf);
5159 dm->fields[f].avoidTensor = avoidTensor;
5160 PetscFunctionReturn(PETSC_SUCCESS);
5161 }
5162
5163 /*@
5164 DMGetFieldAvoidTensor - Get flag to avoid defining the field on tensor cells
5165
5166 Not Collective
5167
5168 Input Parameters:
5169 + dm - The `DM`
5170 - f - The field index
5171
5172 Output Parameter:
5173 . avoidTensor - The flag to avoid defining the field on tensor cells
5174
5175 Level: intermediate
5176
5177 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()`, `DMGetField()`, `DMSetFieldAvoidTensor()`
5178 @*/
DMGetFieldAvoidTensor(DM dm,PetscInt f,PetscBool * avoidTensor)5179 PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
5180 {
5181 PetscFunctionBegin;
5182 PetscCheck((f >= 0) && (f < dm->Nf), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", f, dm->Nf);
5183 *avoidTensor = dm->fields[f].avoidTensor;
5184 PetscFunctionReturn(PETSC_SUCCESS);
5185 }
5186
5187 /*@
5188 DMCopyFields - Copy the discretizations for the `DM` into another `DM`
5189
5190 Collective
5191
5192 Input Parameters:
5193 + dm - The `DM`
5194 . minDegree - Minimum degree for a discretization, or `PETSC_DETERMINE` for no limit
5195 - maxDegree - Maximum degree for a discretization, or `PETSC_DETERMINE` for no limit
5196
5197 Output Parameter:
5198 . newdm - The `DM`
5199
5200 Level: advanced
5201
5202 .seealso: [](ch_dmbase), `DM`, `DMGetField()`, `DMSetField()`, `DMAddField()`, `DMCopyDS()`, `DMGetDS()`, `DMGetCellDS()`
5203 @*/
DMCopyFields(DM dm,PetscInt minDegree,PetscInt maxDegree,DM newdm)5204 PetscErrorCode DMCopyFields(DM dm, PetscInt minDegree, PetscInt maxDegree, DM newdm)
5205 {
5206 PetscInt Nf, f;
5207
5208 PetscFunctionBegin;
5209 if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS);
5210 PetscCall(DMGetNumFields(dm, &Nf));
5211 PetscCall(DMClearFields(newdm));
5212 for (f = 0; f < Nf; ++f) {
5213 DMLabel label;
5214 PetscObject field;
5215 PetscClassId id;
5216 PetscBool useCone, useClosure;
5217
5218 PetscCall(DMGetField(dm, f, &label, &field));
5219 PetscCall(PetscObjectGetClassId(field, &id));
5220 if (id == PETSCFE_CLASSID) {
5221 PetscFE newfe;
5222
5223 PetscCall(PetscFELimitDegree((PetscFE)field, minDegree, maxDegree, &newfe));
5224 PetscCall(DMSetField(newdm, f, label, (PetscObject)newfe));
5225 PetscCall(PetscFEDestroy(&newfe));
5226 } else {
5227 PetscCall(DMSetField(newdm, f, label, field));
5228 }
5229 PetscCall(DMGetAdjacency(dm, f, &useCone, &useClosure));
5230 PetscCall(DMSetAdjacency(newdm, f, useCone, useClosure));
5231 }
5232 // Create nullspace constructor slots
5233 if (dm->nullspaceConstructors) {
5234 PetscCall(PetscFree2(newdm->nullspaceConstructors, newdm->nearnullspaceConstructors));
5235 PetscCall(PetscCalloc2(Nf, &newdm->nullspaceConstructors, Nf, &newdm->nearnullspaceConstructors));
5236 }
5237 PetscFunctionReturn(PETSC_SUCCESS);
5238 }
5239
5240 /*@
5241 DMGetAdjacency - Returns the flags for determining variable influence
5242
5243 Not Collective
5244
5245 Input Parameters:
5246 + dm - The `DM` object
5247 - f - The field number, or `PETSC_DEFAULT` for the default adjacency
5248
5249 Output Parameters:
5250 + useCone - Flag for variable influence starting with the cone operation
5251 - useClosure - Flag for variable influence using transitive closure
5252
5253 Level: developer
5254
5255 Notes:
5256 .vb
5257 FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5258 FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
5259 FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
5260 .ve
5261 Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
5262
5263 .seealso: [](ch_dmbase), `DM`, `DMSetAdjacency()`, `DMGetField()`, `DMSetField()`
5264 @*/
DMGetAdjacency(DM dm,PetscInt f,PetscBool * useCone,PetscBool * useClosure)5265 PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
5266 {
5267 PetscFunctionBegin;
5268 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5269 if (useCone) PetscAssertPointer(useCone, 3);
5270 if (useClosure) PetscAssertPointer(useClosure, 4);
5271 if (f < 0) {
5272 if (useCone) *useCone = dm->adjacency[0];
5273 if (useClosure) *useClosure = dm->adjacency[1];
5274 } else {
5275 PetscInt Nf;
5276
5277 PetscCall(DMGetNumFields(dm, &Nf));
5278 PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
5279 if (useCone) *useCone = dm->fields[f].adjacency[0];
5280 if (useClosure) *useClosure = dm->fields[f].adjacency[1];
5281 }
5282 PetscFunctionReturn(PETSC_SUCCESS);
5283 }
5284
5285 /*@
5286 DMSetAdjacency - Set the flags for determining variable influence
5287
5288 Not Collective
5289
5290 Input Parameters:
5291 + dm - The `DM` object
5292 . f - The field number
5293 . useCone - Flag for variable influence starting with the cone operation
5294 - useClosure - Flag for variable influence using transitive closure
5295
5296 Level: developer
5297
5298 Notes:
5299 .vb
5300 FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5301 FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
5302 FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
5303 .ve
5304 Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
5305
5306 .seealso: [](ch_dmbase), `DM`, `DMGetAdjacency()`, `DMGetField()`, `DMSetField()`
5307 @*/
DMSetAdjacency(DM dm,PetscInt f,PetscBool useCone,PetscBool useClosure)5308 PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
5309 {
5310 PetscFunctionBegin;
5311 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5312 if (f < 0) {
5313 dm->adjacency[0] = useCone;
5314 dm->adjacency[1] = useClosure;
5315 } else {
5316 PetscInt Nf;
5317
5318 PetscCall(DMGetNumFields(dm, &Nf));
5319 PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
5320 dm->fields[f].adjacency[0] = useCone;
5321 dm->fields[f].adjacency[1] = useClosure;
5322 }
5323 PetscFunctionReturn(PETSC_SUCCESS);
5324 }
5325
5326 /*@
5327 DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined
5328
5329 Not collective
5330
5331 Input Parameter:
5332 . dm - The `DM` object
5333
5334 Output Parameters:
5335 + useCone - Flag for variable influence starting with the cone operation
5336 - useClosure - Flag for variable influence using transitive closure
5337
5338 Level: developer
5339
5340 Notes:
5341 .vb
5342 FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5343 FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
5344 FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
5345 .ve
5346
5347 .seealso: [](ch_dmbase), `DM`, `DMSetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5348 @*/
DMGetBasicAdjacency(DM dm,PetscBool * useCone,PetscBool * useClosure)5349 PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
5350 {
5351 PetscInt Nf;
5352
5353 PetscFunctionBegin;
5354 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5355 if (useCone) PetscAssertPointer(useCone, 2);
5356 if (useClosure) PetscAssertPointer(useClosure, 3);
5357 PetscCall(DMGetNumFields(dm, &Nf));
5358 if (!Nf) {
5359 PetscCall(DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure));
5360 } else {
5361 PetscCall(DMGetAdjacency(dm, 0, useCone, useClosure));
5362 }
5363 PetscFunctionReturn(PETSC_SUCCESS);
5364 }
5365
5366 /*@
5367 DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined
5368
5369 Not Collective
5370
5371 Input Parameters:
5372 + dm - The `DM` object
5373 . useCone - Flag for variable influence starting with the cone operation
5374 - useClosure - Flag for variable influence using transitive closure
5375
5376 Level: developer
5377
5378 Notes:
5379 .vb
5380 FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5381 FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE
5382 FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE
5383 .ve
5384
5385 .seealso: [](ch_dmbase), `DM`, `DMGetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5386 @*/
DMSetBasicAdjacency(DM dm,PetscBool useCone,PetscBool useClosure)5387 PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5388 {
5389 PetscInt Nf;
5390
5391 PetscFunctionBegin;
5392 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5393 PetscCall(DMGetNumFields(dm, &Nf));
5394 if (!Nf) {
5395 PetscCall(DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure));
5396 } else {
5397 PetscCall(DMSetAdjacency(dm, 0, useCone, useClosure));
5398 }
5399 PetscFunctionReturn(PETSC_SUCCESS);
5400 }
5401
DMCompleteBCLabels_Internal(DM dm)5402 PetscErrorCode DMCompleteBCLabels_Internal(DM dm)
5403 {
5404 DM plex;
5405 DMLabel *labels, *glabels;
5406 const char **names;
5407 char *sendNames, *recvNames;
5408 PetscInt Nds, s, maxLabels = 0, maxLen = 0, gmaxLen, Nl = 0, gNl, l, gl, m;
5409 size_t len;
5410 MPI_Comm comm;
5411 PetscMPIInt rank, size, p, *counts, *displs;
5412
5413 PetscFunctionBegin;
5414 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5415 PetscCallMPI(MPI_Comm_size(comm, &size));
5416 PetscCallMPI(MPI_Comm_rank(comm, &rank));
5417 PetscCall(DMGetNumDS(dm, &Nds));
5418 for (s = 0; s < Nds; ++s) {
5419 PetscDS dsBC;
5420 PetscInt numBd;
5421
5422 PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL));
5423 PetscCall(PetscDSGetNumBoundary(dsBC, &numBd));
5424 maxLabels += numBd;
5425 }
5426 PetscCall(PetscCalloc1(maxLabels, &labels));
5427 /* Get list of labels to be completed */
5428 for (s = 0; s < Nds; ++s) {
5429 PetscDS dsBC;
5430 PetscInt numBd, bd;
5431
5432 PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL));
5433 PetscCall(PetscDSGetNumBoundary(dsBC, &numBd));
5434 for (bd = 0; bd < numBd; ++bd) {
5435 DMLabel label;
5436 PetscInt field;
5437 PetscObject obj;
5438 PetscClassId id;
5439
5440 PetscCall(PetscDSGetBoundary(dsBC, bd, NULL, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
5441 PetscCall(DMGetField(dm, field, NULL, &obj));
5442 PetscCall(PetscObjectGetClassId(obj, &id));
5443 if (id != PETSCFE_CLASSID || !label) continue;
5444 for (l = 0; l < Nl; ++l)
5445 if (labels[l] == label) break;
5446 if (l == Nl) labels[Nl++] = label;
5447 }
5448 }
5449 /* Get label names */
5450 PetscCall(PetscMalloc1(Nl, &names));
5451 for (l = 0; l < Nl; ++l) PetscCall(PetscObjectGetName((PetscObject)labels[l], &names[l]));
5452 for (l = 0; l < Nl; ++l) {
5453 PetscCall(PetscStrlen(names[l], &len));
5454 maxLen = PetscMax(maxLen, (PetscInt)len + 2);
5455 }
5456 PetscCall(PetscFree(labels));
5457 PetscCallMPI(MPIU_Allreduce(&maxLen, &gmaxLen, 1, MPIU_INT, MPI_MAX, comm));
5458 PetscCall(PetscCalloc1(Nl * gmaxLen, &sendNames));
5459 for (l = 0; l < Nl; ++l) PetscCall(PetscStrncpy(&sendNames[gmaxLen * l], names[l], gmaxLen));
5460 PetscCall(PetscFree(names));
5461 /* Put all names on all processes */
5462 PetscCall(PetscCalloc2(size, &counts, size + 1, &displs));
5463 PetscCallMPI(MPI_Allgather(&Nl, 1, MPI_INT, counts, 1, MPI_INT, comm));
5464 for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + counts[p];
5465 gNl = displs[size];
5466 for (p = 0; p < size; ++p) {
5467 counts[p] *= gmaxLen;
5468 displs[p] *= gmaxLen;
5469 }
5470 PetscCall(PetscCalloc2(gNl * gmaxLen, &recvNames, gNl, &glabels));
5471 PetscCallMPI(MPI_Allgatherv(sendNames, counts[rank], MPI_CHAR, recvNames, counts, displs, MPI_CHAR, comm));
5472 PetscCall(PetscFree2(counts, displs));
5473 PetscCall(PetscFree(sendNames));
5474 for (l = 0, gl = 0; l < gNl; ++l) {
5475 PetscCall(DMGetLabel(dm, &recvNames[l * gmaxLen], &glabels[gl]));
5476 PetscCheck(glabels[gl], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Label %s missing on rank %d", &recvNames[l * gmaxLen], rank);
5477 for (m = 0; m < gl; ++m)
5478 if (glabels[m] == glabels[gl]) goto next_label;
5479 PetscCall(DMConvert(dm, DMPLEX, &plex));
5480 PetscCall(DMPlexLabelComplete(plex, glabels[gl]));
5481 PetscCall(DMDestroy(&plex));
5482 ++gl;
5483 next_label:
5484 continue;
5485 }
5486 PetscCall(PetscFree2(recvNames, glabels));
5487 PetscFunctionReturn(PETSC_SUCCESS);
5488 }
5489
DMDSEnlarge_Static(DM dm,PetscInt NdsNew)5490 static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5491 {
5492 DMSpace *tmpd;
5493 PetscInt Nds = dm->Nds, s;
5494
5495 PetscFunctionBegin;
5496 if (Nds >= NdsNew) PetscFunctionReturn(PETSC_SUCCESS);
5497 PetscCall(PetscMalloc1(NdsNew, &tmpd));
5498 for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5499 for (s = Nds; s < NdsNew; ++s) {
5500 tmpd[s].ds = NULL;
5501 tmpd[s].label = NULL;
5502 tmpd[s].fields = NULL;
5503 }
5504 PetscCall(PetscFree(dm->probs));
5505 dm->Nds = NdsNew;
5506 dm->probs = tmpd;
5507 PetscFunctionReturn(PETSC_SUCCESS);
5508 }
5509
5510 /*@
5511 DMGetNumDS - Get the number of discrete systems in the `DM`
5512
5513 Not Collective
5514
5515 Input Parameter:
5516 . dm - The `DM`
5517
5518 Output Parameter:
5519 . Nds - The number of `PetscDS` objects
5520
5521 Level: intermediate
5522
5523 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMGetCellDS()`
5524 @*/
DMGetNumDS(DM dm,PetscInt * Nds)5525 PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5526 {
5527 PetscFunctionBegin;
5528 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5529 PetscAssertPointer(Nds, 2);
5530 *Nds = dm->Nds;
5531 PetscFunctionReturn(PETSC_SUCCESS);
5532 }
5533
5534 /*@
5535 DMClearDS - Remove all discrete systems from the `DM`
5536
5537 Logically Collective
5538
5539 Input Parameter:
5540 . dm - The `DM`
5541
5542 Level: intermediate
5543
5544 .seealso: [](ch_dmbase), `DM`, `DMGetNumDS()`, `DMGetDS()`, `DMSetField()`
5545 @*/
DMClearDS(DM dm)5546 PetscErrorCode DMClearDS(DM dm)
5547 {
5548 PetscInt s;
5549
5550 PetscFunctionBegin;
5551 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5552 for (s = 0; s < dm->Nds; ++s) {
5553 PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5554 PetscCall(PetscDSDestroy(&dm->probs[s].dsIn));
5555 PetscCall(DMLabelDestroy(&dm->probs[s].label));
5556 PetscCall(ISDestroy(&dm->probs[s].fields));
5557 }
5558 PetscCall(PetscFree(dm->probs));
5559 dm->probs = NULL;
5560 dm->Nds = 0;
5561 PetscFunctionReturn(PETSC_SUCCESS);
5562 }
5563
5564 /*@
5565 DMGetDS - Get the default `PetscDS`
5566
5567 Not Collective
5568
5569 Input Parameter:
5570 . dm - The `DM`
5571
5572 Output Parameter:
5573 . ds - The default `PetscDS`
5574
5575 Level: intermediate
5576
5577 Note:
5578 The `ds` is owned by the `dm` and should not be destroyed directly.
5579
5580 .seealso: [](ch_dmbase), `DM`, `DMGetCellDS()`, `DMGetRegionDS()`
5581 @*/
DMGetDS(DM dm,PetscDS * ds)5582 PetscErrorCode DMGetDS(DM dm, PetscDS *ds)
5583 {
5584 PetscFunctionBeginHot;
5585 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5586 PetscAssertPointer(ds, 2);
5587 PetscCheck(dm->Nds > 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Need to call DMCreateDS() before calling DMGetDS()");
5588 *ds = dm->probs[0].ds;
5589 PetscFunctionReturn(PETSC_SUCCESS);
5590 }
5591
5592 /*@
5593 DMGetCellDS - Get the `PetscDS` defined on a given cell
5594
5595 Not Collective
5596
5597 Input Parameters:
5598 + dm - The `DM`
5599 - point - Cell for the `PetscDS`
5600
5601 Output Parameters:
5602 + ds - The `PetscDS` defined on the given cell
5603 - dsIn - The `PetscDS` for input on the given cell, or `NULL` if the same ds
5604
5605 Level: developer
5606
5607 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMSetRegionDS()`
5608 @*/
DMGetCellDS(DM dm,PetscInt point,PetscDS * ds,PetscDS * dsIn)5609 PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *ds, PetscDS *dsIn)
5610 {
5611 PetscDS dsDef = NULL;
5612 PetscInt s;
5613
5614 PetscFunctionBeginHot;
5615 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5616 if (ds) PetscAssertPointer(ds, 3);
5617 if (dsIn) PetscAssertPointer(dsIn, 4);
5618 PetscCheck(point >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %" PetscInt_FMT, point);
5619 if (ds) *ds = NULL;
5620 if (dsIn) *dsIn = NULL;
5621 for (s = 0; s < dm->Nds; ++s) {
5622 PetscInt val;
5623
5624 if (!dm->probs[s].label) {
5625 dsDef = dm->probs[s].ds;
5626 } else {
5627 PetscCall(DMLabelGetValue(dm->probs[s].label, point, &val));
5628 if (val >= 0) {
5629 if (ds) *ds = dm->probs[s].ds;
5630 if (dsIn) *dsIn = dm->probs[s].dsIn;
5631 break;
5632 }
5633 }
5634 }
5635 if (ds && !*ds) *ds = dsDef;
5636 PetscFunctionReturn(PETSC_SUCCESS);
5637 }
5638
5639 /*@
5640 DMGetRegionDS - Get the `PetscDS` for a given mesh region, defined by a `DMLabel`
5641
5642 Not Collective
5643
5644 Input Parameters:
5645 + dm - The `DM`
5646 - label - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh
5647
5648 Output Parameters:
5649 + fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL`
5650 . ds - The `PetscDS` defined on the given region, or `NULL`
5651 - dsIn - The `PetscDS` for input in the given region, or `NULL`
5652
5653 Level: advanced
5654
5655 Note:
5656 If a non-`NULL` label is given, but there is no `PetscDS` on that specific label,
5657 the `PetscDS` for the full domain (if present) is returned. Returns with
5658 fields = `NULL` and ds = `NULL` if there is no `PetscDS` for the full domain.
5659
5660 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5661 @*/
DMGetRegionDS(DM dm,DMLabel label,IS * fields,PetscDS * ds,PetscDS * dsIn)5662 PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds, PetscDS *dsIn)
5663 {
5664 PetscInt Nds = dm->Nds, s;
5665
5666 PetscFunctionBegin;
5667 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5668 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5669 if (fields) {
5670 PetscAssertPointer(fields, 3);
5671 *fields = NULL;
5672 }
5673 if (ds) {
5674 PetscAssertPointer(ds, 4);
5675 *ds = NULL;
5676 }
5677 if (dsIn) {
5678 PetscAssertPointer(dsIn, 5);
5679 *dsIn = NULL;
5680 }
5681 for (s = 0; s < Nds; ++s) {
5682 if (dm->probs[s].label == label || !dm->probs[s].label) {
5683 if (fields) *fields = dm->probs[s].fields;
5684 if (ds) *ds = dm->probs[s].ds;
5685 if (dsIn) *dsIn = dm->probs[s].dsIn;
5686 if (dm->probs[s].label) PetscFunctionReturn(PETSC_SUCCESS);
5687 }
5688 }
5689 PetscFunctionReturn(PETSC_SUCCESS);
5690 }
5691
5692 /*@
5693 DMSetRegionDS - Set the `PetscDS` for a given mesh region, defined by a `DMLabel`
5694
5695 Collective
5696
5697 Input Parameters:
5698 + dm - The `DM`
5699 . label - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh
5700 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` for all fields
5701 . ds - The `PetscDS` defined on the given region
5702 - dsIn - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS`
5703
5704 Level: advanced
5705
5706 Note:
5707 If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`. If the `PetscDS` is replaced,
5708 the fields argument is ignored.
5709
5710 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionNumDS()`, `DMGetDS()`, `DMGetCellDS()`
5711 @*/
DMSetRegionDS(DM dm,DMLabel label,IS fields,PetscDS ds,PetscDS dsIn)5712 PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
5713 {
5714 PetscInt Nds = dm->Nds, s;
5715
5716 PetscFunctionBegin;
5717 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5718 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5719 if (fields) PetscValidHeaderSpecific(fields, IS_CLASSID, 3);
5720 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 4);
5721 if (dsIn) PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 5);
5722 for (s = 0; s < Nds; ++s) {
5723 if (dm->probs[s].label == label) {
5724 PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5725 PetscCall(PetscDSDestroy(&dm->probs[s].dsIn));
5726 dm->probs[s].ds = ds;
5727 dm->probs[s].dsIn = dsIn;
5728 PetscFunctionReturn(PETSC_SUCCESS);
5729 }
5730 }
5731 PetscCall(DMDSEnlarge_Static(dm, Nds + 1));
5732 PetscCall(PetscObjectReference((PetscObject)label));
5733 PetscCall(PetscObjectReference((PetscObject)fields));
5734 PetscCall(PetscObjectReference((PetscObject)ds));
5735 PetscCall(PetscObjectReference((PetscObject)dsIn));
5736 if (!label) {
5737 /* Put the NULL label at the front, so it is returned as the default */
5738 for (s = Nds - 1; s >= 0; --s) dm->probs[s + 1] = dm->probs[s];
5739 Nds = 0;
5740 }
5741 dm->probs[Nds].label = label;
5742 dm->probs[Nds].fields = fields;
5743 dm->probs[Nds].ds = ds;
5744 dm->probs[Nds].dsIn = dsIn;
5745 PetscFunctionReturn(PETSC_SUCCESS);
5746 }
5747
5748 /*@
5749 DMGetRegionNumDS - Get the `PetscDS` for a given mesh region, defined by the region number
5750
5751 Not Collective
5752
5753 Input Parameters:
5754 + dm - The `DM`
5755 - num - The region number, in [0, Nds)
5756
5757 Output Parameters:
5758 + label - The region label, or `NULL`
5759 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL`
5760 . ds - The `PetscDS` defined on the given region, or `NULL`
5761 - dsIn - The `PetscDS` for input in the given region, or `NULL`
5762
5763 Level: advanced
5764
5765 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5766 @*/
DMGetRegionNumDS(DM dm,PetscInt num,DMLabel * label,IS * fields,PetscDS * ds,PetscDS * dsIn)5767 PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds, PetscDS *dsIn)
5768 {
5769 PetscInt Nds;
5770
5771 PetscFunctionBegin;
5772 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5773 PetscCall(DMGetNumDS(dm, &Nds));
5774 PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5775 if (label) {
5776 PetscAssertPointer(label, 3);
5777 *label = dm->probs[num].label;
5778 }
5779 if (fields) {
5780 PetscAssertPointer(fields, 4);
5781 *fields = dm->probs[num].fields;
5782 }
5783 if (ds) {
5784 PetscAssertPointer(ds, 5);
5785 *ds = dm->probs[num].ds;
5786 }
5787 if (dsIn) {
5788 PetscAssertPointer(dsIn, 6);
5789 *dsIn = dm->probs[num].dsIn;
5790 }
5791 PetscFunctionReturn(PETSC_SUCCESS);
5792 }
5793
5794 /*@
5795 DMSetRegionNumDS - Set the `PetscDS` for a given mesh region, defined by the region number
5796
5797 Not Collective
5798
5799 Input Parameters:
5800 + dm - The `DM`
5801 . num - The region number, in [0, Nds)
5802 . label - The region label, or `NULL`
5803 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` to prevent setting
5804 . ds - The `PetscDS` defined on the given region, or `NULL` to prevent setting
5805 - dsIn - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS`
5806
5807 Level: advanced
5808
5809 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5810 @*/
DMSetRegionNumDS(DM dm,PetscInt num,DMLabel label,IS fields,PetscDS ds,PetscDS dsIn)5811 PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
5812 {
5813 PetscInt Nds;
5814
5815 PetscFunctionBegin;
5816 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5817 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
5818 PetscCall(DMGetNumDS(dm, &Nds));
5819 PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5820 PetscCall(PetscObjectReference((PetscObject)label));
5821 PetscCall(DMLabelDestroy(&dm->probs[num].label));
5822 dm->probs[num].label = label;
5823 if (fields) {
5824 PetscValidHeaderSpecific(fields, IS_CLASSID, 4);
5825 PetscCall(PetscObjectReference((PetscObject)fields));
5826 PetscCall(ISDestroy(&dm->probs[num].fields));
5827 dm->probs[num].fields = fields;
5828 }
5829 if (ds) {
5830 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 5);
5831 PetscCall(PetscObjectReference((PetscObject)ds));
5832 PetscCall(PetscDSDestroy(&dm->probs[num].ds));
5833 dm->probs[num].ds = ds;
5834 }
5835 if (dsIn) {
5836 PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 6);
5837 PetscCall(PetscObjectReference((PetscObject)dsIn));
5838 PetscCall(PetscDSDestroy(&dm->probs[num].dsIn));
5839 dm->probs[num].dsIn = dsIn;
5840 }
5841 PetscFunctionReturn(PETSC_SUCCESS);
5842 }
5843
5844 /*@
5845 DMFindRegionNum - Find the region number for a given `PetscDS`, or -1 if it is not found.
5846
5847 Not Collective
5848
5849 Input Parameters:
5850 + dm - The `DM`
5851 - ds - The `PetscDS` defined on the given region
5852
5853 Output Parameter:
5854 . num - The region number, in [0, Nds), or -1 if not found
5855
5856 Level: advanced
5857
5858 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5859 @*/
DMFindRegionNum(DM dm,PetscDS ds,PetscInt * num)5860 PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5861 {
5862 PetscInt Nds, n;
5863
5864 PetscFunctionBegin;
5865 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5866 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 2);
5867 PetscAssertPointer(num, 3);
5868 PetscCall(DMGetNumDS(dm, &Nds));
5869 for (n = 0; n < Nds; ++n)
5870 if (ds == dm->probs[n].ds) break;
5871 if (n >= Nds) *num = -1;
5872 else *num = n;
5873 PetscFunctionReturn(PETSC_SUCCESS);
5874 }
5875
5876 /*@
5877 DMCreateFEDefault - Create a `PetscFE` based on the celltype for the mesh
5878
5879 Not Collective
5880
5881 Input Parameters:
5882 + dm - The `DM`
5883 . Nc - The number of components for the field
5884 . prefix - The options prefix for the output `PetscFE`, or `NULL`
5885 - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree
5886
5887 Output Parameter:
5888 . fem - The `PetscFE`
5889
5890 Level: intermediate
5891
5892 Note:
5893 This is a convenience method that just calls `PetscFECreateByCell()` underneath.
5894
5895 .seealso: [](ch_dmbase), `DM`, `PetscFECreateByCell()`, `DMAddField()`, `DMCreateDS()`, `DMGetCellDS()`, `DMGetRegionDS()`
5896 @*/
DMCreateFEDefault(DM dm,PetscInt Nc,const char prefix[],PetscInt qorder,PetscFE * fem)5897 PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem)
5898 {
5899 DMPolytopeType ct;
5900 PetscInt dim, cStart;
5901
5902 PetscFunctionBegin;
5903 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5904 PetscValidLogicalCollectiveInt(dm, Nc, 2);
5905 if (prefix) PetscAssertPointer(prefix, 3);
5906 PetscValidLogicalCollectiveInt(dm, qorder, 4);
5907 PetscAssertPointer(fem, 5);
5908 PetscCall(DMGetDimension(dm, &dim));
5909 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
5910 PetscCall(DMPlexGetCellType(dm, cStart, &ct));
5911 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem));
5912 PetscFunctionReturn(PETSC_SUCCESS);
5913 }
5914
5915 /*@
5916 DMCreateDS - Create the discrete systems for the `DM` based upon the fields added to the `DM`
5917
5918 Collective
5919
5920 Input Parameter:
5921 . dm - The `DM`
5922
5923 Options Database Key:
5924 . -dm_petscds_view - View all the `PetscDS` objects in this `DM`
5925
5926 Level: intermediate
5927
5928 Developer Note:
5929 The name of this function is wrong. Create functions always return the created object as one of the arguments.
5930
5931 .seealso: [](ch_dmbase), `DM`, `DMSetField`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
5932 @*/
DMCreateDS(DM dm)5933 PetscErrorCode DMCreateDS(DM dm)
5934 {
5935 MPI_Comm comm;
5936 PetscDS dsDef;
5937 DMLabel *labelSet;
5938 PetscInt dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5939 PetscBool doSetup = PETSC_TRUE, flg;
5940
5941 PetscFunctionBegin;
5942 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5943 if (!dm->fields) PetscFunctionReturn(PETSC_SUCCESS);
5944 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5945 PetscCall(DMGetCoordinateDim(dm, &dE));
5946 // Create nullspace constructor slots
5947 PetscCall(PetscFree2(dm->nullspaceConstructors, dm->nearnullspaceConstructors));
5948 PetscCall(PetscCalloc2(Nf, &dm->nullspaceConstructors, Nf, &dm->nearnullspaceConstructors));
5949 /* Determine how many regions we have */
5950 PetscCall(PetscMalloc1(Nf, &labelSet));
5951 Nl = 0;
5952 Ndef = 0;
5953 for (f = 0; f < Nf; ++f) {
5954 DMLabel label = dm->fields[f].label;
5955 PetscInt l;
5956
5957 #ifdef PETSC_HAVE_LIBCEED
5958 /* Move CEED context to discretizations */
5959 {
5960 PetscClassId id;
5961
5962 PetscCall(PetscObjectGetClassId(dm->fields[f].disc, &id));
5963 if (id == PETSCFE_CLASSID) {
5964 Ceed ceed;
5965
5966 PetscCall(DMGetCeed(dm, &ceed));
5967 PetscCall(PetscFESetCeed((PetscFE)dm->fields[f].disc, ceed));
5968 }
5969 }
5970 #endif
5971 if (!label) {
5972 ++Ndef;
5973 continue;
5974 }
5975 for (l = 0; l < Nl; ++l)
5976 if (label == labelSet[l]) break;
5977 if (l < Nl) continue;
5978 labelSet[Nl++] = label;
5979 }
5980 /* Create default DS if there are no labels to intersect with */
5981 PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL));
5982 if (!dsDef && Ndef && !Nl) {
5983 IS fields;
5984 PetscInt *fld, nf;
5985
5986 for (f = 0, nf = 0; f < Nf; ++f)
5987 if (!dm->fields[f].label) ++nf;
5988 PetscCheck(nf, comm, PETSC_ERR_PLIB, "All fields have labels, but we are trying to create a default DS");
5989 PetscCall(PetscMalloc1(nf, &fld));
5990 for (f = 0, nf = 0; f < Nf; ++f)
5991 if (!dm->fields[f].label) fld[nf++] = f;
5992 PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
5993 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_"));
5994 PetscCall(ISSetType(fields, ISGENERAL));
5995 PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
5996
5997 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
5998 PetscCall(DMSetRegionDS(dm, NULL, fields, dsDef, NULL));
5999 PetscCall(PetscDSDestroy(&dsDef));
6000 PetscCall(ISDestroy(&fields));
6001 }
6002 PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL));
6003 if (dsDef) PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
6004 /* Intersect labels with default fields */
6005 if (Ndef && Nl) {
6006 DM plex;
6007 DMLabel cellLabel;
6008 IS fieldIS, allcellIS, defcellIS = NULL;
6009 PetscInt *fields;
6010 const PetscInt *cells;
6011 PetscInt depth, nf = 0, n, c;
6012
6013 PetscCall(DMConvert(dm, DMPLEX, &plex));
6014 PetscCall(DMPlexGetDepth(plex, &depth));
6015 PetscCall(DMGetStratumIS(plex, "dim", depth, &allcellIS));
6016 if (!allcellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &allcellIS));
6017 /* TODO This looks like it only works for one label */
6018 for (l = 0; l < Nl; ++l) {
6019 DMLabel label = labelSet[l];
6020 IS pointIS;
6021
6022 PetscCall(ISDestroy(&defcellIS));
6023 PetscCall(DMLabelGetStratumIS(label, 1, &pointIS));
6024 PetscCall(ISDifference(allcellIS, pointIS, &defcellIS));
6025 PetscCall(ISDestroy(&pointIS));
6026 }
6027 PetscCall(ISDestroy(&allcellIS));
6028
6029 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel));
6030 PetscCall(ISGetLocalSize(defcellIS, &n));
6031 PetscCall(ISGetIndices(defcellIS, &cells));
6032 for (c = 0; c < n; ++c) PetscCall(DMLabelSetValue(cellLabel, cells[c], 1));
6033 PetscCall(ISRestoreIndices(defcellIS, &cells));
6034 PetscCall(ISDestroy(&defcellIS));
6035 PetscCall(DMPlexLabelComplete(plex, cellLabel));
6036
6037 PetscCall(PetscMalloc1(Ndef, &fields));
6038 for (f = 0; f < Nf; ++f)
6039 if (!dm->fields[f].label) fields[nf++] = f;
6040 PetscCall(ISCreate(PETSC_COMM_SELF, &fieldIS));
6041 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fieldIS, "dm_fields_"));
6042 PetscCall(ISSetType(fieldIS, ISGENERAL));
6043 PetscCall(ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER));
6044
6045 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
6046 PetscCall(DMSetRegionDS(dm, cellLabel, fieldIS, dsDef, NULL));
6047 PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
6048 PetscCall(DMLabelDestroy(&cellLabel));
6049 PetscCall(PetscDSDestroy(&dsDef));
6050 PetscCall(ISDestroy(&fieldIS));
6051 PetscCall(DMDestroy(&plex));
6052 }
6053 /* Create label DSes
6054 - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
6055 */
6056 /* TODO Should check that labels are disjoint */
6057 for (l = 0; l < Nl; ++l) {
6058 DMLabel label = labelSet[l];
6059 PetscDS ds, dsIn = NULL;
6060 IS fields;
6061 PetscInt *fld, nf;
6062
6063 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds));
6064 for (f = 0, nf = 0; f < Nf; ++f)
6065 if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
6066 PetscCall(PetscMalloc1(nf, &fld));
6067 for (f = 0, nf = 0; f < Nf; ++f)
6068 if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
6069 PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
6070 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_"));
6071 PetscCall(ISSetType(fields, ISGENERAL));
6072 PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
6073 PetscCall(PetscDSSetCoordinateDimension(ds, dE));
6074 {
6075 DMPolytopeType ct;
6076 PetscInt lStart, lEnd;
6077 PetscBool isCohesiveLocal = PETSC_FALSE, isCohesive;
6078
6079 PetscCall(DMLabelGetBounds(label, &lStart, &lEnd));
6080 if (lStart >= 0) {
6081 PetscCall(DMPlexGetCellType(dm, lStart, &ct));
6082 switch (ct) {
6083 case DM_POLYTOPE_POINT_PRISM_TENSOR:
6084 case DM_POLYTOPE_SEG_PRISM_TENSOR:
6085 case DM_POLYTOPE_TRI_PRISM_TENSOR:
6086 case DM_POLYTOPE_QUAD_PRISM_TENSOR:
6087 isCohesiveLocal = PETSC_TRUE;
6088 break;
6089 default:
6090 break;
6091 }
6092 }
6093 PetscCallMPI(MPIU_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPI_C_BOOL, MPI_LOR, comm));
6094 if (isCohesive) {
6095 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsIn));
6096 PetscCall(PetscDSSetCoordinateDimension(dsIn, dE));
6097 }
6098 for (f = 0, nf = 0; f < Nf; ++f) {
6099 if (label == dm->fields[f].label || !dm->fields[f].label) {
6100 if (label == dm->fields[f].label) {
6101 PetscCall(PetscDSSetDiscretization(ds, nf, NULL));
6102 PetscCall(PetscDSSetCohesive(ds, nf, isCohesive));
6103 if (dsIn) {
6104 PetscCall(PetscDSSetDiscretization(dsIn, nf, NULL));
6105 PetscCall(PetscDSSetCohesive(dsIn, nf, isCohesive));
6106 }
6107 }
6108 ++nf;
6109 }
6110 }
6111 }
6112 PetscCall(DMSetRegionDS(dm, label, fields, ds, dsIn));
6113 PetscCall(ISDestroy(&fields));
6114 PetscCall(PetscDSDestroy(&ds));
6115 PetscCall(PetscDSDestroy(&dsIn));
6116 }
6117 PetscCall(PetscFree(labelSet));
6118 /* Set fields in DSes */
6119 for (s = 0; s < dm->Nds; ++s) {
6120 PetscDS ds = dm->probs[s].ds;
6121 PetscDS dsIn = dm->probs[s].dsIn;
6122 IS fields = dm->probs[s].fields;
6123 const PetscInt *fld;
6124 PetscInt nf, dsnf;
6125 PetscBool isCohesive;
6126
6127 PetscCall(PetscDSGetNumFields(ds, &dsnf));
6128 PetscCall(PetscDSIsCohesive(ds, &isCohesive));
6129 PetscCall(ISGetLocalSize(fields, &nf));
6130 PetscCall(ISGetIndices(fields, &fld));
6131 for (f = 0; f < nf; ++f) {
6132 PetscObject disc = dm->fields[fld[f]].disc;
6133 PetscBool isCohesiveField;
6134 PetscClassId id;
6135
6136 /* Handle DS with no fields */
6137 if (dsnf) PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField));
6138 /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */
6139 if (isCohesive) {
6140 if (!isCohesiveField) {
6141 PetscObject bdDisc;
6142
6143 PetscCall(PetscFEGetHeightSubspace((PetscFE)disc, 1, (PetscFE *)&bdDisc));
6144 PetscCall(PetscDSSetDiscretization(ds, f, bdDisc));
6145 PetscCall(PetscDSSetDiscretization(dsIn, f, disc));
6146 } else {
6147 PetscCall(PetscDSSetDiscretization(ds, f, disc));
6148 PetscCall(PetscDSSetDiscretization(dsIn, f, disc));
6149 }
6150 } else {
6151 PetscCall(PetscDSSetDiscretization(ds, f, disc));
6152 }
6153 /* We allow people to have placeholder fields and construct the Section by hand */
6154 PetscCall(PetscObjectGetClassId(disc, &id));
6155 if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
6156 }
6157 PetscCall(ISRestoreIndices(fields, &fld));
6158 }
6159 /* Allow k-jet tabulation */
6160 PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)dm)->prefix, "-dm_ds_jet_degree", &k, &flg));
6161 if (flg) {
6162 for (s = 0; s < dm->Nds; ++s) {
6163 PetscDS ds = dm->probs[s].ds;
6164 PetscDS dsIn = dm->probs[s].dsIn;
6165 PetscInt Nf, f;
6166
6167 PetscCall(PetscDSGetNumFields(ds, &Nf));
6168 for (f = 0; f < Nf; ++f) {
6169 PetscCall(PetscDSSetJetDegree(ds, f, k));
6170 if (dsIn) PetscCall(PetscDSSetJetDegree(dsIn, f, k));
6171 }
6172 }
6173 }
6174 /* Setup DSes */
6175 if (doSetup) {
6176 for (s = 0; s < dm->Nds; ++s) {
6177 if (dm->setfromoptionscalled) {
6178 PetscCall(PetscDSSetFromOptions(dm->probs[s].ds));
6179 if (dm->probs[s].dsIn) PetscCall(PetscDSSetFromOptions(dm->probs[s].dsIn));
6180 }
6181 PetscCall(PetscDSSetUp(dm->probs[s].ds));
6182 if (dm->probs[s].dsIn) PetscCall(PetscDSSetUp(dm->probs[s].dsIn));
6183 }
6184 }
6185 PetscFunctionReturn(PETSC_SUCCESS);
6186 }
6187
6188 /*@
6189 DMUseTensorOrder - Use a tensor product closure ordering for the default section
6190
6191 Input Parameters:
6192 + dm - The DM
6193 - tensor - Flag for tensor order
6194
6195 Level: developer
6196
6197 .seealso: `DMPlexSetClosurePermutationTensor()`, `PetscSectionResetClosurePermutation()`
6198 @*/
DMUseTensorOrder(DM dm,PetscBool tensor)6199 PetscErrorCode DMUseTensorOrder(DM dm, PetscBool tensor)
6200 {
6201 PetscInt Nf;
6202 PetscBool reorder = PETSC_TRUE, isPlex;
6203
6204 PetscFunctionBegin;
6205 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex));
6206 PetscCall(DMGetNumFields(dm, &Nf));
6207 for (PetscInt f = 0; f < Nf; ++f) {
6208 PetscObject obj;
6209 PetscClassId id;
6210
6211 PetscCall(DMGetField(dm, f, NULL, &obj));
6212 PetscCall(PetscObjectGetClassId(obj, &id));
6213 if (id == PETSCFE_CLASSID) {
6214 PetscSpace sp;
6215 PetscBool tensor;
6216
6217 PetscCall(PetscFEGetBasisSpace((PetscFE)obj, &sp));
6218 PetscCall(PetscSpacePolynomialGetTensor(sp, &tensor));
6219 reorder = reorder && tensor ? PETSC_TRUE : PETSC_FALSE;
6220 } else reorder = PETSC_FALSE;
6221 }
6222 if (tensor) {
6223 if (reorder && isPlex) PetscCall(DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, NULL));
6224 } else {
6225 PetscSection s;
6226
6227 PetscCall(DMGetLocalSection(dm, &s));
6228 if (s) PetscCall(PetscSectionResetClosurePermutation(s));
6229 }
6230 PetscFunctionReturn(PETSC_SUCCESS);
6231 }
6232
6233 /*@
6234 DMComputeExactSolution - Compute the exact solution for a given `DM`, using the `PetscDS` information.
6235
6236 Collective
6237
6238 Input Parameters:
6239 + dm - The `DM`
6240 - time - The time
6241
6242 Output Parameters:
6243 + u - The vector will be filled with exact solution values, or `NULL`
6244 - u_t - The vector will be filled with the time derivative of exact solution values, or `NULL`
6245
6246 Level: developer
6247
6248 Note:
6249 The user must call `PetscDSSetExactSolution()` before using this routine
6250
6251 .seealso: [](ch_dmbase), `DM`, `PetscDSSetExactSolution()`
6252 @*/
DMComputeExactSolution(DM dm,PetscReal time,Vec u,Vec u_t)6253 PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
6254 {
6255 PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, PetscCtx ctx);
6256 void **ectxs;
6257 Vec locu, locu_t;
6258 PetscInt Nf, Nds, s;
6259
6260 PetscFunctionBegin;
6261 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6262 if (u) {
6263 PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
6264 PetscCall(DMGetLocalVector(dm, &locu));
6265 PetscCall(VecSet(locu, 0.));
6266 }
6267 if (u_t) {
6268 PetscValidHeaderSpecific(u_t, VEC_CLASSID, 4);
6269 PetscCall(DMGetLocalVector(dm, &locu_t));
6270 PetscCall(VecSet(locu_t, 0.));
6271 }
6272 PetscCall(DMGetNumFields(dm, &Nf));
6273 PetscCall(PetscMalloc2(Nf, &exacts, Nf, &ectxs));
6274 PetscCall(DMGetNumDS(dm, &Nds));
6275 for (s = 0; s < Nds; ++s) {
6276 PetscDS ds;
6277 DMLabel label;
6278 IS fieldIS;
6279 const PetscInt *fields, id = 1;
6280 PetscInt dsNf, f;
6281
6282 PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
6283 PetscCall(PetscDSGetNumFields(ds, &dsNf));
6284 PetscCall(ISGetIndices(fieldIS, &fields));
6285 PetscCall(PetscArrayzero(exacts, Nf));
6286 PetscCall(PetscArrayzero(ectxs, Nf));
6287 if (u) {
6288 for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolution(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]]));
6289 if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu));
6290 else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu));
6291 }
6292 if (u_t) {
6293 PetscCall(PetscArrayzero(exacts, Nf));
6294 PetscCall(PetscArrayzero(ectxs, Nf));
6295 for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]]));
6296 if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu_t));
6297 else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu_t));
6298 }
6299 PetscCall(ISRestoreIndices(fieldIS, &fields));
6300 }
6301 if (u) {
6302 PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution"));
6303 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u, "exact_"));
6304 }
6305 if (u_t) {
6306 PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution Time Derivative"));
6307 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u_t, "exact_t_"));
6308 }
6309 PetscCall(PetscFree2(exacts, ectxs));
6310 if (u) {
6311 PetscCall(DMLocalToGlobalBegin(dm, locu, INSERT_ALL_VALUES, u));
6312 PetscCall(DMLocalToGlobalEnd(dm, locu, INSERT_ALL_VALUES, u));
6313 PetscCall(DMRestoreLocalVector(dm, &locu));
6314 }
6315 if (u_t) {
6316 PetscCall(DMLocalToGlobalBegin(dm, locu_t, INSERT_ALL_VALUES, u_t));
6317 PetscCall(DMLocalToGlobalEnd(dm, locu_t, INSERT_ALL_VALUES, u_t));
6318 PetscCall(DMRestoreLocalVector(dm, &locu_t));
6319 }
6320 PetscFunctionReturn(PETSC_SUCCESS);
6321 }
6322
DMTransferDS_Internal(DM dm,DMLabel label,IS fields,PetscInt minDegree,PetscInt maxDegree,PetscDS ds,PetscDS dsIn)6323 static PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscInt minDegree, PetscInt maxDegree, PetscDS ds, PetscDS dsIn)
6324 {
6325 PetscDS dsNew, dsInNew = NULL;
6326
6327 PetscFunctionBegin;
6328 PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)ds), &dsNew));
6329 PetscCall(PetscDSCopy(ds, minDegree, maxDegree, dm, dsNew));
6330 if (dsIn) {
6331 PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)dsIn), &dsInNew));
6332 PetscCall(PetscDSCopy(dsIn, minDegree, maxDegree, dm, dsInNew));
6333 }
6334 PetscCall(DMSetRegionDS(dm, label, fields, dsNew, dsInNew));
6335 PetscCall(PetscDSDestroy(&dsNew));
6336 PetscCall(PetscDSDestroy(&dsInNew));
6337 PetscFunctionReturn(PETSC_SUCCESS);
6338 }
6339
6340 /*@
6341 DMCopyDS - Copy the discrete systems for the `DM` into another `DM`
6342
6343 Collective
6344
6345 Input Parameters:
6346 + dm - The `DM`
6347 . minDegree - Minimum degree for a discretization, or `PETSC_DETERMINE` for no limit
6348 - maxDegree - Maximum degree for a discretization, or `PETSC_DETERMINE` for no limit
6349
6350 Output Parameter:
6351 . newdm - The `DM`
6352
6353 Level: advanced
6354
6355 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
6356 @*/
DMCopyDS(DM dm,PetscInt minDegree,PetscInt maxDegree,DM newdm)6357 PetscErrorCode DMCopyDS(DM dm, PetscInt minDegree, PetscInt maxDegree, DM newdm)
6358 {
6359 PetscInt Nds, s;
6360
6361 PetscFunctionBegin;
6362 if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS);
6363 PetscCall(DMGetNumDS(dm, &Nds));
6364 PetscCall(DMClearDS(newdm));
6365 for (s = 0; s < Nds; ++s) {
6366 DMLabel label;
6367 IS fields;
6368 PetscDS ds, dsIn, newds;
6369 PetscInt Nbd, bd;
6370
6371 PetscCall(DMGetRegionNumDS(dm, s, &label, &fields, &ds, &dsIn));
6372 /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
6373 PetscCall(DMTransferDS_Internal(newdm, label, fields, minDegree, maxDegree, ds, dsIn));
6374 /* Complete new labels in the new DS */
6375 PetscCall(DMGetRegionDS(newdm, label, NULL, &newds, NULL));
6376 PetscCall(PetscDSGetNumBoundary(newds, &Nbd));
6377 for (bd = 0; bd < Nbd; ++bd) {
6378 PetscWeakForm wf;
6379 DMLabel label;
6380 PetscInt field;
6381
6382 PetscCall(PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
6383 PetscCall(PetscWeakFormReplaceLabel(wf, label));
6384 }
6385 }
6386 PetscCall(DMCompleteBCLabels_Internal(newdm));
6387 PetscFunctionReturn(PETSC_SUCCESS);
6388 }
6389
6390 /*@
6391 DMCopyDisc - Copy the fields and discrete systems for the `DM` into another `DM`
6392
6393 Collective
6394
6395 Input Parameter:
6396 . dm - The `DM`
6397
6398 Output Parameter:
6399 . newdm - The `DM`
6400
6401 Level: advanced
6402
6403 Developer Note:
6404 Really ugly name, nothing in PETSc is called a `Disc` plus it is an ugly abbreviation
6405
6406 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMCopyDS()`
6407 @*/
DMCopyDisc(DM dm,DM newdm)6408 PetscErrorCode DMCopyDisc(DM dm, DM newdm)
6409 {
6410 PetscFunctionBegin;
6411 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, newdm));
6412 PetscCall(DMCopyDS(dm, PETSC_DETERMINE, PETSC_DETERMINE, newdm));
6413 PetscFunctionReturn(PETSC_SUCCESS);
6414 }
6415
6416 /*@
6417 DMGetDimension - Return the topological dimension of the `DM`
6418
6419 Not Collective
6420
6421 Input Parameter:
6422 . dm - The `DM`
6423
6424 Output Parameter:
6425 . dim - The topological dimension
6426
6427 Level: beginner
6428
6429 .seealso: [](ch_dmbase), `DM`, `DMSetDimension()`, `DMCreate()`
6430 @*/
DMGetDimension(DM dm,PetscInt * dim)6431 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
6432 {
6433 PetscFunctionBegin;
6434 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6435 PetscAssertPointer(dim, 2);
6436 *dim = dm->dim;
6437 PetscFunctionReturn(PETSC_SUCCESS);
6438 }
6439
6440 /*@
6441 DMSetDimension - Set the topological dimension of the `DM`
6442
6443 Collective
6444
6445 Input Parameters:
6446 + dm - The `DM`
6447 - dim - The topological dimension
6448
6449 Level: beginner
6450
6451 .seealso: [](ch_dmbase), `DM`, `DMGetDimension()`, `DMCreate()`
6452 @*/
DMSetDimension(DM dm,PetscInt dim)6453 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
6454 {
6455 PetscDS ds;
6456 PetscInt Nds, n;
6457
6458 PetscFunctionBegin;
6459 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6460 PetscValidLogicalCollectiveInt(dm, dim, 2);
6461 dm->dim = dim;
6462 if (dm->dim >= 0) {
6463 PetscCall(DMGetNumDS(dm, &Nds));
6464 for (n = 0; n < Nds; ++n) {
6465 PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds, NULL));
6466 if (ds->dimEmbed < 0) PetscCall(PetscDSSetCoordinateDimension(ds, dim));
6467 }
6468 }
6469 PetscFunctionReturn(PETSC_SUCCESS);
6470 }
6471
6472 /*@
6473 DMGetDimPoints - Get the half-open interval for all points of a given dimension
6474
6475 Collective
6476
6477 Input Parameters:
6478 + dm - the `DM`
6479 - dim - the dimension
6480
6481 Output Parameters:
6482 + pStart - The first point of the given dimension
6483 - pEnd - The first point following points of the given dimension
6484
6485 Level: intermediate
6486
6487 Note:
6488 The points are vertices in the Hasse diagram encoding the topology. This is explained in
6489 https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
6490 then the interval is empty.
6491
6492 .seealso: [](ch_dmbase), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
6493 @*/
DMGetDimPoints(DM dm,PetscInt dim,PetscInt * pStart,PetscInt * pEnd)6494 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
6495 {
6496 PetscInt d;
6497
6498 PetscFunctionBegin;
6499 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6500 PetscCall(DMGetDimension(dm, &d));
6501 PetscCheck((dim >= 0) && (dim <= d), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %" PetscInt_FMT, dim);
6502 PetscUseTypeMethod(dm, getdimpoints, dim, pStart, pEnd);
6503 PetscFunctionReturn(PETSC_SUCCESS);
6504 }
6505
6506 /*@
6507 DMGetOutputDM - Retrieve the `DM` associated with the layout for output
6508
6509 Collective
6510
6511 Input Parameter:
6512 . dm - The original `DM`
6513
6514 Output Parameter:
6515 . odm - The `DM` which provides the layout for output
6516
6517 Level: intermediate
6518
6519 Note:
6520 In some situations the vector obtained with `DMCreateGlobalVector()` excludes points for degrees of freedom that are associated with fixed (Dirichelet) boundary
6521 conditions since the algebraic solver does not solve for those variables. The output `DM` includes these excluded points and its global vector contains the
6522 locations for those dof so that they can be output to a file or other viewer along with the unconstrained dof.
6523
6524 .seealso: [](ch_dmbase), `DM`, `VecView()`, `DMGetGlobalSection()`, `DMCreateGlobalVector()`, `PetscSectionHasConstraints()`, `DMSetGlobalSection()`
6525 @*/
DMGetOutputDM(DM dm,DM * odm)6526 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6527 {
6528 PetscSection section;
6529 IS perm;
6530 PetscBool hasConstraints, newDM, gnewDM;
6531 PetscInt num_face_sfs = 0;
6532
6533 PetscFunctionBegin;
6534 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6535 PetscAssertPointer(odm, 2);
6536 PetscCall(DMGetLocalSection(dm, §ion));
6537 PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
6538 PetscCall(PetscSectionGetPermutation(section, &perm));
6539 PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &num_face_sfs, NULL));
6540 newDM = hasConstraints || perm || (num_face_sfs > 0) ? PETSC_TRUE : PETSC_FALSE;
6541 PetscCallMPI(MPIU_Allreduce(&newDM, &gnewDM, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
6542 if (!gnewDM) {
6543 *odm = dm;
6544 PetscFunctionReturn(PETSC_SUCCESS);
6545 }
6546 if (!dm->dmBC) {
6547 PetscSection newSection, gsection;
6548 PetscSF sf, sfNatural;
6549 PetscBool usePerm = dm->ignorePermOutput ? PETSC_FALSE : PETSC_TRUE;
6550
6551 PetscCall(DMClone(dm, &dm->dmBC));
6552 PetscCall(DMCopyDisc(dm, dm->dmBC));
6553 PetscCall(PetscSectionClone(section, &newSection));
6554 PetscCall(DMSetLocalSection(dm->dmBC, newSection));
6555 PetscCall(PetscSectionDestroy(&newSection));
6556 PetscCall(DMGetNaturalSF(dm, &sfNatural));
6557 PetscCall(DMSetNaturalSF(dm->dmBC, sfNatural));
6558 PetscCall(DMGetPointSF(dm->dmBC, &sf));
6559 PetscCall(PetscSectionCreateGlobalSection(section, sf, usePerm, PETSC_TRUE, PETSC_FALSE, &gsection));
6560 PetscCall(DMSetGlobalSection(dm->dmBC, gsection));
6561 PetscCall(PetscSectionDestroy(&gsection));
6562 }
6563 *odm = dm->dmBC;
6564 PetscFunctionReturn(PETSC_SUCCESS);
6565 }
6566
6567 /*@
6568 DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
6569
6570 Input Parameter:
6571 . dm - The original `DM`
6572
6573 Output Parameters:
6574 + num - The output sequence number
6575 - val - The output sequence value
6576
6577 Level: intermediate
6578
6579 Note:
6580 This is intended for output that should appear in sequence, for instance
6581 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6582
6583 Developer Note:
6584 The `DM` serves as a convenient place to store the current iteration value. The iteration is not
6585 not directly related to the `DM`.
6586
6587 .seealso: [](ch_dmbase), `DM`, `VecView()`
6588 @*/
DMGetOutputSequenceNumber(DM dm,PetscInt * num,PetscReal * val)6589 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6590 {
6591 PetscFunctionBegin;
6592 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6593 if (num) {
6594 PetscAssertPointer(num, 2);
6595 *num = dm->outputSequenceNum;
6596 }
6597 if (val) {
6598 PetscAssertPointer(val, 3);
6599 *val = dm->outputSequenceVal;
6600 }
6601 PetscFunctionReturn(PETSC_SUCCESS);
6602 }
6603
6604 /*@
6605 DMSetOutputSequenceNumber - Set the sequence number/value for output
6606
6607 Input Parameters:
6608 + dm - The original `DM`
6609 . num - The output sequence number
6610 - val - The output sequence value
6611
6612 Level: intermediate
6613
6614 Note:
6615 This is intended for output that should appear in sequence, for instance
6616 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6617
6618 .seealso: [](ch_dmbase), `DM`, `VecView()`
6619 @*/
DMSetOutputSequenceNumber(DM dm,PetscInt num,PetscReal val)6620 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6621 {
6622 PetscFunctionBegin;
6623 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6624 dm->outputSequenceNum = num;
6625 dm->outputSequenceVal = val;
6626 PetscFunctionReturn(PETSC_SUCCESS);
6627 }
6628
6629 /*@
6630 DMOutputSequenceLoad - Retrieve the sequence value from a `PetscViewer`
6631
6632 Input Parameters:
6633 + dm - The original `DM`
6634 . viewer - The `PetscViewer` to get it from
6635 . name - The sequence name
6636 - num - The output sequence number
6637
6638 Output Parameter:
6639 . val - The output sequence value
6640
6641 Level: intermediate
6642
6643 Note:
6644 This is intended for output that should appear in sequence, for instance
6645 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6646
6647 Developer Note:
6648 It is unclear at the user API level why a `DM` is needed as input
6649
6650 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6651 @*/
DMOutputSequenceLoad(DM dm,PetscViewer viewer,const char name[],PetscInt num,PetscReal * val)6652 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char name[], PetscInt num, PetscReal *val)
6653 {
6654 PetscBool ishdf5;
6655
6656 PetscFunctionBegin;
6657 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6658 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
6659 PetscAssertPointer(name, 3);
6660 PetscAssertPointer(val, 5);
6661 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6662 PetscCheck(ishdf5, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6663 #if defined(PETSC_HAVE_HDF5)
6664 PetscScalar value;
6665
6666 PetscCall(DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer));
6667 *val = PetscRealPart(value);
6668 #endif
6669 PetscFunctionReturn(PETSC_SUCCESS);
6670 }
6671
6672 /*@
6673 DMGetOutputSequenceLength - Retrieve the number of sequence values from a `PetscViewer`
6674
6675 Input Parameters:
6676 + dm - The original `DM`
6677 . viewer - The `PetscViewer` to get it from
6678 - name - The sequence name
6679
6680 Output Parameter:
6681 . len - The length of the output sequence
6682
6683 Level: intermediate
6684
6685 Note:
6686 This is intended for output that should appear in sequence, for instance
6687 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6688
6689 Developer Note:
6690 It is unclear at the user API level why a `DM` is needed as input
6691
6692 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6693 @*/
DMGetOutputSequenceLength(DM dm,PetscViewer viewer,const char name[],PetscInt * len)6694 PetscErrorCode DMGetOutputSequenceLength(DM dm, PetscViewer viewer, const char name[], PetscInt *len)
6695 {
6696 PetscBool ishdf5;
6697
6698 PetscFunctionBegin;
6699 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6700 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
6701 PetscAssertPointer(name, 3);
6702 PetscAssertPointer(len, 4);
6703 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6704 PetscCheck(ishdf5, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6705 #if defined(PETSC_HAVE_HDF5)
6706 PetscCall(DMSequenceGetLength_HDF5_Internal(dm, name, len, viewer));
6707 #endif
6708 PetscFunctionReturn(PETSC_SUCCESS);
6709 }
6710
6711 /*@
6712 DMGetUseNatural - Get the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6713
6714 Not Collective
6715
6716 Input Parameter:
6717 . dm - The `DM`
6718
6719 Output Parameter:
6720 . useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6721
6722 Level: beginner
6723
6724 .seealso: [](ch_dmbase), `DM`, `DMSetUseNatural()`, `DMCreate()`
6725 @*/
DMGetUseNatural(DM dm,PetscBool * useNatural)6726 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6727 {
6728 PetscFunctionBegin;
6729 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6730 PetscAssertPointer(useNatural, 2);
6731 *useNatural = dm->useNatural;
6732 PetscFunctionReturn(PETSC_SUCCESS);
6733 }
6734
6735 /*@
6736 DMSetUseNatural - Set the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6737
6738 Collective
6739
6740 Input Parameters:
6741 + dm - The `DM`
6742 - useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6743
6744 Level: beginner
6745
6746 Note:
6747 This also causes the map to be build after `DMCreateSubDM()` and `DMCreateSuperDM()`
6748
6749 .seealso: [](ch_dmbase), `DM`, `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
6750 @*/
DMSetUseNatural(DM dm,PetscBool useNatural)6751 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6752 {
6753 PetscFunctionBegin;
6754 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6755 PetscValidLogicalCollectiveBool(dm, useNatural, 2);
6756 dm->useNatural = useNatural;
6757 PetscFunctionReturn(PETSC_SUCCESS);
6758 }
6759
6760 /*@
6761 DMCreateLabel - Create a label of the given name if it does not already exist in the `DM`
6762
6763 Not Collective
6764
6765 Input Parameters:
6766 + dm - The `DM` object
6767 - name - The label name
6768
6769 Level: intermediate
6770
6771 .seealso: [](ch_dmbase), `DM`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6772 @*/
DMCreateLabel(DM dm,const char name[])6773 PetscErrorCode DMCreateLabel(DM dm, const char name[])
6774 {
6775 PetscBool flg;
6776 DMLabel label;
6777
6778 PetscFunctionBegin;
6779 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6780 PetscAssertPointer(name, 2);
6781 PetscCall(DMHasLabel(dm, name, &flg));
6782 if (!flg) {
6783 PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6784 PetscCall(DMAddLabel(dm, label));
6785 PetscCall(DMLabelDestroy(&label));
6786 }
6787 PetscFunctionReturn(PETSC_SUCCESS);
6788 }
6789
6790 /*@
6791 DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists in the `DM`, move it to this index.
6792
6793 Not Collective
6794
6795 Input Parameters:
6796 + dm - The `DM` object
6797 . l - The index for the label
6798 - name - The label name
6799
6800 Level: intermediate
6801
6802 .seealso: [](ch_dmbase), `DM`, `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6803 @*/
DMCreateLabelAtIndex(DM dm,PetscInt l,const char name[])6804 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
6805 {
6806 DMLabelLink orig, prev = NULL;
6807 DMLabel label;
6808 PetscInt Nl, m;
6809 PetscBool flg, match;
6810 const char *lname;
6811
6812 PetscFunctionBegin;
6813 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6814 PetscAssertPointer(name, 3);
6815 PetscCall(DMHasLabel(dm, name, &flg));
6816 if (!flg) {
6817 PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6818 PetscCall(DMAddLabel(dm, label));
6819 PetscCall(DMLabelDestroy(&label));
6820 }
6821 PetscCall(DMGetNumLabels(dm, &Nl));
6822 PetscCheck(l < Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", l, Nl);
6823 for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
6824 PetscCall(PetscObjectGetName((PetscObject)orig->label, &lname));
6825 PetscCall(PetscStrcmp(name, lname, &match));
6826 if (match) break;
6827 }
6828 if (m == l) PetscFunctionReturn(PETSC_SUCCESS);
6829 if (!m) dm->labels = orig->next;
6830 else prev->next = orig->next;
6831 if (!l) {
6832 orig->next = dm->labels;
6833 dm->labels = orig;
6834 } else {
6835 for (m = 0, prev = dm->labels; m < l - 1; ++m, prev = prev->next);
6836 orig->next = prev->next;
6837 prev->next = orig;
6838 }
6839 PetscFunctionReturn(PETSC_SUCCESS);
6840 }
6841
6842 /*@
6843 DMGetLabelValue - Get the value in a `DMLabel` for the given point, with -1 as the default
6844
6845 Not Collective
6846
6847 Input Parameters:
6848 + dm - The `DM` object
6849 . name - The label name
6850 - point - The mesh point
6851
6852 Output Parameter:
6853 . value - The label value for this point, or -1 if the point is not in the label
6854
6855 Level: beginner
6856
6857 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6858 @*/
DMGetLabelValue(DM dm,const char name[],PetscInt point,PetscInt * value)6859 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6860 {
6861 DMLabel label;
6862
6863 PetscFunctionBegin;
6864 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6865 PetscAssertPointer(name, 2);
6866 PetscCall(DMGetLabel(dm, name, &label));
6867 PetscCheck(label, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
6868 PetscCall(DMLabelGetValue(label, point, value));
6869 PetscFunctionReturn(PETSC_SUCCESS);
6870 }
6871
6872 /*@
6873 DMSetLabelValue - Add a point to a `DMLabel` with given value
6874
6875 Not Collective
6876
6877 Input Parameters:
6878 + dm - The `DM` object
6879 . name - The label name
6880 . point - The mesh point
6881 - value - The label value for this point
6882
6883 Output Parameter:
6884
6885 Level: beginner
6886
6887 .seealso: [](ch_dmbase), `DM`, `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
6888 @*/
DMSetLabelValue(DM dm,const char name[],PetscInt point,PetscInt value)6889 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6890 {
6891 DMLabel label;
6892
6893 PetscFunctionBegin;
6894 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6895 PetscAssertPointer(name, 2);
6896 PetscCall(DMGetLabel(dm, name, &label));
6897 if (!label) {
6898 PetscCall(DMCreateLabel(dm, name));
6899 PetscCall(DMGetLabel(dm, name, &label));
6900 }
6901 PetscCall(DMLabelSetValue(label, point, value));
6902 PetscFunctionReturn(PETSC_SUCCESS);
6903 }
6904
6905 /*@
6906 DMClearLabelValue - Remove a point from a `DMLabel` with given value
6907
6908 Not Collective
6909
6910 Input Parameters:
6911 + dm - The `DM` object
6912 . name - The label name
6913 . point - The mesh point
6914 - value - The label value for this point
6915
6916 Level: beginner
6917
6918 .seealso: [](ch_dmbase), `DM`, `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6919 @*/
DMClearLabelValue(DM dm,const char name[],PetscInt point,PetscInt value)6920 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6921 {
6922 DMLabel label;
6923
6924 PetscFunctionBegin;
6925 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6926 PetscAssertPointer(name, 2);
6927 PetscCall(DMGetLabel(dm, name, &label));
6928 if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6929 PetscCall(DMLabelClearValue(label, point, value));
6930 PetscFunctionReturn(PETSC_SUCCESS);
6931 }
6932
6933 /*@
6934 DMGetLabelSize - Get the value of `DMLabelGetNumValues()` of a `DMLabel` in the `DM`
6935
6936 Not Collective
6937
6938 Input Parameters:
6939 + dm - The `DM` object
6940 - name - The label name
6941
6942 Output Parameter:
6943 . size - The number of different integer ids, or 0 if the label does not exist
6944
6945 Level: beginner
6946
6947 Developer Note:
6948 This should be renamed to something like `DMGetLabelNumValues()` or removed.
6949
6950 .seealso: [](ch_dmbase), `DM`, `DMLabelGetNumValues()`, `DMSetLabelValue()`, `DMGetLabel()`
6951 @*/
DMGetLabelSize(DM dm,const char name[],PetscInt * size)6952 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6953 {
6954 DMLabel label;
6955
6956 PetscFunctionBegin;
6957 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6958 PetscAssertPointer(name, 2);
6959 PetscAssertPointer(size, 3);
6960 PetscCall(DMGetLabel(dm, name, &label));
6961 *size = 0;
6962 if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6963 PetscCall(DMLabelGetNumValues(label, size));
6964 PetscFunctionReturn(PETSC_SUCCESS);
6965 }
6966
6967 /*@
6968 DMGetLabelIdIS - Get the `DMLabelGetValueIS()` from a `DMLabel` in the `DM`
6969
6970 Not Collective
6971
6972 Input Parameters:
6973 + dm - The `DM` object
6974 - name - The label name
6975
6976 Output Parameter:
6977 . ids - The integer ids, or `NULL` if the label does not exist
6978
6979 Level: beginner
6980
6981 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValueIS()`, `DMGetLabelSize()`
6982 @*/
DMGetLabelIdIS(DM dm,const char name[],IS * ids)6983 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6984 {
6985 DMLabel label;
6986
6987 PetscFunctionBegin;
6988 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6989 PetscAssertPointer(name, 2);
6990 PetscAssertPointer(ids, 3);
6991 PetscCall(DMGetLabel(dm, name, &label));
6992 *ids = NULL;
6993 if (label) {
6994 PetscCall(DMLabelGetValueIS(label, ids));
6995 } else {
6996 /* returning an empty IS */
6997 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, ids));
6998 }
6999 PetscFunctionReturn(PETSC_SUCCESS);
7000 }
7001
7002 /*@
7003 DMGetStratumSize - Get the number of points in a label stratum
7004
7005 Not Collective
7006
7007 Input Parameters:
7008 + dm - The `DM` object
7009 . name - The label name of the stratum
7010 - value - The stratum value
7011
7012 Output Parameter:
7013 . size - The number of points, also called the stratum size
7014
7015 Level: beginner
7016
7017 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()`
7018 @*/
DMGetStratumSize(DM dm,const char name[],PetscInt value,PetscInt * size)7019 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7020 {
7021 DMLabel label;
7022
7023 PetscFunctionBegin;
7024 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7025 PetscAssertPointer(name, 2);
7026 PetscAssertPointer(size, 4);
7027 PetscCall(DMGetLabel(dm, name, &label));
7028 *size = 0;
7029 if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7030 PetscCall(DMLabelGetStratumSize(label, value, size));
7031 PetscFunctionReturn(PETSC_SUCCESS);
7032 }
7033
7034 /*@
7035 DMGetStratumIS - Get the points in a label stratum
7036
7037 Not Collective
7038
7039 Input Parameters:
7040 + dm - The `DM` object
7041 . name - The label name
7042 - value - The stratum value
7043
7044 Output Parameter:
7045 . points - The stratum points, or `NULL` if the label does not exist or does not have that value
7046
7047 Level: beginner
7048
7049 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumIS()`, `DMGetStratumSize()`
7050 @*/
DMGetStratumIS(DM dm,const char name[],PetscInt value,IS * points)7051 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7052 {
7053 DMLabel label;
7054
7055 PetscFunctionBegin;
7056 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7057 PetscAssertPointer(name, 2);
7058 PetscAssertPointer(points, 4);
7059 PetscCall(DMGetLabel(dm, name, &label));
7060 *points = NULL;
7061 if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7062 PetscCall(DMLabelGetStratumIS(label, value, points));
7063 PetscFunctionReturn(PETSC_SUCCESS);
7064 }
7065
7066 /*@
7067 DMSetStratumIS - Set the points in a label stratum
7068
7069 Not Collective
7070
7071 Input Parameters:
7072 + dm - The `DM` object
7073 . name - The label name
7074 . value - The stratum value
7075 - points - The stratum points
7076
7077 Level: beginner
7078
7079 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMClearLabelStratum()`, `DMLabelClearStratum()`, `DMLabelSetStratumIS()`, `DMGetStratumSize()`
7080 @*/
DMSetStratumIS(DM dm,const char name[],PetscInt value,IS points)7081 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7082 {
7083 DMLabel label;
7084
7085 PetscFunctionBegin;
7086 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7087 PetscAssertPointer(name, 2);
7088 PetscValidHeaderSpecific(points, IS_CLASSID, 4);
7089 PetscCall(DMGetLabel(dm, name, &label));
7090 if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7091 PetscCall(DMLabelSetStratumIS(label, value, points));
7092 PetscFunctionReturn(PETSC_SUCCESS);
7093 }
7094
7095 /*@
7096 DMClearLabelStratum - Remove all points from a stratum from a `DMLabel`
7097
7098 Not Collective
7099
7100 Input Parameters:
7101 + dm - The `DM` object
7102 . name - The label name
7103 - value - The label value for this point
7104
7105 Output Parameter:
7106
7107 Level: beginner
7108
7109 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
7110 @*/
DMClearLabelStratum(DM dm,const char name[],PetscInt value)7111 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7112 {
7113 DMLabel label;
7114
7115 PetscFunctionBegin;
7116 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7117 PetscAssertPointer(name, 2);
7118 PetscCall(DMGetLabel(dm, name, &label));
7119 if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7120 PetscCall(DMLabelClearStratum(label, value));
7121 PetscFunctionReturn(PETSC_SUCCESS);
7122 }
7123
7124 /*@
7125 DMGetNumLabels - Return the number of labels defined by on the `DM`
7126
7127 Not Collective
7128
7129 Input Parameter:
7130 . dm - The `DM` object
7131
7132 Output Parameter:
7133 . numLabels - the number of Labels
7134
7135 Level: intermediate
7136
7137 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabelName()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7138 @*/
DMGetNumLabels(DM dm,PetscInt * numLabels)7139 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7140 {
7141 DMLabelLink next = dm->labels;
7142 PetscInt n = 0;
7143
7144 PetscFunctionBegin;
7145 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7146 PetscAssertPointer(numLabels, 2);
7147 while (next) {
7148 ++n;
7149 next = next->next;
7150 }
7151 *numLabels = n;
7152 PetscFunctionReturn(PETSC_SUCCESS);
7153 }
7154
7155 /*@
7156 DMGetLabelName - Return the name of nth label
7157
7158 Not Collective
7159
7160 Input Parameters:
7161 + dm - The `DM` object
7162 - n - the label number
7163
7164 Output Parameter:
7165 . name - the label name
7166
7167 Level: intermediate
7168
7169 Developer Note:
7170 Some of the functions that appropriate on labels using their number have the suffix ByNum, others do not.
7171
7172 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7173 @*/
DMGetLabelName(DM dm,PetscInt n,const char * name[])7174 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char *name[])
7175 {
7176 DMLabelLink next = dm->labels;
7177 PetscInt l = 0;
7178
7179 PetscFunctionBegin;
7180 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7181 PetscAssertPointer(name, 3);
7182 while (next) {
7183 if (l == n) {
7184 PetscCall(PetscObjectGetName((PetscObject)next->label, name));
7185 PetscFunctionReturn(PETSC_SUCCESS);
7186 }
7187 ++l;
7188 next = next->next;
7189 }
7190 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
7191 }
7192
7193 /*@
7194 DMHasLabel - Determine whether the `DM` has a label of a given name
7195
7196 Not Collective
7197
7198 Input Parameters:
7199 + dm - The `DM` object
7200 - name - The label name
7201
7202 Output Parameter:
7203 . hasLabel - `PETSC_TRUE` if the label is present
7204
7205 Level: intermediate
7206
7207 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabel()`, `DMGetLabelByNum()`, `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7208 @*/
DMHasLabel(DM dm,const char name[],PetscBool * hasLabel)7209 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7210 {
7211 DMLabelLink next = dm->labels;
7212 const char *lname;
7213
7214 PetscFunctionBegin;
7215 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7216 PetscAssertPointer(name, 2);
7217 PetscAssertPointer(hasLabel, 3);
7218 *hasLabel = PETSC_FALSE;
7219 while (next) {
7220 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7221 PetscCall(PetscStrcmp(name, lname, hasLabel));
7222 if (*hasLabel) break;
7223 next = next->next;
7224 }
7225 PetscFunctionReturn(PETSC_SUCCESS);
7226 }
7227
7228 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown
7229 /*@
7230 DMGetLabel - Return the label of a given name, or `NULL`, from a `DM`
7231
7232 Not Collective
7233
7234 Input Parameters:
7235 + dm - The `DM` object
7236 - name - The label name
7237
7238 Output Parameter:
7239 . label - The `DMLabel`, or `NULL` if the label is absent
7240
7241 Default labels in a `DMPLEX`:
7242 + "depth" - Holds the depth (co-dimension) of each mesh point
7243 . "celltype" - Holds the topological type of each cell
7244 . "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7245 . "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII
7246 . "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII
7247 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7248
7249 Level: intermediate
7250
7251 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMHasLabel()`, `DMGetLabelByNum()`, `DMAddLabel()`, `DMCreateLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
7252 @*/
DMGetLabel(DM dm,const char name[],DMLabel * label)7253 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7254 {
7255 DMLabelLink next = dm->labels;
7256 PetscBool hasLabel;
7257 const char *lname;
7258
7259 PetscFunctionBegin;
7260 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7261 PetscAssertPointer(name, 2);
7262 PetscAssertPointer(label, 3);
7263 *label = NULL;
7264 while (next) {
7265 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7266 PetscCall(PetscStrcmp(name, lname, &hasLabel));
7267 if (hasLabel) {
7268 *label = next->label;
7269 break;
7270 }
7271 next = next->next;
7272 }
7273 PetscFunctionReturn(PETSC_SUCCESS);
7274 }
7275
7276 /*@
7277 DMGetLabelByNum - Return the nth label on a `DM`
7278
7279 Not Collective
7280
7281 Input Parameters:
7282 + dm - The `DM` object
7283 - n - the label number
7284
7285 Output Parameter:
7286 . label - the label
7287
7288 Level: intermediate
7289
7290 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7291 @*/
DMGetLabelByNum(DM dm,PetscInt n,DMLabel * label)7292 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7293 {
7294 DMLabelLink next = dm->labels;
7295 PetscInt l = 0;
7296
7297 PetscFunctionBegin;
7298 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7299 PetscAssertPointer(label, 3);
7300 while (next) {
7301 if (l == n) {
7302 *label = next->label;
7303 PetscFunctionReturn(PETSC_SUCCESS);
7304 }
7305 ++l;
7306 next = next->next;
7307 }
7308 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
7309 }
7310
7311 /*@
7312 DMAddLabel - Add the label to this `DM`
7313
7314 Not Collective
7315
7316 Input Parameters:
7317 + dm - The `DM` object
7318 - label - The `DMLabel`
7319
7320 Level: developer
7321
7322 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7323 @*/
DMAddLabel(DM dm,DMLabel label)7324 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7325 {
7326 DMLabelLink l, *p, tmpLabel;
7327 PetscBool hasLabel;
7328 const char *lname;
7329 PetscBool flg;
7330
7331 PetscFunctionBegin;
7332 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7333 PetscCall(PetscObjectGetName((PetscObject)label, &lname));
7334 PetscCall(DMHasLabel(dm, lname, &hasLabel));
7335 PetscCheck(!hasLabel, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7336 PetscCall(PetscCalloc1(1, &tmpLabel));
7337 tmpLabel->label = label;
7338 tmpLabel->output = PETSC_TRUE;
7339 for (p = &dm->labels; (l = *p); p = &l->next) { }
7340 *p = tmpLabel;
7341 PetscCall(PetscObjectReference((PetscObject)label));
7342 PetscCall(PetscStrcmp(lname, "depth", &flg));
7343 if (flg) dm->depthLabel = label;
7344 PetscCall(PetscStrcmp(lname, "celltype", &flg));
7345 if (flg) dm->celltypeLabel = label;
7346 PetscFunctionReturn(PETSC_SUCCESS);
7347 }
7348
7349 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown
7350 /*@
7351 DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present
7352
7353 Not Collective
7354
7355 Input Parameters:
7356 + dm - The `DM` object
7357 - label - The `DMLabel`, having the same name, to substitute
7358
7359 Default labels in a `DMPLEX`:
7360 + "depth" - Holds the depth (co-dimension) of each mesh point
7361 . "celltype" - Holds the topological type of each cell
7362 . "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7363 . "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII
7364 . "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII
7365 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7366
7367 Level: intermediate
7368
7369 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
7370 @*/
DMSetLabel(DM dm,DMLabel label)7371 PetscErrorCode DMSetLabel(DM dm, DMLabel label)
7372 {
7373 DMLabelLink next = dm->labels;
7374 PetscBool hasLabel, flg;
7375 const char *name, *lname;
7376
7377 PetscFunctionBegin;
7378 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7379 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
7380 PetscCall(PetscObjectGetName((PetscObject)label, &name));
7381 while (next) {
7382 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7383 PetscCall(PetscStrcmp(name, lname, &hasLabel));
7384 if (hasLabel) {
7385 PetscCall(PetscObjectReference((PetscObject)label));
7386 PetscCall(PetscStrcmp(lname, "depth", &flg));
7387 if (flg) dm->depthLabel = label;
7388 PetscCall(PetscStrcmp(lname, "celltype", &flg));
7389 if (flg) dm->celltypeLabel = label;
7390 PetscCall(DMLabelDestroy(&next->label));
7391 next->label = label;
7392 break;
7393 }
7394 next = next->next;
7395 }
7396 PetscFunctionReturn(PETSC_SUCCESS);
7397 }
7398
7399 /*@
7400 DMRemoveLabel - Remove the label given by name from this `DM`
7401
7402 Not Collective
7403
7404 Input Parameters:
7405 + dm - The `DM` object
7406 - name - The label name
7407
7408 Output Parameter:
7409 . label - The `DMLabel`, or `NULL` if the label is absent. Pass in `NULL` to call `DMLabelDestroy()` on the label, otherwise the
7410 caller is responsible for calling `DMLabelDestroy()`.
7411
7412 Level: developer
7413
7414 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()`
7415 @*/
DMRemoveLabel(DM dm,const char name[],DMLabel * label)7416 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7417 {
7418 DMLabelLink link, *pnext;
7419 PetscBool hasLabel;
7420 const char *lname;
7421
7422 PetscFunctionBegin;
7423 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7424 PetscAssertPointer(name, 2);
7425 if (label) {
7426 PetscAssertPointer(label, 3);
7427 *label = NULL;
7428 }
7429 for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7430 PetscCall(PetscObjectGetName((PetscObject)link->label, &lname));
7431 PetscCall(PetscStrcmp(name, lname, &hasLabel));
7432 if (hasLabel) {
7433 *pnext = link->next; /* Remove from list */
7434 PetscCall(PetscStrcmp(name, "depth", &hasLabel));
7435 if (hasLabel) dm->depthLabel = NULL;
7436 PetscCall(PetscStrcmp(name, "celltype", &hasLabel));
7437 if (hasLabel) dm->celltypeLabel = NULL;
7438 if (label) *label = link->label;
7439 else PetscCall(DMLabelDestroy(&link->label));
7440 PetscCall(PetscFree(link));
7441 break;
7442 }
7443 }
7444 PetscFunctionReturn(PETSC_SUCCESS);
7445 }
7446
7447 /*@
7448 DMRemoveLabelBySelf - Remove the label from this `DM`
7449
7450 Not Collective
7451
7452 Input Parameters:
7453 + dm - The `DM` object
7454 . label - The `DMLabel` to be removed from the `DM`
7455 - failNotFound - Should it fail if the label is not found in the `DM`?
7456
7457 Level: developer
7458
7459 Note:
7460 Only exactly the same instance is removed if found, name match is ignored.
7461 If the `DM` has an exclusive reference to the label, the label gets destroyed and
7462 *label nullified.
7463
7464 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()`
7465 @*/
DMRemoveLabelBySelf(DM dm,DMLabel * label,PetscBool failNotFound)7466 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7467 {
7468 DMLabelLink link, *pnext;
7469 PetscBool hasLabel = PETSC_FALSE;
7470
7471 PetscFunctionBegin;
7472 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7473 PetscAssertPointer(label, 2);
7474 if (!*label && !failNotFound) PetscFunctionReturn(PETSC_SUCCESS);
7475 PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2);
7476 PetscValidLogicalCollectiveBool(dm, failNotFound, 3);
7477 for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7478 if (*label == link->label) {
7479 hasLabel = PETSC_TRUE;
7480 *pnext = link->next; /* Remove from list */
7481 if (*label == dm->depthLabel) dm->depthLabel = NULL;
7482 if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7483 if (((PetscObject)link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7484 PetscCall(DMLabelDestroy(&link->label));
7485 PetscCall(PetscFree(link));
7486 break;
7487 }
7488 }
7489 PetscCheck(hasLabel || !failNotFound, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7490 PetscFunctionReturn(PETSC_SUCCESS);
7491 }
7492
7493 /*@
7494 DMGetLabelOutput - Get the output flag for a given label
7495
7496 Not Collective
7497
7498 Input Parameters:
7499 + dm - The `DM` object
7500 - name - The label name
7501
7502 Output Parameter:
7503 . output - The flag for output
7504
7505 Level: developer
7506
7507 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7508 @*/
DMGetLabelOutput(DM dm,const char name[],PetscBool * output)7509 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7510 {
7511 DMLabelLink next = dm->labels;
7512 const char *lname;
7513
7514 PetscFunctionBegin;
7515 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7516 PetscAssertPointer(name, 2);
7517 PetscAssertPointer(output, 3);
7518 while (next) {
7519 PetscBool flg;
7520
7521 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7522 PetscCall(PetscStrcmp(name, lname, &flg));
7523 if (flg) {
7524 *output = next->output;
7525 PetscFunctionReturn(PETSC_SUCCESS);
7526 }
7527 next = next->next;
7528 }
7529 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7530 }
7531
7532 /*@
7533 DMSetLabelOutput - Set if a given label should be saved to a `PetscViewer` in calls to `DMView()`
7534
7535 Not Collective
7536
7537 Input Parameters:
7538 + dm - The `DM` object
7539 . name - The label name
7540 - output - `PETSC_TRUE` to save the label to the viewer
7541
7542 Level: developer
7543
7544 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetOutputFlag()`, `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7545 @*/
DMSetLabelOutput(DM dm,const char name[],PetscBool output)7546 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7547 {
7548 DMLabelLink next = dm->labels;
7549 const char *lname;
7550
7551 PetscFunctionBegin;
7552 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7553 PetscAssertPointer(name, 2);
7554 while (next) {
7555 PetscBool flg;
7556
7557 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7558 PetscCall(PetscStrcmp(name, lname, &flg));
7559 if (flg) {
7560 next->output = output;
7561 PetscFunctionReturn(PETSC_SUCCESS);
7562 }
7563 next = next->next;
7564 }
7565 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7566 }
7567
7568 /*@
7569 DMCopyLabels - Copy labels from one `DM` mesh to another `DM` with a superset of the points
7570
7571 Collective
7572
7573 Input Parameters:
7574 + dmA - The `DM` object with initial labels
7575 . dmB - The `DM` object to which labels are copied
7576 . mode - Copy labels by pointers (`PETSC_OWN_POINTER`) or duplicate them (`PETSC_COPY_VALUES`)
7577 . all - Copy all labels including "depth", "dim", and "celltype" (`PETSC_TRUE`) which are otherwise ignored (`PETSC_FALSE`)
7578 - emode - How to behave when a `DMLabel` in the source and destination `DM`s with the same name is encountered (see `DMCopyLabelsMode`)
7579
7580 Level: intermediate
7581
7582 Note:
7583 This is typically used when interpolating or otherwise adding to a mesh, or testing.
7584
7585 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`
7586 @*/
DMCopyLabels(DM dmA,DM dmB,PetscCopyMode mode,PetscBool all,DMCopyLabelsMode emode)7587 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode)
7588 {
7589 DMLabel label, labelNew, labelOld;
7590 const char *name;
7591 PetscBool flg;
7592 DMLabelLink link;
7593
7594 PetscFunctionBegin;
7595 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
7596 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
7597 PetscValidLogicalCollectiveEnum(dmA, mode, 3);
7598 PetscValidLogicalCollectiveBool(dmA, all, 4);
7599 PetscCheck(mode != PETSC_USE_POINTER, PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7600 if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS);
7601 for (link = dmA->labels; link; link = link->next) {
7602 label = link->label;
7603 PetscCall(PetscObjectGetName((PetscObject)label, &name));
7604 if (!all) {
7605 PetscCall(PetscStrcmp(name, "depth", &flg));
7606 if (flg) continue;
7607 PetscCall(PetscStrcmp(name, "dim", &flg));
7608 if (flg) continue;
7609 PetscCall(PetscStrcmp(name, "celltype", &flg));
7610 if (flg) continue;
7611 }
7612 PetscCall(DMGetLabel(dmB, name, &labelOld));
7613 if (labelOld) {
7614 switch (emode) {
7615 case DM_COPY_LABELS_KEEP:
7616 continue;
7617 case DM_COPY_LABELS_REPLACE:
7618 PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE));
7619 break;
7620 case DM_COPY_LABELS_FAIL:
7621 SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name);
7622 default:
7623 SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode);
7624 }
7625 }
7626 if (mode == PETSC_COPY_VALUES) {
7627 PetscCall(DMLabelDuplicate(label, &labelNew));
7628 } else {
7629 labelNew = label;
7630 }
7631 PetscCall(DMAddLabel(dmB, labelNew));
7632 if (mode == PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew));
7633 }
7634 PetscFunctionReturn(PETSC_SUCCESS);
7635 }
7636
7637 /*@C
7638 DMCompareLabels - Compare labels between two `DM` objects
7639
7640 Collective; No Fortran Support
7641
7642 Input Parameters:
7643 + dm0 - First `DM` object
7644 - dm1 - Second `DM` object
7645
7646 Output Parameters:
7647 + equal - (Optional) Flag whether labels of `dm0` and `dm1` are the same
7648 - message - (Optional) Message describing the difference, or `NULL` if there is no difference
7649
7650 Level: intermediate
7651
7652 Notes:
7653 The output flag equal will be the same on all processes.
7654
7655 If equal is passed as `NULL` and difference is found, an error is thrown on all processes.
7656
7657 Make sure to pass equal is `NULL` on all processes or none of them.
7658
7659 The output message is set independently on each rank.
7660
7661 message must be freed with `PetscFree()`
7662
7663 If message is passed as `NULL` and a difference is found, the difference description is printed to `stderr` in synchronized manner.
7664
7665 Make sure to pass message as `NULL` on all processes or no processes.
7666
7667 Labels are matched by name. If the number of labels and their names are equal,
7668 `DMLabelCompare()` is used to compare each pair of labels with the same name.
7669
7670 Developer Note:
7671 Cannot automatically generate the Fortran stub because `message` must be freed with `PetscFree()`
7672
7673 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()`
7674 @*/
DMCompareLabels(DM dm0,DM dm1,PetscBool * equal,char * message[])7675 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char *message[]) PeNS
7676 {
7677 PetscInt n, i;
7678 char msg[PETSC_MAX_PATH_LEN] = "";
7679 PetscBool eq;
7680 MPI_Comm comm;
7681 PetscMPIInt rank;
7682
7683 PetscFunctionBegin;
7684 PetscValidHeaderSpecific(dm0, DM_CLASSID, 1);
7685 PetscValidHeaderSpecific(dm1, DM_CLASSID, 2);
7686 PetscCheckSameComm(dm0, 1, dm1, 2);
7687 if (equal) PetscAssertPointer(equal, 3);
7688 if (message) PetscAssertPointer(message, 4);
7689 PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm));
7690 PetscCallMPI(MPI_Comm_rank(comm, &rank));
7691 {
7692 PetscInt n1;
7693
7694 PetscCall(DMGetNumLabels(dm0, &n));
7695 PetscCall(DMGetNumLabels(dm1, &n1));
7696 eq = (PetscBool)(n == n1);
7697 if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1));
7698 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPI_C_BOOL, MPI_LAND, comm));
7699 if (!eq) goto finish;
7700 }
7701 for (i = 0; i < n; i++) {
7702 DMLabel l0, l1;
7703 const char *name;
7704 char *msgInner;
7705
7706 /* Ignore label order */
7707 PetscCall(DMGetLabelByNum(dm0, i, &l0));
7708 PetscCall(PetscObjectGetName((PetscObject)l0, &name));
7709 PetscCall(DMGetLabel(dm1, name, &l1));
7710 if (!l1) {
7711 PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i));
7712 eq = PETSC_FALSE;
7713 break;
7714 }
7715 PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner));
7716 PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg)));
7717 PetscCall(PetscFree(msgInner));
7718 if (!eq) break;
7719 }
7720 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPI_C_BOOL, MPI_LAND, comm));
7721 finish:
7722 /* If message output arg not set, print to stderr */
7723 if (message) {
7724 *message = NULL;
7725 if (msg[0]) PetscCall(PetscStrallocpy(msg, message));
7726 } else {
7727 if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg));
7728 PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR));
7729 }
7730 /* If same output arg not ser and labels are not equal, throw error */
7731 if (equal) *equal = eq;
7732 else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1");
7733 PetscFunctionReturn(PETSC_SUCCESS);
7734 }
7735
DMSetLabelValue_Fast(DM dm,DMLabel * label,const char name[],PetscInt point,PetscInt value)7736 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
7737 {
7738 PetscFunctionBegin;
7739 PetscAssertPointer(label, 2);
7740 if (!*label) {
7741 PetscCall(DMCreateLabel(dm, name));
7742 PetscCall(DMGetLabel(dm, name, label));
7743 }
7744 PetscCall(DMLabelSetValue(*label, point, value));
7745 PetscFunctionReturn(PETSC_SUCCESS);
7746 }
7747
7748 /*
7749 Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
7750 like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
7751 (label, id) pair in the DM.
7752
7753 However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
7754 each label.
7755 */
DMUniversalLabelCreate(DM dm,DMUniversalLabel * universal)7756 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
7757 {
7758 DMUniversalLabel ul;
7759 PetscBool *active;
7760 PetscInt pStart, pEnd, p, Nl, l, m;
7761
7762 PetscFunctionBegin;
7763 PetscCall(PetscMalloc1(1, &ul));
7764 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label));
7765 PetscCall(DMGetNumLabels(dm, &Nl));
7766 PetscCall(PetscCalloc1(Nl, &active));
7767 ul->Nl = 0;
7768 for (l = 0; l < Nl; ++l) {
7769 PetscBool isdepth, iscelltype;
7770 const char *name;
7771
7772 PetscCall(DMGetLabelName(dm, l, &name));
7773 PetscCall(PetscStrncmp(name, "depth", 6, &isdepth));
7774 PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype));
7775 active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
7776 if (active[l]) ++ul->Nl;
7777 }
7778 PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks));
7779 ul->Nv = 0;
7780 for (l = 0, m = 0; l < Nl; ++l) {
7781 DMLabel label;
7782 PetscInt nv;
7783 const char *name;
7784
7785 if (!active[l]) continue;
7786 PetscCall(DMGetLabelName(dm, l, &name));
7787 PetscCall(DMGetLabelByNum(dm, l, &label));
7788 PetscCall(DMLabelGetNumValues(label, &nv));
7789 PetscCall(PetscStrallocpy(name, &ul->names[m]));
7790 ul->indices[m] = l;
7791 ul->Nv += nv;
7792 ul->offsets[m + 1] = nv;
7793 ul->bits[m + 1] = PetscCeilReal(PetscLog2Real(nv + 1));
7794 ++m;
7795 }
7796 for (l = 1; l <= ul->Nl; ++l) {
7797 ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l];
7798 ul->bits[l] = ul->bits[l - 1] + ul->bits[l];
7799 }
7800 for (l = 0; l < ul->Nl; ++l) {
7801 PetscInt b;
7802
7803 ul->masks[l] = 0;
7804 for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b;
7805 }
7806 PetscCall(PetscMalloc1(ul->Nv, &ul->values));
7807 for (l = 0, m = 0; l < Nl; ++l) {
7808 DMLabel label;
7809 IS valueIS;
7810 const PetscInt *varr;
7811 PetscInt nv, v;
7812
7813 if (!active[l]) continue;
7814 PetscCall(DMGetLabelByNum(dm, l, &label));
7815 PetscCall(DMLabelGetNumValues(label, &nv));
7816 PetscCall(DMLabelGetValueIS(label, &valueIS));
7817 PetscCall(ISGetIndices(valueIS, &varr));
7818 for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v];
7819 PetscCall(ISRestoreIndices(valueIS, &varr));
7820 PetscCall(ISDestroy(&valueIS));
7821 PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]]));
7822 ++m;
7823 }
7824 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
7825 for (p = pStart; p < pEnd; ++p) {
7826 PetscInt uval = 0;
7827 PetscBool marked = PETSC_FALSE;
7828
7829 for (l = 0, m = 0; l < Nl; ++l) {
7830 DMLabel label;
7831 PetscInt val, defval, loc, nv;
7832
7833 if (!active[l]) continue;
7834 PetscCall(DMGetLabelByNum(dm, l, &label));
7835 PetscCall(DMLabelGetValue(label, p, &val));
7836 PetscCall(DMLabelGetDefaultValue(label, &defval));
7837 if (val == defval) {
7838 ++m;
7839 continue;
7840 }
7841 nv = ul->offsets[m + 1] - ul->offsets[m];
7842 marked = PETSC_TRUE;
7843 PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc));
7844 PetscCheck(loc >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %" PetscInt_FMT " not found in compression array", val);
7845 uval += (loc + 1) << ul->bits[m];
7846 ++m;
7847 }
7848 if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval));
7849 }
7850 PetscCall(PetscFree(active));
7851 *universal = ul;
7852 PetscFunctionReturn(PETSC_SUCCESS);
7853 }
7854
DMUniversalLabelDestroy(DMUniversalLabel * universal)7855 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
7856 {
7857 PetscInt l;
7858
7859 PetscFunctionBegin;
7860 for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l]));
7861 PetscCall(DMLabelDestroy(&(*universal)->label));
7862 PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks));
7863 PetscCall(PetscFree((*universal)->values));
7864 PetscCall(PetscFree(*universal));
7865 *universal = NULL;
7866 PetscFunctionReturn(PETSC_SUCCESS);
7867 }
7868
DMUniversalLabelGetLabel(DMUniversalLabel ul,DMLabel * ulabel)7869 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
7870 {
7871 PetscFunctionBegin;
7872 PetscAssertPointer(ulabel, 2);
7873 *ulabel = ul->label;
7874 PetscFunctionReturn(PETSC_SUCCESS);
7875 }
7876
DMUniversalLabelCreateLabels(DMUniversalLabel ul,PetscBool preserveOrder,DM dm)7877 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
7878 {
7879 PetscInt Nl = ul->Nl, l;
7880
7881 PetscFunctionBegin;
7882 PetscValidHeaderSpecific(dm, DM_CLASSID, 3);
7883 for (l = 0; l < Nl; ++l) {
7884 if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]));
7885 else PetscCall(DMCreateLabel(dm, ul->names[l]));
7886 }
7887 if (preserveOrder) {
7888 for (l = 0; l < ul->Nl; ++l) {
7889 const char *name;
7890 PetscBool match;
7891
7892 PetscCall(DMGetLabelName(dm, ul->indices[l], &name));
7893 PetscCall(PetscStrcmp(name, ul->names[l], &match));
7894 PetscCheck(match, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %" PetscInt_FMT " name %s does not match new name %s", l, name, ul->names[l]);
7895 }
7896 }
7897 PetscFunctionReturn(PETSC_SUCCESS);
7898 }
7899
DMUniversalLabelSetLabelValue(DMUniversalLabel ul,DM dm,PetscBool useIndex,PetscInt p,PetscInt value)7900 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
7901 {
7902 PetscInt l;
7903
7904 PetscFunctionBegin;
7905 for (l = 0; l < ul->Nl; ++l) {
7906 DMLabel label;
7907 PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];
7908
7909 if (lval) {
7910 if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label));
7911 else PetscCall(DMGetLabel(dm, ul->names[l], &label));
7912 PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1]));
7913 }
7914 }
7915 PetscFunctionReturn(PETSC_SUCCESS);
7916 }
7917
7918 /*@
7919 DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement
7920
7921 Not Collective
7922
7923 Input Parameter:
7924 . dm - The `DM` object
7925
7926 Output Parameter:
7927 . cdm - The coarse `DM`
7928
7929 Level: intermediate
7930
7931 .seealso: [](ch_dmbase), `DM`, `DMSetCoarseDM()`, `DMCoarsen()`
7932 @*/
DMGetCoarseDM(DM dm,DM * cdm)7933 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7934 {
7935 PetscFunctionBegin;
7936 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7937 PetscAssertPointer(cdm, 2);
7938 *cdm = dm->coarseMesh;
7939 PetscFunctionReturn(PETSC_SUCCESS);
7940 }
7941
7942 /*@
7943 DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement
7944
7945 Input Parameters:
7946 + dm - The `DM` object
7947 - cdm - The coarse `DM`
7948
7949 Level: intermediate
7950
7951 Note:
7952 Normally this is set automatically by `DMRefine()`
7953
7954 .seealso: [](ch_dmbase), `DM`, `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()`
7955 @*/
DMSetCoarseDM(DM dm,DM cdm)7956 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7957 {
7958 PetscFunctionBegin;
7959 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7960 if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
7961 if (dm == cdm) cdm = NULL;
7962 PetscCall(PetscObjectReference((PetscObject)cdm));
7963 PetscCall(DMDestroy(&dm->coarseMesh));
7964 dm->coarseMesh = cdm;
7965 PetscFunctionReturn(PETSC_SUCCESS);
7966 }
7967
7968 /*@
7969 DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening
7970
7971 Input Parameter:
7972 . dm - The `DM` object
7973
7974 Output Parameter:
7975 . fdm - The fine `DM`
7976
7977 Level: intermediate
7978
7979 .seealso: [](ch_dmbase), `DM`, `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()`
7980 @*/
DMGetFineDM(DM dm,DM * fdm)7981 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7982 {
7983 PetscFunctionBegin;
7984 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7985 PetscAssertPointer(fdm, 2);
7986 *fdm = dm->fineMesh;
7987 PetscFunctionReturn(PETSC_SUCCESS);
7988 }
7989
7990 /*@
7991 DMSetFineDM - Set the fine mesh from which this was obtained by coarsening
7992
7993 Input Parameters:
7994 + dm - The `DM` object
7995 - fdm - The fine `DM`
7996
7997 Level: developer
7998
7999 Note:
8000 Normally this is set automatically by `DMCoarsen()`
8001
8002 .seealso: [](ch_dmbase), `DM`, `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()`
8003 @*/
DMSetFineDM(DM dm,DM fdm)8004 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
8005 {
8006 PetscFunctionBegin;
8007 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8008 if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
8009 if (dm == fdm) fdm = NULL;
8010 PetscCall(PetscObjectReference((PetscObject)fdm));
8011 PetscCall(DMDestroy(&dm->fineMesh));
8012 dm->fineMesh = fdm;
8013 PetscFunctionReturn(PETSC_SUCCESS);
8014 }
8015
8016 /*@C
8017 DMAddBoundary - Add a boundary condition, for a single field, to a model represented by a `DM`
8018
8019 Collective
8020
8021 Input Parameters:
8022 + dm - The `DM`, with a `PetscDS` that matches the problem being constrained
8023 . type - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
8024 . name - The BC name
8025 . label - The label defining constrained points
8026 . Nv - The number of `DMLabel` values for constrained points
8027 . values - An array of values for constrained points
8028 . field - The field to constrain
8029 . Nc - The number of constrained field components (0 will constrain all components)
8030 . comps - An array of constrained component numbers
8031 . bcFunc - A pointwise function giving boundary values
8032 . bcFunc_t - A pointwise function giving the time derivative of the boundary values, or `NULL`
8033 - ctx - An optional user context for bcFunc
8034
8035 Output Parameter:
8036 . bd - (Optional) Boundary number
8037
8038 Options Database Keys:
8039 + -bc_<boundary name> <num> - Overrides the boundary ids
8040 - -bc_<boundary name>_comp <num> - Overrides the boundary components
8041
8042 Level: intermediate
8043
8044 Notes:
8045 If the `DM` is of type `DMPLEX` and the field is of type `PetscFE`, then this function completes the label using `DMPlexLabelComplete()`.
8046
8047 Both bcFunc and bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is\:
8048 .vb
8049 void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
8050 .ve
8051
8052 If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is\:
8053
8054 .vb
8055 void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8056 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8057 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8058 PetscReal time, const PetscReal x[], PetscScalar bcval[])
8059 .ve
8060 + dim - the spatial dimension
8061 . Nf - the number of fields
8062 . uOff - the offset into u[] and u_t[] for each field
8063 . uOff_x - the offset into u_x[] for each field
8064 . u - each field evaluated at the current point
8065 . u_t - the time derivative of each field evaluated at the current point
8066 . u_x - the gradient of each field evaluated at the current point
8067 . aOff - the offset into a[] and a_t[] for each auxiliary field
8068 . aOff_x - the offset into a_x[] for each auxiliary field
8069 . a - each auxiliary field evaluated at the current point
8070 . a_t - the time derivative of each auxiliary field evaluated at the current point
8071 . a_x - the gradient of auxiliary each field evaluated at the current point
8072 . t - current time
8073 . x - coordinates of the current point
8074 . numConstants - number of constant parameters
8075 . constants - constant parameters
8076 - bcval - output values at the current point
8077
8078 .seealso: [](ch_dmbase), `DM`, `DSGetBoundary()`, `PetscDSAddBoundary()`
8079 @*/
DMAddBoundary(DM dm,DMBoundaryConditionType type,const char name[],DMLabel label,PetscInt Nv,const PetscInt values[],PetscInt field,PetscInt Nc,const PetscInt comps[],PetscVoidFn * bcFunc,PetscVoidFn * bcFunc_t,PetscCtx ctx,PetscInt * bd)8080 PetscErrorCode DMAddBoundary(DM dm, DMBoundaryConditionType type, const char name[], DMLabel label, PetscInt Nv, const PetscInt values[], PetscInt field, PetscInt Nc, const PetscInt comps[], PetscVoidFn *bcFunc, PetscVoidFn *bcFunc_t, PetscCtx ctx, PetscInt *bd)
8081 {
8082 PetscDS ds;
8083
8084 PetscFunctionBegin;
8085 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8086 PetscValidLogicalCollectiveEnum(dm, type, 2);
8087 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4);
8088 PetscValidLogicalCollectiveInt(dm, Nv, 5);
8089 PetscValidLogicalCollectiveInt(dm, field, 7);
8090 PetscValidLogicalCollectiveInt(dm, Nc, 8);
8091 PetscCheck(!dm->localSection, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot add boundary to DM after creating local section");
8092 PetscCall(DMGetDS(dm, &ds));
8093 /* Complete label */
8094 if (label) {
8095 PetscObject obj;
8096 PetscClassId id;
8097
8098 PetscCall(DMGetField(dm, field, NULL, &obj));
8099 PetscCall(PetscObjectGetClassId(obj, &id));
8100 if (id == PETSCFE_CLASSID) {
8101 DM plex;
8102
8103 PetscCall(DMConvert(dm, DMPLEX, &plex));
8104 if (plex) PetscCall(DMPlexLabelComplete(plex, label));
8105 PetscCall(DMDestroy(&plex));
8106 }
8107 }
8108 PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd));
8109 PetscFunctionReturn(PETSC_SUCCESS);
8110 }
8111
8112 /* TODO Remove this since now the structures are the same */
DMPopulateBoundary(DM dm)8113 static PetscErrorCode DMPopulateBoundary(DM dm)
8114 {
8115 PetscDS ds;
8116 DMBoundary *lastnext;
8117 DSBoundary dsbound;
8118
8119 PetscFunctionBegin;
8120 PetscCall(DMGetDS(dm, &ds));
8121 dsbound = ds->boundary;
8122 if (dm->boundary) {
8123 DMBoundary next = dm->boundary;
8124
8125 /* quick check to see if the PetscDS has changed */
8126 if (next->dsboundary == dsbound) PetscFunctionReturn(PETSC_SUCCESS);
8127 /* the PetscDS has changed: tear down and rebuild */
8128 while (next) {
8129 DMBoundary b = next;
8130
8131 next = b->next;
8132 PetscCall(PetscFree(b));
8133 }
8134 dm->boundary = NULL;
8135 }
8136
8137 lastnext = &dm->boundary;
8138 while (dsbound) {
8139 DMBoundary dmbound;
8140
8141 PetscCall(PetscNew(&dmbound));
8142 dmbound->dsboundary = dsbound;
8143 dmbound->label = dsbound->label;
8144 /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8145 *lastnext = dmbound;
8146 lastnext = &dmbound->next;
8147 dsbound = dsbound->next;
8148 }
8149 PetscFunctionReturn(PETSC_SUCCESS);
8150 }
8151
8152 /* TODO: missing manual page */
DMIsBoundaryPoint(DM dm,PetscInt point,PetscBool * isBd)8153 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8154 {
8155 DMBoundary b;
8156
8157 PetscFunctionBegin;
8158 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8159 PetscAssertPointer(isBd, 3);
8160 *isBd = PETSC_FALSE;
8161 PetscCall(DMPopulateBoundary(dm));
8162 b = dm->boundary;
8163 while (b && !*isBd) {
8164 DMLabel label = b->label;
8165 DSBoundary dsb = b->dsboundary;
8166 PetscInt i;
8167
8168 if (label) {
8169 for (i = 0; i < dsb->Nv && !*isBd; ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd));
8170 }
8171 b = b->next;
8172 }
8173 PetscFunctionReturn(PETSC_SUCCESS);
8174 }
8175
8176 /*@
8177 DMHasBound - Determine whether a bound condition was specified
8178
8179 Logically collective
8180
8181 Input Parameter:
8182 . dm - The `DM`, with a `PetscDS` that matches the problem being constrained
8183
8184 Output Parameter:
8185 . hasBound - Flag indicating if a bound condition was specified
8186
8187 Level: intermediate
8188
8189 .seealso: [](ch_dmbase), `DM`, `DSAddBoundary()`, `PetscDSAddBoundary()`
8190 @*/
DMHasBound(DM dm,PetscBool * hasBound)8191 PetscErrorCode DMHasBound(DM dm, PetscBool *hasBound)
8192 {
8193 PetscDS ds;
8194 PetscInt Nf, numBd;
8195
8196 PetscFunctionBegin;
8197 *hasBound = PETSC_FALSE;
8198 PetscCall(DMGetDS(dm, &ds));
8199 PetscCall(PetscDSGetNumFields(ds, &Nf));
8200 for (PetscInt f = 0; f < Nf; ++f) {
8201 PetscSimplePointFn *lfunc, *ufunc;
8202
8203 PetscCall(PetscDSGetLowerBound(ds, f, &lfunc, NULL));
8204 PetscCall(PetscDSGetUpperBound(ds, f, &ufunc, NULL));
8205 if (lfunc || ufunc) *hasBound = PETSC_TRUE;
8206 }
8207
8208 PetscCall(PetscDSGetNumBoundary(ds, &numBd));
8209 PetscCall(PetscDSUpdateBoundaryLabels(ds, dm));
8210 for (PetscInt b = 0; b < numBd; ++b) {
8211 PetscWeakForm wf;
8212 DMBoundaryConditionType type;
8213 const char *name;
8214 DMLabel label;
8215 PetscInt numids;
8216 const PetscInt *ids;
8217 PetscInt field, Nc;
8218 const PetscInt *comps;
8219 PetscVoidFn *bvfunc;
8220 void *ctx;
8221
8222 PetscCall(PetscDSGetBoundary(ds, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, &bvfunc, NULL, &ctx));
8223 if (type == DM_BC_LOWER_BOUND || type == DM_BC_UPPER_BOUND) *hasBound = PETSC_TRUE;
8224 }
8225 PetscFunctionReturn(PETSC_SUCCESS);
8226 }
8227
8228 /*@C
8229 DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector.
8230
8231 Collective
8232
8233 Input Parameters:
8234 + dm - The `DM`
8235 . time - The time
8236 . funcs - The coordinate functions to evaluate, one per field
8237 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8238 - mode - The insertion mode for values
8239
8240 Output Parameter:
8241 . X - vector
8242
8243 Calling sequence of `funcs`:
8244 + dim - The spatial dimension
8245 . time - The time at which to sample
8246 . x - The coordinates
8247 . Nc - The number of components
8248 . u - The output field values
8249 - ctx - optional user-defined function context
8250
8251 Level: developer
8252
8253 Developer Notes:
8254 This API is specific to only particular usage of `DM`
8255
8256 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8257
8258 .seealso: [](ch_dmbase), `DM`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8259 @*/
DMProjectFunction(DM dm,PetscReal time,PetscErrorCode (** funcs)(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nc,PetscScalar * u,PetscCtx ctx),void ** ctxs,InsertMode mode,Vec X)8260 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx), void **ctxs, InsertMode mode, Vec X)
8261 {
8262 Vec localX;
8263
8264 PetscFunctionBegin;
8265 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8266 PetscCall(PetscLogEventBegin(DM_ProjectFunction, dm, X, 0, 0));
8267 PetscCall(DMGetLocalVector(dm, &localX));
8268 PetscCall(VecSet(localX, 0.));
8269 PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX));
8270 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8271 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8272 PetscCall(DMRestoreLocalVector(dm, &localX));
8273 PetscCall(PetscLogEventEnd(DM_ProjectFunction, dm, X, 0, 0));
8274 PetscFunctionReturn(PETSC_SUCCESS);
8275 }
8276
8277 /*@C
8278 DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector.
8279
8280 Not Collective
8281
8282 Input Parameters:
8283 + dm - The `DM`
8284 . time - The time
8285 . funcs - The coordinate functions to evaluate, one per field
8286 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8287 - mode - The insertion mode for values
8288
8289 Output Parameter:
8290 . localX - vector
8291
8292 Calling sequence of `funcs`:
8293 + dim - The spatial dimension
8294 . time - The current timestep
8295 . x - The coordinates
8296 . Nc - The number of components
8297 . u - The output field values
8298 - ctx - optional user-defined function context
8299
8300 Level: developer
8301
8302 Developer Notes:
8303 This API is specific to only particular usage of `DM`
8304
8305 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8306
8307 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8308 @*/
DMProjectFunctionLocal(DM dm,PetscReal time,PetscErrorCode (** funcs)(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nc,PetscScalar * u,PetscCtx ctx),void ** ctxs,InsertMode mode,Vec localX)8309 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx), void **ctxs, InsertMode mode, Vec localX)
8310 {
8311 PetscFunctionBegin;
8312 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8313 PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
8314 PetscUseTypeMethod(dm, projectfunctionlocal, time, funcs, ctxs, mode, localX);
8315 PetscFunctionReturn(PETSC_SUCCESS);
8316 }
8317
8318 /*@C
8319 DMProjectFunctionLabel - This projects the given function into the function space provided by the `DM`, putting the coefficients in a global vector, setting values only for points in the given label.
8320
8321 Collective
8322
8323 Input Parameters:
8324 + dm - The `DM`
8325 . time - The time
8326 . numIds - The number of ids
8327 . ids - The ids
8328 . Nc - The number of components
8329 . comps - The components
8330 . label - The `DMLabel` selecting the portion of the mesh for projection
8331 . funcs - The coordinate functions to evaluate, one per field
8332 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs may be null.
8333 - mode - The insertion mode for values
8334
8335 Output Parameter:
8336 . X - vector
8337
8338 Calling sequence of `funcs`:
8339 + dim - The spatial dimension
8340 . time - The current timestep
8341 . x - The coordinates
8342 . Nc - The number of components
8343 . u - The output field values
8344 - ctx - optional user-defined function context
8345
8346 Level: developer
8347
8348 Developer Notes:
8349 This API is specific to only particular usage of `DM`
8350
8351 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8352
8353 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()`
8354 @*/
DMProjectFunctionLabel(DM dm,PetscReal time,DMLabel label,PetscInt numIds,const PetscInt ids[],PetscInt Nc,const PetscInt comps[],PetscErrorCode (** funcs)(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nc,PetscScalar * u,PetscCtx ctx),void ** ctxs,InsertMode mode,Vec X)8355 PetscErrorCode DMProjectFunctionLabel(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], PetscErrorCode (**funcs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx), void **ctxs, InsertMode mode, Vec X)
8356 {
8357 Vec localX;
8358
8359 PetscFunctionBegin;
8360 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8361 PetscCall(DMGetLocalVector(dm, &localX));
8362 PetscCall(VecSet(localX, 0.));
8363 PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX));
8364 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8365 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8366 PetscCall(DMRestoreLocalVector(dm, &localX));
8367 PetscFunctionReturn(PETSC_SUCCESS);
8368 }
8369
8370 /*@C
8371 DMProjectFunctionLabelLocal - This projects the given function into the function space provided by the `DM`, putting the coefficients in a local vector, setting values only for points in the given label.
8372
8373 Not Collective
8374
8375 Input Parameters:
8376 + dm - The `DM`
8377 . time - The time
8378 . label - The `DMLabel` selecting the portion of the mesh for projection
8379 . numIds - The number of ids
8380 . ids - The ids
8381 . Nc - The number of components
8382 . comps - The components
8383 . funcs - The coordinate functions to evaluate, one per field
8384 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null.
8385 - mode - The insertion mode for values
8386
8387 Output Parameter:
8388 . localX - vector
8389
8390 Calling sequence of `funcs`:
8391 + dim - The spatial dimension
8392 . time - The current time
8393 . x - The coordinates
8394 . Nc - The number of components
8395 . u - The output field values
8396 - ctx - optional user-defined function context
8397
8398 Level: developer
8399
8400 Developer Notes:
8401 This API is specific to only particular usage of `DM`
8402
8403 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8404
8405 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8406 @*/
DMProjectFunctionLabelLocal(DM dm,PetscReal time,DMLabel label,PetscInt numIds,const PetscInt ids[],PetscInt Nc,const PetscInt comps[],PetscErrorCode (** funcs)(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nc,PetscScalar * u,PetscCtx ctx),void ** ctxs,InsertMode mode,Vec localX)8407 PetscErrorCode DMProjectFunctionLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], PetscErrorCode (**funcs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx), void **ctxs, InsertMode mode, Vec localX)
8408 {
8409 PetscFunctionBegin;
8410 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8411 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8412 PetscUseTypeMethod(dm, projectfunctionlabellocal, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8413 PetscFunctionReturn(PETSC_SUCCESS);
8414 }
8415
8416 /*@C
8417 DMProjectFieldLocal - This projects the given function of the input fields into the function space provided by the `DM`, putting the coefficients in a local vector.
8418
8419 Not Collective
8420
8421 Input Parameters:
8422 + dm - The `DM`
8423 . time - The time
8424 . localU - The input field vector; may be `NULL` if projection is defined purely by coordinates
8425 . funcs - The functions to evaluate, one per field
8426 - mode - The insertion mode for values
8427
8428 Output Parameter:
8429 . localX - The output vector
8430
8431 Calling sequence of `funcs`:
8432 + dim - The spatial dimension
8433 . Nf - The number of input fields
8434 . NfAux - The number of input auxiliary fields
8435 . uOff - The offset of each field in u[]
8436 . uOff_x - The offset of each field in u_x[]
8437 . u - The field values at this point in space
8438 . u_t - The field time derivative at this point in space (or `NULL`)
8439 . u_x - The field derivatives at this point in space
8440 . aOff - The offset of each auxiliary field in u[]
8441 . aOff_x - The offset of each auxiliary field in u_x[]
8442 . a - The auxiliary field values at this point in space
8443 . a_t - The auxiliary field time derivative at this point in space (or `NULL`)
8444 . a_x - The auxiliary field derivatives at this point in space
8445 . t - The current time
8446 . x - The coordinates of this point
8447 . numConstants - The number of constants
8448 . constants - The value of each constant
8449 - f - The value of the function at this point in space
8450
8451 Level: intermediate
8452
8453 Note:
8454 There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
8455 The input `DM`, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
8456 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8457 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8458
8459 Developer Notes:
8460 This API is specific to only particular usage of `DM`
8461
8462 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8463
8464 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`,
8465 `DMProjectFunction()`, `DMComputeL2Diff()`
8466 @*/
DMProjectFieldLocal(DM dm,PetscReal time,Vec localU,void (** funcs)(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f[]),InsertMode mode,Vec localX)8467 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU, void (**funcs)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]), InsertMode mode, Vec localX)
8468 {
8469 PetscFunctionBegin;
8470 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8471 if (localU) PetscValidHeaderSpecific(localU, VEC_CLASSID, 3);
8472 PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
8473 PetscUseTypeMethod(dm, projectfieldlocal, time, localU, funcs, mode, localX);
8474 PetscFunctionReturn(PETSC_SUCCESS);
8475 }
8476
8477 /*@C
8478 DMProjectFieldLabelLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector, calculating only over the portion of the domain specified by the label.
8479
8480 Not Collective
8481
8482 Input Parameters:
8483 + dm - The `DM`
8484 . time - The time
8485 . label - The `DMLabel` marking the portion of the domain to output
8486 . numIds - The number of label ids to use
8487 . ids - The label ids to use for marking
8488 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8489 . comps - The components to set in the output, or `NULL` for all components
8490 . localU - The input field vector
8491 . funcs - The functions to evaluate, one per field
8492 - mode - The insertion mode for values
8493
8494 Output Parameter:
8495 . localX - The output vector
8496
8497 Calling sequence of `funcs`:
8498 + dim - The spatial dimension
8499 . Nf - The number of input fields
8500 . NfAux - The number of input auxiliary fields
8501 . uOff - The offset of each field in u[]
8502 . uOff_x - The offset of each field in u_x[]
8503 . u - The field values at this point in space
8504 . u_t - The field time derivative at this point in space (or `NULL`)
8505 . u_x - The field derivatives at this point in space
8506 . aOff - The offset of each auxiliary field in u[]
8507 . aOff_x - The offset of each auxiliary field in u_x[]
8508 . a - The auxiliary field values at this point in space
8509 . a_t - The auxiliary field time derivative at this point in space (or `NULL`)
8510 . a_x - The auxiliary field derivatives at this point in space
8511 . t - The current time
8512 . x - The coordinates of this point
8513 . numConstants - The number of constants
8514 . constants - The value of each constant
8515 - f - The value of the function at this point in space
8516
8517 Level: intermediate
8518
8519 Note:
8520 There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
8521 The input `DM`, attached to localU, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
8522 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8523 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8524
8525 Developer Notes:
8526 This API is specific to only particular usage of `DM`
8527
8528 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8529
8530 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8531 @*/
DMProjectFieldLabelLocal(DM dm,PetscReal time,DMLabel label,PetscInt numIds,const PetscInt ids[],PetscInt Nc,const PetscInt comps[],Vec localU,void (** funcs)(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f[]),InsertMode mode,Vec localX)8532 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU, void (**funcs)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]), InsertMode mode, Vec localX)
8533 {
8534 PetscFunctionBegin;
8535 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8536 PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8537 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8538 PetscUseTypeMethod(dm, projectfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8539 PetscFunctionReturn(PETSC_SUCCESS);
8540 }
8541
8542 /*@C
8543 DMProjectFieldLabel - This projects the given function of the input fields into the function space provided, putting the coefficients in a global vector, calculating only over the portion of the domain specified by the label.
8544
8545 Not Collective
8546
8547 Input Parameters:
8548 + dm - The `DM`
8549 . time - The time
8550 . label - The `DMLabel` marking the portion of the domain to output
8551 . numIds - The number of label ids to use
8552 . ids - The label ids to use for marking
8553 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8554 . comps - The components to set in the output, or `NULL` for all components
8555 . U - The input field vector
8556 . funcs - The functions to evaluate, one per field
8557 - mode - The insertion mode for values
8558
8559 Output Parameter:
8560 . X - The output vector
8561
8562 Calling sequence of `funcs`:
8563 + dim - The spatial dimension
8564 . Nf - The number of input fields
8565 . NfAux - The number of input auxiliary fields
8566 . uOff - The offset of each field in u[]
8567 . uOff_x - The offset of each field in u_x[]
8568 . u - The field values at this point in space
8569 . u_t - The field time derivative at this point in space (or `NULL`)
8570 . u_x - The field derivatives at this point in space
8571 . aOff - The offset of each auxiliary field in u[]
8572 . aOff_x - The offset of each auxiliary field in u_x[]
8573 . a - The auxiliary field values at this point in space
8574 . a_t - The auxiliary field time derivative at this point in space (or `NULL`)
8575 . a_x - The auxiliary field derivatives at this point in space
8576 . t - The current time
8577 . x - The coordinates of this point
8578 . numConstants - The number of constants
8579 . constants - The value of each constant
8580 - f - The value of the function at this point in space
8581
8582 Level: intermediate
8583
8584 Note:
8585 There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
8586 The input `DM`, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
8587 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8588 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8589
8590 Developer Notes:
8591 This API is specific to only particular usage of `DM`
8592
8593 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8594
8595 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8596 @*/
DMProjectFieldLabel(DM dm,PetscReal time,DMLabel label,PetscInt numIds,const PetscInt ids[],PetscInt Nc,const PetscInt comps[],Vec U,void (** funcs)(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f[]),InsertMode mode,Vec X)8597 PetscErrorCode DMProjectFieldLabel(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec U, void (**funcs)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]), InsertMode mode, Vec X)
8598 {
8599 DM dmIn;
8600 Vec localU, localX;
8601
8602 PetscFunctionBegin;
8603 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8604 PetscCall(VecGetDM(U, &dmIn));
8605 PetscCall(DMGetLocalVector(dmIn, &localU));
8606 PetscCall(DMGetLocalVector(dm, &localX));
8607 PetscCall(VecSet(localX, 0.));
8608 PetscCall(DMGlobalToLocalBegin(dmIn, U, mode, localU));
8609 PetscCall(DMGlobalToLocalEnd(dmIn, U, mode, localU));
8610 PetscCall(DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
8611 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8612 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8613 PetscCall(DMRestoreLocalVector(dm, &localX));
8614 PetscCall(DMRestoreLocalVector(dmIn, &localU));
8615 PetscFunctionReturn(PETSC_SUCCESS);
8616 }
8617
8618 /*@C
8619 DMProjectBdFieldLabelLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector, calculating only over the portion of the domain boundary specified by the label.
8620
8621 Not Collective
8622
8623 Input Parameters:
8624 + dm - The `DM`
8625 . time - The time
8626 . label - The `DMLabel` marking the portion of the domain boundary to output
8627 . numIds - The number of label ids to use
8628 . ids - The label ids to use for marking
8629 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8630 . comps - The components to set in the output, or `NULL` for all components
8631 . localU - The input field vector
8632 . funcs - The functions to evaluate, one per field
8633 - mode - The insertion mode for values
8634
8635 Output Parameter:
8636 . localX - The output vector
8637
8638 Calling sequence of `funcs`:
8639 + dim - The spatial dimension
8640 . Nf - The number of input fields
8641 . NfAux - The number of input auxiliary fields
8642 . uOff - The offset of each field in u[]
8643 . uOff_x - The offset of each field in u_x[]
8644 . u - The field values at this point in space
8645 . u_t - The field time derivative at this point in space (or `NULL`)
8646 . u_x - The field derivatives at this point in space
8647 . aOff - The offset of each auxiliary field in u[]
8648 . aOff_x - The offset of each auxiliary field in u_x[]
8649 . a - The auxiliary field values at this point in space
8650 . a_t - The auxiliary field time derivative at this point in space (or `NULL`)
8651 . a_x - The auxiliary field derivatives at this point in space
8652 . t - The current time
8653 . x - The coordinates of this point
8654 . n - The face normal
8655 . numConstants - The number of constants
8656 . constants - The value of each constant
8657 - f - The value of the function at this point in space
8658
8659 Level: intermediate
8660
8661 Note:
8662 There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
8663 The input `DM`, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
8664 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8665 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8666
8667 Developer Notes:
8668 This API is specific to only particular usage of `DM`
8669
8670 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8671
8672 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8673 @*/
DMProjectBdFieldLabelLocal(DM dm,PetscReal time,DMLabel label,PetscInt numIds,const PetscInt ids[],PetscInt Nc,const PetscInt comps[],Vec localU,void (** funcs)(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],const PetscReal n[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f[]),InsertMode mode,Vec localX)8674 PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU, void (**funcs)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]), InsertMode mode, Vec localX)
8675 {
8676 PetscFunctionBegin;
8677 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8678 PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8679 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8680 PetscUseTypeMethod(dm, projectbdfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8681 PetscFunctionReturn(PETSC_SUCCESS);
8682 }
8683
8684 /*@C
8685 DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8686
8687 Collective
8688
8689 Input Parameters:
8690 + dm - The `DM`
8691 . time - The time
8692 . funcs - The functions to evaluate for each field component
8693 . ctxs - Optional array of contexts to pass to each function, or `NULL`.
8694 - X - The coefficient vector u_h, a global vector
8695
8696 Output Parameter:
8697 . diff - The diff ||u - u_h||_2
8698
8699 Level: developer
8700
8701 Developer Notes:
8702 This API is specific to only particular usage of `DM`
8703
8704 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8705
8706 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
8707 @*/
DMComputeL2Diff(DM dm,PetscReal time,PetscErrorCode (** funcs)(PetscInt,PetscReal,const PetscReal[],PetscInt,PetscScalar *,void *),void ** ctxs,Vec X,PetscReal * diff)8708 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8709 {
8710 PetscFunctionBegin;
8711 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8712 PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8713 PetscUseTypeMethod(dm, computel2diff, time, funcs, ctxs, X, diff);
8714 PetscFunctionReturn(PETSC_SUCCESS);
8715 }
8716
8717 /*@C
8718 DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
8719
8720 Collective
8721
8722 Input Parameters:
8723 + dm - The `DM`
8724 . time - The time
8725 . funcs - The gradient functions to evaluate for each field component
8726 . ctxs - Optional array of contexts to pass to each function, or `NULL`.
8727 . X - The coefficient vector u_h, a global vector
8728 - n - The vector to project along
8729
8730 Output Parameter:
8731 . diff - The diff ||(grad u - grad u_h) . n||_2
8732
8733 Level: developer
8734
8735 Developer Notes:
8736 This API is specific to only particular usage of `DM`
8737
8738 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8739
8740 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()`
8741 @*/
DMComputeL2GradientDiff(DM dm,PetscReal time,PetscErrorCode (** funcs)(PetscInt,PetscReal,const PetscReal[],const PetscReal[],PetscInt,PetscScalar *,void *),void ** ctxs,Vec X,const PetscReal n[],PetscReal * diff)8742 PetscErrorCode DMComputeL2GradientDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, const PetscReal n[], PetscReal *diff)
8743 {
8744 PetscFunctionBegin;
8745 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8746 PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8747 PetscUseTypeMethod(dm, computel2gradientdiff, time, funcs, ctxs, X, n, diff);
8748 PetscFunctionReturn(PETSC_SUCCESS);
8749 }
8750
8751 /*@C
8752 DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
8753
8754 Collective
8755
8756 Input Parameters:
8757 + dm - The `DM`
8758 . time - The time
8759 . funcs - The functions to evaluate for each field component
8760 . ctxs - Optional array of contexts to pass to each function, or `NULL`.
8761 - X - The coefficient vector u_h, a global vector
8762
8763 Output Parameter:
8764 . diff - The array of differences, ||u^f - u^f_h||_2
8765
8766 Level: developer
8767
8768 Developer Notes:
8769 This API is specific to only particular usage of `DM`
8770
8771 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8772
8773 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2GradientDiff()`
8774 @*/
DMComputeL2FieldDiff(DM dm,PetscReal time,PetscErrorCode (** funcs)(PetscInt,PetscReal,const PetscReal[],PetscInt,PetscScalar *,void *),void ** ctxs,Vec X,PetscReal diff[])8775 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8776 {
8777 PetscFunctionBegin;
8778 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8779 PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8780 PetscUseTypeMethod(dm, computel2fielddiff, time, funcs, ctxs, X, diff);
8781 PetscFunctionReturn(PETSC_SUCCESS);
8782 }
8783
8784 /*@C
8785 DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors
8786
8787 Not Collective
8788
8789 Input Parameter:
8790 . dm - The `DM`
8791
8792 Output Parameters:
8793 + nranks - the number of neighbours
8794 - ranks - the neighbors ranks
8795
8796 Level: beginner
8797
8798 Note:
8799 Do not free the array, it is freed when the `DM` is destroyed.
8800
8801 .seealso: [](ch_dmbase), `DM`, `DMDAGetNeighbors()`, `PetscSFGetRootRanks()`
8802 @*/
DMGetNeighbors(DM dm,PetscInt * nranks,const PetscMPIInt * ranks[])8803 PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
8804 {
8805 PetscFunctionBegin;
8806 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8807 PetscUseTypeMethod(dm, getneighbors, nranks, ranks);
8808 PetscFunctionReturn(PETSC_SUCCESS);
8809 }
8810
8811 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
8812
8813 /*
8814 Converts the input vector to a ghosted vector and then calls the standard coloring code.
8815 This must be a different function because it requires DM which is not defined in the Mat library
8816 */
MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void * sctx)8817 static PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx)
8818 {
8819 PetscFunctionBegin;
8820 if (coloring->ctype == IS_COLORING_LOCAL) {
8821 Vec x1local;
8822 DM dm;
8823 PetscCall(MatGetDM(J, &dm));
8824 PetscCheck(dm, PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_INCOMP, "IS_COLORING_LOCAL requires a DM");
8825 PetscCall(DMGetLocalVector(dm, &x1local));
8826 PetscCall(DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local));
8827 PetscCall(DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local));
8828 x1 = x1local;
8829 }
8830 PetscCall(MatFDColoringApply_AIJ(J, coloring, x1, sctx));
8831 if (coloring->ctype == IS_COLORING_LOCAL) {
8832 DM dm;
8833 PetscCall(MatGetDM(J, &dm));
8834 PetscCall(DMRestoreLocalVector(dm, &x1));
8835 }
8836 PetscFunctionReturn(PETSC_SUCCESS);
8837 }
8838
8839 /*@
8840 MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring
8841
8842 Input Parameters:
8843 + coloring - The matrix to get the `DM` from
8844 - fdcoloring - the `MatFDColoring` object
8845
8846 Level: advanced
8847
8848 Developer Note:
8849 This routine exists because the PETSc `Mat` library does not know about the `DM` objects
8850
8851 .seealso: [](ch_dmbase), `DM`, `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType`
8852 @*/
MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)8853 PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring)
8854 {
8855 PetscFunctionBegin;
8856 coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8857 PetscFunctionReturn(PETSC_SUCCESS);
8858 }
8859
8860 /*@
8861 DMGetCompatibility - determine if two `DM`s are compatible
8862
8863 Collective
8864
8865 Input Parameters:
8866 + dm1 - the first `DM`
8867 - dm2 - the second `DM`
8868
8869 Output Parameters:
8870 + compatible - whether or not the two `DM`s are compatible
8871 - set - whether or not the compatible value was actually determined and set
8872
8873 Level: advanced
8874
8875 Notes:
8876 Two `DM`s are deemed compatible if they represent the same parallel decomposition
8877 of the same topology. This implies that the section (field data) on one
8878 "makes sense" with respect to the topology and parallel decomposition of the other.
8879 Loosely speaking, compatible `DM`s represent the same domain and parallel
8880 decomposition, but hold different data.
8881
8882 Typically, one would confirm compatibility if intending to simultaneously iterate
8883 over a pair of vectors obtained from different `DM`s.
8884
8885 For example, two `DMDA` objects are compatible if they have the same local
8886 and global sizes and the same stencil width. They can have different numbers
8887 of degrees of freedom per node. Thus, one could use the node numbering from
8888 either `DM` in bounds for a loop over vectors derived from either `DM`.
8889
8890 Consider the operation of summing data living on a 2-dof `DMDA` to data living
8891 on a 1-dof `DMDA`, which should be compatible, as in the following snippet.
8892 .vb
8893 ...
8894 PetscCall(DMGetCompatibility(da1,da2,&compatible,&set));
8895 if (set && compatible) {
8896 PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1));
8897 PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2));
8898 PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL));
8899 for (j=y; j<y+n; ++j) {
8900 for (i=x; i<x+m, ++i) {
8901 arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8902 }
8903 }
8904 PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1));
8905 PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2));
8906 } else {
8907 SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8908 }
8909 ...
8910 .ve
8911
8912 Checking compatibility might be expensive for a given implementation of `DM`,
8913 or might be impossible to unambiguously confirm or deny. For this reason,
8914 this function may decline to determine compatibility, and hence users should
8915 always check the "set" output parameter.
8916
8917 A `DM` is always compatible with itself.
8918
8919 In the current implementation, `DM`s which live on "unequal" communicators
8920 (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8921 incompatible.
8922
8923 This function is labeled "Collective," as information about all subdomains
8924 is required on each rank. However, in `DM` implementations which store all this
8925 information locally, this function may be merely "Logically Collective".
8926
8927 Developer Note:
8928 Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B
8929 iff B is compatible with A. Thus, this function checks the implementations
8930 of both dm and dmc (if they are of different types), attempting to determine
8931 compatibility. It is left to `DM` implementers to ensure that symmetry is
8932 preserved. The simplest way to do this is, when implementing type-specific
8933 logic for this function, is to check for existing logic in the implementation
8934 of other `DM` types and let *set = PETSC_FALSE if found.
8935
8936 .seealso: [](ch_dmbase), `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()`
8937 @*/
DMGetCompatibility(DM dm1,DM dm2,PetscBool * compatible,PetscBool * set)8938 PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set)
8939 {
8940 PetscMPIInt compareResult;
8941 DMType type, type2;
8942 PetscBool sameType;
8943
8944 PetscFunctionBegin;
8945 PetscValidHeaderSpecific(dm1, DM_CLASSID, 1);
8946 PetscValidHeaderSpecific(dm2, DM_CLASSID, 2);
8947
8948 /* Declare a DM compatible with itself */
8949 if (dm1 == dm2) {
8950 *set = PETSC_TRUE;
8951 *compatible = PETSC_TRUE;
8952 PetscFunctionReturn(PETSC_SUCCESS);
8953 }
8954
8955 /* Declare a DM incompatible with a DM that lives on an "unequal"
8956 communicator. Note that this does not preclude compatibility with
8957 DMs living on "congruent" or "similar" communicators, but this must be
8958 determined by the implementation-specific logic */
8959 PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult));
8960 if (compareResult == MPI_UNEQUAL) {
8961 *set = PETSC_TRUE;
8962 *compatible = PETSC_FALSE;
8963 PetscFunctionReturn(PETSC_SUCCESS);
8964 }
8965
8966 /* Pass to the implementation-specific routine, if one exists. */
8967 if (dm1->ops->getcompatibility) {
8968 PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set);
8969 if (*set) PetscFunctionReturn(PETSC_SUCCESS);
8970 }
8971
8972 /* If dm1 and dm2 are of different types, then attempt to check compatibility
8973 with an implementation of this function from dm2 */
8974 PetscCall(DMGetType(dm1, &type));
8975 PetscCall(DMGetType(dm2, &type2));
8976 PetscCall(PetscStrcmp(type, type2, &sameType));
8977 if (!sameType && dm2->ops->getcompatibility) {
8978 PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */
8979 } else {
8980 *set = PETSC_FALSE;
8981 }
8982 PetscFunctionReturn(PETSC_SUCCESS);
8983 }
8984
8985 /*@C
8986 DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance.
8987
8988 Logically Collective
8989
8990 Input Parameters:
8991 + dm - the `DM`
8992 . f - the monitor function
8993 . mctx - [optional] user-defined context for private data for the monitor routine (use `NULL` if no context is desired)
8994 - monitordestroy - [optional] routine that frees monitor context (may be `NULL`), see `PetscCtxDestroyFn` for the calling sequence
8995
8996 Options Database Key:
8997 . -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but
8998 does not cancel those set via the options database.
8999
9000 Level: intermediate
9001
9002 Note:
9003 Several different monitoring routines may be set by calling
9004 `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the
9005 order in which they were set.
9006
9007 Fortran Note:
9008 Only a single monitor function can be set for each `DM` object
9009
9010 Developer Note:
9011 This API has a generic name but seems specific to a very particular aspect of the use of `DM`
9012
9013 .seealso: [](ch_dmbase), `DM`, `DMMonitorCancel()`, `DMMonitorSetFromOptions()`, `DMMonitor()`, `PetscCtxDestroyFn`
9014 @*/
DMMonitorSet(DM dm,PetscErrorCode (* f)(DM,void *),void * mctx,PetscCtxDestroyFn * monitordestroy)9015 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscCtxDestroyFn *monitordestroy)
9016 {
9017 PetscFunctionBegin;
9018 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9019 for (PetscInt m = 0; m < dm->numbermonitors; ++m) {
9020 PetscBool identical;
9021
9022 PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void))(PetscVoidFn *)f, mctx, monitordestroy, (PetscErrorCode (*)(void))(PetscVoidFn *)dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical));
9023 if (identical) PetscFunctionReturn(PETSC_SUCCESS);
9024 }
9025 PetscCheck(dm->numbermonitors < MAXDMMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
9026 dm->monitor[dm->numbermonitors] = f;
9027 dm->monitordestroy[dm->numbermonitors] = monitordestroy;
9028 dm->monitorcontext[dm->numbermonitors++] = mctx;
9029 PetscFunctionReturn(PETSC_SUCCESS);
9030 }
9031
9032 /*@
9033 DMMonitorCancel - Clears all the monitor functions for a `DM` object.
9034
9035 Logically Collective
9036
9037 Input Parameter:
9038 . dm - the DM
9039
9040 Options Database Key:
9041 . -dm_monitor_cancel - cancels all monitors that have been hardwired
9042 into a code by calls to `DMonitorSet()`, but does not cancel those
9043 set via the options database
9044
9045 Level: intermediate
9046
9047 Note:
9048 There is no way to clear one specific monitor from a `DM` object.
9049
9050 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`, `DMMonitor()`
9051 @*/
DMMonitorCancel(DM dm)9052 PetscErrorCode DMMonitorCancel(DM dm)
9053 {
9054 PetscInt m;
9055
9056 PetscFunctionBegin;
9057 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9058 for (m = 0; m < dm->numbermonitors; ++m) {
9059 if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m]));
9060 }
9061 dm->numbermonitors = 0;
9062 PetscFunctionReturn(PETSC_SUCCESS);
9063 }
9064
9065 /*@C
9066 DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
9067
9068 Collective
9069
9070 Input Parameters:
9071 + dm - `DM` object you wish to monitor
9072 . name - the monitor type one is seeking
9073 . help - message indicating what monitoring is done
9074 . manual - manual page for the monitor
9075 . monitor - the monitor function, this must use a `PetscViewerFormat` as its context
9076 - monitorsetup - a function that is called once ONLY if the user selected this monitor that may set additional features of the `DM` or `PetscViewer` objects
9077
9078 Output Parameter:
9079 . flg - Flag set if the monitor was created
9080
9081 Level: developer
9082
9083 .seealso: [](ch_dmbase), `DM`, `PetscOptionsCreateViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
9084 `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
9085 `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`,
9086 `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
9087 `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
9088 `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
9089 `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()`
9090 @*/
DMMonitorSetFromOptions(DM dm,const char name[],const char help[],const char manual[],PetscErrorCode (* monitor)(DM,void *),PetscErrorCode (* monitorsetup)(DM,PetscViewerAndFormat *),PetscBool * flg)9091 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
9092 {
9093 PetscViewer viewer;
9094 PetscViewerFormat format;
9095
9096 PetscFunctionBegin;
9097 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9098 PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg));
9099 if (*flg) {
9100 PetscViewerAndFormat *vf;
9101
9102 PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
9103 PetscCall(PetscViewerDestroy(&viewer));
9104 if (monitorsetup) PetscCall((*monitorsetup)(dm, vf));
9105 PetscCall(DMMonitorSet(dm, monitor, vf, (PetscCtxDestroyFn *)PetscViewerAndFormatDestroy));
9106 }
9107 PetscFunctionReturn(PETSC_SUCCESS);
9108 }
9109
9110 /*@
9111 DMMonitor - runs the user provided monitor routines, if they exist
9112
9113 Collective
9114
9115 Input Parameter:
9116 . dm - The `DM`
9117
9118 Level: developer
9119
9120 Developer Note:
9121 Note should indicate when during the life of the `DM` the monitor is run. It appears to be
9122 related to the discretization process seems rather specialized since some `DM` have no
9123 concept of discretization.
9124
9125 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`
9126 @*/
DMMonitor(DM dm)9127 PetscErrorCode DMMonitor(DM dm)
9128 {
9129 PetscInt m;
9130
9131 PetscFunctionBegin;
9132 if (!dm) PetscFunctionReturn(PETSC_SUCCESS);
9133 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9134 for (m = 0; m < dm->numbermonitors; ++m) PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m]));
9135 PetscFunctionReturn(PETSC_SUCCESS);
9136 }
9137
9138 /*@
9139 DMComputeError - Computes the error assuming the user has provided the exact solution functions
9140
9141 Collective
9142
9143 Input Parameters:
9144 + dm - The `DM`
9145 - sol - The solution vector
9146
9147 Input/Output Parameter:
9148 . errors - An array of length Nf, the number of fields, or `NULL` for no output; on output
9149 contains the error in each field
9150
9151 Output Parameter:
9152 . errorVec - A vector to hold the cellwise error (may be `NULL`)
9153
9154 Level: developer
9155
9156 Note:
9157 The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`.
9158
9159 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()`
9160 @*/
DMComputeError(DM dm,Vec sol,PetscReal errors[],Vec * errorVec)9161 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
9162 {
9163 PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
9164 void **ctxs;
9165 PetscReal time;
9166 PetscInt Nf, f, Nds, s;
9167
9168 PetscFunctionBegin;
9169 PetscCall(DMGetNumFields(dm, &Nf));
9170 PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs));
9171 PetscCall(DMGetNumDS(dm, &Nds));
9172 for (s = 0; s < Nds; ++s) {
9173 PetscDS ds;
9174 DMLabel label;
9175 IS fieldIS;
9176 const PetscInt *fields;
9177 PetscInt dsNf;
9178
9179 PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
9180 PetscCall(PetscDSGetNumFields(ds, &dsNf));
9181 if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields));
9182 for (f = 0; f < dsNf; ++f) {
9183 const PetscInt field = fields[f];
9184 PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]));
9185 }
9186 if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields));
9187 }
9188 for (f = 0; f < Nf; ++f) PetscCheck(exactSol[f], PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "DS must contain exact solution functions in order to calculate error, missing for field %" PetscInt_FMT, f);
9189 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
9190 if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors));
9191 if (errorVec) {
9192 DM edm;
9193 DMPolytopeType ct;
9194 PetscBool simplex;
9195 PetscInt dim, cStart, Nf;
9196
9197 PetscCall(DMClone(dm, &edm));
9198 PetscCall(DMGetDimension(edm, &dim));
9199 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
9200 PetscCall(DMPlexGetCellType(dm, cStart, &ct));
9201 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
9202 PetscCall(DMGetNumFields(dm, &Nf));
9203 for (f = 0; f < Nf; ++f) {
9204 PetscFE fe, efe;
9205 PetscQuadrature q;
9206 const char *name;
9207
9208 PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe));
9209 PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe));
9210 PetscCall(PetscObjectGetName((PetscObject)fe, &name));
9211 PetscCall(PetscObjectSetName((PetscObject)efe, name));
9212 PetscCall(PetscFEGetQuadrature(fe, &q));
9213 PetscCall(PetscFESetQuadrature(efe, q));
9214 PetscCall(DMSetField(edm, f, NULL, (PetscObject)efe));
9215 PetscCall(PetscFEDestroy(&efe));
9216 }
9217 PetscCall(DMCreateDS(edm));
9218
9219 PetscCall(DMCreateGlobalVector(edm, errorVec));
9220 PetscCall(PetscObjectSetName((PetscObject)*errorVec, "Error"));
9221 PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec));
9222 PetscCall(DMDestroy(&edm));
9223 }
9224 PetscCall(PetscFree2(exactSol, ctxs));
9225 PetscFunctionReturn(PETSC_SUCCESS);
9226 }
9227
9228 /*@
9229 DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM`
9230
9231 Not Collective
9232
9233 Input Parameter:
9234 . dm - The `DM`
9235
9236 Output Parameter:
9237 . numAux - The number of auxiliary data vectors
9238
9239 Level: advanced
9240
9241 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()`
9242 @*/
DMGetNumAuxiliaryVec(DM dm,PetscInt * numAux)9243 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
9244 {
9245 PetscFunctionBegin;
9246 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9247 PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux));
9248 PetscFunctionReturn(PETSC_SUCCESS);
9249 }
9250
9251 /*@
9252 DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part
9253
9254 Not Collective
9255
9256 Input Parameters:
9257 + dm - The `DM`
9258 . label - The `DMLabel`
9259 . value - The label value indicating the region
9260 - part - The equation part, or 0 if unused
9261
9262 Output Parameter:
9263 . aux - The `Vec` holding auxiliary field data
9264
9265 Level: advanced
9266
9267 Note:
9268 If no auxiliary vector is found for this (label, value), (`NULL`, 0, 0) is checked as well.
9269
9270 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()`
9271 @*/
DMGetAuxiliaryVec(DM dm,DMLabel label,PetscInt value,PetscInt part,Vec * aux)9272 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux)
9273 {
9274 PetscHashAuxKey key, wild = {NULL, 0, 0};
9275 PetscBool has;
9276
9277 PetscFunctionBegin;
9278 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9279 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
9280 key.label = label;
9281 key.value = value;
9282 key.part = part;
9283 PetscCall(PetscHMapAuxHas(dm->auxData, key, &has));
9284 if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key, aux));
9285 else PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux));
9286 PetscFunctionReturn(PETSC_SUCCESS);
9287 }
9288
9289 /*@
9290 DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part
9291
9292 Not Collective because auxiliary vectors are not parallel
9293
9294 Input Parameters:
9295 + dm - The `DM`
9296 . label - The `DMLabel`
9297 . value - The label value indicating the region
9298 . part - The equation part, or 0 if unused
9299 - aux - The `Vec` holding auxiliary field data
9300
9301 Level: advanced
9302
9303 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()`
9304 @*/
DMSetAuxiliaryVec(DM dm,DMLabel label,PetscInt value,PetscInt part,Vec aux)9305 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux)
9306 {
9307 Vec old;
9308 PetscHashAuxKey key;
9309
9310 PetscFunctionBegin;
9311 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9312 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
9313 key.label = label;
9314 key.value = value;
9315 key.part = part;
9316 PetscCall(PetscHMapAuxGet(dm->auxData, key, &old));
9317 PetscCall(PetscObjectReference((PetscObject)aux));
9318 if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key));
9319 else PetscCall(PetscHMapAuxSet(dm->auxData, key, aux));
9320 PetscCall(VecDestroy(&old));
9321 PetscFunctionReturn(PETSC_SUCCESS);
9322 }
9323
9324 /*@
9325 DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM`
9326
9327 Not Collective
9328
9329 Input Parameter:
9330 . dm - The `DM`
9331
9332 Output Parameters:
9333 + labels - The `DMLabel`s for each `Vec`
9334 . values - The label values for each `Vec`
9335 - parts - The equation parts for each `Vec`
9336
9337 Level: advanced
9338
9339 Note:
9340 The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`.
9341
9342 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMCopyAuxiliaryVec()`
9343 @*/
DMGetAuxiliaryLabels(DM dm,DMLabel labels[],PetscInt values[],PetscInt parts[])9344 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[])
9345 {
9346 PetscHashAuxKey *keys;
9347 PetscInt n, i, off = 0;
9348
9349 PetscFunctionBegin;
9350 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9351 PetscAssertPointer(labels, 2);
9352 PetscAssertPointer(values, 3);
9353 PetscAssertPointer(parts, 4);
9354 PetscCall(DMGetNumAuxiliaryVec(dm, &n));
9355 PetscCall(PetscMalloc1(n, &keys));
9356 PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys));
9357 for (i = 0; i < n; ++i) {
9358 labels[i] = keys[i].label;
9359 values[i] = keys[i].value;
9360 parts[i] = keys[i].part;
9361 }
9362 PetscCall(PetscFree(keys));
9363 PetscFunctionReturn(PETSC_SUCCESS);
9364 }
9365
9366 /*@
9367 DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM`
9368
9369 Not Collective
9370
9371 Input Parameter:
9372 . dm - The `DM`
9373
9374 Output Parameter:
9375 . dmNew - The new `DM`, now with the same auxiliary data
9376
9377 Level: advanced
9378
9379 Note:
9380 This is a shallow copy of the auxiliary vectors
9381
9382 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9383 @*/
DMCopyAuxiliaryVec(DM dm,DM dmNew)9384 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
9385 {
9386 PetscFunctionBegin;
9387 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9388 PetscValidHeaderSpecific(dmNew, DM_CLASSID, 2);
9389 if (dm == dmNew) PetscFunctionReturn(PETSC_SUCCESS);
9390 PetscCall(DMClearAuxiliaryVec(dmNew));
9391
9392 PetscCall(PetscHMapAuxDestroy(&dmNew->auxData));
9393 PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData));
9394 {
9395 Vec *auxData;
9396 PetscInt n, i, off = 0;
9397
9398 PetscCall(PetscHMapAuxGetSize(dmNew->auxData, &n));
9399 PetscCall(PetscMalloc1(n, &auxData));
9400 PetscCall(PetscHMapAuxGetVals(dmNew->auxData, &off, auxData));
9401 for (i = 0; i < n; ++i) PetscCall(PetscObjectReference((PetscObject)auxData[i]));
9402 PetscCall(PetscFree(auxData));
9403 }
9404 PetscFunctionReturn(PETSC_SUCCESS);
9405 }
9406
9407 /*@
9408 DMClearAuxiliaryVec - Destroys the auxiliary vector information and creates a new empty one
9409
9410 Not Collective
9411
9412 Input Parameter:
9413 . dm - The `DM`
9414
9415 Level: advanced
9416
9417 .seealso: [](ch_dmbase), `DM`, `DMCopyAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9418 @*/
DMClearAuxiliaryVec(DM dm)9419 PetscErrorCode DMClearAuxiliaryVec(DM dm)
9420 {
9421 Vec *auxData;
9422 PetscInt n, i, off = 0;
9423
9424 PetscFunctionBegin;
9425 PetscCall(PetscHMapAuxGetSize(dm->auxData, &n));
9426 PetscCall(PetscMalloc1(n, &auxData));
9427 PetscCall(PetscHMapAuxGetVals(dm->auxData, &off, auxData));
9428 for (i = 0; i < n; ++i) PetscCall(VecDestroy(&auxData[i]));
9429 PetscCall(PetscFree(auxData));
9430 PetscCall(PetscHMapAuxDestroy(&dm->auxData));
9431 PetscCall(PetscHMapAuxCreate(&dm->auxData));
9432 PetscFunctionReturn(PETSC_SUCCESS);
9433 }
9434
9435 /*@
9436 DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9437
9438 Not Collective
9439
9440 Input Parameters:
9441 + ct - The `DMPolytopeType`
9442 . sourceCone - The source arrangement of faces
9443 - targetCone - The target arrangement of faces
9444
9445 Output Parameters:
9446 + ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
9447 - found - Flag indicating that a suitable orientation was found
9448
9449 Level: advanced
9450
9451 Note:
9452 An arrangement is a face order combined with an orientation for each face
9453
9454 Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2
9455 that labels each arrangement (face ordering plus orientation for each face).
9456
9457 See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement
9458
9459 .seealso: [](ch_dmbase), `DM`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()`
9460 @*/
DMPolytopeMatchOrientation(DMPolytopeType ct,const PetscInt sourceCone[],const PetscInt targetCone[],PetscInt * ornt,PetscBool * found)9461 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
9462 {
9463 const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
9464 const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2;
9465 PetscInt o, c;
9466
9467 PetscFunctionBegin;
9468 if (!nO) {
9469 *ornt = 0;
9470 *found = PETSC_TRUE;
9471 PetscFunctionReturn(PETSC_SUCCESS);
9472 }
9473 for (o = -nO; o < nO; ++o) {
9474 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o);
9475
9476 for (c = 0; c < cS; ++c)
9477 if (sourceCone[arr[c * 2]] != targetCone[c]) break;
9478 if (c == cS) {
9479 *ornt = o;
9480 break;
9481 }
9482 }
9483 *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9484 PetscFunctionReturn(PETSC_SUCCESS);
9485 }
9486
9487 /*@
9488 DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9489
9490 Not Collective
9491
9492 Input Parameters:
9493 + ct - The `DMPolytopeType`
9494 . sourceCone - The source arrangement of faces
9495 - targetCone - The target arrangement of faces
9496
9497 Output Parameter:
9498 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
9499
9500 Level: advanced
9501
9502 Note:
9503 This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found.
9504
9505 Developer Note:
9506 It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found
9507
9508 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()`
9509 @*/
DMPolytopeGetOrientation(DMPolytopeType ct,const PetscInt sourceCone[],const PetscInt targetCone[],PetscInt * ornt)9510 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9511 {
9512 PetscBool found;
9513
9514 PetscFunctionBegin;
9515 PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found));
9516 PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9517 PetscFunctionReturn(PETSC_SUCCESS);
9518 }
9519
9520 /*@
9521 DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9522
9523 Not Collective
9524
9525 Input Parameters:
9526 + ct - The `DMPolytopeType`
9527 . sourceVert - The source arrangement of vertices
9528 - targetVert - The target arrangement of vertices
9529
9530 Output Parameters:
9531 + ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
9532 - found - Flag indicating that a suitable orientation was found
9533
9534 Level: advanced
9535
9536 Notes:
9537 An arrangement is a vertex order
9538
9539 Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2
9540 that labels each arrangement (vertex ordering).
9541
9542 See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement
9543
9544 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangement()`
9545 @*/
DMPolytopeMatchVertexOrientation(DMPolytopeType ct,const PetscInt sourceVert[],const PetscInt targetVert[],PetscInt * ornt,PetscBool * found)9546 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
9547 {
9548 const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
9549 const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2;
9550 PetscInt o, c;
9551
9552 PetscFunctionBegin;
9553 if (!nO) {
9554 *ornt = 0;
9555 *found = PETSC_TRUE;
9556 PetscFunctionReturn(PETSC_SUCCESS);
9557 }
9558 for (o = -nO; o < nO; ++o) {
9559 const PetscInt *arr = DMPolytopeTypeGetVertexArrangement(ct, o);
9560
9561 for (c = 0; c < cS; ++c)
9562 if (sourceVert[arr[c]] != targetVert[c]) break;
9563 if (c == cS) {
9564 *ornt = o;
9565 break;
9566 }
9567 }
9568 *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9569 PetscFunctionReturn(PETSC_SUCCESS);
9570 }
9571
9572 /*@
9573 DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9574
9575 Not Collective
9576
9577 Input Parameters:
9578 + ct - The `DMPolytopeType`
9579 . sourceCone - The source arrangement of vertices
9580 - targetCone - The target arrangement of vertices
9581
9582 Output Parameter:
9583 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
9584
9585 Level: advanced
9586
9587 Note:
9588 This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible.
9589
9590 Developer Note:
9591 It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found
9592
9593 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()`
9594 @*/
DMPolytopeGetVertexOrientation(DMPolytopeType ct,const PetscInt sourceCone[],const PetscInt targetCone[],PetscInt * ornt)9595 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9596 {
9597 PetscBool found;
9598
9599 PetscFunctionBegin;
9600 PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found));
9601 PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9602 PetscFunctionReturn(PETSC_SUCCESS);
9603 }
9604
9605 /*@
9606 DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type
9607
9608 Not Collective
9609
9610 Input Parameters:
9611 + ct - The `DMPolytopeType`
9612 - point - Coordinates of the point
9613
9614 Output Parameter:
9615 . inside - Flag indicating whether the point is inside the reference cell of given type
9616
9617 Level: advanced
9618
9619 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMLocatePoints()`
9620 @*/
DMPolytopeInCellTest(DMPolytopeType ct,const PetscReal point[],PetscBool * inside)9621 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
9622 {
9623 PetscReal sum = 0.0;
9624 PetscInt d;
9625
9626 PetscFunctionBegin;
9627 *inside = PETSC_TRUE;
9628 switch (ct) {
9629 case DM_POLYTOPE_TRIANGLE:
9630 case DM_POLYTOPE_TETRAHEDRON:
9631 for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
9632 if (point[d] < -1.0) {
9633 *inside = PETSC_FALSE;
9634 break;
9635 }
9636 sum += point[d];
9637 }
9638 if (sum > PETSC_SMALL) {
9639 *inside = PETSC_FALSE;
9640 break;
9641 }
9642 break;
9643 case DM_POLYTOPE_QUADRILATERAL:
9644 case DM_POLYTOPE_HEXAHEDRON:
9645 for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
9646 if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) {
9647 *inside = PETSC_FALSE;
9648 break;
9649 }
9650 break;
9651 default:
9652 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
9653 }
9654 PetscFunctionReturn(PETSC_SUCCESS);
9655 }
9656
9657 /*@
9658 DMReorderSectionSetDefault - Set flag indicating whether the local section should be reordered by default
9659
9660 Logically collective
9661
9662 Input Parameters:
9663 + dm - The DM
9664 - reorder - Flag for reordering
9665
9666 Level: intermediate
9667
9668 .seealso: `DMReorderSectionGetDefault()`
9669 @*/
DMReorderSectionSetDefault(DM dm,DMReorderDefaultFlag reorder)9670 PetscErrorCode DMReorderSectionSetDefault(DM dm, DMReorderDefaultFlag reorder)
9671 {
9672 PetscFunctionBegin;
9673 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9674 PetscTryMethod(dm, "DMReorderSectionSetDefault_C", (DM, DMReorderDefaultFlag), (dm, reorder));
9675 PetscFunctionReturn(PETSC_SUCCESS);
9676 }
9677
9678 /*@
9679 DMReorderSectionGetDefault - Get flag indicating whether the local section should be reordered by default
9680
9681 Not collective
9682
9683 Input Parameter:
9684 . dm - The DM
9685
9686 Output Parameter:
9687 . reorder - Flag for reordering
9688
9689 Level: intermediate
9690
9691 .seealso: `DMReorderSetDefault()`
9692 @*/
DMReorderSectionGetDefault(DM dm,DMReorderDefaultFlag * reorder)9693 PetscErrorCode DMReorderSectionGetDefault(DM dm, DMReorderDefaultFlag *reorder)
9694 {
9695 PetscFunctionBegin;
9696 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9697 PetscAssertPointer(reorder, 2);
9698 *reorder = DM_REORDER_DEFAULT_NOTSET;
9699 PetscTryMethod(dm, "DMReorderSectionGetDefault_C", (DM, DMReorderDefaultFlag *), (dm, reorder));
9700 PetscFunctionReturn(PETSC_SUCCESS);
9701 }
9702
9703 /*@
9704 DMReorderSectionSetType - Set the type of local section reordering
9705
9706 Logically collective
9707
9708 Input Parameters:
9709 + dm - The DM
9710 - reorder - The reordering method
9711
9712 Level: intermediate
9713
9714 .seealso: `DMReorderSectionGetType()`, `DMReorderSectionSetDefault()`
9715 @*/
DMReorderSectionSetType(DM dm,MatOrderingType reorder)9716 PetscErrorCode DMReorderSectionSetType(DM dm, MatOrderingType reorder)
9717 {
9718 PetscFunctionBegin;
9719 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9720 PetscTryMethod(dm, "DMReorderSectionSetType_C", (DM, MatOrderingType), (dm, reorder));
9721 PetscFunctionReturn(PETSC_SUCCESS);
9722 }
9723
9724 /*@
9725 DMReorderSectionGetType - Get the reordering type for the local section
9726
9727 Not collective
9728
9729 Input Parameter:
9730 . dm - The DM
9731
9732 Output Parameter:
9733 . reorder - The reordering method
9734
9735 Level: intermediate
9736
9737 .seealso: `DMReorderSetDefault()`, `DMReorderSectionGetDefault()`
9738 @*/
DMReorderSectionGetType(DM dm,MatOrderingType * reorder)9739 PetscErrorCode DMReorderSectionGetType(DM dm, MatOrderingType *reorder)
9740 {
9741 PetscFunctionBegin;
9742 PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9743 PetscAssertPointer(reorder, 2);
9744 *reorder = NULL;
9745 PetscTryMethod(dm, "DMReorderSectionGetType_C", (DM, MatOrderingType *), (dm, reorder));
9746 PetscFunctionReturn(PETSC_SUCCESS);
9747 }
9748