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