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