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