diff --git a/tests/test_fftw.cpp b/tests/test_fftw.cpp index 854c2c0d..7e586e6c 100644 --- a/tests/test_fftw.cpp +++ b/tests/test_fftw.cpp @@ -1,240 +1,240 @@ /* * SPDX-License-Indentifier: AGPL-3.0-or-later * * Copyright (©) 2016-2023 EPFL (École Polytechnique Fédérale de Lausanne), * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * Copyright (©) 2020-2023 Lucas Frérot * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "fftw/fftw_engine.hh" #include "grid.hh" #include "grid_hermitian.hh" #include "grid_view.hh" #include "test.hh" using namespace tamaas; using fft = fftw::helper<Real>; /* -------------------------------------------------------------------------- */ namespace fftw_impl { template <typename T> struct span { T* ptr; std::size_t size; ~span() { fftw::free(ptr); } const T* begin() const { return ptr; } const T* end() const { return ptr + size; } T* begin() { return ptr; } T* end() { return ptr + size; } operator T*() { return ptr; } }; } // namespace fftw_impl /* -------------------------------------------------------------------------- */ TEST(TestFFTWEngine, FFT1D) { constexpr UInt size = 1000; FFTWEngine engine; fftw::span<Real> data{fft::alloc_real(size), size}; fftw::span<fft::complex> solution{fft::alloc_complex(size / 2 + 1), size / 2 + 1}; fftw::plan<Real> solution_plan{ fftw::plan_1d_forward(size, data, solution, engine.flags())}; std::iota(data.begin(), data.end(), 0); fftw::execute(solution_plan); - Grid<Real, 1> grid({size}, 1); - GridHermitian<Real, 1> result({size / 2 + 1}, 1); + Grid<Real, 1> grid{{size}, 1}; + GridHermitian<Real, 1> result{{size / 2 + 1}, 1}; std::iota(grid.begin(), grid.end(), 0); engine.forward(grid, result); ASSERT_TRUE(compare(result, solution, AreComplexEqual())) << "1D FFTW transform failed"; } /* -------------------------------------------------------------------------- */ TEST(TestFFTWEngine, FFT2D) { constexpr UInt size = 100; constexpr UInt rsize = size * size; constexpr UInt csize = size * (size / 2 + 1); FFTWEngine engine; fftw::span<Real> data{fft::alloc_real(rsize), rsize}; fftw::span<fft::complex> solution{fft::alloc_complex(csize), csize}; fftw::plan<Real> solution_plan{ fftw::plan_2d_forward(size, size, data, solution, engine.flags())}; std::iota(data.begin(), data.end(), 0); fftw::execute(solution_plan); - Grid<Real, 2> grid({size, size}, 1); - GridHermitian<Real, 2> result({size, size / 2 + 1}, 1); + Grid<Real, 2> grid{{size, size}, 1}; + GridHermitian<Real, 2> result{{size, size / 2 + 1}, 1}; std::iota(grid.begin(), grid.end(), 0); engine.forward(grid, result); ASSERT_TRUE(compare(result, solution, AreComplexEqual())) << "2D FFTW transform failed"; } /* -------------------------------------------------------------------------- */ TEST(TestFFTWEngine, FFT2DBackwards) { const std::ptrdiff_t N0 = 20, N1 = 20; - Grid<Real, 2> real({N0, N1}, 1); - GridHermitian<Real, 2> spectral({N0, N1 / 2 + 1}, 1); + Grid<Real, 2> real{{N0, N1}, 1}; + GridHermitian<Real, 2> spectral{{N0, N1 / 2 + 1}, 1}; real = 1.; FFTWEngine engine; engine.forward(real, spectral); real = 0; engine.backward(real, spectral); - Grid<Real, 2> reference({N0, N1}, 1); + Grid<Real, 2> reference{{N0, N1}, 1}; reference = 1.; ASSERT_TRUE(compare(real, reference, AreFloatEqual())); } /* -------------------------------------------------------------------------- */ TEST(TestFFTWEngine, FFT1D2Comp) { constexpr UInt size = 20; /// 1D single component FFT should be working here - Grid<Real, 1> grid({size}, 2), data({size}, 1); + Grid<Real, 1> grid{{size}, 2}, data{{size}, 1}; std::iota(grid.begin(), grid.end(), 0); std::iota(data.begin(), data.end(), 0); - GridHermitian<Real, 1> result({size / 2 + 1}, 2), solution({size / 2 + 1}, 1); + GridHermitian<Real, 1> result{{size / 2 + 1}, 2}, solution{{size / 2 + 1}, 1}; FFTWEngine engine; engine.forward(grid, result); std::iota(data.begin(), data.end(), 0); data *= 2; engine.forward(data, solution); const Real tol = 200 * std::numeric_limits<Real>::epsilon(); ASSERT_TRUE( compare(make_component_view(result, 0), solution, AreComplexEqual{tol})) << "1D FFTW transform with 2 components failed on 1st component"; data += 1; engine.forward(data, solution); ASSERT_TRUE( compare(make_component_view(result, 1), solution, AreComplexEqual{tol})) << "1D FFTW transform with 2 components failed on 2nd component"; } /* -------------------------------------------------------------------------- */ TEST(TestFFTWEngine, FFT2D3Comp) { constexpr UInt size = 20; /// 2D single component FFT should be working here - Grid<Real, 2> grid({size, size}, 3), data({size, size}, 1); + Grid<Real, 2> grid{{size, size}, 3}, data{{size, size}, 1}; std::iota(grid.begin(), grid.end(), 0); std::iota(data.begin(), data.end(), 0); data *= 3; - GridHermitian<Real, 2> result({size, size / 2 + 1}, 3), + GridHermitian<Real, 2> result{{size, size / 2 + 1}, 3}, solution({size, size / 2 + 1}, 1); FFTWEngine engine; engine.forward(grid, result); constexpr Real tol = 5000 * std::numeric_limits<Real>::epsilon(); for (UInt i = 0; i < 3; ++i) { engine.forward(data, solution); ASSERT_TRUE( compare(make_component_view(result, i), solution, AreComplexEqual{tol})) << "2D FFTW transform with 3 components failed on " << i << "th component"; data += 1; } } /* -------------------------------------------------------------------------- */ TEST(TestFFTWEngine, FFT2DViewTransform) { constexpr UInt size = 20; - Grid<Real, 2> data({size, size}, 1); - GridHermitian<Real, 2> solution({size, size / 2 + 1}, 1); + Grid<Real, 2> data{{size, size}, 1}; + GridHermitian<Real, 2> solution{{size, size / 2 + 1}, 1}; std::iota(std::begin(data), std::end(data), 0); FFTWEngine engine; engine.forward(data, solution); - Grid<Real, 2> grid({size, size}, 3); + Grid<Real, 2> grid{{size, size}, 3}; auto view = make_component_view(grid, 1); std::iota(view.begin(), view.end(), 0); - GridHermitian<Real, 2> result({size, size / 2 + 1}, 1); + GridHermitian<Real, 2> result{{size, size / 2 + 1}, 1}; engine.forward(view, result); constexpr Real tol = 5000 * std::numeric_limits<Real>::epsilon(); ASSERT_TRUE(compare(result, solution, AreComplexEqual{tol})) << "Fourier transform on component view fail"; } /* -------------------------------------------------------------------------- */ TEST(TestFFTWEngine, FFTI1D2Comp) { constexpr UInt size = 20; - Grid<Real, 1> grid({size}, 2); + Grid<Real, 1> grid{{size}, 2}; std::iota(grid.begin(), grid.end(), 0); - GridHermitian<Real, 1> grid_hermitian({size / 2 + 1}, 2); - Grid<Real, 1> result({size}, 2); + GridHermitian<Real, 1> grid_hermitian{{size / 2 + 1}, 2}; + Grid<Real, 1> result{{size}, 2}; FFTWEngine engine; engine.forward(grid, grid_hermitian); engine.backward(result, grid_hermitian); ASSERT_TRUE(compare(grid, result, AreFloatEqual())) << "1D FFTI transform with 2 components failed"; } /* -------------------------------------------------------------------------- */ TEST(TestFFTWEngine, FFTI2D3Comp) { constexpr UInt size = 20; - Grid<Real, 2> grid({size, size}, 3); + Grid<Real, 2> grid{{size, size}, 3}; std::iota(grid.begin(), grid.end(), 0); - GridHermitian<Real, 2> grid_hermitian({size, size / 2 + 1}, 3); - Grid<Real, 2> result({size, size}, 3); + GridHermitian<Real, 2> grid_hermitian{{size, size / 2 + 1}, 3}; + Grid<Real, 2> result{{size, size}, 3}; FFTWEngine engine; engine.forward(grid, grid_hermitian); engine.backward(result, grid_hermitian); ASSERT_TRUE(compare(grid, result, AreFloatEqual())) << "2D FFTI transform with 3 components failed"; } diff --git a/tests/test_grid.cpp b/tests/test_grid.cpp index 41b74017..cbd20c34 100644 --- a/tests/test_grid.cpp +++ b/tests/test_grid.cpp @@ -1,305 +1,305 @@ /* * SPDX-License-Indentifier: AGPL-3.0-or-later * * Copyright (©) 2016-2023 EPFL (École Polytechnique Fédérale de Lausanne), * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * Copyright (©) 2020-2023 Lucas Frérot * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "grid.hh" #include "grid_view.hh" #include "model_type.hh" #include "test.hh" using namespace tamaas; /* -------------------------------------------------------------------------- */ // Testing 1D creation TEST(TestGridCreation, Creation1d) { Grid<Real, 1> grid{{5}, 2}; std::array<UInt, 1> correct_size{{5}}; ASSERT_TRUE(grid.sizes() == correct_size) << "Wrong sizes"; std::array<UInt, 2> correct_strides{{2, 1}}; ASSERT_TRUE(grid.getStrides() == correct_strides) << "Wrong strides"; } // Testing 2D creation TEST(TestGridCreation, Creation2d) { - Grid<Real, 2> grid({5, 2}, 3); + Grid<Real, 2> grid{{5, 2}, 3}; std::array<UInt, 2> correct_size{{5, 2}}; ASSERT_TRUE(grid.sizes() == correct_size) << "Wrong sizes"; std::array<UInt, 3> correct_strides{{6, 3, 1}}; ASSERT_TRUE(grid.getStrides() == correct_strides) << "Wrong strides"; } // Testing 3D creation TEST(TestGridCreation, Creation3d) { - Grid<Real, 3> grid({8, 5, 2}, 3); - std::array<UInt, 3> correct_size{{8, 5, 2}}; + Grid<Real, 3> grid{{8, 5, 2}, 3}; + std::array<UInt, 3> correct_size{8, 5, 2}; ASSERT_TRUE(grid.sizes() == correct_size) << "Wrong sizes"; - std::array<UInt, 4> correct_strides{{30, 6, 3, 1}}; + std::array<UInt, 4> correct_strides{30, 6, 3, 1}; ASSERT_TRUE(grid.getStrides() == correct_strides) << "Wrong strides"; } /* -------------------------------------------------------------------------- */ TEST(TestWrap, Creation) { std::array<Real, 10> buffer; std::array<UInt, 2> shape{5, 2}; span<Real> view{buffer.data(), 10}; // Fill values std::iota(std::begin(buffer), std::end(buffer), 0); // Wrap grid on view Grid<Real, 2> grid(shape.begin(), shape.end(), 1, view); grid(1, 1) = 1; ASSERT_TRUE(compare(view, buffer)); ASSERT_TRUE(compare(grid, buffer)); } /* -------------------------------------------------------------------------- */ // Testing iterators in STL function iota TEST(TestGridIterators, Iota) { constexpr UInt N = 20; - Grid<UInt, 1> grid({N}, 1); + Grid<UInt, 1> grid{{N}, 1}; std::iota(grid.begin(), grid.end(), 0); - const UInt* p = grid.getInternalData(); + const auto* p{grid.getInternalData()}; for (UInt i = 0; i < N; ++i) ASSERT_TRUE(p[i] == i) << "Iota fill failed"; } // Testing filling grid with OpenMP loop TEST(TestGridIterators, OpenMPLoops) { - Grid<UInt, 1> grid({20}, 1); + Grid<UInt, 1> grid{{20}, 1}; #ifndef TAMAAS_USE_CUDA #pragma omp parallel for #endif for (auto it = grid.begin(); it < grid.end(); ++it) { UInt i = it - grid.begin(); *it = i; } std::vector<UInt> correct(20); std::iota(correct.begin(), correct.end(), 0); ASSERT_TRUE(compare(grid, correct)) << "Fill using OpenMP loop failed"; } /* -------------------------------------------------------------------------- */ // Testing access operator TEST(TestGridAccess, 3D) { - Grid<UInt, 3> grid({1, 3, 5}, 3); + Grid<UInt, 3> grid{{1, 3, 5}, 3}; std::iota(grid.begin(), grid.end(), 0); for (UInt i = 0; i < grid.sizes()[0]; ++i) for (UInt j = 0; j < grid.sizes()[1]; ++j) for (UInt k = 0; k < grid.sizes()[2]; ++k) for (UInt m = 0; m < grid.getNbComponents(); ++m) ASSERT_EQ(grid(i, j, k, m), m + 3 * k + (3 * 5) * j + (3 * 5 * 3) * i); - Grid<UInt, 2> grid1({5, 3}, 1); + Grid<UInt, 2> grid1{{5, 3}, 1}; grid1(2, 1, 0) = 1; ASSERT_EQ(grid1(2 * 3 + 1), 1); } /* -------------------------------------------------------------------------- */ // Testing scalar simple loop-based operators TEST(TestGridOperators, LoopOperators) { - Grid<UInt, 1> grid({20}, 1); + Grid<UInt, 1> grid{{20}, 1}; grid = 1; EXPECT_TRUE(std::all_of(grid.begin(), grid.end(), [](UInt x) { return x == 1; })) << "Assignement operator failed"; grid += 1; EXPECT_TRUE(std::all_of(grid.begin(), grid.end(), [](UInt x) { return x == 2; })) << "Plus-equal operator failed"; } // Testing loop-based functions with reductions TEST(TestGridOperators, Stats) { constexpr UInt n = 20; const UInt N = mpi::allreduce<operation::plus>(n); - Grid<Real, 1> grid({n}, 1); + Grid<Real, 1> grid{{n}, 1}; std::iota(grid.begin(), grid.end(), 0); std::vector<Real> v(n); std::iota(v.begin(), v.end(), 0); const auto b = v.cbegin(), e = v.cend(); Real min = mpi::allreduce<operation::min>(*std::min_element(b, e)); Real max = mpi::allreduce<operation::max>(*std::max_element(b, e)); Real sum = mpi::allreduce<operation::plus>(std::accumulate(b, e, 0.)); Real mea = sum / N; std::transform(b, e, v.begin(), [mea](Real v) { return (v - mea) * (v - mea); }); Real acc = mpi::allreduce<operation::plus>(std::accumulate(b, e, 0.)); Real var = acc / (N - 1); EXPECT_DOUBLE_EQ(grid.min(), min) << "Minimum function failed"; EXPECT_DOUBLE_EQ(grid.max(), max) << "Maximum function failed"; EXPECT_DOUBLE_EQ(grid.sum(), sum) << "Sum function failed"; EXPECT_DOUBLE_EQ(grid.mean(), mea) << "Mean function failed"; EXPECT_DOUBLE_EQ(grid.var(), var) << "Var function failed"; } /* -------------------------------------------------------------------------- */ TEST(TestGridView, View2D) { - Grid<UInt, 3> grid3d({10, 10, 10}, 3); + Grid<UInt, 3> grid3d{{10, 10, 10}, 3}; std::iota(grid3d.begin(), grid3d.end(), 0); for (UInt i : Loop::range(10)) { auto grid_view = make_view(grid3d, i); std::vector<UInt> reference(300); std::iota(reference.begin(), reference.end(), 300 * i); EXPECT_TRUE( std::equal(grid_view.begin(), grid_view.end(), reference.begin())) << "View on slice fail"; } } TEST(TestGridView, ViewOnComponent) { - Grid<UInt, 3> grid3d({10, 9, 8}, 3), solution({10, 9, 8}, 3); + Grid<UInt, 3> grid3d{{10, 9, 8}, 3}, solution{{10, 9, 8}, 3}; grid3d = solution = 0; auto view = make_component_view(grid3d, 2u); std::iota(view.begin(), view.end(), 0); for (UInt i = 0; i < solution.getNbPoints(); ++i) solution(3 * i + 2) = i; EXPECT_TRUE(std::equal(grid3d.begin(), grid3d.end(), solution.begin())) << "View on components fail"; view(9, 8, 7) = 1; ASSERT_EQ(grid3d(9, 8, 7, 2), 1); } TEST(TestGridView, ViewCopy) { - Grid<UInt, 3> grid3d({10, 10, 10}, 2); - Grid<UInt, 1> copy, solution({10}, 1); + Grid<UInt, 3> grid3d{{10, 10, 10}, 2}; + Grid<UInt, 1> copy, solution{{10}, 1}; auto view_on_slice = make_view(grid3d, 3, 4); - Grid<UInt, 1>* view_on_slice_ptr = &view_on_slice; + auto* view_on_slice_ptr = &view_on_slice; auto view = make_component_view(*view_on_slice_ptr, 1u); std::iota(view.begin(), view.end(), 0); std::iota(solution.begin(), solution.end(), 0); copy = view; EXPECT_TRUE(std::equal(copy.begin(), copy.end(), solution.begin())) << "Copy of view fail"; } TEST(TestGridView, HigherOrderView) { - Grid<UInt, 2> grid({10, 10}, 2); + Grid<UInt, 2> grid{{10, 10}, 2}; std::iota(grid.begin(), grid.end(), 0); - GridView<Grid, UInt, 2, 3> view(grid, {}, -1); + GridView<Grid, UInt, 2, 3> view{grid, {}, -1}; EXPECT_TRUE(std::equal(grid.begin(), grid.end(), view.begin())) << "Higher order view fail"; } /* -------------------------------------------------------------------------- */ struct BroadcastSet123 { CUDA_LAMBDA inline void operator()(VectorProxy<UInt, 3> v) { v(0) = 1; v(1) = 2; v(2) = 3; } }; TEST(TestGridOperators, BroadcastOperators) { - Grid<UInt, 2> grid({10, 10}, 3), solution({10, 10}, 3); + Grid<UInt, 2> grid{{10, 10}, 3}, solution{{10, 10}, 3}; auto set = BroadcastSet123(); // Filling up solution Loop::loop(set, range<VectorProxy<UInt, 3>>(solution)); Vector<UInt, 3> v; v(0) = 1; v(1) = 2; v(2) = 3; grid = v; EXPECT_TRUE(std::equal(grid.begin(), grid.end(), solution.begin())) << "Broadcast assignement failure"; v(1) = 1; v(2) = 1; solution += 1; grid += v; EXPECT_TRUE(std::equal(grid.begin(), grid.end(), solution.begin())) << "Broadcast += failure"; solution -= 1; grid -= v; EXPECT_TRUE(std::equal(grid.begin(), grid.end(), solution.begin())) << "Broadcast -= failure"; v(1) = 2; v(2) = 3; solution *= solution; grid *= v; EXPECT_TRUE(std::equal(grid.begin(), grid.end(), solution.begin())) << "Broadcast *= failure"; Loop::loop(set, range<VectorProxy<UInt, 3>>(solution)); grid /= v; EXPECT_TRUE(std::equal(grid.begin(), grid.end(), solution.begin())) << "Broadcast /= failure"; } TEST(TestAllocation, HardType) { std::array<UInt, 2> dims{4, 5}; auto grid = allocateGrid<model_type::basic_2d, true, Real>(dims, 1); static_assert( std::is_same<decltype(grid), std::unique_ptr<Grid<Real, 2>>>::value, "allocation type incorrect"); EXPECT_TRUE(std::equal(dims.begin(), dims.end(), grid->sizes().begin())); EXPECT_EQ(grid->getNbComponents(), 1); } TEST(TestAllocation, SoftType) { std::array<UInt, 2> dims{4, 5}; auto grid = allocateGrid<true, Real>(model_type::basic_2d, dims, 1); static_assert( std::is_same<decltype(grid), std::unique_ptr<GridBase<Real>>>::value, "allocation type incorrect"); EXPECT_EQ(grid->dataSize(), 20); EXPECT_EQ(grid->getNbComponents(), 1); } diff --git a/tests/test_mpi.cpp b/tests/test_mpi.cpp index e486972b..fb5357b2 100644 --- a/tests/test_mpi.cpp +++ b/tests/test_mpi.cpp @@ -1,205 +1,189 @@ /* * SPDX-License-Indentifier: AGPL-3.0-or-later * * Copyright (©) 2016-2023 EPFL (École Polytechnique Fédérale de Lausanne), * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * Copyright (©) 2020-2023 Lucas Frérot * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "fftw/mpi/fftw_mpi_engine.hh" #include "grid.hh" #include "grid_hermitian.hh" #include "grid_view.hh" #include "partitioner.hh" #include "test.hh" #include <fftw3-mpi.h> using namespace tamaas; using fft = fftw::helper<Real>; -/* -------------------------------------------------------------------------- */ - -template <typename T> -struct span { - T* ptr; - std::size_t size; - - ~span() { fftw::free(ptr); } - const T* begin() const { return ptr; } - const T* end() const { return ptr + size; } - T* begin() { return ptr; } - T* end() { return ptr + size; } - - operator T*() { return ptr; } -}; - /* -------------------------------------------------------------------------- */ TEST(TestMPIInterface, SequentialGuard) { mpi::sequential_guard guard; EXPECT_EQ(mpi::rank(), 0); EXPECT_EQ(mpi::size(), 1); ASSERT_EQ(mpi::comm::world()._comm, MPI_COMM_SELF); } /* -------------------------------------------------------------------------- */ TEST(TestFFTWInterface, MPISizes) { const std::ptrdiff_t N0 = 100, N1 = 100; std::ptrdiff_t local_n0, local_n0_start; auto alloc_local = fftw_mpi_local_size_2d(N0, N1 / 2 + 1, mpi::comm::world(), &local_n0, &local_n0_start); const std::ptrdiff_t N[] = {N0, N1 / 2 + 1}; auto sizes = fftw::mpi::local_size_many(2, N, 1); ASSERT_EQ(std::get<0>(sizes), alloc_local); ASSERT_EQ(std::get<1>(sizes), local_n0); ASSERT_EQ(std::get<2>(sizes), local_n0_start); } /* -------------------------------------------------------------------------- */ TEST(TestPartitioner, LocalSizes) { const std::ptrdiff_t N0 = 100, N1 = 100; std::ptrdiff_t local_n0, local_n0_start; fftw_mpi_local_size_2d(N0, N1 / 2 + 1, mpi::comm::world(), &local_n0, &local_n0_start); auto local_size = Partitioner<2>::local_size({N0, N1 / 2 + 1}); ASSERT_EQ(local_size[0], local_n0); ASSERT_EQ(local_size[1], N1 / 2 + 1); ASSERT_EQ(Partitioner<2>::local_offset({N0, N1 / 2 + 1}), local_n0_start); } /* -------------------------------------------------------------------------- */ TEST(TestPartitioner, LocalOffsetInGrid) { std::array<UInt, 2> N = {10, 10}; std::array<UInt, 2> Nglobal = {mpi::allreduce(N.front()), N.back()}; Grid<UInt, 2> local(N, 1), global(Nglobal, 1); auto offset = Partitioner<2>::local_offset(local); auto local_n0_start = Partitioner<2>::local_offset(Nglobal); ASSERT_EQ(offset, &global(local_n0_start, 0) - &global(0, 0)); } /* -------------------------------------------------------------------------- */ TEST(TestPartitioner, Scatter) { - std::array<UInt, 2> N = {10, 10}; - Grid<Real, 2> global(N, 3); + std::array<UInt, 2> N{10, 10}; + Grid<Real, 2> global{N, 3}; if (mpi::rank() != 0) global.resize({0, 0}); std::iota(global.begin(), global.end(), 0); auto local = Partitioner<2>::scatter(global); auto gathered = Partitioner<2>::gather(local); if (mpi::rank() != 0) return; ASSERT_TRUE(compare(gathered, global, AreFloatEqual())); } /* -------------------------------------------------------------------------- */ TEST(TestFFTWMPIEngine, BasicTransform) { const std::ptrdiff_t N0 = 60, N1 = 60; auto local_size = Partitioner<2>::local_size({N0, N1 / 2 + 1}); - Grid<Real, 2> real({local_size[0], N1}, 1); - GridHermitian<Real, 2> spectral(local_size, 1); + Grid<Real, 2> real{{local_size[0], N1}, 1}; + GridHermitian<Real, 2> spectral{local_size, 1}; auto offset = Partitioner<2>::local_offset(real); std::iota(real.begin(), real.end(), offset); FFTWMPIEngine().forward(real, spectral); auto gathered = Partitioner<2>::gather(spectral); if (mpi::rank() != 0) return; - Grid<Real, 2> real_global({N0, N1}, 1); - GridHermitian<Real, 2> solution({N0, N1 / 2 + 1}, 1); + Grid<Real, 2> real_global{{N0, N1}, 1}; + GridHermitian<Real, 2> solution{{N0, N1 / 2 + 1}, 1}; std::iota(real_global.begin(), real_global.end(), 0); FFTWEngine().forward(real_global, solution); // solution -= gathered; // Logger().get(LogLevel::info) << solution << '\n'; // Increased error here because the iota input is bad: // because operations are not the same in parallel, // some parts of the output that should be close to zeros // have different values in serial and parallel cases ASSERT_TRUE(compare(gathered, solution, AreComplexEqual{1e-11})); } /* -------------------------------------------------------------------------- */ TEST(TestFFTWMPIEngine, BackwardsTransform) { const std::ptrdiff_t N0 = 128, N1 = 128; auto local_size = Partitioner<2>::local_size({N0, N1 / 2 + 1}); - Grid<Real, 2> real({local_size[0], N1}, 1); - GridHermitian<Real, 2> spectral(local_size, 1); + Grid<Real, 2> real{{local_size[0], N1}, 1}; + GridHermitian<Real, 2> spectral{local_size, 1}; real = 1.; FFTWMPIEngine engine; engine.forward(real, spectral); real = 0; engine.backward(real, spectral); auto gathered = Partitioner<2>::gather(real); if (mpi::rank() != 0) return; - Grid<Real, 2> reference({N0, N1}, 1); + Grid<Real, 2> reference{{N0, N1}, 1}; reference = 1.; ASSERT_TRUE(compare(gathered, reference, AreFloatEqual())); } TEST(TestFFTWMPIEngine, ComponentsTransform) { const std::ptrdiff_t N0 = 10, N1 = 10; auto local_size = Partitioner<2>::local_size({N0, N1 / 2 + 1}); - Grid<Real, 2> real({local_size[0], N1}, 2); - GridHermitian<Real, 2> spectral(local_size, 2); + Grid<Real, 2> real{{local_size[0], N1}, 2}; + GridHermitian<Real, 2> spectral{local_size, 2}; real = 1; FFTWMPIEngine().forward(real, spectral); auto gathered = Partitioner<2>::gather(spectral); if (mpi::rank() != 0) return; - Grid<Real, 2> real_global({N0, N1}, 2); - GridHermitian<Real, 2> solution({N0, N1 / 2 + 1}, 2); + Grid<Real, 2> real_global{{N0, N1}, 2}; + GridHermitian<Real, 2> solution{{N0, N1 / 2 + 1}, 2}; real_global = 1; FFTWEngine().forward(real_global, solution); ASSERT_TRUE(compare(gathered, solution, AreComplexEqual())); }