Actual source code: dmmbmg.cxx
1: #include <petsc/private/dmmbimpl.h>
2: #include <petscdmmoab.h>
3: #include <MBTagConventions.hpp>
4: #include <moab/NestedRefine.hpp>
6: // A helper function to convert Real vector to Scalar vector (required by MatSetValues)
7: static inline std::vector<PetscScalar> VecReal_to_VecScalar(const std::vector<PetscReal> &v)
8: {
9: std::vector<PetscScalar> res(v.size());
10: for (size_t i = 0; i < res.size(); i++) res[i] = v[i];
11: return res;
12: }
14: /*@C
15: DMMoabGenerateHierarchy - Generate a multi-level uniform refinement hierarchy
16: by succesively refining a coarse mesh, already defined in the `DM` object
17: provided by the user.
19: Collective
21: Input Parameter:
22: . dm - The `DMMOAB` object
24: Output Parameters:
25: + nlevels - The number of levels of refinement needed to generate the hierarchy
26: - ldegrees - The degree of refinement at each level in the hierarchy
28: Level: beginner
30: .seealso: `DMMoabCreate()`
31: @*/
32: PetscErrorCode DMMoabGenerateHierarchy(DM dm, PetscInt nlevels, PetscInt *ldegrees)
33: {
34: DM_Moab *dmmoab;
35: PetscInt *pdegrees, ilevel;
36: std::vector<moab::EntityHandle> hsets;
38: PetscFunctionBegin;
40: dmmoab = (DM_Moab *)dm->data;
42: if (!ldegrees) {
43: PetscCall(PetscMalloc1(nlevels, &pdegrees));
44: for (ilevel = 0; ilevel < nlevels; ilevel++) pdegrees[ilevel] = 2; /* default = Degree 2 refinement */
45: } else pdegrees = ldegrees;
47: /* initialize set level refinement data for hierarchy */
48: dmmoab->nhlevels = nlevels;
50: /* Instantiate the nested refinement class */
51: #ifdef MOAB_HAVE_MPI
52: dmmoab->hierarchy = new moab::NestedRefine(dynamic_cast<moab::Core *>(dmmoab->mbiface), dmmoab->pcomm, dmmoab->fileset);
53: #else
54: dmmoab->hierarchy = new moab::NestedRefine(dynamic_cast<moab::Core *>(dmmoab->mbiface), NULL, dmmoab->fileset);
55: #endif
57: PetscCall(PetscMalloc1(nlevels + 1, &dmmoab->hsets));
59: /* generate the mesh hierarchy */
60: PetscCallMOAB(dmmoab->hierarchy->generate_mesh_hierarchy(nlevels, pdegrees, hsets, false));
62: #ifdef MOAB_HAVE_MPI
63: if (dmmoab->pcomm->size() > 1) PetscCallMOAB(dmmoab->hierarchy->exchange_ghosts(hsets, dmmoab->nghostrings));
64: #endif
66: /* copy the mesh sets for nested refinement hierarchy */
67: dmmoab->hsets[0] = hsets[0];
68: for (ilevel = 1; ilevel <= nlevels; ilevel++) {
69: dmmoab->hsets[ilevel] = hsets[ilevel];
71: #ifdef MOAB_HAVE_MPI
72: PetscCallMOAB(dmmoab->pcomm->assign_global_ids(hsets[ilevel], dmmoab->dim, 0, false, true, false));
73: #endif
75: /* Update material and other geometric tags from parent to child sets */
76: PetscCallMOAB(dmmoab->hierarchy->update_special_tags(ilevel, hsets[ilevel]));
77: }
79: hsets.clear();
80: if (!ldegrees) PetscCall(PetscFree(pdegrees));
81: PetscFunctionReturn(PETSC_SUCCESS);
82: }
84: // PetscClangLinter pragma ignore: -fdoc-*
85: /*
86: DMRefineHierarchy_Moab - Generate a multi-level `DM` hierarchy
87: by succesively refining a coarse mesh.
89: Collective
91: Input Parameter:
92: . dm - The `DMMOAB` object
94: Output Parameters:
95: + nlevels - The number of levels of refinement needed to generate the hierarchy
96: - dmf - The DM objects after successive refinement of the hierarchy
98: Level: beginner
99: */
100: PETSC_INTERN PetscErrorCode DMRefineHierarchy_Moab(DM dm, PetscInt nlevels, DM dmf[])
101: {
102: PetscInt i;
104: PetscFunctionBegin;
105: PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &dmf[0]));
106: for (i = 1; i < nlevels; i++) PetscCall(DMRefine(dmf[i - 1], PetscObjectComm((PetscObject)dm), &dmf[i]));
107: PetscFunctionReturn(PETSC_SUCCESS);
108: }
110: // PetscClangLinter pragma ignore: -fdoc-*
111: /*
112: DMCoarsenHierarchy_Moab - Generate a multi-level `DM` hierarchy
113: by succesively coarsening a refined mesh.
115: Collective
117: Input Parameter:
118: . dm - The `DMMOAB` object
120: Output Parameters:
121: + nlevels - The number of levels of refinement needed to generate the hierarchy
122: - dmc - The `DM` objects after successive coarsening of the hierarchy
124: Level: beginner
125: */
126: PETSC_INTERN PetscErrorCode DMCoarsenHierarchy_Moab(DM dm, PetscInt nlevels, DM dmc[])
127: {
128: PetscInt i;
130: PetscFunctionBegin;
131: PetscCall(DMCoarsen(dm, PetscObjectComm((PetscObject)dm), &dmc[0]));
132: for (i = 1; i < nlevels; i++) PetscCall(DMCoarsen(dmc[i - 1], PetscObjectComm((PetscObject)dm), &dmc[i]));
133: PetscFunctionReturn(PETSC_SUCCESS);
134: }
136: PETSC_INTERN PetscErrorCode DMMoab_Compute_NNZ_From_Connectivity(DM, PetscInt *, PetscInt *, PetscInt *, PetscInt *, PetscBool);
138: // PetscClangLinter pragma ignore: -fdoc-*
139: /*
140: DMCreateInterpolation_Moab - Generate the interpolation operators to transform
141: operators (matrices, vectors) from parent level to child level as defined by
142: the `DM` inputs provided by the user.
144: Collective
146: Input Parameters:
147: + dmp - The `DMMOAB` object
148: - dmc - the second, finer `DMMOAB` object
150: Output Parameters:
151: + interpl - The interpolation operator for transferring data between the levels
152: - vec - The scaling vector (optional)
154: Level: developer
155: */
156: PETSC_INTERN PetscErrorCode DMCreateInterpolation_Moab(DM dmp, DM dmc, Mat *interpl, Vec *vec)
157: {
158: DM_Moab *dmbp, *dmbc;
159: PetscInt dim;
160: PetscReal factor;
161: PetscInt innz, *nnz, ionz, *onz;
162: PetscInt nlsizp, nlsizc, nlghsizp, ngsizp, ngsizc;
163: const PetscBool use_consistent_bases = PETSC_TRUE;
165: PetscFunctionBegin;
168: dmbp = (DM_Moab *)dmp->data;
169: dmbc = (DM_Moab *)dmc->data;
170: nlsizp = dmbp->nloc; // *dmb1->numFields;
171: nlsizc = dmbc->nloc; // *dmb2->numFields;
172: ngsizp = dmbp->n; // *dmb1->numFields;
173: ngsizc = dmbc->n; // *dmb2->numFields;
174: nlghsizp = (dmbp->nloc + dmbp->nghost); // *dmb1->numFields;
176: // Columns = Parent DoFs ; Rows = Child DoFs
177: // Interpolation matrix: \sum_{i=1}^P Owned(Child) * (Owned(Parent) + Ghosted(Parent))
178: // Size: nlsizc * nlghsizp
179: PetscCall(PetscInfo(NULL, "Creating interpolation matrix %" PetscInt_FMT " X %" PetscInt_FMT " to apply transformation between levels %" PetscInt_FMT " -> %" PetscInt_FMT ".\n", ngsizc, nlghsizp, dmbp->hlevel, dmbc->hlevel));
181: PetscCall(DMGetDimension(dmp, &dim));
183: /* allocate the nnz, onz arrays based on block size and local nodes */
184: PetscCall(PetscCalloc2(nlsizc, &nnz, nlsizc, &onz));
186: /* Loop through the local elements and compute the relation between the current parent and the refined_level. */
187: for (moab::Range::iterator iter = dmbc->vowned->begin(); iter != dmbc->vowned->end(); iter++) {
188: const moab::EntityHandle vhandle = *iter;
189: /* define local variables */
190: moab::EntityHandle parent;
191: std::vector<moab::EntityHandle> adjs;
192: moab::Range found;
194: /* store the vertex DoF number */
195: const int ldof = dmbc->lidmap[vhandle - dmbc->seqstart];
197: /* Get adjacency information for current vertex - i.e., all elements of dimension (dim) that connects
198: to the current vertex. We can then decipher if a vertex is ghosted or not and compute the
199: non-zero pattern accordingly. */
200: PetscCallMOAB(dmbc->hierarchy->get_adjacencies(vhandle, dmbc->dim, adjs));
202: /* loop over vertices and update the number of connectivity */
203: for (unsigned jter = 0; jter < adjs.size(); jter++) {
204: const moab::EntityHandle jhandle = adjs[jter];
206: /* Get the relation between the current (coarse) parent and its corresponding (finer) children elements */
207: PetscCallMOAB(dmbc->hierarchy->child_to_parent(jhandle, dmbc->hlevel, dmbp->hlevel, &parent));
209: /* Get connectivity information in canonical ordering for the local element */
210: std::vector<moab::EntityHandle> connp;
211: PetscCallMOAB(dmbp->hierarchy->get_connectivity(parent, dmbp->hlevel, connp));
213: for (unsigned ic = 0; ic < connp.size(); ++ic) {
214: /* loop over each element connected to the adjacent vertex and update as needed */
215: /* find the truly user-expected layer of ghosted entities to decipher NNZ pattern */
216: if (found.find(connp[ic]) != found.end()) continue; /* make sure we don't double count shared vertices */
217: if (dmbp->vghost->find(connp[ic]) != dmbp->vghost->end()) onz[ldof]++; /* update out-of-proc onz */
218: else nnz[ldof]++; /* else local vertex */
219: found.insert(connp[ic]);
220: }
221: }
222: }
224: for (int i = 0; i < nlsizc; i++) nnz[i] += 1; /* self count the node */
226: ionz = onz[0];
227: innz = nnz[0];
228: for (int tc = 0; tc < nlsizc; tc++) {
229: // check for maximum allowed sparsity = fully dense
230: nnz[tc] = std::min(nlsizp, nnz[tc]);
231: onz[tc] = std::min(ngsizp - nlsizp, onz[tc]);
233: PetscCall(PetscInfo(NULL, " %d: NNZ = %d, ONZ = %d\n", tc, nnz[tc], onz[tc]));
235: innz = (innz < nnz[tc] ? nnz[tc] : innz);
236: ionz = (ionz < onz[tc] ? onz[tc] : ionz);
237: }
239: /* create interpolation matrix */
240: PetscCall(MatCreate(PetscObjectComm((PetscObject)dmc), interpl));
241: PetscCall(MatSetSizes(*interpl, nlsizc, nlsizp, ngsizc, ngsizp));
242: PetscCall(MatSetType(*interpl, MATAIJ));
243: PetscCall(MatSetFromOptions(*interpl));
245: PetscCall(MatSeqAIJSetPreallocation(*interpl, innz, nnz));
246: PetscCall(MatMPIAIJSetPreallocation(*interpl, innz, nnz, ionz, onz));
248: /* clean up temporary memory */
249: PetscCall(PetscFree2(nnz, onz));
251: /* set up internal matrix data-structures */
252: PetscCall(MatSetUp(*interpl));
254: /* Define variables for assembly */
255: std::vector<moab::EntityHandle> children;
256: std::vector<moab::EntityHandle> connp, connc;
257: std::vector<PetscReal> pcoords, ccoords, values_phi;
258: std::vector<PetscScalar> values_phi_scalar;
260: if (use_consistent_bases) {
261: const moab::EntityHandle ehandle = dmbp->elocal->front();
263: PetscCallMOAB(dmbp->hierarchy->parent_to_child(ehandle, dmbp->hlevel, dmbc->hlevel, children));
265: /* Get connectivity and coordinates of the parent vertices */
266: PetscCallMOAB(dmbp->hierarchy->get_connectivity(ehandle, dmbp->hlevel, connp));
267: PetscCallMOAB(dmbc->mbiface->get_connectivity(&children[0], children.size(), connc));
269: std::vector<PetscReal> natparam(3 * connc.size(), 0.0);
270: pcoords.resize(connp.size() * 3);
271: ccoords.resize(connc.size() * 3);
272: values_phi.resize(connp.size() * connc.size());
273: /* Get coordinates for connectivity entities in canonical order for both coarse and finer levels */
274: PetscCallMOAB(dmbp->hierarchy->get_coordinates(&connp[0], connp.size(), dmbp->hlevel, &pcoords[0]));
275: PetscCallMOAB(dmbc->hierarchy->get_coordinates(&connc[0], connc.size(), dmbc->hlevel, &ccoords[0]));
277: /* Set values: For each DOF in coarse grid cell, set the contribution or PHI evaluated at each fine grid DOF point */
278: for (unsigned tc = 0; tc < connc.size(); tc++) {
279: const PetscInt offset = tc * 3;
281: /* Scale ccoords relative to pcoords */
282: PetscCall(DMMoabPToRMapping(dim, connp.size(), &pcoords[0], &ccoords[offset], &natparam[offset], &values_phi[connp.size() * tc]));
283: }
284: } else {
285: factor = std::pow(2.0 /*degree_P_for_refinement*/, (dmbc->hlevel - dmbp->hlevel) * dmbp->dim * 1.0);
286: }
288: /* TODO: Decipher the correct non-zero pattern. There is still some issue with onz allocation */
289: PetscCall(MatSetOption(*interpl, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
291: /* Loop through the remaining vertices. These vertices appear only on the current refined_level. */
292: values_phi_scalar = VecReal_to_VecScalar(values_phi);
293: for (moab::Range::iterator iter = dmbp->elocal->begin(); iter != dmbp->elocal->end(); iter++) {
294: const moab::EntityHandle ehandle = *iter;
296: /* Get the relation between the current (coarse) parent and its corresponding (finer) children elements */
297: children.clear();
298: connc.clear();
299: PetscCallMOAB(dmbp->hierarchy->parent_to_child(ehandle, dmbp->hlevel, dmbc->hlevel, children));
301: /* Get connectivity and coordinates of the parent vertices */
302: PetscCallMOAB(dmbp->hierarchy->get_connectivity(ehandle, dmbp->hlevel, connp));
303: PetscCallMOAB(dmbc->mbiface->get_connectivity(&children[0], children.size(), connc));
305: pcoords.resize(connp.size() * 3);
306: ccoords.resize(connc.size() * 3);
307: /* Get coordinates for connectivity entities in canonical order for both coarse and finer levels */
308: PetscCallMOAB(dmbp->hierarchy->get_coordinates(&connp[0], connp.size(), dmbp->hlevel, &pcoords[0]));
309: PetscCallMOAB(dmbc->hierarchy->get_coordinates(&connc[0], connc.size(), dmbc->hlevel, &ccoords[0]));
311: std::vector<int> dofsp(connp.size()), dofsc(connc.size());
312: /* TODO: specific to scalar system - use GetDofs */
313: PetscCall(DMMoabGetDofsBlocked(dmp, connp.size(), &connp[0], &dofsp[0]));
314: PetscCall(DMMoabGetDofsBlocked(dmc, connc.size(), &connc[0], &dofsc[0]));
316: /* Compute the actual interpolation weights when projecting solution/residual between levels */
317: if (use_consistent_bases) {
318: /* Use the cached values of natural parametric coordinates and basis pre-evaluated.
319: We are making an assumption here that UMR used in GMG to generate the hierarchy uses
320: the same template for all elements; This will fail for mixed element meshes (TRI/QUAD).
322: TODO: Fix the above assumption by caching data for families (especially for Tets and mixed meshes)
323: */
325: /* Set values: For each DOF in coarse grid cell, set the contribution or PHI evaluated at each fine grid DOF point */
326: for (unsigned tc = 0; tc < connc.size(); tc++) {
327: /* TODO: Check if we should be using INSERT_VALUES instead */
328: PetscCall(MatSetValues(*interpl, 1, &dofsc[tc], connp.size(), &dofsp[0], &values_phi_scalar[connp.size() * tc], ADD_VALUES));
329: }
330: } else {
331: /* Compute the interpolation weights by determining distance of 1-ring
332: neighbor vertices from current vertex
334: This should be used only when FEM basis is not used for the discretization.
335: Else, the consistent interface to compute the basis function for interpolation
336: between the levels should be evaluated correctly to preserve convergence of GMG.
337: Shephard's basis will be terrible for any unsmooth problems.
338: */
339: values_phi.resize(connp.size());
340: for (unsigned tc = 0; tc < connc.size(); tc++) {
341: PetscReal normsum = 0.0;
342: std::vector<PetscScalar> values_phi_scalar2;
343: for (unsigned tp = 0; tp < connp.size(); tp++) {
344: values_phi[tp] = 0.0;
345: for (unsigned k = 0; k < 3; k++) values_phi[tp] += std::pow(pcoords[tp * 3 + k] - ccoords[k + tc * 3], dim);
346: if (values_phi[tp] < 1e-12) {
347: values_phi[tp] = 1e12;
348: } else {
349: //values_phi[tp] = std::pow(values_phi[tp], -1.0/dim);
350: values_phi[tp] = std::pow(values_phi[tp], -1.0);
351: normsum += values_phi[tp];
352: }
353: }
354: for (unsigned tp = 0; tp < connp.size(); tp++) {
355: if (values_phi[tp] > 1e11) values_phi[tp] = factor * 0.5 / connp.size();
356: else values_phi[tp] = factor * values_phi[tp] * 0.5 / (connp.size() * normsum);
357: }
358: values_phi_scalar2 = VecReal_to_VecScalar(values_phi);
359: PetscCall(MatSetValues(*interpl, 1, &dofsc[tc], connp.size(), &dofsp[0], &values_phi_scalar2[0], ADD_VALUES));
360: }
361: }
362: }
363: if (vec) *vec = NULL; // TODO: <-- is it safe/appropriate?
364: PetscCall(MatAssemblyBegin(*interpl, MAT_FINAL_ASSEMBLY));
365: PetscCall(MatAssemblyEnd(*interpl, MAT_FINAL_ASSEMBLY));
366: PetscFunctionReturn(PETSC_SUCCESS);
367: }
369: // PetscClangLinter pragma ignore: -fdoc-*
370: /*
371: DMCreateInjection_Moab - Generate a multi-level uniform refinement hierarchy
372: by succesively refining a coarse mesh, already defined in the `DM` object
373: provided by the user.
375: Collective
377: Input Parameter:
378: . dmb - The `DMMOAB` object
380: Output Parameters:
381: + nlevels - The number of levels of refinement needed to generate the hierarchy
382: - ldegrees - The degree of refinement at each level in the hierarchy
384: Level: beginner
385: */
386: PETSC_INTERN PetscErrorCode DMCreateInjection_Moab(DM dm1, DM dm2, VecScatter *ctx)
387: {
388: PetscFunctionBegin;
391: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "[DMCreateInjection_Moab] :: Placeholder\n"));
392: PetscFunctionReturn(PETSC_SUCCESS);
393: }
395: static PetscErrorCode DMMoab_UMR_Private(DM dm, MPI_Comm comm, PetscBool refine, DM *dmref)
396: {
397: PetscInt i, dim;
398: DM dm2;
399: DM_Moab *dmb = (DM_Moab *)dm->data, *dd2;
401: PetscFunctionBegin;
403: PetscAssertPointer(dmref, 4);
405: if ((dmb->hlevel == dmb->nhlevels && refine) || (dmb->hlevel == 0 && !refine)) {
406: if (dmb->hlevel + 1 > dmb->nhlevels && refine) {
407: PetscCall(PetscInfo(NULL, "Invalid multigrid refinement hierarchy level specified (%" PetscInt_FMT "). MOAB UMR max levels = %" PetscInt_FMT ". Creating a NULL object.\n", dmb->hlevel + 1, dmb->nhlevels));
408: }
409: if (dmb->hlevel - 1 < 0 && !refine) PetscCall(PetscInfo(NULL, "Invalid multigrid coarsen hierarchy level specified (%" PetscInt_FMT "). Creating a NULL object.\n", dmb->hlevel - 1));
410: *dmref = NULL;
411: PetscFunctionReturn(PETSC_SUCCESS);
412: }
414: PetscCall(DMMoabCreate(PetscObjectComm((PetscObject)dm), &dm2));
415: dd2 = (DM_Moab *)dm2->data;
417: dd2->mbiface = dmb->mbiface;
418: #ifdef MOAB_HAVE_MPI
419: dd2->pcomm = dmb->pcomm;
420: #endif
421: dd2->icreatedinstance = PETSC_FALSE;
422: dd2->nghostrings = dmb->nghostrings;
424: /* set the new level based on refinement/coarsening */
425: if (refine) {
426: dd2->hlevel = dmb->hlevel + 1;
427: } else {
428: dd2->hlevel = dmb->hlevel - 1;
429: }
431: /* Copy the multilevel hierarchy pointers in MOAB */
432: dd2->hierarchy = dmb->hierarchy;
433: dd2->nhlevels = dmb->nhlevels;
434: PetscCall(PetscMalloc1(dd2->nhlevels + 1, &dd2->hsets));
435: for (i = 0; i <= dd2->nhlevels; i++) dd2->hsets[i] = dmb->hsets[i];
436: dd2->fileset = dd2->hsets[dd2->hlevel];
438: /* do the remaining initializations for DMMoab */
439: dd2->bs = dmb->bs;
440: dd2->numFields = dmb->numFields;
441: dd2->rw_dbglevel = dmb->rw_dbglevel;
442: dd2->partition_by_rank = dmb->partition_by_rank;
443: PetscCall(PetscStrncpy(dd2->extra_read_options, dmb->extra_read_options, sizeof(dd2->extra_read_options)));
444: PetscCall(PetscStrncpy(dd2->extra_write_options, dmb->extra_write_options, sizeof(dd2->extra_write_options)));
445: dd2->read_mode = dmb->read_mode;
446: dd2->write_mode = dmb->write_mode;
448: /* set global ID tag handle */
449: PetscCall(DMMoabSetLocalToGlobalTag(dm2, dmb->ltog_tag));
451: PetscCallMOAB(dd2->mbiface->tag_get_handle(MATERIAL_SET_TAG_NAME, dd2->material_tag));
453: PetscCall(DMSetOptionsPrefix(dm2, ((PetscObject)dm)->prefix));
454: PetscCall(DMGetDimension(dm, &dim));
455: PetscCall(DMSetDimension(dm2, dim));
457: /* allow overloaded (user replaced) operations to be inherited by refinement clones */
458: dm2->ops->creatematrix = dm->ops->creatematrix;
460: /* copy fill information if given */
461: PetscCall(DMMoabSetBlockFills(dm2, dmb->dfill, dmb->ofill));
463: /* copy vector type information */
464: PetscCall(DMSetMatType(dm2, dm->mattype));
465: PetscCall(DMSetVecType(dm2, dm->vectype));
466: dd2->numFields = dmb->numFields;
467: if (dmb->numFields) PetscCall(DMMoabSetFieldNames(dm2, dmb->numFields, dmb->fieldNames));
469: PetscCall(DMSetFromOptions(dm2));
471: /* recreate Dof numbering for the refined DM and make sure the distribution is correctly populated */
472: PetscCall(DMSetUp(dm2));
474: *dmref = dm2;
475: PetscFunctionReturn(PETSC_SUCCESS);
476: }
478: // PetscClangLinter pragma ignore: -fdoc-*
479: /*
480: DMRefine_Moab - Generate a multi-level uniform refinement hierarchy
481: by succesively refining a coarse mesh, already defined in the `DM` object
482: provided by the user.
484: Collective
486: Input Parameters:
487: + dm - The `DMMOAB` object
488: - comm - the communicator to contain the new DM object (or `MPI_COMM_NULL`)
490: Output Parameter:
491: . dmf - the refined `DM`, or `NULL`
493: Level: developer
495: Note:
496: If no refinement was done, the return value is `NULL`
497: */
498: PETSC_INTERN PetscErrorCode DMRefine_Moab(DM dm, MPI_Comm comm, DM *dmf)
499: {
500: PetscFunctionBegin;
503: PetscCall(DMMoab_UMR_Private(dm, comm, PETSC_TRUE, dmf));
504: PetscFunctionReturn(PETSC_SUCCESS);
505: }
507: // PetscClangLinter pragma ignore: -fdoc-*
508: /*
509: DMCoarsen_Moab - Generate a multi-level uniform refinement hierarchy
510: by succesively refining a coarse mesh, already defined in the `DM` object
511: provided by the user.
513: Collective
515: Input Parameters:
516: + dm - The `DMMOAB` object
517: - comm - the communicator to contain the new `DM` object (or `MPI_COMM_NULL`)
519: Output Parameter:
520: . dmc - the coarsened `DM`, or `NULL`
522: Level: developer
524: Note:
525: If no coarsening was done, the return value is `NULL`
526: */
527: PETSC_INTERN PetscErrorCode DMCoarsen_Moab(DM dm, MPI_Comm comm, DM *dmc)
528: {
529: PetscFunctionBegin;
531: PetscCall(DMMoab_UMR_Private(dm, comm, PETSC_FALSE, dmc));
532: PetscFunctionReturn(PETSC_SUCCESS);
533: }