netxsimdg
Loading...
Searching...
No Matches
ModelArray_test.cpp
1
8#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
9#include <doctest/doctest.h>
10
11#include "include/ModelArray.hpp"
12
13namespace Nextsim {
14
15TEST_SUITE_BEGIN("ModelArray");
16// Test that the (special case) two dimensional index functions correctly
17TEST_CASE("Two dimensional data access test")
18{
19 ModelArray::MultiDim dims2 = {15, 25};
20
21 ModelArray::setDimensions(ModelArray::Type::TWOD, dims2);
22
23 ModelArray check1d = ModelArray::TwoDField();
24
25 REQUIRE(check1d.nDimensions() == 2);
26
27 // Check the ordering: later indexes should vary faster
28 // Fill data as 1d
29 for (size_t i = 0; i < dims2[0] * dims2[1]; ++i) {
30 check1d[i] = i;
31 }
32
33 size_t x = 7;
34 size_t y = 13;
35 // Check neighbouring x indices differ in value by 1
36 REQUIRE(check1d(x+1, y) - check1d(x, y) == 1);
37 // Check neighbouring y indices differ in value by nx
38 REQUIRE(check1d(x, y+1) - check1d(x, y) == dims2[0]);
39
40 REQUIRE(check1d(dims2[0]-1, dims2[1]-1) == dims2[0] * dims2[1] - 1);
41}
42
43// Test that higher dimensional indexing functions correctly
44TEST_CASE("Higher dimensional indexing")
45{
46 size_t dimLen = 10;
47 size_t arrayLen = dimLen * dimLen * dimLen * dimLen;
48 ModelArray::MultiDim dims4 = {dimLen, dimLen, dimLen, dimLen};
49 ModelArray::setDimensions(ModelArray::Type::FOURD, dims4);
50
51 ModelArray check4d = ModelArray::FourDField();
52
53 REQUIRE(check4d.nDimensions() == 4);
54 REQUIRE(check4d.size() == dimLen * dimLen * dimLen * dimLen);
55
56 for (size_t i = 0; i < check4d.size(); ++i) {
57 check4d[i] = i;
58 }
59
60 // Check indexing using the fact that the dimensions are the same as our counting base
61 REQUIRE(check4d(4, 7, 2, 5) == 5274);
62
63 // Reset the data to zero
64 for (size_t i = 0; i < check4d.size(); ++i) {
65 check4d[i] = 0.;
66 }
67 REQUIRE(check4d(4, 7, 2, 5) == 0);
68
69 double* data = new double[arrayLen];
70 for (size_t i = 0; i < arrayLen; ++i) {
71 data[i] = i;
72 }
73
74 check4d.setData(data);
75
76 REQUIRE(check4d(4, 7, 2, 5) == 5274);
77
78 // Reset the data to zero
79 for (size_t i = 0; i < check4d.size(); ++i) {
80 check4d[i] = 0.;
81 }
82 REQUIRE(check4d(4, 7, 2, 5) == 0);
83
84 std::vector<double> vData = std::vector<double>(arrayLen);
85 for (size_t i = 0; i < arrayLen; ++i) {
86 vData[i] = i;
87 }
88
89 check4d.setData(vData.data());
90
91 REQUIRE(check4d(4, 7, 2, 5) == 5274);
92
93
94 REQUIRE(check4d[{5, 7, 2, 5}] == 5275);
95}
96
97// Test that higher dimensional indexing functions correctly
98TEST_CASE("Higher dimensional indexing 2")
99{
100 ModelArray::MultiDim dims4 = {3, 5, 7, 11};
101 size_t totalSize = dims4[0] * dims4[1] * dims4[2] * dims4[3];
102 ModelArray::setDimensions(ModelArray::Type::FOURD, dims4);
103
104 FourDField primorial = ModelArray::FourDField();
105
106 REQUIRE(primorial.nDimensions() == 4);
107 REQUIRE(primorial.size() == totalSize);
108
109 for (size_t i = 0; i < primorial.size(); ++i) {
110 primorial[i] = i;
111 }
112
113 size_t i = 2;
114 size_t j = 4;
115 size_t k = 5;
116 size_t l = 7;
117
118 size_t target = i + dims4[0] * (j + dims4[1] * (k + dims4[2] * (l)));
119 //(((i) * dims4[1] + j) * dims4[2] + k) * dims4[3] + l;
120 REQUIRE(primorial[target] == target);
121
122 REQUIRE(primorial(i, j, k, l) == target);
123
124}
125
126// Test that the copy constructor and copy assignment operator initialize that
127// data correctly.
128TEST_CASE("Copy constructor and copy assignment operator")
129{
130 size_t n = 10;
131 ModelArray::setDimensions(ModelArray::Type::TWOD, {n, n});
132
133 ModelArray src = ModelArray::TwoDField();
134 for (int i = 0; i < n * n; ++i) {
135 src[i] = i;
136 }
137
138 // Test the copy constructor
139 ModelArray copyConstructor(src);
140 REQUIRE(copyConstructor(2, 3) == src(2, 3));
141
142 // Test copy assignment
143 ModelArray copyAssignment = ModelArray::TwoDField();
144 copyAssignment = src;
145 REQUIRE(copyAssignment(2, 3) == src(2, 3));
146}
147
148// Test that setting the dimension via the function applied to an instance
149// correctly propagates to the dimensions of the type.
150TEST_CASE("Instance setDimensions sets instance dimensions")
151{
152 ZUField uu = ModelArray::ZUField();
153 ModelArray::MultiDim udim = {5, 5};
154 uu.setDimensions(udim);
155 REQUIRE(uu.size() == udim[0] * udim[1]);
156 REQUIRE(uu.nDimensions() == 2);
157 REQUIRE(uu.dimensions() == udim);
158}
159
160// Test the arithmetic operators of the class.
161TEST_CASE("Arithmetic tests")
162{
163 // Only test HField for now
164 ModelArray::setDimensions(ModelArray::Type::ONED, {2});
165 OneDField lhs;
166 OneDField rhs;
167 lhs[0] = 9.;
168 lhs[1] = 10.;
169 rhs[0] = 3.;
170 rhs[1] = -5.;
171
172 OneDField sum = lhs + rhs;
173 REQUIRE(sum[0] == 12.);
174 REQUIRE(sum[1] == 5.);
175 OneDField difference = lhs - rhs;
176 REQUIRE(difference[0] == 6.);
177 REQUIRE(difference[1] == 15.);
178 OneDField product = lhs * rhs;
179 REQUIRE(product[0] == 27.);
180 REQUIRE(product[1] == -50.);
181 OneDField quotient = lhs / rhs;
182 REQUIRE(quotient[0] == 3.);
183 REQUIRE(quotient[1] == -2.);
184 OneDField negative = -rhs;
185 REQUIRE(negative[0] == -3);
186 REQUIRE(negative[1] == 5);
187
188 double three = 3;
189 double four = 4;
190 sum = lhs + three;
191 REQUIRE(sum[0] == 12);
192 REQUIRE(sum[1] == 13);
193 sum = four + rhs;
194 REQUIRE(sum[0] == 7);
195 REQUIRE(sum[1] == -1);
196 difference = lhs - three;
197 REQUIRE(difference[0] == 6);
198 REQUIRE(difference[1] == 7);
199 difference = four - rhs;
200 REQUIRE(difference[0] == 1);
201 REQUIRE(difference[1] == 9);
202 product = lhs * three;
203 REQUIRE(product[0] == 27);
204 REQUIRE(product[1] == 30);
205 product = four * rhs;
206 REQUIRE(product[0] == 12);
207 REQUIRE(product[1] == -20);
208 quotient = lhs / three;
209 REQUIRE(quotient[0] == 3);
210 REQUIRE(quotient[1] == (10. / 3.));
211 quotient = four / rhs;
212 REQUIRE(quotient[0] == (4. / 3.));
213 REQUIRE(quotient[1] == (4. / -5.));
214
215 // Finally, in-place arithmetic
216 lhs += rhs;
217 REQUIRE(lhs[0] == 12);
218 REQUIRE(lhs[1] == 5);
219 lhs -= rhs;
220 REQUIRE(lhs[0] == 9);
221 REQUIRE(lhs[1] == 10);
222 lhs *= rhs;
223 REQUIRE(lhs[0] == 27);
224 REQUIRE(lhs[1] == -50);
225 lhs /= rhs;
226 REQUIRE(lhs[0] == 9);
227 REQUIRE(lhs[1] == 10);
228
229 lhs += three;
230 REQUIRE(lhs[0] == 12);
231 REQUIRE(lhs[1] == 13);
232 lhs -= four;
233 REQUIRE(lhs[0] == 8);
234 REQUIRE(lhs[1] == 9);
235 lhs *= three;
236 REQUIRE(lhs[0] == 24);
237 REQUIRE(lhs[1] == 27);
238 lhs /= four;
239 REQUIRE(lhs[0] == 6);
240 REQUIRE(lhs[1] == 6.75);
241
242 OneDField fill = ModelArray::OneDField();
243 double filldub = 5.2354;
244 fill = filldub;
245
246 REQUIRE(fill[0] == filldub);
247 REQUIRE(fill[1] == filldub);
248}
249
250// Location from index. Index from location is assumed to work as it is a
251// wrapper around indexr()
252TEST_CASE("Location from index")
253{
254 const size_t nx = 31;
255 const size_t ny = 37;
256 const size_t nz = 41;
257
258 ModelArray::setDimensions(ModelArray::Type::FOURD, {nx, ny, nz, 1});
259 size_t x = 13;
260 size_t y = 17;
261 size_t z = 19;
262
263 size_t index = ModelArray::indexFromLocation(ModelArray::Type::FOURD, {x, y, z, 0});
264 ModelArray::MultiDim loc = ModelArray::locationFromIndex(ModelArray::Type::FOURD, index);
265 REQUIRE(loc[0] == x);
266 REQUIRE(loc[1] == y);
267 REQUIRE(loc[2] == z);
268}
269
270// Test the zIndexAndLayer function to ensure that it accesses the correct
271// point in a three-dimensional ModelArray.
272TEST_CASE("zIndexAndLayer")
273{
274 const size_t nx = 29;
275 const size_t ny = 23;
276 const size_t nz = 11;
277
278 ModelArray::setDimensions(ModelArray::Type::THREED, {nx, ny, nz});
279
280 ThreeDField threeD(ModelArray::Type::THREED);
281 threeD.resize();
282
283 size_t mul = 100;
284 // Fill the array fastest last
285 for (size_t i = 0; i < nx; ++i) {
286 for (size_t j = 0; j < ny; ++j) {
287 for (size_t k = 0; k < nz; ++k) {
288 threeD(i, j, k) = k + mul * (j + mul * (i));
289 }
290 }
291 }
292
293 size_t x = 19;
294 size_t y = 17;
295 size_t z = 7;
296 size_t ind = ModelArray::indexFromLocation(ModelArray::Type::TWOD, {x, y});
297 REQUIRE(threeD.zIndexAndLayer(ind, z) == threeD(x, y, z));
298
299}
300TEST_SUITE_END();
301
302} /* namespace Nextsim */
size_t indexFromLocation(const MultiDim &loc) const
Returns the index for a given set of multi-dimensional location for this array's type.
static void setDimensions(Type, const MultiDim &)
Sets the number and size of the dimensions of a specified type of ModelArray.
MultiDim locationFromIndex(size_t index) const
Returns the multi-dimensional location for a given index for this array's type.