diff --git a/miniapp/io.cpp b/miniapp/io.cpp index c1d4f6fc0297b08e9311cdf5bef683e0de720b87..348489ac6bb03491e3573d0c9d61b369325bba76 100644 --- a/miniapp/io.cpp +++ b/miniapp/io.cpp @@ -110,7 +110,7 @@ static void update_option(util::optional<T>& opt, const nlohmann::json& j, const } // Read options from (optional) json file and command line arguments. -cl_options read_options(int argc, char** argv) { +cl_options read_options(int argc, char** argv, bool allow_write) { // Default options: const cl_options defopts{ @@ -271,7 +271,7 @@ cl_options read_options(int argc, char** argv) { } // Save option values if requested. - if (save_file != "") { + if (save_file != "" && allow_write) { std::ofstream fid(save_file); if (fid) { try { @@ -284,6 +284,8 @@ cl_options read_options(int argc, char** argv) { fopts["dt"] = options.dt; fopts["tfinal"] = options.tfinal; fopts["all_to_all"] = options.all_to_all; + fopts["ring"] = options.ring; + fopts["group_size"] = options.group_size; fopts["probe_ratio"] = options.probe_ratio; fopts["probe_soma_only"] = options.probe_soma_only; fopts["trace_prefix"] = options.trace_prefix; @@ -316,6 +318,8 @@ std::ostream& operator<<(std::ostream& o, const cl_options& options) { o << " simulation time : " << options.tfinal << "\n"; o << " dt : " << options.dt << "\n"; o << " all to all network : " << (options.all_to_all ? "yes" : "no") << "\n"; + o << " ring network : " << (options.ring ? "yes" : "no") << "\n"; + o << " group size : " << options.group_size << "\n"; o << " probe ratio : " << options.probe_ratio << "\n"; o << " probe soma only : " << (options.probe_soma_only ? "yes" : "no") << "\n"; o << " trace prefix : " << options.trace_prefix << "\n"; diff --git a/miniapp/io.hpp b/miniapp/io.hpp index 1c5bba8163596dcf5bdcbed10113c901a1c816b0..ac769d436b6a36550afe2e64b33e0b35a69f3f80 100644 --- a/miniapp/io.hpp +++ b/miniapp/io.hpp @@ -51,7 +51,7 @@ public: std::ostream& operator<<(std::ostream& o, const cl_options& opt); -cl_options read_options(int argc, char** argv); +cl_options read_options(int argc, char** argv, bool allow_write = true); } // namespace io diff --git a/miniapp/miniapp.cpp b/miniapp/miniapp.cpp index 9ad224efd7c1597ef848559b02921911cfe19b15..2b5df5d963305f82263d4cb3676d949989d90ea2 100644 --- a/miniapp/miniapp.cpp +++ b/miniapp/miniapp.cpp @@ -51,7 +51,7 @@ int main(int argc, char** argv) { banner(); // read parameters - io::cl_options options = io::read_options(argc, argv); + io::cl_options options = io::read_options(argc, argv, global_policy::id()==0); std::cout << options << "\n"; std::cout << "\n"; std::cout << ":: simulation to " << options.tfinal << " ms in " diff --git a/src/cell_group.hpp b/src/cell_group.hpp index d8fd2f2ad18edf9e401658cf3c2372190e0226c7..30bdd99dbd66f07fe0851a42cd052028a52b1f89 100644 --- a/src/cell_group.hpp +++ b/src/cell_group.hpp @@ -11,6 +11,7 @@ #include <event_queue.hpp> #include <spike.hpp> #include <spike_source.hpp> +#include <util/debug.hpp> #include <util/partition.hpp> #include <util/range.hpp> @@ -130,7 +131,7 @@ public: // time step. This should be a parameter. e.g. with for variable // order time stepping, use the minimum possible time step size. while(auto e = events_.pop_if_before(cell_.time()+dt/10.)) { - auto handle = get_target_handle(next->target); + auto handle = get_target_handle(e->target); cell_.deliver_event(handle, e->weight); } } diff --git a/src/communication/mpi.hpp b/src/communication/mpi.hpp index 9ebb0ca412d83dbb600471417beb299fd1a55a8b..472c64039ba8b4b74e96adf97cc6f63782a69f72 100644 --- a/src/communication/mpi.hpp +++ b/src/communication/mpi.hpp @@ -11,6 +11,7 @@ #include <algorithms.hpp> #include <communication/gathered_vector.hpp> +#include <util/debug.hpp> namespace nest { namespace mc { @@ -97,7 +98,7 @@ namespace mpi { } template <typename T> - std::vector<T> gather_all(const std::vector<T> &values) { + std::vector<T> gather_all(const std::vector<T>& values) { static_assert( true,//std::is_trivially_copyable<T>::value, "gather_all can only be performed on trivally copyable types"); @@ -149,6 +150,10 @@ namespace mpi { MPI_COMM_WORLD ); + for (auto& d : displs) { + d /= traits::count(); + } + return gathered_type( std::move(buffer), std::vector<count_type>(displs.begin(), displs.end()) diff --git a/src/fvm_multicell.hpp b/src/fvm_multicell.hpp index f885906f1ce52902eca89403d27cde9e25559924..1c9c799a933ba67a05bde76bf0b7fc22bdf88396 100644 --- a/src/fvm_multicell.hpp +++ b/src/fvm_multicell.hpp @@ -19,6 +19,7 @@ #include <segment.hpp> #include <stimulus.hpp> #include <util.hpp> +#include <util/debug.hpp> #include <util/meta.hpp> #include <util/partition.hpp> #include <util/span.hpp> diff --git a/src/util/range.hpp b/src/util/range.hpp index 89fcaddbfc8b0b6161f97bd5f3f2cb0cc2d20545..3addca60883e5ad5dafc24e93240b6f0c189c092 100644 --- a/src/util/range.hpp +++ b/src/util/range.hpp @@ -332,13 +332,16 @@ range<const T*> singleton_view(const T& item) { */ template <typename Container, typename Seq> -void append(Container &c, const Seq& seq) { - c.insert(c.end(), seq.begin(), seq.end()); +Container& append(Container &c, const Seq& seq) { + auto canon = canonical_view(seq); + c.insert(c.end(), std::begin(canon), std::end(canon)); + return c; } template <typename AssignableContainer, typename Seq> AssignableContainer& assign(AssignableContainer& c, const Seq& seq) { - c.assign(seq.begin(), seq.end()); + auto canon = canonical_view(seq); + c.assign(std::begin(canon), std::end(canon)); return c; } diff --git a/tests/global_communication/CMakeLists.txt b/tests/global_communication/CMakeLists.txt index cc1e1af8b6567a2fc887815fa4eaeb25c561841e..800e7d193dcb335d2ee8ae164ed38b947eaae313 100644 --- a/tests/global_communication/CMakeLists.txt +++ b/tests/global_communication/CMakeLists.txt @@ -4,6 +4,7 @@ set(HEADERS set(COMMUNICATION_SOURCES test_exporter_spike_file.cpp test_communicator.cpp + test_mpi_gather_all.cpp # unit test driver test.cpp diff --git a/tests/global_communication/test_mpi_gather_all.cpp b/tests/global_communication/test_mpi_gather_all.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ed99089fd517ae424201637ededfe8049168ca76 --- /dev/null +++ b/tests/global_communication/test_mpi_gather_all.cpp @@ -0,0 +1,100 @@ +#include "gtest.h" + +#ifdef WITH_MPI + +#include <cstring> +#include <vector> + +#include <communication/mpi_global_policy.hpp> +#include <communication/mpi.hpp> +#include <util/range.hpp> + +using namespace nest::mc; +using namespace nest::mc::communication; + +struct big_thing { + big_thing() {} + big_thing(int i): value_(i) {} + + bool operator==(const big_thing& other) const { + return value_==other.value_ && !memcmp(salt_, other.salt_, sizeof(salt_)); + } + + bool operator!=(const big_thing& other) const { + return !(*this==other); + } + +private: + int value_; + char salt_[32] = "it's a lovely day for a picnic"; +}; + +TEST(mpi, gather_all) { + using policy = mpi_global_policy; + + int id = policy::id(); + + std::vector<big_thing> data; + // odd ranks: three items; even ranks: one item. + if (id%2) { + data = { id, id+7, id+8 }; + } + else { + data = { id }; + } + + std::vector<big_thing> expected; + for (int i = 0; i<policy::size(); ++i) { + if (i%2) { + int rank_data[] = { i, i+7, i+8 }; + util::append(expected, rank_data); + } + else { + int rank_data[] = { i }; + util::append(expected, rank_data); + } + } + + auto gathered = mpi::gather_all(data); + + EXPECT_EQ(expected, gathered); +} + +TEST(mpi, gather_all_with_partition) { + using policy = mpi_global_policy; + + int id = policy::id(); + + std::vector<big_thing> data; + // odd ranks: three items; even ranks: one item. + if (id%2) { + data = { id, id+7, id+8 }; + } + else { + data = { id }; + } + + std::vector<big_thing> expected_values; + std::vector<unsigned> expected_divisions; + + expected_divisions.push_back(0); + for (int i = 0; i<policy::size(); ++i) { + if (i%2) { + int rank_data[] = { i, i+7, i+8 }; + util::append(expected_values, rank_data); + expected_divisions.push_back(expected_divisions.back()+util::size(rank_data)); + } + else { + int rank_data[] = { i }; + util::append(expected_values, rank_data); + expected_divisions.push_back(expected_divisions.back()+util::size(rank_data)); + } + } + + auto gathered = mpi::gather_all_with_partition(data); + + EXPECT_EQ(expected_values, gathered.values()); + EXPECT_EQ(expected_divisions, gathered.partition()); +} + +#endif // WITH_MPI