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