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