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