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/config.hpp" // for compile-time type definitions
6
7 // Mint includes
8 #include "axom/mint/mesh/blueprint.hpp" // for blueprint functions
9 #include "axom/mint/mesh/CellTypes.hpp" // for CellTypes enum definition
10 #include "axom/mint/mesh/CurvilinearMesh.hpp" // for CurivilinearMesh
11 #include "axom/mint/mesh/ParticleMesh.hpp" // for ParticleMesh
12 #include "axom/mint/mesh/internal/MeshHelpers.hpp" // for internal::dim
13 #include "StructuredMesh_helpers.hpp" // for StructuredMesh test helpers
14
15 // Slic includes
16 #include "axom/slic/interface/slic.hpp" // for slic macros
17
18 // Sidre includes
19 #ifdef AXOM_MINT_USE_SIDRE
20 #include "axom/sidre/core/sidre.hpp"
21 namespace sidre = axom::sidre;
22 #endif
23
24 #include "gtest/gtest.h" // for gtest macros
25
26 using namespace axom::mint;
27 using IndexType = axom::IndexType;
28
29 // globals
30 const char* IGNORE_OUTPUT = ".*";
31
32 //------------------------------------------------------------------------------
33 // HELPER METHODS
34 //------------------------------------------------------------------------------
35 namespace
36 {
37 //------------------------------------------------------------------------------
set_coordinates(IndexType N,double * x,double * y=nullptr,double * z=nullptr)38 void set_coordinates(IndexType N, double* x, double* y = nullptr, double* z = nullptr)
39 {
40 const IndexType ndims = internal::dim(x, y, z);
41 double* const coords[3] = {x, y, z};
42
43 double factor = internal::PI;
44 for(int dim = 0; dim < ndims; ++dim)
45 {
46 SLIC_ASSERT(coords[dim] != nullptr);
47 for(IndexType i = 0; i < N; ++i)
48 {
49 coords[dim][i] = factor * i;
50 }
51
52 factor *= internal::PI;
53 }
54 }
55
56 //------------------------------------------------------------------------------
set_coordinates(CurvilinearMesh * m)57 void set_coordinates(CurvilinearMesh* m)
58 {
59 const int ndims = m->getDimension();
60 const IndexType numNodes = m->getNumberOfNodes();
61 double* x = m->getCoordinateArray(X_COORDINATE);
62
63 if(ndims == 1)
64 {
65 set_coordinates(numNodes, x);
66 }
67 else if(ndims == 2)
68 {
69 double* y = m->getCoordinateArray(Y_COORDINATE);
70 set_coordinates(numNodes, x, y);
71 }
72 else
73 {
74 double* y = m->getCoordinateArray(Y_COORDINATE);
75 double* z = m->getCoordinateArray(Z_COORDINATE);
76 set_coordinates(numNodes, x, y, z);
77 }
78 }
79
80 //------------------------------------------------------------------------------
check_coordinates(IndexType N,int ndims,const double * x,const double * y=nullptr,const double * z=nullptr)81 void check_coordinates(IndexType N,
82 int ndims,
83 const double* x,
84 const double* y = nullptr,
85 const double* z = nullptr)
86 {
87 const double* const coords[3] = {x, y, z};
88
89 double factor = internal::PI;
90 for(int dim = 0; dim < ndims; ++dim)
91 {
92 ASSERT_NE(coords[dim], nullptr);
93 for(IndexType i = 0; i < N; ++i)
94 {
95 EXPECT_DOUBLE_EQ(coords[dim][i], factor * i);
96 }
97
98 factor *= internal::PI;
99 }
100 }
101
102 //------------------------------------------------------------------------------
check_coordinates(const CurvilinearMesh * m)103 void check_coordinates(const CurvilinearMesh* m)
104 {
105 const int ndims = m->getDimension();
106 const IndexType numNodes = m->getNumberOfNodes();
107 const double* x = m->getCoordinateArray(X_COORDINATE);
108
109 if(ndims == 1)
110 {
111 check_coordinates(numNodes, ndims, x);
112 }
113 else if(ndims == 2)
114 {
115 const double* y = m->getCoordinateArray(Y_COORDINATE);
116 check_coordinates(numNodes, ndims, x, y);
117 }
118 else
119 {
120 const double* y = m->getCoordinateArray(Y_COORDINATE);
121 const double* z = m->getCoordinateArray(Z_COORDINATE);
122 check_coordinates(numNodes, ndims, x, y, z);
123 }
124 }
125
126 } // END namespace
127
128 //------------------------------------------------------------------------------
129 // UNIT TESTS
130 //------------------------------------------------------------------------------
TEST(mint_mesh_curvilinear_mesh_DeathTest,invalid_construction)131 TEST(mint_mesh_curvilinear_mesh_DeathTest, invalid_construction)
132 {
133 const IndexType N[] = {5, 5, 5};
134 double x[] = {0, 1, 2, 3, 4, 5};
135
136 // check 2nd native constructor
137 EXPECT_DEATH_IF_SUPPORTED(CurvilinearMesh(-1, N[1], N[2]), IGNORE_OUTPUT);
138
139 // check external constructor
140 EXPECT_DEATH_IF_SUPPORTED(CurvilinearMesh(5, nullptr), IGNORE_OUTPUT);
141 EXPECT_DEATH_IF_SUPPORTED(CurvilinearMesh(-1, x), IGNORE_OUTPUT);
142
143 #ifdef AXOM_MINT_USE_SIDRE
144
145 sidre::DataStore ds;
146 sidre::Group* root = ds.getRoot();
147 sidre::Group* valid_group = root->createGroup("mesh");
148 sidre::Group* particle_mesh = root->createGroup("particle_mesh");
149 ParticleMesh(3, 10, particle_mesh);
150
151 // check pull constructor
152 EXPECT_DEATH_IF_SUPPORTED(CurvilinearMesh(nullptr, ""), IGNORE_OUTPUT);
153 EXPECT_DEATH_IF_SUPPORTED(CurvilinearMesh(root, ""), IGNORE_OUTPUT);
154 EXPECT_DEATH_IF_SUPPORTED(CurvilinearMesh(particle_mesh, ""), IGNORE_OUTPUT);
155
156 // check 2nd push constructor
157 EXPECT_DEATH_IF_SUPPORTED(CurvilinearMesh(nullptr, N[0]), IGNORE_OUTPUT);
158
159 EXPECT_DEATH_IF_SUPPORTED(CurvilinearMesh(valid_group, -1), IGNORE_OUTPUT);
160
161 #endif
162 }
163
164 //------------------------------------------------------------------------------
TEST(mint_mesh_curvilinear_mesh,native_constructor)165 TEST(mint_mesh_curvilinear_mesh, native_constructor)
166 {
167 constexpr int NDIMS = 3;
168 const IndexType N[] = {5, 6, 7};
169 const int64 extent[] = {0, 4, 10, 15, 7, 13};
170
171 for(int idim = 1; idim <= NDIMS; ++idim)
172 {
173 CurvilinearMesh* m;
174 switch(idim)
175 {
176 case 1:
177 m = new CurvilinearMesh(N[0]);
178 break;
179 case 2:
180 m = new CurvilinearMesh(N[0], N[1]);
181 break;
182 default:
183 EXPECT_EQ(idim, 3);
184 m = new CurvilinearMesh(N[0], N[1], N[2]);
185 } // END switch
186
187 internal::check_constructor(m, STRUCTURED_CURVILINEAR_MESH, idim, N);
188 EXPECT_FALSE(m->isExternal());
189 EXPECT_FALSE(m->hasSidreGroup());
190 m->setExtent(idim, extent);
191 internal::check_node_extent(m, extent);
192 set_coordinates(m);
193 internal::check_create_fields(m);
194 delete m;
195 } // END for all dimensions
196 }
197
198 //------------------------------------------------------------------------------
TEST(mint_mesh_curvilinear_mesh,external_constructor)199 TEST(mint_mesh_curvilinear_mesh, external_constructor)
200 {
201 constexpr int NDIMS = 3;
202 const IndexType N[] = {5, 6, 7};
203 const int64 extent[] = {0, 4, 10, 15, 7, 13};
204 const IndexType maxNumNodes = N[0] * N[1] * N[2];
205
206 double* x = new double[maxNumNodes];
207 double* y = new double[maxNumNodes];
208 double* z = new double[maxNumNodes];
209 set_coordinates(maxNumNodes, x, y, z);
210
211 IndexType curNumNodes = 1;
212 IndexType curNumCells = 1;
213 for(int idim = 1; idim <= NDIMS; ++idim)
214 {
215 curNumNodes *= N[idim - 1];
216 curNumCells *= N[idim - 1] - 1;
217 CurvilinearMesh* m = nullptr;
218
219 switch(idim)
220 {
221 case 1:
222 {
223 m = new CurvilinearMesh(N[0], x);
224 EXPECT_EQ(x, m->getCoordinateArray(X_COORDINATE));
225 } // END 1D
226 break;
227 case 2:
228 {
229 m = new CurvilinearMesh(N[0], x, N[1], y);
230 EXPECT_EQ(x, m->getCoordinateArray(X_COORDINATE));
231 EXPECT_EQ(y, m->getCoordinateArray(Y_COORDINATE));
232 } // END 2D
233 break;
234 default:
235 {
236 m = new CurvilinearMesh(N[0], x, N[1], y, N[2], z);
237 EXPECT_EQ(x, m->getCoordinateArray(X_COORDINATE));
238 EXPECT_EQ(y, m->getCoordinateArray(Y_COORDINATE));
239 EXPECT_EQ(z, m->getCoordinateArray(Z_COORDINATE));
240 } // END 3D
241 } // END switch
242
243 check_coordinates(m);
244 internal::check_constructor(m, STRUCTURED_CURVILINEAR_MESH, idim, N);
245 m->setExtent(idim, extent);
246 internal::check_node_extent(m, extent);
247
248 EXPECT_FALSE(m->hasSidreGroup());
249 EXPECT_TRUE(m->isExternal());
250 EXPECT_EQ(m->getNumberOfNodes(), curNumNodes);
251 EXPECT_EQ(m->getNumberOfCells(), curNumCells);
252
253 delete m;
254 m = nullptr;
255
256 // ensure array buffers are persistent
257 check_coordinates(curNumNodes, idim, x, y, z);
258 } // END for all dimensions
259
260 delete[] x;
261 delete[] y;
262 delete[] z;
263 }
264
265 //------------------------------------------------------------------------------
266 #ifdef AXOM_MINT_USE_SIDRE
267
TEST(mint_mesh_curvilinear_mesh,sidre_constructor)268 TEST(mint_mesh_curvilinear_mesh, sidre_constructor)
269 {
270 constexpr int NDIMS = 3;
271 const IndexType N[] = {5, 6, 7};
272 const int64 extent[] = {0, 4, 10, 15, 7, 13};
273
274 IndexType numNodes = 1;
275 for(int idim = 1; idim <= NDIMS; ++idim)
276 {
277 numNodes *= N[idim - 1];
278
279 // STEP 0: create a data-store with an groups
280 sidre::DataStore ds;
281 sidre::Group* root = ds.getRoot();
282 sidre::Group* meshGroup = root->createGroup("mesh");
283
284 // STEP 1: populate the mesh in sidre.
285 CurvilinearMesh* m;
286 switch(idim)
287 {
288 case 1:
289 m = new CurvilinearMesh(meshGroup, N[I_DIRECTION]);
290 break;
291 case 2:
292 m = new CurvilinearMesh(meshGroup, N[I_DIRECTION], N[J_DIRECTION]);
293 break;
294 default:
295 EXPECT_EQ(idim, 3);
296 m = new CurvilinearMesh(meshGroup,
297 N[I_DIRECTION],
298 N[J_DIRECTION],
299 N[K_DIRECTION]);
300 } // END switch
301
302 EXPECT_TRUE(m->hasSidreGroup());
303 EXPECT_FALSE(m->isExternal());
304 internal::check_constructor(m, STRUCTURED_CURVILINEAR_MESH, idim, N);
305 m->setExtent(idim, extent);
306 internal::check_node_extent(m, extent);
307 set_coordinates(m);
308 internal::check_create_fields(m);
309
310 delete m;
311 m = nullptr;
312
313 // STEP 2: pull the mesh from sidre in to new instances.
314 m = new CurvilinearMesh(meshGroup);
315 EXPECT_TRUE(m->hasSidreGroup());
316 EXPECT_FALSE(m->isExternal());
317 internal::check_constructor(m, STRUCTURED_CURVILINEAR_MESH, idim, N);
318 internal::check_fields(m, true);
319 EXPECT_EQ(idim, m->getDimension());
320 EXPECT_EQ(numNodes, m->getNumberOfNodes());
321 check_coordinates(m);
322
323 delete m;
324
325 EXPECT_TRUE(blueprint::isValidRootGroup(meshGroup));
326
327 } // END for all dimensions
328 }
329
330 #endif /* AXOM_MINT_USE_SIDRE */
331
332 //------------------------------------------------------------------------------
333 #include "axom/slic/core/SimpleLogger.hpp"
334 using axom::slic::SimpleLogger;
335
main(int argc,char * argv[])336 int main(int argc, char* argv[])
337 {
338 int result = 0;
339
340 ::testing::InitGoogleTest(&argc, argv);
341
342 SimpleLogger logger; // create & initialize test logger,
343
344 // finalized when exiting main scope
345
346 result = RUN_ALL_TESTS();
347
348 return result;
349 }
350