1 // Copyright (c) 2017-2021, Lawrence Livermore National Security, LLC and
2 // other Axom Project Developers. See the top-level LICENSE file for details.
3 //
4 // SPDX-License-Identifier: (BSD-3-Clause)
5 #include "axom/mint/mesh/blueprint.hpp"
6 
7 // Axom includes
8 #include "axom/core/Types.hpp"  // for nullptr
9 
10 // Mint includes
11 #include "axom/mint/config.hpp"          // for AXOM_MINT_USE_SIDRE
12 #include "axom/mint/mesh/MeshTypes.hpp"  // for mesh types
13 
14 // Slic includes
15 #include "axom/slic/interface/slic.hpp"  // for SLIC macros
16 
17 #ifdef AXOM_MINT_USE_SIDRE
18   #include "axom/sidre/core/Group.hpp"  // for sidre::Group
19   #include "axom/sidre/core/View.hpp"   // for sidre::View
20 #endif
21 
22 namespace axom
23 {
24 namespace mint
25 {
26 namespace blueprint
27 {
28 #ifdef AXOM_MINT_USE_SIDRE
29 
30 //------------------------------------------------------------------------------
isValidRootGroup(const sidre::Group * group)31 bool isValidRootGroup(const sidre::Group* group)
32 {
33   if(group == nullptr)
34   {
35     SLIC_WARNING("supplied group is NULL!");
36     return false;
37   }
38 
39   const bool hasCoordsets = group->hasChildGroup("coordsets");
40   const bool hasTopologies = group->hasChildGroup("topologies");
41   const bool hasFields = group->hasChildGroup("fields");
42 
43   SLIC_WARNING_IF(
44     !hasCoordsets,
45     "sidre::Group " << group->getPathName() << " is missing coordsets group!");
46   SLIC_WARNING_IF(
47     !hasTopologies,
48     "sidre::Group " << group->getPathName() << " is missing topologies group!");
49   SLIC_WARNING_IF(
50     !hasFields,
51     "sidre::Group " << group->getPathName() << " is missing fields group!");
52 
53   return ((hasCoordsets && hasTopologies && hasFields));
54 }
55 
56 //------------------------------------------------------------------------------
isValidTopologyGroup(const sidre::Group * topo)57 bool isValidTopologyGroup(const sidre::Group* topo)
58 {
59   if(topo == nullptr)
60   {
61     SLIC_WARNING("supplied topology group is NULL!");
62     return false;
63   }
64 
65   const std::string path = topo->getPathName();
66 
67   const bool hasTypeView = topo->hasChildView("type");
68   SLIC_WARNING_IF(!hasTypeView, "[" << path << "] is missing 'type' view!");
69 
70   const bool isTypeAString =
71     (hasTypeView) ? topo->getView("type")->isString() : false;
72   SLIC_WARNING_IF(!isTypeAString,
73                   "'type' view in [" << path << "] is not a string");
74 
75   const bool hasCoordset = topo->hasChildView("coordset");
76   SLIC_WARNING_IF(!hasCoordset, "[" << path << "] is missing 'coordset' view!");
77 
78   const bool isCoordsetAString =
79     (hasCoordset) ? topo->getView("coordset")->isString() : false;
80   SLIC_WARNING_IF(!isCoordsetAString,
81                   "'coordset' view in [" << path << "] is not a string");
82 
83   const bool status =
84     hasTypeView && hasCoordset && isTypeAString && isCoordsetAString;
85 
86   return (status);
87 }
88 
89 //------------------------------------------------------------------------------
isValidCoordsetGroup(const sidre::Group * coordset)90 bool isValidCoordsetGroup(const sidre::Group* coordset)
91 {
92   if(coordset == nullptr)
93   {
94     SLIC_WARNING("supplied coordset group is NULL!");
95     return false;
96   }
97 
98   const std::string path = coordset->getPathName();
99 
100   const bool hasTypeView = coordset->hasChildView("type");
101   SLIC_WARNING_IF(!hasTypeView, "[" << path << "] is missing 'type' view!");
102 
103   const bool isTypeAString =
104     (hasTypeView) ? coordset->getView("type")->isString() : false;
105   SLIC_WARNING_IF(!isTypeAString,
106                   "'type' view in [" << path << "] is not a string");
107 
108   return (hasTypeView && isTypeAString);
109 }
110 
111 //------------------------------------------------------------------------------
getCoordsetGroup(const sidre::Group * group,const sidre::Group * topology)112 const sidre::Group* getCoordsetGroup(const sidre::Group* group,
113                                      const sidre::Group* topology)
114 {
115   SLIC_ERROR_IF(!blueprint::isValidRootGroup(group),
116                 "supplied group does not conform to the blueprint!");
117   SLIC_ERROR_IF(topology == nullptr, "supplied topology group is null!");
118   SLIC_ERROR_IF(!blueprint::isValidTopologyGroup(topology),
119                 "supplied topology group does not conform to the blueprint!");
120 
121   const sidre::Group* coordsets = group->getGroup("coordsets");
122 
123   const char* coordset_name = topology->getView("coordset")->getString();
124   SLIC_WARNING_IF(!coordsets->hasChildGroup(coordset_name),
125                   "cannot find coordset [" << coordset_name << "] in "
126                                            << coordsets->getPathName());
127 
128   const sidre::Group* coords = coordsets->getGroup(coordset_name);
129   SLIC_WARNING_IF(
130     coords == nullptr,
131     "null coordset [" << coordset_name << "] in " << coordsets->getPathName());
132 
133   return coords;
134 }
135 
136 //------------------------------------------------------------------------------
getCoordsetGroup(const sidre::Group * group,const std::string & coords)137 const sidre::Group* getCoordsetGroup(const sidre::Group* group,
138                                      const std::string& coords)
139 {
140   SLIC_ERROR_IF(!blueprint::isValidRootGroup(group),
141                 "supplied group does not conform to the blueprint!");
142 
143   const sidre::Group* coordsets = group->getGroup("coordsets");
144   const std::string path = coordsets->getPathName();
145 
146   // get coordset group
147   const sidre::Group* coordset = nullptr;
148   if(coords.empty())
149   {
150     SLIC_ERROR_IF(coordsets->getNumGroups() == 0,
151                   "[" << coordsets->getPathName() << "] is empty!");
152     SLIC_WARNING_IF(coordsets->getNumGroups() > 1,
153                     "multiple coordsets found!  ");
154     coordset = coordsets->getGroup(0);
155   }
156   else
157   {
158     SLIC_ERROR_IF(!coordsets->hasChildGroup(coords),
159                   "[" << path << "] is missing requested coordset group ["
160                       << coords << "]");
161 
162     coordset = coordsets->getGroup(coords);
163   }
164 
165   return (coordset);
166 }
167 
168 //------------------------------------------------------------------------------
getTopologyGroup(const sidre::Group * group,const std::string & topo)169 const sidre::Group* getTopologyGroup(const sidre::Group* group,
170                                      const std::string& topo)
171 {
172   SLIC_ERROR_IF(!blueprint::isValidRootGroup(group),
173                 "supplied group does not conform to the blueprint!");
174 
175   const sidre::Group* topologies = group->getGroup("topologies");
176   const std::string path = topologies->getPathName();
177 
178   // get topology group
179   const sidre::Group* topology = nullptr;
180   if(topo.empty())
181   {
182     SLIC_ERROR_IF(topologies->getNumGroups() == 0,
183                   "[" << topologies->getPathName() << "] is empty!");
184     SLIC_WARNING_IF(topologies->getNumGroups() > 1,
185                     "multiple topologies found!  ");
186     topology = topologies->getGroup(0);
187   }
188   else
189   {
190     SLIC_ERROR_IF(
191       !topologies->hasChildGroup(topo),
192       "[" << path << "] is missing requested topology group [" << topo << "]");
193 
194     topology = topologies->getGroup(topo);
195   }
196 
197   return (topology);
198 }
199 
200 //------------------------------------------------------------------------------
initializeTopologyGroup(sidre::Group * group,const std::string & topo,const std::string & coordset,const std::string & type)201 void initializeTopologyGroup(sidre::Group* group,
202                              const std::string& topo,
203                              const std::string& coordset,
204                              const std::string& type)
205 {
206   SLIC_ASSERT(group != nullptr);
207   sidre::Group* topo_group = group->getGroup("topologies");
208   SLIC_ASSERT(topo_group != nullptr);
209   sidre::Group* cur_topo = topo_group->getGroup(topo);
210   SLIC_ASSERT(cur_topo != nullptr);
211 
212   cur_topo->createView("type")->setString(type);
213   cur_topo->createView("coordset")->setString(coordset);
214 }
215 
216 //------------------------------------------------------------------------------
getMeshTypeAndDimension(int & mesh_type,int & dimension,const sidre::Group * group,const std::string & topo)217 void getMeshTypeAndDimension(int& mesh_type,
218                              int& dimension,
219                              const sidre::Group* group,
220                              const std::string& topo)
221 {
222   SLIC_ERROR_IF(!blueprint::isValidRootGroup(group),
223                 "supplied group does not conform to the blueprint!");
224 
225   const sidre::Group* topology = blueprint::getTopologyGroup(group, topo);
226   SLIC_ERROR_IF(!blueprint::isValidTopologyGroup(topology),
227                 "mesh topology does not conform to the blueprint!");
228 
229   const sidre::Group* coords = blueprint::getCoordsetGroup(group, topology);
230   SLIC_ERROR_IF(!blueprint::isValidCoordsetGroup(coords),
231                 "mesh coordset does not conform to the blueprint!");
232 
233   // get topology type
234   const char* topo_type = topology->getView("type")->getString();
235   SLIC_ASSERT(topo_type != nullptr);
236 
237   // detect mesh type based on the topology type
238   if(strcmp(topo_type, "uniform") == 0)
239   {
240     SLIC_ERROR_IF(!coords->hasChildGroup("origin"),
241                   "missing [origin] group from ["
242                     << coords->getPathName() << "], required for a uniform mesh");
243 
244     mesh_type = STRUCTURED_UNIFORM_MESH;
245     dimension = coords->getGroup("origin")->getNumViews();
246 
247   }  // END if UNIFORM MESH
248   else if(strcmp(topo_type, "rectilinear") == 0)
249   {
250     SLIC_ERROR_IF(!coords->hasChildGroup("values"),
251                   "missing [values] group from ["
252                     << coords->getPathName()
253                     << "], required for a rectilinear mesh");
254 
255     mesh_type = STRUCTURED_RECTILINEAR_MESH;
256     dimension = coords->getGroup("values")->getNumViews();
257 
258   }  // END if RECTILINEAR_MESH
259   else if(strcmp(topo_type, "structured") == 0)
260   {
261     SLIC_ERROR_IF(!coords->hasChildGroup("values"),
262                   "missing [values] group from ["
263                     << coords->getPathName()
264                     << "], required for a structured mesh");
265 
266     mesh_type = STRUCTURED_CURVILINEAR_MESH;
267     dimension = coords->getGroup("values")->getNumViews();
268 
269   }  // END if STRUCTURED_MESH
270   else if(strcmp(topo_type, "points") == 0)
271   {
272     SLIC_ERROR_IF(!coords->hasChildGroup("values"),
273                   "missing [values] group from ["
274                     << coords->getPathName()
275                     << "], required for a particle mesh");
276 
277     mesh_type = PARTICLE_MESH;
278     dimension = coords->getGroup("values")->getNumViews();
279 
280   }  // END if PARTICLE_MESH
281   else if(strcmp(topo_type, "unstructured") == 0)
282   {
283     SLIC_ERROR_IF(!coords->hasChildGroup("values"),
284                   "missing [values] group from ["
285                     << coords->getPathName()
286                     << "], required for a unstructured mesh");
287 
288     // check if this is a particle mesh stored as an unstructured mesh
289     const char* shape = topology->getView("elements/shape")->getString();
290     mesh_type = (strcmp(shape, "point") == 0) ? PARTICLE_MESH : UNSTRUCTURED_MESH;
291     dimension = coords->getGroup("values")->getNumViews();
292 
293   }  // END if UNSTRUCTURED_MESH
294   else
295   {
296     mesh_type = UNDEFINED_MESH;
297     dimension = -1;
298     SLIC_ERROR("invalid mesh topology_type=[" << topo_type << "] ");
299   }
300 }
301 
302 //------------------------------------------------------------------------------
hasMixedCellTypes(const sidre::Group * group,const std::string & topo)303 bool hasMixedCellTypes(const sidre::Group* group, const std::string& topo)
304 {
305   SLIC_ERROR_IF(!blueprint::isValidRootGroup(group),
306                 "supplied group does not conform to the blueprint!");
307 
308   const sidre::Group* topology = blueprint::getTopologyGroup(group, topo);
309   SLIC_ERROR_IF(!blueprint::isValidTopologyGroup(topology),
310                 "mesh topology does not conform to the blueprint!");
311 
312   if(topology->getView("type")->getString() != std::string("unstructured"))
313   {
314     return false;
315   }
316 
317   SLIC_ERROR_IF(!topology->hasChildGroup("elements"),
318                 "Unstructured topology has no 'elements' group.");
319 
320   const sidre::Group* elems_group = topology->getGroup("elements");
321 
322   SLIC_ERROR_IF(!elems_group->hasChildView("shape"),
323                 "elements group has no 'shape' view.");
324 
325   const sidre::View* shape_view = elems_group->getView("shape");
326   SLIC_ERROR_IF(!shape_view->isString(), "'shape' view must hold a string.");
327 
328   if(shape_view->getString() == std::string("mixed"))
329   {
330     return true;
331   }
332   else
333   {
334     return false;
335   }
336 }
337 
338 //------------------------------------------------------------------------------
getStructuredMeshProperties(int dimension,IndexType node_dims[3],int64 node_ext[6],const sidre::Group * coordset)339 void getStructuredMeshProperties(int dimension,
340                                  IndexType node_dims[3],
341                                  int64 node_ext[6],
342                                  const sidre::Group* coordset)
343 {
344   SLIC_ERROR_IF(dimension < 1 || dimension > 3, "invalid dimension!");
345   SLIC_ERROR_IF(node_dims == nullptr, "supplied extent is null!");
346   SLIC_ERROR_IF(node_ext == nullptr, "supplied global extent is null!");
347   SLIC_ERROR_IF(!blueprint::isValidCoordsetGroup(coordset),
348                 "invalid coordset group!");
349 
350   sidre::Group* c = const_cast<sidre::Group*>(coordset);
351 
352   const char* dim_names[] = {"dims/i", "dims/j", "dims/k"};
353   const char* global_names[] = {"global_ext/i_min",
354                                 "global_ext/i_max",
355                                 "global_ext/j_min",
356                                 "global_ext/j_max",
357                                 "global_ext/k_min",
358                                 "global_ext/k_max"};
359 
360   for(int dim = 0; dim < dimension; ++dim)
361   {
362     node_dims[dim] = c->getView(dim_names[dim])->getScalar();
363   }  // END for
364 
365   for(int i = 0; i < 6; ++i)
366   {
367     node_ext[i] = c->getView(global_names[i])->getScalar();
368   }
369 }
370 
371 //------------------------------------------------------------------------------
setStructuredMeshProperties(int dimension,const IndexType node_dims[3],const int64 node_ext[6],sidre::Group * coordset)372 void setStructuredMeshProperties(int dimension,
373                                  const IndexType node_dims[3],
374                                  const int64 node_ext[6],
375                                  sidre::Group* coordset)
376 {
377   SLIC_ERROR_IF(dimension < 1 || dimension > 3, "invalid dimension!");
378   SLIC_ERROR_IF(node_dims == nullptr, "supplied extent is null!");
379   SLIC_ERROR_IF(node_ext == nullptr, "supplied global extent is null!");
380   SLIC_ERROR_IF(coordset == nullptr, "invalid coordset group!");
381 
382   const char* dim_names[] = {"dims/i", "dims/j", "dims/k"};
383   const char* global_names[] = {"global_ext/i_min",
384                                 "global_ext/i_max",
385                                 "global_ext/j_min",
386                                 "global_ext/j_max",
387                                 "global_ext/k_min",
388                                 "global_ext/k_max"};
389 
390   sidre::Group* c = const_cast<sidre::Group*>(coordset);
391 
392   for(int dim = 0; dim < dimension; ++dim)
393   {
394     coordset->createView(dim_names[dim])->setScalar(node_dims[dim]);
395   }  // END for
396 
397   for(int i = 0; i < 6; ++i)
398   {
399     c->createView(global_names[i])->setScalar(node_ext[i]);
400   }
401 }
402 
setExtent(sidre::Group * coordset,const int64 node_ext[6])403 void setExtent(sidre::Group* coordset, const int64 node_ext[6])
404 {
405   SLIC_ERROR_IF(node_ext == nullptr, "supplied global extent is null!");
406   SLIC_ERROR_IF(coordset == nullptr, "invalid coordset group!");
407 
408   const char* global_names[] = {"global_ext/i_min",
409                                 "global_ext/i_max",
410                                 "global_ext/j_min",
411                                 "global_ext/j_max",
412                                 "global_ext/k_min",
413                                 "global_ext/k_max"};
414 
415   for(int i = 0; i < 6; ++i)
416   {
417     coordset->getView(global_names[i])->setScalar(node_ext[i]);
418   }
419 }
420 
421 //------------------------------------------------------------------------------
getUniformMeshProperties(int dimension,double * origin,double * spacing,const sidre::Group * coordset)422 void getUniformMeshProperties(int dimension,
423                               double* origin,
424                               double* spacing,
425                               const sidre::Group* coordset)
426 {
427   SLIC_ERROR_IF(dimension < 1 || dimension > 3, "invalid dimension!");
428   SLIC_ERROR_IF(origin == nullptr, "supplied null pointer for origin!");
429   SLIC_ERROR_IF(spacing == nullptr, "supplied null pointer for spacing!");
430   SLIC_ERROR_IF(!blueprint::isValidCoordsetGroup(coordset),
431                 "invalid coordset group!");
432 
433   sidre::Group* c = const_cast<sidre::Group*>(coordset);
434 
435   const char* origin_names[] = {"origin/x", "origin/y", "origin/z"};
436   const char* spacing_names[] = {"spacing/dx", "spacing/dy", "spacing/dz"};
437 
438   SLIC_ERROR_IF(c->getView("type")->getString() != std::string("uniform"),
439                 "Mesh is not a UniformMesh.");
440   for(int dim = 0; dim < dimension; ++dim)
441   {
442     origin[dim] = c->getView(origin_names[dim])->getScalar();
443     spacing[dim] = c->getView(spacing_names[dim])->getScalar();
444   }  // END for
445 }
446 
447 //------------------------------------------------------------------------------
setUniformMeshProperties(int dimension,const double * origin,const double * spacing,sidre::Group * coordset)448 void setUniformMeshProperties(int dimension,
449                               const double* origin,
450                               const double* spacing,
451                               sidre::Group* coordset)
452 {
453   SLIC_ERROR_IF(dimension < 1 || dimension > 3, "invalid dimension!");
454   SLIC_ERROR_IF(origin == nullptr, "supplied null pointer for origin!");
455   SLIC_ERROR_IF(spacing == nullptr, "supplied null pointer for spacing!");
456 
457   const char* origin_names[] = {"origin/x", "origin/y", "origin/z"};
458   const char* spacing_names[] = {"spacing/dx", "spacing/dy", "spacing/dz"};
459 
460   coordset->createView("type")->setString("uniform");
461   for(int dim = 0; dim < dimension; ++dim)
462   {
463     coordset->createView(origin_names[dim])->setScalar(origin[dim]);
464     coordset->createView(spacing_names[dim])->setScalar(spacing[dim]);
465   }  // END for
466 }
467 
468 #endif
469 
470 } /* namespace blueprint */
471 } /* namespace mint */
472 } /* namespace axom */
473