template <typename T> std::vector<T> mpi_scatter(std::vector<T> const &a, communicator c, int root, std::false_type) { int s = a.size(); std::vector<T> lhs; lhs.reserve(s); for (auto i = 0; i < s; ++i) lhs.push_back(mpi_scatter(a[i], c, root)); return lhs; }
TEST(Gfs, MPI_multivar) { mpi::communicator world; int nw = 2, nbw = 10; double beta = 10; clef::placeholder<0> k_; clef::placeholder<1> q_; clef::placeholder<2> r_; clef::placeholder<3> iw_; clef::placeholder<4> inu_; clef::placeholder<5> inup_; auto g = gf3_s{{{beta, Boson, nbw}, {beta, Fermion, nw}, {beta, Fermion, nw}}}; g(iw_, inu_, inup_) << inu_ + 10 * inup_ + 100 * iw_; auto g2 = g; g2 = mpi_reduce(g, world); if (world.rank() == 0) EXPECT_ARRAY_NEAR(g2.data(), g.data() * world.size()); mpi_broadcast(g2, world); if (world.rank() == 1) EXPECT_ARRAY_NEAR(g2.data(), g.data()* world.size()); gf3_s g3 = mpi_all_reduce(g, world); EXPECT_ARRAY_NEAR(g3.data(), g.data() * world.size()); gf3_s g4 = mpi_scatter(g); g2(iw_, inu_, inup_) << g2(iw_, inu_, inup_) * (1 + world.rank()); g4 = mpi_gather(g2); // Test the result ? auto G = make_block_gf<cartesian_product<imfreq, imfreq, imfreq>, scalar_valued>({g}); auto g0 = gf<imfreq, scalar_valued>{{beta, Boson, nbw}}; auto G2 = make_block_gf<imfreq, scalar_valued>({g0}); mpi_broadcast(G, world); mpi_broadcast(G2, world); }
template <typename T>[[gnu::always_inline]] inline decltype(auto) scatter(T &&x, mpi::communicator c = {}, int root = 0) { return mpi_scatter(std::forward<T>(x), c, root); }
template <typename T> std::vector<T> mpi_scatter(std::vector<T> const &a, communicator c={}, int root=0) { return mpi_scatter(a, c, root, is_basic<T>{}); }
/// Scatter the first mesh over the communicator c friend gf_mesh mpi_scatter(gf_mesh const &m, mpi::communicator c, int root) { auto r = m; // same domain, but mesh with a window. std::get<0>(r.m_tuple) = mpi_scatter(std::get<0>(r.m_tuple), c, root); return r; }