LCOV - code coverage report
Current view: top level - elsa/core/tests - test_DataContainer.cpp (source / functions) Hit Total Coverage
Test: coverage-all.lcov Lines: 1253 1253 100.0 %
Date: 2023-01-26 04:22:16 Functions: 44 44 100.0 %

          Line data    Source code
       1             : /**
       2             :  * @file test_DataContainer.cpp
       3             :  *
       4             :  * @brief Tests for DataContainer class
       5             :  *
       6             :  * @author Matthias Wieczorek - initial code
       7             :  * @author David Frank - rewrite to use doctest and BDD
       8             :  * @author Tobias Lasser - rewrite and added code coverage
       9             :  */
      10             : 
      11             : #include "doctest/doctest.h"
      12             : #include "DataContainer.h"
      13             : #include "IdenticalBlocksDescriptor.h"
      14             : #include "testHelpers.h"
      15             : #include "VolumeDescriptor.h"
      16             : 
      17             : #include <type_traits>
      18             : 
      19             : using namespace elsa;
      20             : using namespace doctest;
      21             : 
      22             : // Provides object to be used with TEMPLATE_PRODUCT_TEST_CASE, necessary because enum cannot be
      23             : // passed directly
      24             : template <typename T>
      25             : struct TestHelperCPU {
      26             :     using data_t = T;
      27             : };
      28             : 
      29             : using CPUTypeTuple =
      30             :     std::tuple<TestHelperCPU<float>, TestHelperCPU<double>, TestHelperCPU<complex<float>>,
      31             :                TestHelperCPU<complex<double>>, TestHelperCPU<index_t>>;
      32             : 
      33             : TYPE_TO_STRING(TestHelperCPU<float>);
      34             : TYPE_TO_STRING(TestHelperCPU<double>);
      35             : TYPE_TO_STRING(TestHelperCPU<index_t>);
      36             : TYPE_TO_STRING(TestHelperCPU<complex<float>>);
      37             : TYPE_TO_STRING(TestHelperCPU<complex<double>>);
      38             : 
      39             : TYPE_TO_STRING(DataContainer<float>);
      40             : TYPE_TO_STRING(DataContainer<double>);
      41             : TYPE_TO_STRING(DataContainer<index_t>);
      42             : TYPE_TO_STRING(DataContainer<complex<float>>);
      43             : TYPE_TO_STRING(DataContainer<complex<double>>);
      44             : 
      45             : TYPE_TO_STRING(complex<float>);
      46             : TYPE_TO_STRING(complex<double>);
      47             : 
      48             : TEST_SUITE_BEGIN("core");
      49             : 
      50             : TEST_CASE_TEMPLATE_DEFINE("DataContainer: Testing construction", TestType,
      51             :                           datacontainer_construction)
      52          50 : {
      53          50 :     using data_t = typename TestType::data_t;
      54             : 
      55          50 :     INFO("Testing type: " << TypeName_v<const data_t>);
      56             : 
      57          50 :     GIVEN("a DataDescriptor")
      58          50 :     {
      59          20 :         IndexVector_t numCoeff(3);
      60          20 :         numCoeff << 17, 47, 91;
      61          20 :         VolumeDescriptor desc(numCoeff);
      62             : 
      63          20 :         WHEN("constructing an empty DataContainer")
      64          20 :         {
      65          10 :             DataContainer<data_t> dc(desc);
      66             : 
      67          10 :             THEN("it has the correct DataDescriptor")
      68          10 :             {
      69           5 :                 REQUIRE_EQ(dc.getDataDescriptor(), desc);
      70           5 :             }
      71             : 
      72          10 :             THEN("it has a data vector of correct size")
      73          10 :             {
      74           5 :                 REQUIRE_EQ(dc.getSize(), desc.getNumberOfCoefficients());
      75           5 :             }
      76          10 :         }
      77             : 
      78          20 :         WHEN("constructing an initialized DataContainer")
      79          20 :         {
      80          10 :             auto data = generateRandomMatrix<data_t>(desc.getNumberOfCoefficients());
      81             : 
      82          10 :             DataContainer<data_t> dc(desc, data);
      83             : 
      84          10 :             THEN("it has the correct DataDescriptor")
      85          10 :             {
      86           5 :                 REQUIRE_EQ(dc.getDataDescriptor(), desc);
      87           5 :             }
      88             : 
      89          10 :             THEN("it has correctly initialized data")
      90          10 :             {
      91           5 :                 REQUIRE_EQ(dc.getSize(), desc.getNumberOfCoefficients());
      92             : 
      93      363550 :                 for (index_t i = 0; i < dc.getSize(); ++i)
      94           5 :                     REQUIRE_UNARY(checkApproxEq(dc[i], data[i]));
      95           5 :             }
      96          10 :         }
      97          20 :     }
      98             : 
      99          50 :     GIVEN("another DataContainer")
     100          50 :     {
     101          30 :         IndexVector_t numCoeff(2);
     102          30 :         numCoeff << 32, 57;
     103          30 :         VolumeDescriptor desc(numCoeff);
     104             : 
     105          30 :         DataContainer<data_t> otherDc(desc);
     106             : 
     107          30 :         auto randVec = generateRandomMatrix<data_t>(otherDc.getSize());
     108       54750 :         for (index_t i = 0; i < otherDc.getSize(); ++i)
     109       54720 :             otherDc[i] = randVec(i);
     110             : 
     111          30 :         WHEN("copy constructing")
     112          30 :         {
     113           5 :             DataContainer dc(otherDc);
     114             : 
     115           5 :             THEN("it copied correctly")
     116           5 :             {
     117           5 :                 REQUIRE_EQ(dc.getDataDescriptor(), otherDc.getDataDescriptor());
     118           5 :                 REQUIRE_NE(&dc.getDataDescriptor(), &otherDc.getDataDescriptor());
     119             : 
     120           5 :                 REQUIRE_EQ(dc, otherDc);
     121           5 :             }
     122           5 :         }
     123             : 
     124          30 :         WHEN("copy assigning")
     125          30 :         {
     126           5 :             DataContainer<data_t> dc(desc);
     127           5 :             dc = otherDc;
     128             : 
     129           5 :             THEN("it copied correctly")
     130           5 :             {
     131           5 :                 REQUIRE_EQ(dc.getDataDescriptor(), otherDc.getDataDescriptor());
     132           5 :                 REQUIRE_NE(&dc.getDataDescriptor(), &otherDc.getDataDescriptor());
     133             : 
     134           5 :                 REQUIRE_EQ(dc, otherDc);
     135           5 :             }
     136           5 :         }
     137             : 
     138          30 :         WHEN("move constructing")
     139          30 :         {
     140          10 :             DataContainer oldOtherDc(otherDc);
     141             : 
     142          10 :             DataContainer dc(std::move(otherDc));
     143             : 
     144          10 :             THEN("it moved correctly")
     145          10 :             {
     146           5 :                 REQUIRE_EQ(dc.getDataDescriptor(), oldOtherDc.getDataDescriptor());
     147             : 
     148           5 :                 REQUIRE_EQ(dc, oldOtherDc);
     149           5 :             }
     150             : 
     151          10 :             THEN("the moved from object is still valid (but empty)")
     152          10 :             {
     153           5 :                 otherDc = dc;
     154           5 :             }
     155          10 :         }
     156             : 
     157          30 :         WHEN("move assigning")
     158          30 :         {
     159          10 :             DataContainer oldOtherDc(otherDc);
     160             : 
     161          10 :             DataContainer<data_t> dc(desc);
     162          10 :             dc = std::move(otherDc);
     163             : 
     164          10 :             THEN("it moved correctly")
     165          10 :             {
     166           5 :                 REQUIRE_EQ(dc.getDataDescriptor(), oldOtherDc.getDataDescriptor());
     167             : 
     168           5 :                 REQUIRE_EQ(dc, oldOtherDc);
     169           5 :             }
     170             : 
     171          10 :             THEN("the moved from object is still valid (but empty)")
     172          10 :             {
     173           5 :                 otherDc = dc;
     174           5 :             }
     175          10 :         }
     176          30 :     }
     177          50 : }
     178             : 
     179             : TEST_CASE_TEMPLATE_DEFINE("DataContainer: Testing the reduction operations", TestType,
     180             :                           datacontainer_reduction)
     181           5 : {
     182           5 :     using data_t = typename TestType::data_t;
     183             : 
     184           5 :     INFO("Testing type: " << TypeName_v<const data_t>);
     185             : 
     186           5 :     GIVEN("a DataContainer")
     187           5 :     {
     188           5 :         IndexVector_t numCoeff(3);
     189           5 :         numCoeff << 11, 73, 45;
     190           5 :         VolumeDescriptor desc(numCoeff);
     191             : 
     192           5 :         WHEN("putting in some random data")
     193           5 :         {
     194           5 :             auto [dc, randVec] = generateRandomContainer<data_t>(desc);
     195             : 
     196           5 :             THEN("the reductions work a expected")
     197           5 :             {
     198           5 :                 REQUIRE_UNARY(checkApproxEq(dc.sum(), randVec.sum()));
     199           5 :                 REQUIRE_UNARY(checkApproxEq(
     200           5 :                     dc.l0PseudoNorm(),
     201           5 :                     (randVec.array().cwiseAbs()
     202           5 :                      >= std::numeric_limits<GetFloatingPointType_t<data_t>>::epsilon())
     203           5 :                         .count()));
     204           5 :                 REQUIRE_UNARY(checkApproxEq(dc.l1Norm(), randVec.array().abs().sum()));
     205           5 :                 REQUIRE_UNARY(checkApproxEq(dc.lInfNorm(), randVec.array().abs().maxCoeff()));
     206           5 :                 REQUIRE_UNARY(checkApproxEq(dc.squaredL2Norm(), randVec.squaredNorm()));
     207             : 
     208           5 :                 auto [dc2, randVec2] = generateRandomContainer<data_t>(desc);
     209             : 
     210           5 :                 REQUIRE_UNARY(checkApproxEq(dc.dot(dc2), randVec.dot(randVec2)));
     211             : 
     212           5 :                 if constexpr (!isComplex<data_t>) {
     213           3 :                     REQUIRE_UNARY(checkApproxEq(dc.minElement(), randVec.array().minCoeff()));
     214           3 :                     REQUIRE_UNARY(checkApproxEq(dc.maxElement(), randVec.array().maxCoeff()));
     215           3 :                 }
     216           5 :             }
     217           5 :         }
     218           5 :     }
     219           5 : }
     220             : 
     221             : TEST_CASE_TEMPLATE_DEFINE("DataContainer: Testing element-wise access", TestType,
     222             :                           datacontainer_elemwise)
     223          75 : {
     224          75 :     using data_t = typename TestType::data_t;
     225             : 
     226          75 :     INFO("Testing type: " << TypeName_v<const data_t>);
     227             : 
     228          75 :     GIVEN("a DataContainer")
     229          75 :     {
     230           5 :         IndexVector_t numCoeff(2);
     231           5 :         numCoeff << 47, 11;
     232           5 :         VolumeDescriptor desc(numCoeff);
     233           5 :         DataContainer<data_t> dc(desc);
     234             : 
     235           5 :         WHEN("accessing the elements")
     236           5 :         {
     237           5 :             IndexVector_t coord(2);
     238           5 :             coord << 17, 4;
     239           5 :             index_t index = desc.getIndexFromCoordinate(coord);
     240             : 
     241           5 :             THEN("it works as expected when using indices/coordinates")
     242           5 :             {
     243             :                 // For integral typeps don't have a floating point value
     244           5 :                 if constexpr (std::is_integral_v<data_t>) {
     245           4 :                     dc[index] = data_t(2);
     246           4 :                     REQUIRE_UNARY(checkApproxEq(dc[index], 2));
     247           4 :                     REQUIRE_UNARY(checkApproxEq(dc(coord), 2));
     248           4 :                     REQUIRE_UNARY(checkApproxEq(dc(17, 4), 2));
     249             : 
     250           4 :                     dc(coord) = data_t(3);
     251           4 :                     REQUIRE_UNARY(checkApproxEq(dc[index], 3));
     252           4 :                     REQUIRE_UNARY(checkApproxEq(dc(coord), 3));
     253           4 :                     REQUIRE_UNARY(checkApproxEq(dc(17, 4), 3));
     254           4 :                 } else {
     255           4 :                     dc[index] = data_t(2.2f);
     256           4 :                     REQUIRE_UNARY(checkApproxEq(dc[index], 2.2f));
     257           4 :                     REQUIRE_UNARY(checkApproxEq(dc(coord), 2.2f));
     258           4 :                     REQUIRE_UNARY(checkApproxEq(dc(17, 4), 2.2f));
     259             : 
     260           4 :                     dc(coord) = data_t(3.3f);
     261           4 :                     REQUIRE_UNARY(checkApproxEq(dc[index], 3.3f));
     262           4 :                     REQUIRE_UNARY(checkApproxEq(dc(coord), 3.3f));
     263           4 :                     REQUIRE_UNARY(checkApproxEq(dc(17, 4), 3.3f));
     264           4 :                 }
     265           5 :             }
     266           5 :         }
     267           5 :     }
     268             : 
     269          75 :     GIVEN("a DataContainer")
     270          75 :     {
     271          70 :         IndexVector_t numCoeff(2);
     272          70 :         numCoeff << 47, 11;
     273          70 :         VolumeDescriptor desc(numCoeff);
     274             : 
     275          70 :         WHEN("putting in some random data")
     276          70 :         {
     277          30 :             auto [dc, randVec] = generateRandomContainer<data_t>(desc);
     278             : 
     279          30 :             THEN("the element-wise unary operations work as expected")
     280          30 :             {
     281           5 :                 DataContainer dcAbs = cwiseAbs(dc);
     282        2590 :                 for (index_t i = 0; i < dc.getSize(); ++i)
     283           5 :                     REQUIRE_UNARY(checkApproxEq(dcAbs[i], randVec.array().abs()[i]));
     284             : 
     285           5 :                 DataContainer dcSquare = square(dc);
     286        2590 :                 for (index_t i = 0; i < dc.getSize(); ++i)
     287           5 :                     REQUIRE_UNARY(checkApproxEq(dcSquare[i], randVec.array().square()[i]));
     288           5 :                 DataContainer dcSqrt = sqrt(dcSquare);
     289        2590 :                 for (index_t i = 0; i < dc.getSize(); ++i)
     290           5 :                     REQUIRE_UNARY(checkApproxEq(dcSqrt[i], randVec.array().square().sqrt()[i]));
     291             : 
     292             :                 // do exponent check only for floating point types as for integer will likely
     293             :                 // lead to overflow due to random init over full value range
     294           5 :                 if constexpr (!std::is_integral_v<data_t>) {
     295           4 :                     DataContainer dcExp = exp(dc);
     296        2072 :                     for (index_t i = 0; i < dc.getSize(); ++i)
     297           4 :                         REQUIRE_UNARY(checkApproxEq(dcExp[i], randVec.array().exp()[i]));
     298           4 :                 }
     299             : 
     300           5 :                 DataContainer dcLog = log(dcSquare);
     301        2590 :                 for (index_t i = 0; i < dc.getSize(); ++i)
     302           5 :                     REQUIRE_UNARY(checkApproxEq(dcLog[i], randVec.array().square().log()[i]));
     303             : 
     304           5 :                 DataContainer dcReal = real(dc);
     305        2590 :                 for (index_t i = 0; i < dc.getSize(); ++i)
     306           5 :                     REQUIRE_UNARY(checkApproxEq(dcReal[i], randVec.array().real()[i]));
     307             : 
     308           5 :                 DataContainer dcImag = imag(dc);
     309             : 
     310           5 :                 if constexpr (isComplex<data_t>) {
     311        1036 :                     for (index_t i = 0; i < dc.getSize(); ++i)
     312           3 :                         REQUIRE_UNARY(checkApproxEq(dcImag[i], randVec.array().imag()[i]));
     313           3 :                 } else {
     314        1554 :                     for (index_t i = 0; i < dc.getSize(); ++i)
     315           3 :                         REQUIRE_UNARY(checkApproxEq(dcImag[i], 0));
     316           3 :                 }
     317           5 :             }
     318             : 
     319          30 :             auto scalar = static_cast<data_t>(923.41f);
     320             : 
     321          30 :             THEN("the binary in-place addition of a scalar work as expected")
     322          30 :             {
     323           5 :                 dc += scalar;
     324        2590 :                 for (index_t i = 0; i < dc.getSize(); ++i)
     325           5 :                     REQUIRE_UNARY(checkApproxEq(dc[i], randVec(i) + scalar));
     326           5 :             }
     327             : 
     328          30 :             THEN("the binary in-place subtraction of a scalar work as expected")
     329          30 :             {
     330           5 :                 dc -= scalar;
     331        2590 :                 for (index_t i = 0; i < dc.getSize(); ++i)
     332           5 :                     REQUIRE_UNARY(checkApproxEq(dc[i], randVec(i) - scalar));
     333           5 :             }
     334             : 
     335          30 :             THEN("the binary in-place multiplication with a scalar work as expected")
     336          30 :             {
     337           5 :                 dc *= scalar;
     338        2590 :                 for (index_t i = 0; i < dc.getSize(); ++i)
     339           5 :                     REQUIRE_UNARY(checkApproxEq(dc[i], randVec(i) * scalar));
     340           5 :             }
     341             : 
     342          30 :             THEN("the binary in-place division by a scalar work as expected")
     343          30 :             {
     344           5 :                 dc /= scalar;
     345        2590 :                 for (index_t i = 0; i < dc.getSize(); ++i)
     346           5 :                     REQUIRE_UNARY(checkApproxEq(dc[i], randVec(i) / scalar));
     347           5 :             }
     348             : 
     349          30 :             THEN("the element-wise assignment of a scalar works as expected")
     350          30 :             {
     351           5 :                 dc = scalar;
     352        2590 :                 for (index_t i = 0; i < dc.getSize(); ++i)
     353           5 :                     REQUIRE_UNARY(checkApproxEq(dc[i], scalar));
     354           5 :             }
     355          30 :         }
     356             : 
     357          70 :         WHEN("having two containers with random data")
     358          70 :         {
     359          20 :             auto [dc, randVec] = generateRandomContainer<data_t>(desc);
     360          20 :             auto [dc2, randVec2] = generateRandomContainer<data_t>(desc);
     361             : 
     362          20 :             THEN("the element-wise in-place addition works as expected")
     363          20 :             {
     364           5 :                 dc += dc2;
     365        2590 :                 for (index_t i = 0; i < dc.getSize(); ++i)
     366           5 :                     REQUIRE_UNARY(checkApproxEq(dc[i], randVec(i) + randVec2(i)));
     367           5 :             }
     368             : 
     369          20 :             THEN("the element-wise in-place subtraction works as expected")
     370          20 :             {
     371           5 :                 dc -= dc2;
     372        2590 :                 for (index_t i = 0; i < dc.getSize(); ++i)
     373           5 :                     REQUIRE_UNARY(checkApproxEq(dc[i], randVec(i) - randVec2(i)));
     374           5 :             }
     375             : 
     376          20 :             THEN("the element-wise in-place multiplication works as expected")
     377          20 :             {
     378           5 :                 dc *= dc2;
     379        2590 :                 for (index_t i = 0; i < dc.getSize(); ++i)
     380           5 :                     REQUIRE_UNARY(checkApproxEq(dc[i], randVec(i) * randVec2(i)));
     381           5 :             }
     382             : 
     383          20 :             THEN("the element-wise in-place division works as expected")
     384          20 :             {
     385           5 :                 dc /= dc2;
     386        2590 :                 for (index_t i = 0; i < dc.getSize(); ++i)
     387        2585 :                     if (dc2[i] != data_t(0))
     388        2585 :                         REQUIRE_UNARY(checkApproxEq(dc[i], randVec(i) / randVec2(i)));
     389           5 :             }
     390          20 :         }
     391             : 
     392          70 :         WHEN("having two containers with real and complex data each")
     393          70 :         {
     394          20 :             auto [dcReals1, realsVec1] = generateRandomContainer<real_t>(desc);
     395          20 :             auto [dcComps1, compsVec1] = generateRandomContainer<complex<real_t>>(desc);
     396             : 
     397          20 :             THEN("the element-wise maximum operation works as expected for two real "
     398          20 :                  "DataContainers")
     399          20 :             {
     400           5 :                 auto [dcReals2, realsVec2] = generateRandomContainer<real_t>(desc);
     401             : 
     402           5 :                 DataContainer dcCWiseMax = cwiseMax(dcReals1, dcReals2);
     403        2590 :                 for (index_t i = 0; i < dcCWiseMax.getSize(); ++i)
     404           5 :                     REQUIRE_UNARY(
     405           5 :                         checkApproxEq(dcCWiseMax[i], realsVec1.array().max(realsVec2.array())[i]));
     406           5 :             }
     407             : 
     408          20 :             THEN("the element-wise maximum operation works as expected for a real and a complex "
     409          20 :                  "DataContainer")
     410          20 :             {
     411           5 :                 auto [dcComps2, compsVec2] = generateRandomContainer<complex<real_t>>(desc);
     412             : 
     413           5 :                 DataContainer dcCWiseMax = cwiseMax(dcReals1, dcComps2);
     414        2590 :                 for (index_t i = 0; i < dcCWiseMax.getSize(); ++i)
     415           5 :                     REQUIRE_UNARY(checkApproxEq(dcCWiseMax[i],
     416           5 :                                                 realsVec1.array().max(compsVec2.array().abs())[i]));
     417           5 :             }
     418             : 
     419          20 :             THEN("the element-wise maximum operation works as expected for a complex and a real "
     420          20 :                  "DataContainer")
     421          20 :             {
     422           5 :                 auto [dcComps2, compsVec2] = generateRandomContainer<complex<real_t>>(desc);
     423             : 
     424           5 :                 DataContainer dcCWiseMax = cwiseMax(dcComps2, dcReals1);
     425        2590 :                 for (index_t i = 0; i < dcCWiseMax.getSize(); ++i)
     426           5 :                     REQUIRE_UNARY(checkApproxEq(dcCWiseMax[i],
     427           5 :                                                 compsVec2.array().abs().max(realsVec1.array())[i]));
     428           5 :             }
     429             : 
     430          20 :             THEN("the element-wise maximum operation works as expected for two DataContainers")
     431          20 :             {
     432           5 :                 auto [dcComps2, compsVec2] = generateRandomContainer<complex<real_t>>(desc);
     433             : 
     434           5 :                 DataContainer dcCWiseMax = cwiseMax(dcComps1, dcComps2);
     435        2590 :                 for (index_t i = 0; i < dcCWiseMax.getSize(); ++i)
     436           5 :                     REQUIRE_UNARY(checkApproxEq(
     437           5 :                         dcCWiseMax[i], compsVec1.array().abs().max(compsVec2.array().abs())[i]));
     438           5 :             }
     439          20 :         }
     440          70 :     }
     441          75 : }
     442             : 
     443             : TEST_CASE_TEMPLATE_DEFINE(
     444             :     "DataContainer: Testing the arithmetic operations with DataContainers arguments", TestType,
     445             :     datacontainer_arithmetic)
     446          10 : {
     447          10 :     using data_t = typename TestType::data_t;
     448             : 
     449          10 :     INFO("Testing type: " << TypeName_v<const data_t>);
     450             : 
     451          10 :     GIVEN("some DataContainers")
     452          10 :     {
     453          10 :         IndexVector_t numCoeff(3);
     454          10 :         numCoeff << 52, 7, 29;
     455          10 :         VolumeDescriptor desc(numCoeff);
     456             : 
     457          10 :         auto [dc, randVec] = generateRandomContainer<data_t>(desc);
     458          10 :         auto [dc2, randVec2] = generateRandomContainer<data_t>(desc);
     459             : 
     460          10 :         THEN("the binary element-wise operations work as expected")
     461          10 :         {
     462           5 :             DataContainer resultPlus = dc + dc2;
     463       52785 :             for (index_t i = 0; i < dc.getSize(); ++i)
     464           5 :                 REQUIRE_UNARY(checkApproxEq(resultPlus[i], dc[i] + dc2[i]));
     465             : 
     466           5 :             DataContainer resultMinus = dc - dc2;
     467       52785 :             for (index_t i = 0; i < dc.getSize(); ++i)
     468           5 :                 REQUIRE_UNARY(checkApproxEq(resultMinus[i], dc[i] - dc2[i]));
     469             : 
     470           5 :             DataContainer resultMult = dc * dc2;
     471       52785 :             for (index_t i = 0; i < dc.getSize(); ++i)
     472           5 :                 REQUIRE_UNARY(checkApproxEq(resultMult[i], dc[i] * dc2[i]));
     473             : 
     474           5 :             DataContainer resultDiv = dc / dc2;
     475       52785 :             for (index_t i = 0; i < dc.getSize(); ++i)
     476       52780 :                 if (dc2[i] != data_t(0))
     477       52780 :                     REQUIRE_UNARY(checkApproxEq(resultDiv[i], dc[i] / dc2[i]));
     478           5 :         }
     479             : 
     480          10 :         THEN("the operations with a scalar work as expected")
     481          10 :         {
     482           5 :             data_t scalar = static_cast<data_t>(4.92f);
     483             : 
     484           5 :             DataContainer resultScalarPlus = scalar + dc;
     485       52785 :             for (index_t i = 0; i < dc.getSize(); ++i)
     486           5 :                 REQUIRE_UNARY(checkApproxEq(resultScalarPlus[i], scalar + dc[i]));
     487             : 
     488           5 :             DataContainer resultPlusScalar = dc + scalar;
     489       52785 :             for (index_t i = 0; i < dc.getSize(); ++i)
     490           5 :                 REQUIRE_UNARY(checkApproxEq(resultPlusScalar[i], dc[i] + scalar));
     491             : 
     492           5 :             DataContainer resultScalarMinus = scalar - dc;
     493       52785 :             for (index_t i = 0; i < dc.getSize(); ++i)
     494           5 :                 REQUIRE_UNARY(checkApproxEq(resultScalarMinus[i], scalar - dc[i]));
     495             : 
     496           5 :             DataContainer resultMinusScalar = dc - scalar;
     497       52785 :             for (index_t i = 0; i < dc.getSize(); ++i)
     498           5 :                 REQUIRE_UNARY(checkApproxEq(resultMinusScalar[i], dc[i] - scalar));
     499             : 
     500           5 :             DataContainer resultScalarMult = scalar * dc;
     501       52785 :             for (index_t i = 0; i < dc.getSize(); ++i)
     502           5 :                 REQUIRE_UNARY(checkApproxEq(resultScalarMult[i], scalar * dc[i]));
     503             : 
     504           5 :             DataContainer resultMultScalar = dc * scalar;
     505       52785 :             for (index_t i = 0; i < dc.getSize(); ++i)
     506           5 :                 REQUIRE_UNARY(checkApproxEq(resultMultScalar[i], dc[i] * scalar));
     507             : 
     508           5 :             DataContainer resultScalarDiv = scalar / dc;
     509       52785 :             for (index_t i = 0; i < dc.getSize(); ++i)
     510       52780 :                 if (dc[i] != data_t(0))
     511       52780 :                     REQUIRE_UNARY(checkApproxEq(resultScalarDiv[i], scalar / dc[i]));
     512             : 
     513           5 :             DataContainer resultDivScalar = dc / scalar;
     514       52785 :             for (index_t i = 0; i < dc.getSize(); ++i)
     515           5 :                 REQUIRE_UNARY(checkApproxEq(resultDivScalar[i], dc[i] / scalar));
     516           5 :         }
     517          10 :     }
     518          10 : }
     519             : 
     520             : TEST_CASE_TEMPLATE_DEFINE("DataContainer: Testing creation of Maps through DataContainer", TestType,
     521             :                           datacontainer_maps)
     522          20 : {
     523          20 :     using data_t = typename TestType::data_t;
     524             : 
     525          20 :     INFO("Testing type: " << TypeName_v<const data_t>);
     526             : 
     527          20 :     GIVEN("a non-blocked container")
     528          20 :     {
     529          10 :         IndexVector_t numCoeff(3);
     530          10 :         numCoeff << 52, 7, 29;
     531          10 :         VolumeDescriptor desc(numCoeff);
     532             : 
     533          10 :         DataContainer<data_t> dc(desc);
     534          10 :         const DataContainer<data_t> constDc(desc);
     535             : 
     536          10 :         WHEN("trying to reference a block")
     537          10 :         {
     538           5 :             THEN("an exception occurs")
     539           5 :             {
     540           5 :                 REQUIRE_THROWS(dc.getBlock(0));
     541           5 :                 REQUIRE_THROWS(constDc.getBlock(0));
     542           5 :             }
     543           5 :         }
     544             : 
     545          10 :         WHEN("creating a view")
     546          10 :         {
     547           5 :             IndexVector_t numCoeff(1);
     548           5 :             numCoeff << desc.getNumberOfCoefficients();
     549           5 :             VolumeDescriptor linearDesc(numCoeff);
     550           5 :             auto linearDc = dc.viewAs(linearDesc);
     551           5 :             auto linearConstDc = constDc.viewAs(linearDesc);
     552             : 
     553           5 :             THEN("view has the correct descriptor and data")
     554           5 :             {
     555           5 :                 REQUIRE_EQ(linearDesc, linearDc.getDataDescriptor());
     556           5 :                 REQUIRE_EQ(&linearDc[0], &dc[0]);
     557             : 
     558           5 :                 REQUIRE_EQ(linearDesc, linearConstDc.getDataDescriptor());
     559           5 :                 REQUIRE_EQ(&linearConstDc[0], &constDc[0]);
     560             : 
     561           5 :                 AND_THEN("view is not a shallow copy")
     562           5 :                 {
     563           5 :                     const auto dcCopy = dc;
     564           5 :                     const auto constDcCopy = constDc;
     565             : 
     566           5 :                     linearDc[0] = 1;
     567           5 :                     REQUIRE_EQ(&linearDc[0], &dc[0]);
     568           5 :                     REQUIRE_NE(&linearDc[0], &dcCopy[0]);
     569             : 
     570           5 :                     linearConstDc[0] = 1;
     571           5 :                     REQUIRE_EQ(&linearConstDc[0], &constDc[0]);
     572           5 :                     REQUIRE_NE(&linearConstDc[0], &constDcCopy[0]);
     573           5 :                 }
     574           5 :             }
     575           5 :         }
     576          10 :     }
     577             : 
     578          20 :     GIVEN("a blocked container")
     579          20 :     {
     580          10 :         IndexVector_t numCoeff(2);
     581          10 :         numCoeff << 52, 29;
     582          10 :         VolumeDescriptor desc(numCoeff);
     583          10 :         index_t numBlocks = 7;
     584          10 :         IdenticalBlocksDescriptor blockDesc(numBlocks, desc);
     585             : 
     586          10 :         DataContainer<data_t> dc(blockDesc);
     587          10 :         const DataContainer<data_t> constDc(blockDesc);
     588             : 
     589          10 :         WHEN("referencing a block")
     590          10 :         {
     591           5 :             THEN("block has the correct descriptor and data")
     592           5 :             {
     593          40 :                 for (index_t i = 0; i < numBlocks; i++) {
     594          35 :                     auto dcBlock = dc.getBlock(i);
     595          35 :                     const auto constDcBlock = constDc.getBlock(i);
     596             : 
     597          35 :                     REQUIRE_EQ(dcBlock.getDataDescriptor(), blockDesc.getDescriptorOfBlock(i));
     598          35 :                     REQUIRE_EQ(&dcBlock[0], &dc[0] + blockDesc.getOffsetOfBlock(i));
     599             : 
     600          35 :                     REQUIRE_EQ(constDcBlock.getDataDescriptor(), blockDesc.getDescriptorOfBlock(i));
     601          35 :                     REQUIRE_EQ(&constDcBlock[0], &constDc[0] + blockDesc.getOffsetOfBlock(i));
     602          35 :                 }
     603           5 :             }
     604           5 :         }
     605             : 
     606          10 :         WHEN("creating a view")
     607          10 :         {
     608           5 :             IndexVector_t numCoeff(1);
     609           5 :             numCoeff << blockDesc.getNumberOfCoefficients();
     610           5 :             VolumeDescriptor linearDesc(numCoeff);
     611           5 :             auto linearDc = dc.viewAs(linearDesc);
     612           5 :             auto linearConstDc = constDc.viewAs(linearDesc);
     613             : 
     614           5 :             THEN("view has the correct descriptor and data")
     615           5 :             {
     616           5 :                 REQUIRE_EQ(linearDesc, linearDc.getDataDescriptor());
     617           5 :                 REQUIRE_EQ(&linearDc[0], &dc[0]);
     618             : 
     619           5 :                 REQUIRE_EQ(linearDesc, linearConstDc.getDataDescriptor());
     620           5 :                 REQUIRE_EQ(&linearConstDc[0], &constDc[0]);
     621             : 
     622           5 :                 AND_THEN("view is not a shallow copy")
     623           5 :                 {
     624           5 :                     const auto dcCopy = dc;
     625           5 :                     const auto constDcCopy = constDc;
     626             : 
     627           5 :                     linearDc[0] = 1;
     628           5 :                     REQUIRE_EQ(&linearDc[0], &dc[0]);
     629           5 :                     REQUIRE_NE(&linearDc[0], &dcCopy[0]);
     630             : 
     631           5 :                     linearConstDc[0] = 1;
     632           5 :                     REQUIRE_EQ(&linearConstDc[0], &constDc[0]);
     633           5 :                     REQUIRE_NE(&linearConstDc[0], &constDcCopy[0]);
     634           5 :                 }
     635           5 :             }
     636           5 :         }
     637          10 :     }
     638          20 : }
     639             : 
     640             : TEST_CASE("DataContainer: Testing iterators for DataContainer")
     641           9 : {
     642           9 :     GIVEN("A 1D container")
     643           9 :     {
     644           3 :         constexpr index_t size = 20;
     645           3 :         IndexVector_t numCoeff(1);
     646           3 :         numCoeff << size;
     647           3 :         VolumeDescriptor desc(numCoeff);
     648             : 
     649           3 :         DataContainer dc1(desc);
     650           3 :         DataContainer dc2(desc);
     651             : 
     652           3 :         Eigen::VectorXf randVec1 = Eigen::VectorXf::Ones(size);
     653           3 :         Eigen::VectorXf randVec2 = Eigen::VectorXf::Random(size);
     654             : 
     655          63 :         for (index_t i = 0; i < size; ++i) {
     656          60 :             dc1[i] = randVec1(i);
     657          60 :             dc2[i] = randVec2(i);
     658          60 :         }
     659             : 
     660           3 :         THEN("We can iterate forward")
     661           3 :         {
     662           1 :             int i = 0;
     663           1 :             auto first = dc1.begin();
     664           1 :             auto last = dc1.end();
     665             : 
     666          21 :             while (first != last) {
     667          20 :                 INFO("Error at position: ", i);
     668          20 :                 CHECK_UNARY(checkApproxEq(*first, randVec1[i]));
     669          20 :                 ++i;
     670          20 :                 ++first;
     671          20 :             }
     672           1 :             REQUIRE_EQ(i, size);
     673           1 :         }
     674             : 
     675             :         // THEN("We can iterate backward")
     676             :         // {
     677             :         //     int i = size;
     678             :         //     for (auto v = dc1.crbegin(); v != dc1.crend(); v++) {
     679             :         //         REQUIRE_UNARY(checkApproxEq(*v, randVec1[--i]));
     680             :         //     }
     681             :         //     REQUIRE_EQ(i, 0);
     682             :         // }
     683             : 
     684           3 :         THEN("We can iterate and mutate")
     685           3 :         {
     686           1 :             int i = 0;
     687          20 :             for (auto& v : dc1) {
     688          20 :                 v = v * 2;
     689          20 :                 REQUIRE_UNARY(checkApproxEq(v, 2 * randVec1[i++]));
     690          20 :             }
     691           1 :             REQUIRE_EQ(i, size);
     692             : 
     693           1 :             i = 0;
     694          20 :             for (auto v : dc1) {
     695          20 :                 REQUIRE_UNARY(checkApproxEq(v, 2 * randVec1[i++]));
     696          20 :             }
     697           1 :             REQUIRE_EQ(i, size);
     698           1 :         }
     699             : 
     700           3 :         THEN("We can use STL algorithms")
     701           3 :         {
     702           1 :             REQUIRE_EQ(*std::min_element(dc1.cbegin(), dc1.cend()), randVec1.minCoeff());
     703           1 :             REQUIRE_EQ(*std::max_element(dc1.cbegin(), dc1.cend()), randVec1.maxCoeff());
     704           1 :         }
     705           3 :     }
     706           9 :     GIVEN("A 2D container")
     707           9 :     {
     708           3 :         constexpr index_t size = 20;
     709           3 :         IndexVector_t numCoeff(2);
     710           3 :         numCoeff << size, size;
     711           3 :         VolumeDescriptor desc(numCoeff);
     712             : 
     713           3 :         DataContainer dc1(desc);
     714             : 
     715           3 :         Eigen::VectorXf randVec1 = Eigen::VectorXf::Random(size * size);
     716             : 
     717        1203 :         for (index_t i = 0; i < dc1.getSize(); ++i) {
     718        1200 :             dc1[i] = randVec1[i];
     719        1200 :         }
     720             : 
     721           3 :         THEN("We can iterate forward")
     722           3 :         {
     723           1 :             int i = 0;
     724         400 :             for (auto v : dc1) {
     725         400 :                 REQUIRE_UNARY(checkApproxEq(v, randVec1[i++]));
     726         400 :             }
     727           1 :             REQUIRE_EQ(i, size * size);
     728           1 :         }
     729             : 
     730             :         // THEN("We can iterate backward")
     731             :         // {
     732             :         //     int i = size * size;
     733             :         //     for (auto v = dc1.crbegin(); v != dc1.crend(); v++) {
     734             :         //         REQUIRE_UNARY(checkApproxEq(*v, randVec1[--i]));
     735             :         //     }
     736             :         //     REQUIRE_EQ(i, 0);
     737             :         // }
     738             : 
     739           3 :         THEN("We can iterate and mutate")
     740           3 :         {
     741           1 :             int i = 0;
     742         400 :             for (auto& v : dc1) {
     743         400 :                 v = v * 2;
     744         400 :                 REQUIRE_UNARY(checkApproxEq(v, 2 * randVec1[i++]));
     745         400 :             }
     746           1 :             REQUIRE_EQ(i, size * size);
     747             : 
     748           1 :             i = 0;
     749         400 :             for (auto v : dc1) {
     750         400 :                 REQUIRE_UNARY(checkApproxEq(v, 2 * randVec1[i++]));
     751         400 :             }
     752           1 :             REQUIRE_EQ(i, size * size);
     753           1 :         }
     754             : 
     755           3 :         THEN("We can use STL algorithms")
     756           3 :         {
     757           1 :             REQUIRE_EQ(*std::min_element(dc1.cbegin(), dc1.cend()), randVec1.minCoeff());
     758           1 :             REQUIRE_EQ(*std::max_element(dc1.cbegin(), dc1.cend()), randVec1.maxCoeff());
     759           1 :         }
     760           3 :     }
     761           9 :     GIVEN("A 3D container")
     762           9 :     {
     763           3 :         constexpr index_t size = 20;
     764           3 :         IndexVector_t numCoeff(3);
     765           3 :         numCoeff << size, size, size;
     766           3 :         VolumeDescriptor desc(numCoeff);
     767             : 
     768           3 :         DataContainer dc1(desc);
     769             : 
     770           3 :         Eigen::VectorXf randVec1 = Eigen::VectorXf::Random(size * size * size);
     771             : 
     772       24003 :         for (index_t i = 0; i < dc1.getSize(); ++i) {
     773       24000 :             dc1[i] = randVec1[i];
     774       24000 :         }
     775             : 
     776           3 :         THEN("We can iterate forward")
     777           3 :         {
     778           1 :             int i = 0;
     779        8000 :             for (auto v : dc1) {
     780        8000 :                 REQUIRE_UNARY(checkApproxEq(v, randVec1[i++]));
     781        8000 :             }
     782           1 :             REQUIRE_EQ(i, size * size * size);
     783           1 :         }
     784             : 
     785             :         // THEN("We can iterate backward")
     786             :         // {
     787             :         //     int i = size * size * size;
     788             :         //     for (auto v = dc1.crbegin(); v != dc1.crend(); v++) {
     789             :         //         REQUIRE_UNARY(checkApproxEq(*v, randVec1[--i]));
     790             :         //     }
     791             :         //     REQUIRE_EQ(i, 0);
     792             :         // }
     793             : 
     794           3 :         THEN("We can iterate and mutate")
     795           3 :         {
     796           1 :             int i = 0;
     797        8000 :             for (auto& v : dc1) {
     798        8000 :                 v = v * 2;
     799        8000 :                 REQUIRE_UNARY(checkApproxEq(v, 2 * randVec1[i++]));
     800        8000 :             }
     801           1 :             REQUIRE_EQ(i, size * size * size);
     802             : 
     803           1 :             i = 0;
     804        8000 :             for (auto v : dc1) {
     805        8000 :                 REQUIRE_UNARY(checkApproxEq(v, 2 * randVec1[i++]));
     806        8000 :             }
     807           1 :             REQUIRE_EQ(i, size * size * size);
     808           1 :         }
     809             : 
     810           3 :         THEN("We can use STL algorithms")
     811           3 :         {
     812           1 :             REQUIRE_EQ(*std::min_element(dc1.cbegin(), dc1.cend()), randVec1.minCoeff());
     813           1 :             REQUIRE_EQ(*std::max_element(dc1.cbegin(), dc1.cend()), randVec1.maxCoeff());
     814           1 :         }
     815           3 :     }
     816           9 : }
     817             : 
     818             : TEST_CASE_TEMPLATE("DataContainer: Clip a DataContainer", data_t, float, double)
     819          20 : {
     820          20 :     GIVEN("some 1D vectors")
     821          20 :     {
     822          16 :         index_t size = 7;
     823          16 :         IndexVector_t numCoeff(1);
     824          16 :         numCoeff << size;
     825          16 :         VolumeDescriptor desc(numCoeff);
     826             : 
     827          16 :         data_t min = 6;
     828          16 :         data_t max = 19;
     829             : 
     830          16 :         Vector_t<data_t> dataVec1(desc.getNumberOfCoefficients());
     831          16 :         dataVec1 << 6, 10, 7, 18, 10, 11, 9;
     832          16 :         Vector_t<data_t> expectedDataVec1(desc.getNumberOfCoefficients());
     833          16 :         expectedDataVec1 << 6, 10, 7, 18, 10, 11, 9;
     834             : 
     835          16 :         Vector_t<data_t> dataVec2(desc.getNumberOfCoefficients());
     836          16 :         dataVec2 << 4, -23, 7, 18, 18, 10, 10;
     837          16 :         Vector_t<data_t> expectedDataVec2(desc.getNumberOfCoefficients());
     838          16 :         expectedDataVec2 << min, min, 7, 18, 18, 10, 10;
     839             : 
     840          16 :         Vector_t<data_t> dataVec3(desc.getNumberOfCoefficients());
     841          16 :         dataVec3 << 14, 23, 7, 18, 20, 10, 10;
     842          16 :         Vector_t<data_t> expectedDataVec3(desc.getNumberOfCoefficients());
     843          16 :         expectedDataVec3 << 14, max, 7, 18, max, 10, 10;
     844             : 
     845          16 :         Vector_t<data_t> dataVec4(desc.getNumberOfCoefficients());
     846          16 :         dataVec4 << 1, 23, 5, 28, 20, 30, 0;
     847          16 :         Vector_t<data_t> expectedDataVec4(desc.getNumberOfCoefficients());
     848          16 :         expectedDataVec4 << min, max, min, max, max, max, min;
     849             : 
     850          16 :         WHEN("creating a data container out of a vector within bounds")
     851          16 :         {
     852           4 :             DataContainer dc(desc, dataVec1);
     853           4 :             auto clipped = clip(dc, min, max);
     854             : 
     855           4 :             THEN("the size of the clipped DataContainer is equal to that of the original container")
     856           4 :             {
     857           2 :                 REQUIRE_EQ(clipped.getSize(), size);
     858           2 :             }
     859             : 
     860           4 :             THEN("the values correspond to the original DataContainers")
     861           4 :             {
     862          16 :                 for (int i = 0; i < size; ++i) {
     863          14 :                     INFO("Error at position: ", i);
     864          14 :                     REQUIRE_EQ(clipped[i], expectedDataVec1[i]);
     865          14 :                 }
     866           2 :             }
     867           4 :         }
     868             : 
     869          16 :         WHEN("creating a data container out of a vector within or lower than the bounds")
     870          16 :         {
     871           4 :             DataContainer dc(desc, dataVec2);
     872           4 :             auto clipped = clip(dc, min, max);
     873             : 
     874           4 :             THEN("the size of the clipped DataContainer is equal to that of the original container")
     875           4 :             {
     876           2 :                 REQUIRE_EQ(clipped.getSize(), size);
     877           2 :             }
     878             : 
     879           4 :             THEN("the values correspond to the original DataContainers")
     880           4 :             {
     881          16 :                 for (int i = 0; i < size; ++i) {
     882          14 :                     INFO("Error at position: ", i);
     883          14 :                     REQUIRE_EQ(clipped[i], expectedDataVec2[i]);
     884          14 :                 }
     885           2 :             }
     886           4 :         }
     887             : 
     888          16 :         WHEN("creating a data container out of a vector within or higher than the bounds")
     889          16 :         {
     890           4 :             DataContainer dc(desc, dataVec3);
     891           4 :             auto clipped = clip(dc, min, max);
     892             : 
     893           4 :             THEN("the size of the clipped DataContainer is equal to that of the original container")
     894           4 :             {
     895           2 :                 REQUIRE_EQ(clipped.getSize(), size);
     896           2 :             }
     897             : 
     898           4 :             THEN("the values correspond to the original DataContainers")
     899           4 :             {
     900          16 :                 for (int i = 0; i < size; ++i) {
     901          14 :                     INFO("Error at position: ", i);
     902          14 :                     REQUIRE_EQ(clipped[i], expectedDataVec3[i]);
     903          14 :                 }
     904           2 :             }
     905           4 :         }
     906             : 
     907          16 :         WHEN("creating a data container out of a vector outside the bounds")
     908          16 :         {
     909           4 :             DataContainer dc(desc, dataVec4);
     910           4 :             auto clipped = clip(dc, min, max);
     911             : 
     912           4 :             THEN("the size of the clipped DataContainer is equal to that of the original container")
     913           4 :             {
     914           2 :                 REQUIRE_EQ(clipped.getSize(), size);
     915           2 :             }
     916             : 
     917           4 :             THEN("the values correspond to the original DataContainers")
     918           4 :             {
     919          16 :                 for (int i = 0; i < size; ++i) {
     920          14 :                     INFO("Error at position: ", i);
     921          14 :                     REQUIRE_EQ(clipped[i], expectedDataVec4[i]);
     922          14 :                 }
     923           2 :             }
     924           4 :         }
     925          16 :     }
     926             : 
     927          20 :     GIVEN("a 2D data container")
     928          20 :     {
     929           4 :         IndexVector_t numCoeff(2);
     930           4 :         numCoeff << 3, 2;
     931           4 :         VolumeDescriptor desc(numCoeff);
     932             : 
     933           4 :         data_t min = 0;
     934           4 :         data_t max = 8;
     935             : 
     936           4 :         Vector_t<data_t> dataVec(desc.getNumberOfCoefficients());
     937           4 :         dataVec << -19, -23, 7, 8, 20, 1;
     938           4 :         Vector_t<data_t> expectedDataVec(desc.getNumberOfCoefficients());
     939           4 :         expectedDataVec << min, min, 7, 8, max, 1;
     940             : 
     941           4 :         WHEN("creating a data container out of a vector within and outside of both bounds")
     942           4 :         {
     943           4 :             DataContainer dc(desc, dataVec);
     944           4 :             auto clipped = clip(dc, min, max);
     945             : 
     946           4 :             THEN("the size of the clipped DataContainer is equal to that of the original container")
     947           4 :             {
     948           2 :                 REQUIRE_EQ(clipped.getSize(), desc.getNumberOfCoefficients());
     949           2 :             }
     950             : 
     951           4 :             THEN("the values correspond to the original DataContainers")
     952           4 :             {
     953          14 :                 for (int i = 0; i < desc.getNumberOfCoefficients(); ++i) {
     954          12 :                     INFO("Error at position: ", i);
     955          12 :                     REQUIRE_EQ(clipped[i], expectedDataVec[i]);
     956          12 :                 }
     957           2 :             }
     958           4 :         }
     959           4 :     }
     960          20 : }
     961             : 
     962             : TEST_CASE_TEMPLATE("DataContainer: Concatenate two DataContainers", data_t, float, double,
     963             :                    complex<float>, complex<double>)
     964          28 : {
     965          28 :     GIVEN("Two equally sized 1D data containers")
     966          28 :     {
     967           8 :         constexpr index_t size = 20;
     968           8 :         IndexVector_t numCoeff(1);
     969           8 :         numCoeff << size;
     970           8 :         VolumeDescriptor desc(numCoeff);
     971             : 
     972           8 :         Vector_t<data_t> randVec1 = Vector_t<data_t>::Random(size);
     973           8 :         Vector_t<data_t> randVec2 = Vector_t<data_t>::Random(size);
     974             : 
     975           8 :         DataContainer dc1(desc, randVec1);
     976           8 :         DataContainer dc2(desc, randVec2);
     977             : 
     978           8 :         auto concated = concatenate(dc1, dc2);
     979           8 :         THEN("The size of the concatenated DataContainer is twice the original one")
     980           8 :         {
     981           4 :             REQUIRE_EQ(concated.getSize(), 2 * size);
     982           4 :         }
     983             : 
     984           8 :         THEN("The values correspond to the original DataContainers")
     985           8 :         {
     986          84 :             for (int i = 0; i < size; ++i) {
     987          80 :                 INFO("Error at position: ", i);
     988          80 :                 REQUIRE_EQ(concated[i], randVec1[i]);
     989          80 :             }
     990             : 
     991          84 :             for (int i = 0; i < size; ++i) {
     992          80 :                 INFO("Error at position: ", i + size);
     993          80 :                 REQUIRE_EQ(concated[i + size], randVec2[i]);
     994          80 :             }
     995           4 :         }
     996           8 :     }
     997             : 
     998          28 :     GIVEN("Two differently sized 1D data containers")
     999          28 :     {
    1000           8 :         IndexVector_t numCoeff(1);
    1001             : 
    1002           8 :         constexpr index_t size1 = 20;
    1003           8 :         numCoeff[0] = size1;
    1004           8 :         VolumeDescriptor desc1(numCoeff);
    1005             : 
    1006           8 :         constexpr index_t size2 = 10;
    1007           8 :         numCoeff[0] = size2;
    1008           8 :         VolumeDescriptor desc2(numCoeff);
    1009             : 
    1010           8 :         Vector_t<data_t> randVec1 = Vector_t<data_t>::Random(size1);
    1011           8 :         Vector_t<data_t> randVec2 = Vector_t<data_t>::Random(size2);
    1012             : 
    1013           8 :         DataContainer dc1(desc1, randVec1);
    1014           8 :         DataContainer dc2(desc2, randVec2);
    1015             : 
    1016           8 :         auto concated = concatenate(dc1, dc2);
    1017             : 
    1018           8 :         THEN("The size of the concatenated DataContainer is twice the original one")
    1019           8 :         {
    1020           4 :             REQUIRE_EQ(concated.getSize(), size1 + size2);
    1021           4 :         }
    1022             : 
    1023           8 :         THEN("The values correspond to the original DataContainers")
    1024           8 :         {
    1025          84 :             for (int i = 0; i < size1; ++i) {
    1026          80 :                 INFO("Error at position: ", i);
    1027          80 :                 REQUIRE_EQ(concated[i], randVec1[i]);
    1028          80 :             }
    1029             : 
    1030          44 :             for (int i = 0; i < size2; ++i) {
    1031          40 :                 INFO("Error at position: ", i + size1);
    1032          40 :                 REQUIRE_EQ(concated[i + size1], randVec2[i]);
    1033          40 :             }
    1034           4 :         }
    1035           8 :     }
    1036             : 
    1037          28 :     GIVEN("Two equally sized 2D data containers")
    1038          28 :     {
    1039           8 :         constexpr index_t size = 20;
    1040           8 :         IndexVector_t numCoeff(2);
    1041           8 :         numCoeff << size, size;
    1042           8 :         VolumeDescriptor desc(numCoeff);
    1043             : 
    1044           8 :         Vector_t<data_t> randVec1 = Vector_t<data_t>::Random(size * size);
    1045           8 :         Vector_t<data_t> randVec2 = Vector_t<data_t>::Random(size * size);
    1046             : 
    1047           8 :         DataContainer dc1(desc, randVec1);
    1048           8 :         DataContainer dc2(desc, randVec2);
    1049             : 
    1050           8 :         auto concated = concatenate(dc1, dc2);
    1051           8 :         THEN("The size of the concatenated DataContainer is twice the original one")
    1052           8 :         {
    1053           4 :             REQUIRE_EQ(concated.getSize(), 2 * (size * size));
    1054           4 :         }
    1055             : 
    1056           8 :         THEN("The values correspond to the original DataContainers")
    1057           8 :         {
    1058        1604 :             for (int i = 0; i < size * size; ++i) {
    1059        1600 :                 INFO("Error at position: ", i);
    1060        1600 :                 REQUIRE_EQ(concated[i], randVec1[i]);
    1061        1600 :             }
    1062             : 
    1063        1604 :             for (int i = 0; i < size * size; ++i) {
    1064        1600 :                 INFO("Error at position: ", i + size);
    1065        1600 :                 REQUIRE_EQ(concated[i + size * size], randVec2[i]);
    1066        1600 :             }
    1067           4 :         }
    1068           8 :     }
    1069             : 
    1070          28 :     GIVEN("DataContainers of different dimension")
    1071          28 :     {
    1072           4 :         IndexVector_t numCoeff1D(1);
    1073           4 :         numCoeff1D << 20;
    1074           4 :         VolumeDescriptor desc1D(numCoeff1D);
    1075             : 
    1076           4 :         IndexVector_t numCoeff2D(2);
    1077           4 :         numCoeff2D << 20, 20;
    1078           4 :         VolumeDescriptor desc2D(numCoeff2D);
    1079             : 
    1080           4 :         DataContainer dc1(desc1D);
    1081           4 :         DataContainer dc2(desc2D);
    1082             : 
    1083           4 :         THEN("The concatenation throws")
    1084           4 :         {
    1085           4 :             REQUIRE_THROWS_AS(concatenate(dc1, dc2), LogicError);
    1086           4 :         }
    1087           4 :     }
    1088          28 : }
    1089             : 
    1090             : TEST_CASE_TEMPLATE("DataContainer: Assign to a slice of a DataContainer", data_t, float, double,
    1091             :                    complex<float>, complex<double>)
    1092           4 : {
    1093             :     // Set seed for Eigen Matrices!
    1094           4 :     srand((unsigned int) 666);
    1095             : 
    1096           4 :     constexpr index_t size = 20;
    1097           4 :     IndexVector_t numCoeff2D(2);
    1098           4 :     numCoeff2D << size, size;
    1099             : 
    1100           4 :     const VolumeDescriptor desc(numCoeff2D);
    1101           4 :     const Vector_t<data_t> randVec = Vector_t<data_t>::Random(size * size);
    1102           4 :     const DataContainer<data_t> dc(desc, randVec);
    1103             : 
    1104           4 :     IndexVector_t sliceCoeffs({{4, 5}});
    1105           4 :     const VolumeDescriptor sliceDesc(sliceCoeffs);
    1106             : 
    1107          84 :     for (int i = 0; i < size; ++i) {
    1108          80 :         auto slice = dc.slice(i);
    1109          80 :         auto ones = DataContainer<data_t>(sliceDesc, Vector_t<data_t>::Ones(size));
    1110          80 :         auto tmp = slice.viewAs(sliceDesc);
    1111             : 
    1112          80 :         slice.viewAs(sliceDesc) = ones;
    1113             : 
    1114        1680 :         for (int j = 0; j < size; ++j) {
    1115        1600 :             CHECK_UNARY(checkApproxEq(slice[j], ones[j]));
    1116        1600 :             CHECK_UNARY(checkApproxEq(dc(j, i), ones[j]));
    1117        1600 :         }
    1118          80 :     }
    1119           4 : }
    1120             : 
    1121             : TEST_CASE_TEMPLATE("DataContainer: Slice a DataContainer", data_t, float, double, complex<float>,
    1122             :                    complex<double>)
    1123          72 : {
    1124             :     // Set seed for Eigen Matrices!
    1125          72 :     srand((unsigned int) 666);
    1126             : 
    1127          72 :     GIVEN("A non 3D DataContainer")
    1128          72 :     {
    1129          16 :         constexpr index_t size = 20;
    1130          16 :         IndexVector_t numCoeff2D(2);
    1131          16 :         numCoeff2D << size, size;
    1132             : 
    1133          16 :         const VolumeDescriptor desc(numCoeff2D);
    1134          16 :         const Vector_t<data_t> randVec = Vector_t<data_t>::Random(size * size);
    1135          16 :         const DataContainer<data_t> dc(desc, randVec);
    1136             : 
    1137          16 :         IndexVector_t sliceCoeffs({{4, 5}});
    1138          16 :         const VolumeDescriptor sliceDesc(sliceCoeffs);
    1139             : 
    1140          16 :         THEN("Accessing an out of bounds slice throws")
    1141          16 :         {
    1142           4 :             REQUIRE_THROWS_AS(dc.slice(20), LogicError);
    1143           4 :         }
    1144             : 
    1145          16 :         WHEN("Accessing a slice")
    1146          16 :         {
    1147          12 :             const auto i = 5;
    1148          12 :             auto slice = dc.slice(5);
    1149             : 
    1150          12 :             THEN("The the slice is a 2D slice of \"thickness\" 1")
    1151          12 :             {
    1152           4 :                 REQUIRE_EQ(slice.getDataDescriptor().getNumberOfDimensions(), 2);
    1153             : 
    1154           4 :                 auto coeffs = slice.getDataDescriptor().getNumberOfCoefficientsPerDimension();
    1155           4 :                 auto expectedCoeffs = IndexVector_t(2);
    1156           4 :                 expectedCoeffs << size, 1;
    1157           4 :                 REQUIRE_EQ(coeffs, expectedCoeffs);
    1158           4 :             }
    1159             : 
    1160          12 :             THEN("All values are the same as of the original DataContainer")
    1161          12 :             {
    1162             :                 // Check that it's read correctly
    1163           4 :                 auto vecSlice = randVec.segment(i * size, size);
    1164          84 :                 for (int j = 0; j < size; ++j) {
    1165          80 :                     REQUIRE_UNARY(checkApproxEq(slice(j, 0), vecSlice[j]));
    1166          80 :                 }
    1167           4 :             }
    1168             : 
    1169          12 :             THEN("Assigning to slice changes original container")
    1170          12 :             {
    1171           4 :                 auto ones = DataContainer<data_t>(sliceDesc, Vector_t<data_t>::Ones(size));
    1172           4 :                 auto tmp = slice.viewAs(sliceDesc);
    1173             : 
    1174           4 :                 slice = ones;
    1175             : 
    1176          84 :                 for (int j = 0; j < size; ++j) {
    1177          80 :                     CHECK_UNARY(checkApproxEq(slice(j, 0), ones[j]));
    1178          80 :                     CHECK_UNARY(checkApproxEq(dc(j, i), ones[j]));
    1179          80 :                 }
    1180           4 :             }
    1181          12 :         }
    1182          16 :     }
    1183             : 
    1184          72 :     GIVEN("A const 3D DataContainer")
    1185          72 :     {
    1186          16 :         constexpr index_t size = 20;
    1187             : 
    1188          16 :         const VolumeDescriptor desc({size, size, size});
    1189          16 :         const Vector_t<data_t> randVec = Vector_t<data_t>::Random(size * size * size);
    1190          16 :         const DataContainer<data_t> dc(desc, randVec);
    1191             : 
    1192          16 :         THEN("Accessing an out of bounds slice throws")
    1193          16 :         {
    1194           4 :             REQUIRE_THROWS_AS(dc.slice(20), LogicError);
    1195           4 :         }
    1196             : 
    1197          16 :         WHEN("Accessing all the slices")
    1198          16 :         {
    1199         252 :             for (int i = 0; i < size; ++i) {
    1200         240 :                 auto slice = dc.slice(i);
    1201             : 
    1202         240 :                 THEN("The the slice is a 3D slice of \"thickness\" 1")
    1203         240 :                 {
    1204           4 :                     REQUIRE_EQ(slice.getDataDescriptor().getNumberOfDimensions(), 3);
    1205             : 
    1206           4 :                     auto coeffs = slice.getDataDescriptor().getNumberOfCoefficientsPerDimension();
    1207           4 :                     auto expectedCoeffs = IndexVector_t(3);
    1208           4 :                     expectedCoeffs << size, size, 1;
    1209           4 :                     REQUIRE_EQ(coeffs, expectedCoeffs);
    1210           4 :                 }
    1211             : 
    1212         240 :                 THEN("All values are the same as of the original DataContainer")
    1213         240 :                 {
    1214             :                     // Check that it's read correctly
    1215           4 :                     auto vecSlice = randVec.segment(i * size * size, size * size);
    1216          84 :                     for (int j = 0; j < size; ++j) {
    1217        1680 :                         for (int k = 0; k < size; ++k) {
    1218        1600 :                             REQUIRE_UNARY(checkApproxEq(slice(k, j, 0), vecSlice[k + j * size]));
    1219        1600 :                         }
    1220          80 :                     }
    1221           4 :                 }
    1222         240 :             }
    1223          12 :         }
    1224          16 :     }
    1225             : 
    1226          72 :     GIVEN("A non-const 3D DataContainer")
    1227          72 :     {
    1228          32 :         constexpr index_t size = 20;
    1229          32 :         IndexVector_t numCoeff(3);
    1230          32 :         numCoeff << size, size, size;
    1231             : 
    1232          32 :         const VolumeDescriptor desc(numCoeff);
    1233          32 :         DataContainer<data_t> dc(desc);
    1234          32 :         dc = 0;
    1235             : 
    1236          32 :         THEN("Accessing an out of bounds slice throws")
    1237          32 :         {
    1238           4 :             REQUIRE_THROWS_AS(dc.slice(20), LogicError);
    1239           4 :         }
    1240             : 
    1241          32 :         WHEN("Setting the first slice to 1")
    1242          32 :         {
    1243           8 :             dc.slice(0) = 1;
    1244             : 
    1245           8 :             THEN("Only the first slice is set to 1")
    1246           8 :             {
    1247          84 :                 for (int j = 0; j < size; ++j) {
    1248        1680 :                     for (int i = 0; i < size; ++i) {
    1249        1600 :                         data_t val = dc(i, j, 0);
    1250        1600 :                         INFO("Expected slice 0 to be ", data_t{1}, " but it's ", val, " (at (", i,
    1251        1600 :                              ", ", j, ", 0))");
    1252        1600 :                         REQUIRE_UNARY(checkApproxEq(val, 1));
    1253        1600 :                     }
    1254          80 :                 }
    1255           4 :             }
    1256             : 
    1257           8 :             THEN("The other slices are still set to 0")
    1258           8 :             {
    1259          80 :                 for (int k = 1; k < size; ++k) {
    1260        1596 :                     for (int j = 0; j < size; ++j) {
    1261       31920 :                         for (int i = 0; i < size; ++i) {
    1262       30400 :                             data_t val = dc(i, j, k);
    1263       30400 :                             INFO("Expected all slices but the first to be ", data_t{0},
    1264       30400 :                                  " but it's ", val, " (at (", i, ", ", j, ", 0))");
    1265       30400 :                             REQUIRE_UNARY(checkApproxEq(val, 0));
    1266       30400 :                         }
    1267        1520 :                     }
    1268          76 :                 }
    1269           4 :             }
    1270           8 :         }
    1271             : 
    1272          32 :         WHEN("Setting the fifth slice to some random data using a 3D DataContainer")
    1273          32 :         {
    1274          12 :             Vector_t<data_t> randVec = Vector_t<data_t>::Random(size * size * 1);
    1275          12 :             const DataContainer slice(VolumeDescriptor({size, size, 1}), randVec);
    1276             : 
    1277          12 :             dc.slice(5) = slice;
    1278          12 :             THEN("The first 4 slices are still zero")
    1279          12 :             {
    1280          24 :                 for (int k = 0; k < 5; ++k) {
    1281         420 :                     for (int j = 0; j < size; ++j) {
    1282        8400 :                         for (int i = 0; i < size; ++i) {
    1283        8000 :                             data_t val = dc(i, j, k);
    1284             : 
    1285        8000 :                             INFO("Expected all slices but the first to be ", data_t{0},
    1286        8000 :                                  " but it's ", val, " (at (", i, ", ", j, ", 0))");
    1287        8000 :                             REQUIRE_UNARY(checkApproxEq(val, 0));
    1288        8000 :                         }
    1289         400 :                     }
    1290          20 :                 }
    1291           4 :             }
    1292             : 
    1293          12 :             THEN("The fifth slices set correctly")
    1294          12 :             {
    1295          84 :                 for (int j = 0; j < size; ++j) {
    1296        1680 :                     for (int i = 0; i < size; ++i) {
    1297        1600 :                         data_t val = dc(i, j, 5);
    1298        1600 :                         auto expected = randVec[i + j * size];
    1299        1600 :                         INFO("Expected slice 0 to be ", expected, " but it's ", val, " (at (", i,
    1300        1600 :                              ", ", j, ", 0))");
    1301        1600 :                         REQUIRE_UNARY(checkApproxEq(val, expected));
    1302        1600 :                     }
    1303          80 :                 }
    1304           4 :             }
    1305             : 
    1306          12 :             THEN("The last 14 slices are still zero")
    1307          12 :             {
    1308             :                 // Check last slices
    1309          60 :                 for (int k = 6; k < size; ++k) {
    1310        1176 :                     for (int j = 0; j < size; ++j) {
    1311       23520 :                         for (int i = 0; i < size; ++i) {
    1312       22400 :                             data_t val = dc(i, j, k);
    1313             : 
    1314       22400 :                             INFO("Expected all slices but the first to be ", data_t{0},
    1315       22400 :                                  " but it's ", val, " (at (", i, ", ", j, ", 0))");
    1316       22400 :                             REQUIRE_UNARY(checkApproxEq(val, 0));
    1317       22400 :                         }
    1318        1120 :                     }
    1319          56 :                 }
    1320           4 :             }
    1321          12 :         }
    1322             : 
    1323          32 :         WHEN("Setting the first slice to some random data using a 2D DataContainer")
    1324          32 :         {
    1325           8 :             Vector_t<data_t> randVec = Vector_t<data_t>::Random(size * size);
    1326           8 :             const DataContainer slice(VolumeDescriptor({size, size}), randVec);
    1327             : 
    1328           8 :             dc.slice(0) = slice;
    1329           8 :             THEN("The fifth slices set correctly")
    1330           8 :             {
    1331          84 :                 for (int j = 0; j < size; ++j) {
    1332        1680 :                     for (int i = 0; i < size; ++i) {
    1333        1600 :                         data_t val = dc(i, j, 0);
    1334        1600 :                         auto expected = randVec[i + j * size];
    1335        1600 :                         INFO("Expected slice 0 to be ", expected, " but it's ", val, " (at (", i,
    1336        1600 :                              ", ", j, ", 0))");
    1337        1600 :                         REQUIRE_UNARY(checkApproxEq(val, expected));
    1338        1600 :                     }
    1339          80 :                 }
    1340           4 :             }
    1341           8 :             THEN("The other slices are still zero")
    1342           8 :             {
    1343          80 :                 for (int k = 1; k < size; ++k) {
    1344        1596 :                     for (int j = 0; j < size; ++j) {
    1345       31920 :                         for (int i = 0; i < size; ++i) {
    1346       30400 :                             data_t val = dc(i, j, k);
    1347       30400 :                             INFO("Expected all slices but the first to be ", data_t{0},
    1348       30400 :                                  " but it's ", val, " (at (", i, ", ", j, ", 0))");
    1349       30400 :                             REQUIRE_UNARY(checkApproxEq(val, 0));
    1350       30400 :                         }
    1351        1520 :                     }
    1352          76 :                 }
    1353           4 :             }
    1354           8 :         }
    1355          32 :     }
    1356             : 
    1357          72 :     GIVEN("a 3D DataDescriptor and a 3D random Vector")
    1358          72 :     {
    1359           8 :         constexpr index_t size = 28;
    1360           8 :         constexpr index_t one = 1;
    1361           8 :         IndexVector_t numCoeff3D(3);
    1362           8 :         numCoeff3D << size, size, one;
    1363             : 
    1364           8 :         const VolumeDescriptor desc(numCoeff3D);
    1365           8 :         const Vector_t<data_t> randVec = Vector_t<data_t>::Random(size * size * one);
    1366             : 
    1367           8 :         WHEN("slicing a non-const DataContainer with the size of the last dimension of 1")
    1368           8 :         {
    1369           4 :             DataContainer<data_t> dc(desc, randVec);
    1370             : 
    1371           4 :             DataContainer<data_t> res = dc.slice(0);
    1372             : 
    1373           4 :             THEN("the DataContainers match")
    1374           4 :             {
    1375           4 :                 REQUIRE_EQ(dc, res);
    1376           4 :             }
    1377           4 :         }
    1378             : 
    1379           8 :         WHEN("slicing a const DataContainer with the size of the last dimension of 1")
    1380           8 :         {
    1381           4 :             const DataContainer<data_t> dc(desc, randVec);
    1382             : 
    1383           4 :             const DataContainer<data_t> res = dc.slice(0);
    1384             : 
    1385           4 :             THEN("the DataContainers match")
    1386           4 :             {
    1387           4 :                 REQUIRE_EQ(dc, res);
    1388           4 :             }
    1389           4 :         }
    1390           8 :     }
    1391          72 : }
    1392             : 
    1393             : TEST_CASE_TEMPLATE("DataContainer: FFT shift and IFFT shift a DataContainer", data_t, float, double,
    1394             :                    complex<float>, complex<double>)
    1395          48 : {
    1396          48 :     GIVEN("a one-element 2D data container")
    1397          48 :     {
    1398          16 :         DataContainer<data_t> dc(VolumeDescriptor{{1, 1}});
    1399          16 :         dc[0] = 8;
    1400          16 :         WHEN("running the FFT shift operation to the container")
    1401          16 :         {
    1402           8 :             DataContainer<data_t> fftShiftedDC = fftShift2D(dc);
    1403           8 :             THEN("the data descriptors match")
    1404           8 :             {
    1405           4 :                 REQUIRE_EQ(dc.getDataDescriptor(), fftShiftedDC.getDataDescriptor());
    1406           4 :             }
    1407           8 :             THEN("the data containers match")
    1408           8 :             {
    1409           4 :                 REQUIRE_UNARY(fftShiftedDC == dc);
    1410           4 :             }
    1411           8 :         }
    1412             : 
    1413          16 :         WHEN("running the IFFT shift operation to the container")
    1414          16 :         {
    1415           8 :             DataContainer<data_t> ifftShiftedDC = ifftShift2D(dc);
    1416           8 :             THEN("the data descriptors match")
    1417           8 :             {
    1418           4 :                 REQUIRE_EQ(dc.getDataDescriptor(), ifftShiftedDC.getDataDescriptor());
    1419           4 :             }
    1420           8 :             THEN("the data containers match")
    1421           8 :             {
    1422           4 :                 REQUIRE_UNARY(ifftShiftedDC == dc);
    1423           4 :             }
    1424           8 :         }
    1425          16 :     }
    1426             : 
    1427          48 :     GIVEN("a 3x3 2D data container")
    1428          48 :     {
    1429          16 :         DataContainer<data_t> dc(VolumeDescriptor{{3, 3}});
    1430          16 :         dc(0, 0) = 0;
    1431          16 :         dc(0, 1) = 1;
    1432          16 :         dc(0, 2) = 2;
    1433          16 :         dc(1, 0) = 3;
    1434          16 :         dc(1, 1) = 4;
    1435          16 :         dc(1, 2) = -4;
    1436          16 :         dc(2, 0) = -3;
    1437          16 :         dc(2, 1) = -2;
    1438          16 :         dc(2, 2) = -1;
    1439             : 
    1440          16 :         DataContainer<data_t> expectedFFTShiftDC(VolumeDescriptor{{3, 3}});
    1441          16 :         expectedFFTShiftDC(0, 0) = -1;
    1442          16 :         expectedFFTShiftDC(0, 1) = -3;
    1443          16 :         expectedFFTShiftDC(0, 2) = -2;
    1444          16 :         expectedFFTShiftDC(1, 0) = 2;
    1445          16 :         expectedFFTShiftDC(1, 1) = 0;
    1446          16 :         expectedFFTShiftDC(1, 2) = 1;
    1447          16 :         expectedFFTShiftDC(2, 0) = -4;
    1448          16 :         expectedFFTShiftDC(2, 1) = 3;
    1449          16 :         expectedFFTShiftDC(2, 2) = 4;
    1450             : 
    1451          16 :         WHEN("running the FFT shift operation to the container")
    1452          16 :         {
    1453           8 :             DataContainer<data_t> fftShiftedDC = fftShift2D(dc);
    1454           8 :             THEN("the data descriptors match")
    1455           8 :             {
    1456           4 :                 REQUIRE_EQ(fftShiftedDC.getDataDescriptor(),
    1457           4 :                            expectedFFTShiftDC.getDataDescriptor());
    1458           4 :             }
    1459           8 :             THEN("the data containers match")
    1460           8 :             {
    1461           4 :                 REQUIRE_UNARY(fftShiftedDC == expectedFFTShiftDC);
    1462           4 :             }
    1463           8 :         }
    1464             : 
    1465          16 :         DataContainer<data_t> expectedIFFTShiftDC(VolumeDescriptor{{3, 3}});
    1466          16 :         expectedIFFTShiftDC(0, 0) = 4;
    1467          16 :         expectedIFFTShiftDC(0, 1) = -4;
    1468          16 :         expectedIFFTShiftDC(0, 2) = 3;
    1469          16 :         expectedIFFTShiftDC(1, 0) = -2;
    1470          16 :         expectedIFFTShiftDC(1, 1) = -1;
    1471          16 :         expectedIFFTShiftDC(1, 2) = -3;
    1472          16 :         expectedIFFTShiftDC(2, 0) = 1;
    1473          16 :         expectedIFFTShiftDC(2, 1) = 2;
    1474          16 :         expectedIFFTShiftDC(2, 2) = 0;
    1475             : 
    1476          16 :         WHEN("running the IFFT shift operation to the container")
    1477          16 :         {
    1478           8 :             DataContainer<data_t> ifftShiftedDC = ifftShift2D(dc);
    1479           8 :             THEN("the data descriptors match")
    1480           8 :             {
    1481           4 :                 REQUIRE_EQ(ifftShiftedDC.getDataDescriptor(),
    1482           4 :                            expectedIFFTShiftDC.getDataDescriptor());
    1483           4 :             }
    1484           8 :             THEN("the data containers match")
    1485           8 :             {
    1486           4 :                 REQUIRE_UNARY(ifftShiftedDC == expectedIFFTShiftDC);
    1487           4 :             }
    1488           8 :         }
    1489          16 :     }
    1490             : 
    1491          48 :     GIVEN("a 5x5 2D data container")
    1492          48 :     {
    1493          16 :         DataContainer<data_t> dc(VolumeDescriptor{{5, 5}});
    1494          16 :         dc(0, 0) = 28;
    1495          16 :         dc(0, 1) = 1;
    1496          16 :         dc(0, 2) = 5;
    1497          16 :         dc(0, 3) = -18;
    1498          16 :         dc(0, 4) = 8;
    1499          16 :         dc(1, 0) = 5;
    1500          16 :         dc(1, 1) = 6;
    1501          16 :         dc(1, 2) = 50;
    1502          16 :         dc(1, 3) = -8;
    1503          16 :         dc(1, 4) = 9;
    1504          16 :         dc(2, 0) = 8;
    1505          16 :         dc(2, 1) = 9;
    1506          16 :         dc(2, 2) = 10;
    1507          16 :         dc(2, 3) = 11;
    1508          16 :         dc(2, 4) = 12;
    1509          16 :         dc(3, 0) = -12;
    1510          16 :         dc(3, 1) = -41;
    1511          16 :         dc(3, 2) = -10;
    1512          16 :         dc(3, 3) = -9;
    1513          16 :         dc(3, 4) = -8;
    1514          16 :         dc(4, 0) = -70;
    1515          16 :         dc(4, 1) = -6;
    1516          16 :         dc(4, 2) = 22;
    1517          16 :         dc(4, 3) = -10;
    1518          16 :         dc(4, 4) = -3;
    1519             : 
    1520          16 :         DataContainer<data_t> expectedFFTShiftDC(VolumeDescriptor{{5, 5}});
    1521          16 :         expectedFFTShiftDC(0, 0) = -9;
    1522          16 :         expectedFFTShiftDC(0, 1) = -8;
    1523          16 :         expectedFFTShiftDC(0, 2) = -12;
    1524          16 :         expectedFFTShiftDC(0, 3) = -41;
    1525          16 :         expectedFFTShiftDC(0, 4) = -10;
    1526          16 :         expectedFFTShiftDC(1, 0) = -10;
    1527          16 :         expectedFFTShiftDC(1, 1) = -3;
    1528          16 :         expectedFFTShiftDC(1, 2) = -70;
    1529          16 :         expectedFFTShiftDC(1, 3) = -6;
    1530          16 :         expectedFFTShiftDC(1, 4) = 22;
    1531          16 :         expectedFFTShiftDC(2, 0) = -18;
    1532          16 :         expectedFFTShiftDC(2, 1) = 8;
    1533          16 :         expectedFFTShiftDC(2, 2) = 28;
    1534          16 :         expectedFFTShiftDC(2, 3) = 1;
    1535          16 :         expectedFFTShiftDC(2, 4) = 5;
    1536          16 :         expectedFFTShiftDC(3, 0) = -8;
    1537          16 :         expectedFFTShiftDC(3, 1) = 9;
    1538          16 :         expectedFFTShiftDC(3, 2) = 5;
    1539          16 :         expectedFFTShiftDC(3, 3) = 6;
    1540          16 :         expectedFFTShiftDC(3, 4) = 50;
    1541          16 :         expectedFFTShiftDC(4, 0) = 11;
    1542          16 :         expectedFFTShiftDC(4, 1) = 12;
    1543          16 :         expectedFFTShiftDC(4, 2) = 8;
    1544          16 :         expectedFFTShiftDC(4, 3) = 9;
    1545          16 :         expectedFFTShiftDC(4, 4) = 10;
    1546             : 
    1547          16 :         WHEN("running the FFT shift operation to the container")
    1548          16 :         {
    1549           8 :             DataContainer<data_t> fftShiftedDC = fftShift2D(dc);
    1550           8 :             THEN("the data descriptors match")
    1551           8 :             {
    1552           4 :                 REQUIRE_EQ(fftShiftedDC.getDataDescriptor(),
    1553           4 :                            expectedFFTShiftDC.getDataDescriptor());
    1554           4 :             }
    1555           8 :             THEN("the data containers match")
    1556           8 :             {
    1557           4 :                 REQUIRE_UNARY(fftShiftedDC == expectedFFTShiftDC);
    1558           4 :             }
    1559           8 :         }
    1560             : 
    1561          16 :         DataContainer<data_t> expectedIFFTShiftDC(VolumeDescriptor{{5, 5}});
    1562          16 :         expectedIFFTShiftDC(0, 0) = 10;
    1563          16 :         expectedIFFTShiftDC(0, 1) = 11;
    1564          16 :         expectedIFFTShiftDC(0, 2) = 12;
    1565          16 :         expectedIFFTShiftDC(0, 3) = 8;
    1566          16 :         expectedIFFTShiftDC(0, 4) = 9;
    1567          16 :         expectedIFFTShiftDC(1, 0) = -10;
    1568          16 :         expectedIFFTShiftDC(1, 1) = -9;
    1569          16 :         expectedIFFTShiftDC(1, 2) = -8;
    1570          16 :         expectedIFFTShiftDC(1, 3) = -12;
    1571          16 :         expectedIFFTShiftDC(1, 4) = -41;
    1572          16 :         expectedIFFTShiftDC(2, 0) = 22;
    1573          16 :         expectedIFFTShiftDC(2, 1) = -10;
    1574          16 :         expectedIFFTShiftDC(2, 2) = -3;
    1575          16 :         expectedIFFTShiftDC(2, 3) = -70;
    1576          16 :         expectedIFFTShiftDC(2, 4) = -6;
    1577          16 :         expectedIFFTShiftDC(3, 0) = 5;
    1578          16 :         expectedIFFTShiftDC(3, 1) = -18;
    1579          16 :         expectedIFFTShiftDC(3, 2) = 8;
    1580          16 :         expectedIFFTShiftDC(3, 3) = 28;
    1581          16 :         expectedIFFTShiftDC(3, 4) = 1;
    1582          16 :         expectedIFFTShiftDC(4, 0) = 50;
    1583          16 :         expectedIFFTShiftDC(4, 1) = -8;
    1584          16 :         expectedIFFTShiftDC(4, 2) = 9;
    1585          16 :         expectedIFFTShiftDC(4, 3) = 5;
    1586          16 :         expectedIFFTShiftDC(4, 4) = 6;
    1587             : 
    1588          16 :         WHEN("running the IFFT shift operation to the container")
    1589          16 :         {
    1590           8 :             DataContainer<data_t> ifftShiftedDC = ifftShift2D(dc);
    1591           8 :             THEN("the data descriptors match")
    1592           8 :             {
    1593           4 :                 REQUIRE_EQ(ifftShiftedDC.getDataDescriptor(),
    1594           4 :                            expectedIFFTShiftDC.getDataDescriptor());
    1595           4 :             }
    1596           8 :             THEN("the data containers match")
    1597           8 :             {
    1598           4 :                 REQUIRE_UNARY(ifftShiftedDC == expectedIFFTShiftDC);
    1599           4 :             }
    1600           8 :         }
    1601          16 :     }
    1602          48 : }
    1603             : 
    1604             : // "instantiate" the test templates for CPU types
    1605             : TEST_CASE_TEMPLATE_APPLY(datacontainer_construction, CPUTypeTuple);
    1606             : TEST_CASE_TEMPLATE_APPLY(datacontainer_reduction, CPUTypeTuple);
    1607             : TEST_CASE_TEMPLATE_APPLY(datacontainer_elemwise, CPUTypeTuple);
    1608             : TEST_CASE_TEMPLATE_APPLY(datacontainer_arithmetic, CPUTypeTuple);
    1609             : TEST_CASE_TEMPLATE_APPLY(datacontainer_maps, CPUTypeTuple);
    1610             : 
    1611             : #ifdef ELSA_CUDA_VECTOR
    1612             : // "instantiate" the test templates for GPU types
    1613             : TEST_CASE_TEMPLATE_APPLY(datacontainer_construction, GPUTypeTuple);
    1614             : TEST_CASE_TEMPLATE_APPLY(datacontainer_reduction, GPUTypeTuple);
    1615             : TEST_CASE_TEMPLATE_APPLY(datacontainer_elemwise, GPUTypeTuple);
    1616             : TEST_CASE_TEMPLATE_APPLY(datacontainer_arithmetic, GPUTypeTuple);
    1617             : TEST_CASE_TEMPLATE_APPLY(datacontainer_maps, GPUTypeTuple);
    1618             : #endif
    1619             : 
    1620             : TEST_SUITE_END();

Generated by: LCOV version 1.14