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 
6 // Axom includes
7 #include "axom/config.hpp"                          // compile-time definitions
8 #include "axom/core/execution/execution_space.hpp"  // for execution_space traits
9 
10 // Mint includes
11 #include "axom/mint/config.hpp"               // mint compile-time definitions
12 #include "axom/mint/execution/interface.hpp"  // for_all()
13 
14 // Slic includes
15 #include "axom/slic.hpp"  // for SLIC macros
16 
17 #include "mint_test_utilities.hpp"
18 
19 // gtest includes
20 #include "gtest/gtest.h"  // for gtest
21 
22 namespace axom
23 {
24 namespace mint
25 {
26 //------------------------------------------------------------------------------
27 // HELPER METHODS
28 //------------------------------------------------------------------------------
29 namespace
30 {
31 template <typename ExecPolicy, int MeshType, int Topology = SINGLE_SHAPE>
check_for_all_faces(int dimension)32 void check_for_all_faces(int dimension)
33 {
34   constexpr char* mesh_name = internal::mesh_type<MeshType, Topology>::name();
35   SLIC_INFO("dimension=" << dimension
36                          << ", policy=" << execution_space<ExecPolicy>::name()
37                          << ", mesh_type=" << mesh_name);
38 
39   const IndexType Ni = 20;
40   const IndexType Nj = (dimension >= 2) ? Ni : -1;
41   const IndexType Nk = (dimension == 3) ? Ni : -1;
42 
43   const double lo[] = {-10, -9, -8};
44   const double hi[] = {10, 9, 8};
45   UniformMesh uniform_mesh(lo, hi, Ni, Nj, Nk);
46 
47   using MESH = typename internal::mesh_type<MeshType, Topology>::MeshType;
48   MESH* test_mesh =
49     dynamic_cast<MESH*>(internal::create_mesh<MeshType, Topology>(uniform_mesh));
50   EXPECT_TRUE(test_mesh != nullptr);
51 
52   const IndexType numFaces = test_mesh->getNumberOfFaces();
53 
54   IndexType* field =
55     test_mesh->template createField<IndexType>("f1", FACE_CENTERED);
56 
57   for_all_faces<ExecPolicy>(
58     test_mesh,
59     AXOM_LAMBDA(IndexType faceID) { field[faceID] = faceID; });
60 
61   for(IndexType faceID = 0; faceID < numFaces; ++faceID)
62   {
63     EXPECT_EQ(field[faceID], faceID);
64   }
65 
66   delete test_mesh;
67   test_mesh = nullptr;
68 }
69 
70 //------------------------------------------------------------------------------
71 template <typename ExecPolicy, int MeshType, int Topology = SINGLE_SHAPE>
check_for_all_face_nodes(int dimension)72 void check_for_all_face_nodes(int dimension)
73 {
74   constexpr char* mesh_name = internal::mesh_type<MeshType, Topology>::name();
75   SLIC_INFO("dimension=" << dimension
76                          << ", policy=" << execution_space<ExecPolicy>::name()
77                          << ", mesh_type=" << mesh_name);
78 
79   const IndexType Ni = 20;
80   const IndexType Nj = (dimension >= 2) ? Ni : -1;
81   const IndexType Nk = (dimension == 3) ? Ni : -1;
82 
83   const double lo[] = {-10, -9, -8};
84   const double hi[] = {10, 9, 8};
85   UniformMesh uniform_mesh(lo, hi, Ni, Nj, Nk);
86 
87   using MESH = typename internal::mesh_type<MeshType, Topology>::MeshType;
88   MESH* test_mesh =
89     dynamic_cast<MESH*>(internal::create_mesh<MeshType, Topology>(uniform_mesh));
90   EXPECT_TRUE(test_mesh != nullptr);
91 
92   const IndexType numFaces = test_mesh->getNumberOfFaces();
93   IndexType* conn = test_mesh->template createField<IndexType>("f1",
94                                                                FACE_CENTERED,
95                                                                MAX_FACE_NODES);
96 
97   for_all_faces<ExecPolicy, xargs::nodeids>(
98     test_mesh,
99     AXOM_LAMBDA(IndexType faceID, const IndexType* nodes, IndexType N) {
100       for(int i = 0; i < N; ++i)
101       {
102         conn[faceID * MAX_FACE_NODES + i] = nodes[i];
103       }  // END for all face nodes
104     });
105 
106   IndexType faceNodes[MAX_FACE_NODES];
107   for(IndexType faceID = 0; faceID < numFaces; ++faceID)
108   {
109     const IndexType N = test_mesh->getFaceNodeIDs(faceID, faceNodes);
110     for(int i = 0; i < N; ++i)
111     {
112       EXPECT_EQ(conn[faceID * MAX_FACE_NODES + i], faceNodes[i]);
113     }
114   }  // END for all cells
115 
116   /* clean up */
117   delete test_mesh;
118   test_mesh = nullptr;
119 }
120 
121 //------------------------------------------------------------------------------
122 template <typename ExecPolicy, int MeshType, int Topology = SINGLE_SHAPE>
check_for_all_face_coords(int dimension)123 void check_for_all_face_coords(int dimension)
124 {
125   constexpr char* mesh_name = internal::mesh_type<MeshType, Topology>::name();
126   SLIC_INFO("dimension=" << dimension
127                          << ", policy=" << execution_space<ExecPolicy>::name()
128                          << ", mesh_type=" << mesh_name);
129 
130   const IndexType Ni = 20;
131   const IndexType Nj = (dimension >= 2) ? Ni : -1;
132   const IndexType Nk = (dimension == 3) ? Ni : -1;
133 
134   const double lo[] = {-10, -9, -8};
135   const double hi[] = {10, 9, 8};
136   UniformMesh uniform_mesh(lo, hi, Ni, Nj, Nk);
137 
138   using MESH = typename internal::mesh_type<MeshType, Topology>::MeshType;
139   MESH* test_mesh =
140     dynamic_cast<MESH*>(internal::create_mesh<MeshType, Topology>(uniform_mesh));
141   EXPECT_TRUE(test_mesh != nullptr);
142 
143   const IndexType numFaces = test_mesh->getNumberOfFaces();
144   IndexType* conn = test_mesh->template createField<IndexType>("conn",
145                                                                FACE_CENTERED,
146                                                                MAX_FACE_NODES);
147   double* coords =
148     test_mesh->template createField<double>("coords",
149                                             FACE_CENTERED,
150                                             dimension * MAX_FACE_NODES);
151 
152   for_all_faces<ExecPolicy, xargs::coords>(
153     test_mesh,
154     AXOM_LAMBDA(IndexType faceID,
155                 const numerics::Matrix<double>& coordsMatrix,
156                 const IndexType* nodes) {
157       const IndexType numNodes = coordsMatrix.getNumColumns();
158       for(int i = 0; i < numNodes; ++i)
159       {
160         conn[faceID * MAX_FACE_NODES + i] = nodes[i];
161 
162         for(int dim = 0; dim < dimension; ++dim)
163         {
164           coords[faceID * dimension * MAX_FACE_NODES + i * dimension + dim] =
165             coordsMatrix(dim, i);
166         }
167       }  // END for all face nodes
168     });
169 
170   double nodeCoords[3];
171   IndexType faceNodes[MAX_FACE_NODES];
172   for(IndexType faceID = 0; faceID < numFaces; ++faceID)
173   {
174     const IndexType numNodes = test_mesh->getFaceNodeIDs(faceID, faceNodes);
175     for(int i = 0; i < numNodes; ++i)
176     {
177       EXPECT_EQ(conn[faceID * MAX_FACE_NODES + i], faceNodes[i]);
178 
179       for(int dim = 0; dim < dimension; ++dim)
180       {
181         test_mesh->getNode(faceNodes[i], nodeCoords);
182         EXPECT_NEAR(
183           coords[faceID * dimension * MAX_FACE_NODES + i * dimension + dim],
184           nodeCoords[dim],
185           1e-8);
186       }
187     }
188   }  // END for all cells
189 
190   /* clean up */
191   delete test_mesh;
192   test_mesh = nullptr;
193 }
194 
195 //------------------------------------------------------------------------------
196 template <typename ExecPolicy, int MeshType, int Topology = SINGLE_SHAPE>
check_for_all_face_cells(int dimension)197 void check_for_all_face_cells(int dimension)
198 {
199   constexpr char* mesh_name = internal::mesh_type<MeshType, Topology>::name();
200   SLIC_INFO("dimension=" << dimension
201                          << ", policy=" << execution_space<ExecPolicy>::name()
202                          << ", mesh_type=" << mesh_name);
203 
204   const IndexType Ni = 20;
205   const IndexType Nj = (dimension >= 2) ? Ni : -1;
206   const IndexType Nk = (dimension == 3) ? Ni : -1;
207 
208   const double lo[] = {-10, -9, -8};
209   const double hi[] = {10, 9, 8};
210   UniformMesh uniform_mesh(lo, hi, Ni, Nj, Nk);
211 
212   using MESH = typename internal::mesh_type<MeshType, Topology>::MeshType;
213   MESH* test_mesh =
214     dynamic_cast<MESH*>(internal::create_mesh<MeshType, Topology>(uniform_mesh));
215   EXPECT_TRUE(test_mesh != nullptr);
216 
217   const IndexType numFaces = test_mesh->getNumberOfFaces();
218   IndexType* faceCells =
219     test_mesh->template createField<IndexType>("f1", FACE_CENTERED, 2);
220 
221   for_all_faces<ExecPolicy, xargs::cellids>(
222     test_mesh,
223     AXOM_LAMBDA(IndexType faceID, IndexType cellIDOne, IndexType cellIDTwo) {
224       faceCells[2 * faceID + 0] = cellIDOne;
225       faceCells[2 * faceID + 1] = cellIDTwo;
226     });
227 
228   for(IndexType faceID = 0; faceID < numFaces; ++faceID)
229   {
230     IndexType cellIDOne, cellIDTwo;
231     test_mesh->getFaceCellIDs(faceID, cellIDOne, cellIDTwo);
232 
233     EXPECT_EQ(faceCells[2 * faceID + 0], cellIDOne);
234     EXPECT_EQ(faceCells[2 * faceID + 1], cellIDTwo);
235   }
236 
237   /* clean up */
238   delete test_mesh;
239   test_mesh = nullptr;
240 }
241 
242 } /* end anonymous namespace */
243 
244 //------------------------------------------------------------------------------
245 // UNIT TESTS
246 //------------------------------------------------------------------------------
247 
AXOM_CUDA_TEST(mint_execution_face_traversals,for_all_face_nodeids)248 AXOM_CUDA_TEST(mint_execution_face_traversals, for_all_face_nodeids)
249 {
250   for(int dim = 2; dim <= 3; ++dim)
251   {
252     using seq_exec = axom::SEQ_EXEC;
253     check_for_all_face_nodes<seq_exec, STRUCTURED_UNIFORM_MESH>(dim);
254     check_for_all_face_nodes<seq_exec, STRUCTURED_CURVILINEAR_MESH>(dim);
255     check_for_all_face_nodes<seq_exec, STRUCTURED_RECTILINEAR_MESH>(dim);
256     check_for_all_face_nodes<seq_exec, UNSTRUCTURED_MESH, SINGLE_SHAPE>(dim);
257     check_for_all_face_nodes<seq_exec, UNSTRUCTURED_MESH, MIXED_SHAPE>(dim);
258 
259 #if defined(AXOM_USE_RAJA) && defined(AXOM_USE_OPENMP) && \
260   defined(RAJA_ENABLE_OPENMP)
261 
262     using omp_exec = axom::OMP_EXEC;
263     check_for_all_face_nodes<omp_exec, STRUCTURED_UNIFORM_MESH>(dim);
264     check_for_all_face_nodes<omp_exec, STRUCTURED_CURVILINEAR_MESH>(dim);
265     check_for_all_face_nodes<omp_exec, STRUCTURED_RECTILINEAR_MESH>(dim);
266     check_for_all_face_nodes<omp_exec, UNSTRUCTURED_MESH, SINGLE_SHAPE>(dim);
267     check_for_all_face_nodes<omp_exec, UNSTRUCTURED_MESH, MIXED_SHAPE>(dim);
268 
269 #endif
270 
271 #if defined(AXOM_USE_RAJA) && defined(AXOM_USE_CUDA) && \
272   defined(RAJA_ENABLE_CUDA) && defined(AXOM_USE_UMPIRE)
273 
274     using cuda_exec = axom::CUDA_EXEC<512>;
275 
276     const int exec_space_id = axom::execution_space<cuda_exec>::allocatorID();
277     const int prev_allocator = axom::getDefaultAllocatorID();
278     axom::setDefaultAllocator(exec_space_id);
279 
280     check_for_all_face_nodes<cuda_exec, STRUCTURED_UNIFORM_MESH>(dim);
281     check_for_all_face_nodes<cuda_exec, STRUCTURED_CURVILINEAR_MESH>(dim);
282     check_for_all_face_nodes<cuda_exec, STRUCTURED_RECTILINEAR_MESH>(dim);
283     check_for_all_face_nodes<cuda_exec, UNSTRUCTURED_MESH, SINGLE_SHAPE>(dim);
284     check_for_all_face_nodes<cuda_exec, UNSTRUCTURED_MESH, MIXED_SHAPE>(dim);
285 
286     setDefaultAllocator(prev_allocator);
287 #endif
288 
289   }  // END for all dimensions
290 }
291 
AXOM_CUDA_TEST(mint_execution_face_traversals,for_all_face_coords)292 AXOM_CUDA_TEST(mint_execution_face_traversals, for_all_face_coords)
293 {
294   for(int dim = 2; dim <= 3; ++dim)
295   {
296     using seq_exec = axom::SEQ_EXEC;
297     check_for_all_face_coords<seq_exec, STRUCTURED_UNIFORM_MESH>(dim);
298     check_for_all_face_coords<seq_exec, STRUCTURED_CURVILINEAR_MESH>(dim);
299     check_for_all_face_coords<seq_exec, STRUCTURED_RECTILINEAR_MESH>(dim);
300     check_for_all_face_coords<seq_exec, UNSTRUCTURED_MESH, SINGLE_SHAPE>(dim);
301     check_for_all_face_coords<seq_exec, UNSTRUCTURED_MESH, MIXED_SHAPE>(dim);
302 
303 #if defined(AXOM_USE_RAJA) && defined(AXOM_USE_OPENMP) && \
304   defined(RAJA_ENABLE_OPENMP)
305 
306     using omp_exec = axom::OMP_EXEC;
307     check_for_all_face_coords<omp_exec, STRUCTURED_UNIFORM_MESH>(dim);
308     check_for_all_face_coords<omp_exec, STRUCTURED_CURVILINEAR_MESH>(dim);
309     check_for_all_face_coords<omp_exec, STRUCTURED_RECTILINEAR_MESH>(dim);
310     check_for_all_face_coords<omp_exec, UNSTRUCTURED_MESH, SINGLE_SHAPE>(dim);
311     check_for_all_face_coords<omp_exec, UNSTRUCTURED_MESH, MIXED_SHAPE>(dim);
312 
313 #endif
314 
315 #if defined(AXOM_USE_RAJA) && defined(AXOM_USE_CUDA) && \
316   defined(RAJA_ENABLE_CUDA) && defined(AXOM_USE_UMPIRE)
317 
318     using cuda_exec = axom::CUDA_EXEC<512>;
319 
320     const int exec_space_id = axom::execution_space<cuda_exec>::allocatorID();
321     const int prev_allocator = axom::getDefaultAllocatorID();
322     axom::setDefaultAllocator(exec_space_id);
323 
324     check_for_all_face_coords<cuda_exec, STRUCTURED_UNIFORM_MESH>(dim);
325     check_for_all_face_coords<cuda_exec, STRUCTURED_CURVILINEAR_MESH>(dim);
326     check_for_all_face_coords<cuda_exec, STRUCTURED_RECTILINEAR_MESH>(dim);
327     check_for_all_face_coords<cuda_exec, UNSTRUCTURED_MESH, SINGLE_SHAPE>(dim);
328     check_for_all_face_coords<cuda_exec, UNSTRUCTURED_MESH, MIXED_SHAPE>(dim);
329 
330     setDefaultAllocator(prev_allocator);
331 #endif
332 
333   }  // END for all dimensions
334 }
335 
AXOM_CUDA_TEST(mint_execution_face_traversals,for_all_face_cellids)336 AXOM_CUDA_TEST(mint_execution_face_traversals, for_all_face_cellids)
337 {
338   for(int dim = 2; dim <= 3; ++dim)
339   {
340     using seq_exec = axom::SEQ_EXEC;
341     check_for_all_face_cells<seq_exec, STRUCTURED_UNIFORM_MESH>(dim);
342     check_for_all_face_cells<seq_exec, STRUCTURED_CURVILINEAR_MESH>(dim);
343     check_for_all_face_cells<seq_exec, STRUCTURED_RECTILINEAR_MESH>(dim);
344     check_for_all_face_nodes<seq_exec, UNSTRUCTURED_MESH, SINGLE_SHAPE>(dim);
345     check_for_all_face_nodes<seq_exec, UNSTRUCTURED_MESH, MIXED_SHAPE>(dim);
346 
347 #if defined(AXOM_USE_RAJA) && defined(AXOM_USE_OPENMP) && \
348   defined(RAJA_ENABLE_OPENMP)
349 
350     using omp_exec = axom::OMP_EXEC;
351     check_for_all_face_cells<omp_exec, STRUCTURED_UNIFORM_MESH>(dim);
352     check_for_all_face_cells<omp_exec, STRUCTURED_CURVILINEAR_MESH>(dim);
353     check_for_all_face_cells<omp_exec, STRUCTURED_RECTILINEAR_MESH>(dim);
354     check_for_all_face_nodes<omp_exec, UNSTRUCTURED_MESH, SINGLE_SHAPE>(dim);
355     check_for_all_face_nodes<omp_exec, UNSTRUCTURED_MESH, MIXED_SHAPE>(dim);
356 
357 #endif
358 
359 #if defined(AXOM_USE_RAJA) && defined(AXOM_USE_CUDA) && \
360   defined(RAJA_ENABLE_CUDA) && defined(AXOM_USE_UMPIRE)
361 
362     using cuda_exec = axom::CUDA_EXEC<512>;
363 
364     const int exec_space_id = axom::execution_space<cuda_exec>::allocatorID();
365     const int prev_allocator = axom::getDefaultAllocatorID();
366     axom::setDefaultAllocator(exec_space_id);
367 
368     check_for_all_face_cells<cuda_exec, STRUCTURED_UNIFORM_MESH>(dim);
369     check_for_all_face_cells<cuda_exec, STRUCTURED_CURVILINEAR_MESH>(dim);
370     check_for_all_face_cells<cuda_exec, STRUCTURED_RECTILINEAR_MESH>(dim);
371     check_for_all_face_nodes<cuda_exec, UNSTRUCTURED_MESH, SINGLE_SHAPE>(dim);
372     check_for_all_face_nodes<cuda_exec, UNSTRUCTURED_MESH, MIXED_SHAPE>(dim);
373 
374     setDefaultAllocator(prev_allocator);
375 #endif
376 
377   }  // END for all dimensions
378 }
379 
380 //------------------------------------------------------------------------------
AXOM_CUDA_TEST(mint_execution_face_traversals,for_all_faces_index)381 AXOM_CUDA_TEST(mint_execution_face_traversals, for_all_faces_index)
382 {
383   for(int dim = 2; dim <= 3; ++dim)
384   {
385     using seq_exec = axom::SEQ_EXEC;
386     check_for_all_faces<seq_exec, STRUCTURED_UNIFORM_MESH>(dim);
387     check_for_all_faces<seq_exec, STRUCTURED_CURVILINEAR_MESH>(dim);
388     check_for_all_faces<seq_exec, STRUCTURED_RECTILINEAR_MESH>(dim);
389     check_for_all_faces<seq_exec, UNSTRUCTURED_MESH, SINGLE_SHAPE>(dim);
390     check_for_all_faces<seq_exec, UNSTRUCTURED_MESH, MIXED_SHAPE>(dim);
391 
392 #if defined(AXOM_USE_RAJA) && defined(AXOM_USE_OPENMP) && \
393   defined(RAJA_ENABLE_OPENMP)
394 
395     using omp_exec = axom::OMP_EXEC;
396     check_for_all_faces<omp_exec, STRUCTURED_UNIFORM_MESH>(dim);
397     check_for_all_faces<omp_exec, STRUCTURED_CURVILINEAR_MESH>(dim);
398     check_for_all_faces<omp_exec, STRUCTURED_RECTILINEAR_MESH>(dim);
399     check_for_all_faces<omp_exec, UNSTRUCTURED_MESH, SINGLE_SHAPE>(dim);
400     check_for_all_faces<omp_exec, UNSTRUCTURED_MESH, MIXED_SHAPE>(dim);
401 
402 #endif
403 
404 #if defined(AXOM_USE_RAJA) && defined(AXOM_USE_CUDA) && \
405   defined(RAJA_ENABLE_CUDA) && defined(AXOM_USE_UMPIRE)
406 
407     using cuda_exec = axom::CUDA_EXEC<512>;
408 
409     const int exec_space_id = axom::execution_space<cuda_exec>::allocatorID();
410     const int prev_allocator = axom::getDefaultAllocatorID();
411     axom::setDefaultAllocator(exec_space_id);
412 
413     check_for_all_faces<cuda_exec, STRUCTURED_UNIFORM_MESH>(dim);
414     check_for_all_faces<cuda_exec, STRUCTURED_CURVILINEAR_MESH>(dim);
415     check_for_all_faces<cuda_exec, STRUCTURED_RECTILINEAR_MESH>(dim);
416     check_for_all_faces<cuda_exec, UNSTRUCTURED_MESH, SINGLE_SHAPE>(dim);
417     check_for_all_faces<cuda_exec, UNSTRUCTURED_MESH, MIXED_SHAPE>(dim);
418 
419     setDefaultAllocator(prev_allocator);
420 #endif
421 
422   }  // END for all dimensions
423 }
424 
425 } /* namespace mint */
426 } /* namespace axom */
427 
428 //------------------------------------------------------------------------------
429 #include "axom/slic/core/SimpleLogger.hpp"
430 using axom::slic::SimpleLogger;
431 
main(int argc,char * argv[])432 int main(int argc, char* argv[])
433 {
434   int result = 0;
435 
436   ::testing::InitGoogleTest(&argc, argv);
437 
438   SimpleLogger logger;  // create & initialize test logger,
439 
440   // finalized when exiting main scope
441 
442   result = RUN_ALL_TESTS();
443 
444   return result;
445 }
446