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 #include "gtest/gtest.h"
7
8 #include "axom/primal/geometry/NumericArray.hpp"
9
10 #include "axom/core/execution/execution_space.hpp" // for execution_space traits
11 #include "axom/core/execution/for_all.hpp" // for_all()
12
13 #include "axom/slic/core/SimpleLogger.hpp"
14 using axom::slic::SimpleLogger;
15
16 using namespace axom;
17
18 //------------------------------------------------------------------------------
19 template <typename ExecSpace>
check_numeric_array_policy()20 void check_numeric_array_policy()
21 {
22 const int DIM = 3;
23 using NumericArrayType = primal::NumericArray<double, DIM>;
24
25 double* coords =
26 axom::allocate<double>(DIM, axom::execution_space<ExecSpace>::allocatorID());
27
28 axom::for_all<ExecSpace>(
29 1,
30 AXOM_LAMBDA(int /*i*/) {
31 NumericArrayType ones(1.0);
32 ones.to_array(coords);
33 });
34
35 EXPECT_EQ(NumericArrayType(coords), NumericArrayType(1));
36 axom::deallocate(coords);
37 }
38
39 //------------------------------------------------------------------------------
TEST(primal_numeric_array,constructors)40 TEST(primal_numeric_array, constructors)
41 {
42 static const int DIM = 5;
43 typedef double CoordType;
44 typedef primal::NumericArray<CoordType, DIM> QArray;
45
46 QArray arr1;
47 EXPECT_EQ(QArray::size(), DIM);
48 for(int i = 0; i < DIM; ++i)
49 {
50 EXPECT_EQ(arr1[i], CoordType());
51 }
52
53 CoordType val = 5.;
54 QArray arr2(val);
55 EXPECT_EQ(QArray::size(), DIM);
56 for(int i = 0; i < DIM; ++i)
57 {
58 EXPECT_EQ(arr2[i], val);
59 }
60
61 CoordType val3 = 5.;
62 int halfPt = DIM / 2;
63 QArray arr3(val3, halfPt);
64 for(int i = 0; i < DIM; ++i)
65 {
66 CoordType expVal = i < halfPt ? val3 : CoordType();
67 EXPECT_EQ(arr3[i], expVal);
68 }
69
70 // Compare array initialized from arbitrary array
71 CoordType valsArr[DIM] = {12., 23., 34., 45., 56.432};
72 QArray arrArr(valsArr);
73 for(int i = 0; i < DIM; ++i)
74 {
75 EXPECT_EQ(arrArr[i], valsArr[i]);
76 }
77
78 QArray arrHalfVec(valsArr, halfPt);
79 for(int i = 0; i < DIM; ++i)
80 {
81 CoordType expVal = i < halfPt ? valsArr[i] : CoordType();
82 EXPECT_EQ(arrHalfVec[i], expVal);
83 }
84
85 primal::NumericArray<int, 3> fromInitializerListRightSize = {10, 20, 30};
86 for(int i = 0; i < 3; ++i)
87 {
88 EXPECT_EQ(10 * (i + 1), fromInitializerListRightSize[i]);
89 }
90
91 primal::NumericArray<int, 3> fromInitializerListTooLong = {10, 20, 30, 40};
92 for(int i = 0; i < 3; ++i)
93 {
94 EXPECT_EQ(10 * (i + 1), fromInitializerListTooLong[i]);
95 }
96
97 primal::NumericArray<int, 5> fromInitializerListTooShort = {10, 20};
98 for(int i = 0; i < 2; ++i)
99 {
100 EXPECT_EQ(10 * (i + 1), fromInitializerListTooShort[i]);
101 }
102 for(int i = 2; i < 5; ++i)
103 {
104 EXPECT_EQ(0, fromInitializerListTooShort[i]);
105 }
106
107 primal::NumericArray<int, 3> fromInitializerNoEqualsSign {10, 20, 30};
108 for(int i = 0; i < 3; ++i)
109 {
110 EXPECT_EQ(10 * (i + 1), fromInitializerNoEqualsSign[i]);
111 }
112 }
113
114 //------------------------------------------------------------------------------
TEST(primal_numeric_array,num_array_to_array)115 TEST(primal_numeric_array, num_array_to_array)
116 {
117 static const int DIM = 5;
118 typedef double CoordType;
119 typedef primal::NumericArray<CoordType, DIM> QArray;
120
121 // Compare array initialized from arbitrary array
122 CoordType valsArr[DIM] = {12., 23., 34., 45., 56.432};
123 QArray arrArr(valsArr);
124
125 for(int i = 0; i < DIM; ++i)
126 {
127 EXPECT_EQ(arrArr[i], valsArr[i]);
128 }
129
130 // Copy data into new array
131 CoordType arrCopy[DIM];
132 arrArr.to_array(arrCopy);
133 for(int i = 0; i < DIM; ++i)
134 {
135 EXPECT_EQ(arrCopy[i], valsArr[i]);
136 EXPECT_EQ(arrCopy[i], arrArr.data()[i]);
137 }
138 }
139
140 //------------------------------------------------------------------------------
TEST(primal_numeric_array,component_wise_arithmetic)141 TEST(primal_numeric_array, component_wise_arithmetic)
142 {
143 static const int DIM = 3;
144 typedef double CoordType;
145 typedef primal::NumericArray<CoordType, DIM> QArray;
146
147 CoordType ca1[] = {3, 0, 1.2};
148 CoordType ca2[] = {0, 4, 1.2};
149 CoordType caSum[] = {3, 4, 2.4};
150 CoordType caDiff[] = {-3, 4, 0};
151 CoordType scalar = 5.3;
152
153 CoordType caScalar[] = {scalar * 3, scalar * 4, scalar * 2.4};
154
155 CoordType caProduct[] = {-3 * 3, 4 * 4, 0. * 2.4};
156
157 QArray arr1(ca1);
158 QArray arr2(ca2);
159
160 // testing component-wise addition and subtraction
161 EXPECT_EQ(QArray(caDiff), arr2 - arr1);
162 EXPECT_EQ(QArray(caSum), arr2 + arr1);
163 EXPECT_EQ(arr2 + arr1, arr1 + arr2);
164
165 QArray aSum(arr1);
166 aSum += arr2;
167 EXPECT_EQ(aSum, QArray(caSum));
168
169 QArray aDiff(arr2);
170 aDiff -= arr1;
171 EXPECT_EQ(aDiff, QArray(caDiff));
172
173 // Testing scalar multiplication
174 EXPECT_EQ(QArray(caScalar), QArray(caSum) * scalar);
175 EXPECT_EQ(QArray(caScalar), scalar * QArray(caSum));
176 EXPECT_EQ(QArray(caScalar), (arr1 + arr2) * scalar);
177
178 // Testing unary negation
179 EXPECT_EQ(-arr1, QArray() - arr1);
180
181 // Testing component-wise product
182 EXPECT_EQ(QArray(caProduct), aSum * aDiff);
183 EXPECT_EQ(QArray(caProduct), aDiff * aSum);
184
185 // Testing component-wise product
186 EXPECT_EQ(QArray(caProduct) / aSum, aDiff);
187 }
188
189 //------------------------------------------------------------------------------
TEST(primal_numeric_array,component_min_max)190 TEST(primal_numeric_array, component_min_max)
191 {
192 static const int DIM = 3;
193 typedef int CoordType;
194 typedef primal::NumericArray<CoordType, DIM> QArray;
195
196 CoordType incSeq[] = {1, 2, 3};
197 CoordType decSeq[] = {3, 2, 1};
198 CoordType upDownSeq[] = {5, 8, 3};
199 CoordType downUpSeq[] = {6, 2, 5};
200
201 QArray incArr(incSeq);
202 QArray decArr(decSeq);
203 QArray udArr(upDownSeq);
204 QArray duArr(downUpSeq);
205
206 // testing component-wise min and max functions
207 EXPECT_EQ(incArr.max(), 3);
208 EXPECT_EQ(decArr.max(), 3);
209 EXPECT_EQ(incArr.argMax(), 2);
210 EXPECT_EQ(decArr.argMax(), 0);
211
212 EXPECT_EQ(udArr.max(), 8);
213 EXPECT_EQ(udArr.argMax(), 1);
214
215 EXPECT_EQ(incArr.min(), 1);
216 EXPECT_EQ(decArr.min(), 1);
217 EXPECT_EQ(incArr.argMin(), 0);
218 EXPECT_EQ(decArr.argMin(), 2);
219
220 EXPECT_EQ(duArr.min(), 2);
221 EXPECT_EQ(duArr.argMin(), 1);
222 }
223
224 //------------------------------------------------------------------------------
TEST(primal_numeric_array,clamping)225 TEST(primal_numeric_array, clamping)
226 {
227 static const int DIM = 3;
228 typedef int CoordType;
229 typedef primal::NumericArray<CoordType, DIM> QArray;
230
231 CoordType seq[] = {15, 4, 2};
232 CoordType seqClampUp7[] = {7, 4, 2};
233 CoordType seqClampLow3[] = {15, 4, 3};
234 CoordType seqClamp37[] = {7, 4, 3};
235
236 // testing component-wise clamping functions
237 QArray seqUp(seq);
238 EXPECT_EQ(seqUp.max(), 15);
239 EXPECT_EQ(seqUp.clampUpper(7).max(), 7);
240 EXPECT_EQ(seqUp, QArray(seqClampUp7));
241
242 QArray seqLow(seq);
243 EXPECT_EQ(seqLow.min(), 2);
244 EXPECT_EQ(seqLow.clampLower(3).min(), 3);
245 EXPECT_EQ(seqLow, QArray(seqClampLow3));
246
247 QArray seqBoth(seq);
248 seqBoth.clamp(3, 7);
249 EXPECT_EQ(seqBoth.min(), 3);
250 EXPECT_EQ(seqBoth.max(), 7);
251 EXPECT_EQ(seqBoth, QArray(seqClamp37));
252
253 // Test that order of clamping doesn't matter
254 EXPECT_EQ(seqBoth, seqLow.clampUpper(7));
255 EXPECT_EQ(seqBoth, seqUp.clampLower(3));
256
257 EXPECT_EQ(QArray(seq).clamp(3, 7), QArray(seq).clampUpper(7).clampLower(3));
258 EXPECT_EQ(QArray(seq).clamp(3, 7), QArray(seq).clampLower(3).clampUpper(7));
259
260 #ifdef AXOM_DEBUG
261 // NOTE: AXOM_DEBUG is disabled in release mode, so this test will only fail
262 // in
263 // debug mode
264 SLIC_INFO("Checking that clamping with ill-formed range throws an assert.");
265
266 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
267 EXPECT_DEATH_IF_SUPPORTED(QArray(seq).clamp(7, 3), "");
268
269 #endif
270 }
271
272 //------------------------------------------------------------------------------
AXOM_CUDA_TEST(primal_numeric_array,numeric_array_check_policies)273 AXOM_CUDA_TEST(primal_numeric_array, numeric_array_check_policies)
274 {
275 using seq_exec = axom::SEQ_EXEC;
276 check_numeric_array_policy<seq_exec>();
277
278 #if defined(AXOM_USE_RAJA) && defined(AXOM_USE_OPENMP) && \
279 defined(RAJA_ENABLE_OPENMP)
280
281 using omp_exec = axom::OMP_EXEC;
282 check_numeric_array_policy<omp_exec>();
283
284 #endif
285
286 #if defined(AXOM_USE_RAJA) && defined(AXOM_USE_CUDA) && \
287 defined(RAJA_ENABLE_CUDA) && defined(AXOM_USE_UMPIRE)
288
289 using cuda_exec = axom::CUDA_EXEC<512>;
290
291 check_numeric_array_policy<cuda_exec>();
292 #endif
293 }
294
295 //----------------------------------------------------------------------
296 //----------------------------------------------------------------------
297
main(int argc,char * argv[])298 int main(int argc, char* argv[])
299 {
300 int result = 0;
301
302 ::testing::InitGoogleTest(&argc, argv);
303
304 SimpleLogger logger; // create & initialize test logger,
305
306 // finalized when exiting main scope
307
308 result = RUN_ALL_TESTS();
309
310 return result;
311 }
312