LCOV - code coverage report
Current view: top level - core/tests - test_DataContainer.cpp (source / functions) Hit Total Coverage
Test: test_coverage.info.cleaned Lines: 775 775 100.0 %
Date: 2022-02-28 03:37:41 Functions: 90 167 53.9 %

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

Generated by: LCOV version 1.15