diff --git a/example/brunel/brunel_miniapp.cpp b/example/brunel/brunel_miniapp.cpp index 2041b7bf13b5c752c6e925b4e895417c0e98a6c6..1c83d2bcd5449e72d95c6ba6fa953845f4f3696a 100644 --- a/example/brunel/brunel_miniapp.cpp +++ b/example/brunel/brunel_miniapp.cpp @@ -1,6 +1,7 @@ #include <cmath> #include <exception> #include <fstream> +#include <iomanip> #include <iostream> #include <memory> #include <set> @@ -24,7 +25,6 @@ #include <sup/ioutil.hpp> #include <sup/json_meter.hpp> #include <sup/path.hpp> -#include <sup/spike_emitter.hpp> #include <sup/strsub.hpp> #ifdef ARB_MPI_ENABLED @@ -216,7 +216,12 @@ int main(int argc, char** argv) { meters.start(context); // read parameters - io::cl_options options = io::read_options(argc, argv, root); + io::cl_options options = io::read_options(argc, argv); + + std::fstream spike_out; + if (options.spike_file_output && root) { + spike_out = sup::open_or_throw("./spikes.gdf", std::ios_base::out, false); + } meters.checkpoint("setup", context); @@ -257,31 +262,29 @@ int main(int argc, char** argv) { simulation sim(recipe, decomp, context); - // Initialize the spike exporting interface - std::fstream spike_out; - if (options.spike_file_output) { - using std::ios_base; - - sup::path p = options.output_path; - p /= sup::strsub("%_%.%", options.file_name, rank, options.file_extension); - - if (options.single_file_per_rank) { - spike_out = sup::open_or_throw(p, ios_base::out, !options.over_write); - sim.set_local_spike_callback(sup::spike_emitter(spike_out)); - } - else if (root) { - spike_out = sup::open_or_throw(p, ios_base::out, !options.over_write); - sim.set_global_spike_callback(sup::spike_emitter(spike_out)); - } + // Set up spike recording. + std::vector<arb::spike> recorded_spikes; + if (spike_out) { + sim.set_global_spike_callback([&recorded_spikes](auto& spikes) { + recorded_spikes.insert(recorded_spikes.end(), spikes.begin(), spikes.end()); + }); } meters.checkpoint("model-init", context); - // run simulation + // Run simulation. sim.run(options.tfinal, options.dt); meters.checkpoint("model-simulate", context); + // Output spikes if requested. + if (spike_out) { + spike_out << std::fixed << std::setprecision(4); + for (auto& s: recorded_spikes) { + spike_out << s.source.gid << ' ' << s.time << '\n'; + } + } + // output profile and diagnostic feedback std::cout << profile::profiler_summary() << "\n"; std::cout << "\nThere were " << sim.num_spikes() << " spikes\n"; diff --git a/example/brunel/io.cpp b/example/brunel/io.cpp index 540cc559526f6181a58f53a6ffce09b8bca88513..72b6ca815bc29869342b7fe29b0599d05013e1de 100644 --- a/example/brunel/io.cpp +++ b/example/brunel/io.cpp @@ -79,9 +79,8 @@ namespace io { } // Read options from (optional) json file and command line arguments. - cl_options read_options(int argc, char** argv, bool allow_write) { + cl_options read_options(int argc, char** argv) { cl_options options; - std::string save_file = ""; // Parse command line arguments. try { diff --git a/example/brunel/io.hpp b/example/brunel/io.hpp index 370e02acf6b8918ba5c6e43623ad500385ca4fc3..28c76bdb28ad605b069925c1b2fb699636230882 100644 --- a/example/brunel/io.hpp +++ b/example/brunel/io.hpp @@ -30,11 +30,6 @@ namespace io { // Parameters for spike output. bool spike_file_output = false; - bool single_file_per_rank = false; - bool over_write = true; - std::string output_path = "./"; - std::string file_name = "spikes"; - std::string file_extension = "gdf"; // Turn on/off profiling output for all ranks. bool profile_only_zero = false; @@ -57,5 +52,5 @@ namespace io { std::ostream& operator<<(std::ostream& o, const cl_options& opt); - cl_options read_options(int argc, char** argv, bool allow_write = true); + cl_options read_options(int argc, char** argv); } // namespace io diff --git a/example/miniapp/io.cpp b/example/miniapp/io.cpp index ac171ca503601471dd482a7c145c4d9ad851d5e4..4d8b19700086810030abccf7cc44282f25380a2e 100644 --- a/example/miniapp/io.cpp +++ b/example/miniapp/io.cpp @@ -229,13 +229,11 @@ cl_options read_options(int argc, char** argv, bool allow_write) { // Parameters for spike output update_option(options.spike_file_output, fopts, "spike_file_output"); - if (options.spike_file_output) { - update_option(options.single_file_per_rank, fopts, "single_file_per_rank"); - update_option(options.over_write, fopts, "over_write"); - update_option(options.output_path, fopts, "output_path"); - update_option(options.file_name, fopts, "file_name"); - update_option(options.file_extension, fopts, "file_extension"); - } + update_option(options.single_file_per_rank, fopts, "single_file_per_rank"); + update_option(options.over_write, fopts, "over_write"); + update_option(options.output_path, fopts, "output_path"); + update_option(options.file_name, fopts, "file_name"); + update_option(options.file_extension, fopts, "file_extension"); update_option(options.dry_run_ranks, fopts, "dry_run_ranks"); } diff --git a/example/miniapp/miniapp.cpp b/example/miniapp/miniapp.cpp index 5fe1cc5fc5934904e050beffa9dba5c8d1d8db2d..f4d744403d5f743e477c454b5373796edee2daa8 100644 --- a/example/miniapp/miniapp.cpp +++ b/example/miniapp/miniapp.cpp @@ -1,5 +1,6 @@ #include <cmath> #include <exception> +#include <iomanip> #include <iostream> #include <fstream> #include <memory> @@ -23,7 +24,6 @@ #include <sup/ioutil.hpp> #include <sup/json_meter.hpp> #include <sup/path.hpp> -#include <sup/spike_emitter.hpp> #include <sup/strsub.hpp> #ifdef ARB_MPI_ENABLED @@ -62,7 +62,8 @@ int main(int argc, char** argv) { arbenv::with_mpi guard(argc, argv, false); resources.gpu_id = arbenv::find_private_gpu(MPI_COMM_WORLD); auto context = arb::make_context(resources, MPI_COMM_WORLD); - root = arb::rank(context) == 0; + rank = arb::rank(context); + root = rank == 0; #else resources.gpu_id = arbenv::default_gpu(); auto context = arb::make_context(resources); @@ -85,6 +86,14 @@ int main(int argc, char** argv) { // threading back end, and 1 gpu if available. banner(context); + // Set up spike output if requested. + std::fstream spike_out; + if (options.spike_file_output && (root || options.single_file_per_rank)) { + sup::path p = options.output_path; + p /= sup::strsub("%_%.%", options.file_name, rank, options.file_extension); + spike_out = sup::open_or_throw(p, std::ios_base::out, !options.over_write); + } + meters.checkpoint("setup", context); // determine what to attach probes to @@ -130,37 +139,42 @@ int main(int argc, char** argv) { sim.set_binning_policy(binning_policy, options.bin_dt); - // Initialize the spike exporting interface - std::fstream spike_out; - if (options.spike_file_output) { - using std::ios_base; - - sup::path p = options.output_path; - p /= sup::strsub("%_%.%", options.file_name, rank, options.file_extension); + // Set up spike recording. + std::vector<arb::spike> recorded_spikes; + if (spike_out) { + auto spike_callback = [&recorded_spikes](auto& spikes) { + recorded_spikes.insert(recorded_spikes.end(), spikes.begin(), spikes.end()); + }; if (options.single_file_per_rank) { - spike_out = sup::open_or_throw(p, ios_base::out, !options.over_write); - sim.set_local_spike_callback(sup::spike_emitter(spike_out)); + sim.set_local_spike_callback(spike_callback); } - else if (rank==0) { - spike_out = sup::open_or_throw(p, ios_base::out, !options.over_write); - sim.set_global_spike_callback(sup::spike_emitter(spike_out)); + else { + sim.set_global_spike_callback(spike_callback); } } meters.checkpoint("model-init", context); - // run model + // Run model. sim.run(options.tfinal, options.dt); meters.checkpoint("model-simulate", context); - // output profile and diagnostic feedback + // Output profile and diagnostic feedback. auto profile = profile::profiler_summary(); std::cout << profile << "\n"; std::cout << "\nthere were " << sim.num_spikes() << " spikes\n"; - // save traces + // Save spikes. + if (spike_out) { + spike_out << std::fixed << std::setprecision(4); + for (auto& s: recorded_spikes) { + spike_out << s.source.gid << ' ' << s.time << '\n'; + } + } + + // Save traces. auto write_trace = options.trace_format=="json"? write_trace_json: write_trace_csv; for (const auto& trace: sample_traces) { write_trace(trace, options.trace_prefix); diff --git a/sup/CMakeLists.txt b/sup/CMakeLists.txt index 9e014f07681e8d693cb83a8a4b7b0b0c1760f281..227a760b3379e5b6ab26c0657ed62680684a492c 100644 --- a/sup/CMakeLists.txt +++ b/sup/CMakeLists.txt @@ -3,7 +3,6 @@ set(sup-sources ioutil.cpp json_meter.cpp path.cpp - spike_emitter.cpp ) add_library(arbor-sup ${sup-sources}) diff --git a/sup/include/sup/spike_emitter.hpp b/sup/include/sup/spike_emitter.hpp deleted file mode 100644 index 0656f00b3117f308c37b57dc56f701df4fb6a318..0000000000000000000000000000000000000000 --- a/sup/include/sup/spike_emitter.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#include <functional> -#include <iosfwd> -#include <vector> - -#include <arbor/spike.hpp> - -namespace sup { - -struct spike_emitter { - std::reference_wrapper<std::ostream> out; - - spike_emitter(std::ostream& out); - void operator()(const std::vector<arb::spike>&); -}; - -} // namespace sup diff --git a/sup/spike_emitter.cpp b/sup/spike_emitter.cpp deleted file mode 100644 index ec451be1a8daa2c939671e010bef15e4e515769c..0000000000000000000000000000000000000000 --- a/sup/spike_emitter.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include <functional> -#include <iostream> - -#include <arbor/spike.hpp> -#include <sup/spike_emitter.hpp> - -namespace sup { - -spike_emitter::spike_emitter(std::ostream& out): out(out) {} - -void spike_emitter::operator()(const std::vector<arb::spike>& spikes) { - char line[45]; - for (auto& s: spikes) { - int n = std::snprintf(line, sizeof(line), "%u %.4f", s.source.gid, s.time); - if (n<0) { - throw std::system_error(errno, std::generic_category()); - } - - out.get().write(line, n).put('\n'); - } -}; - -} // namespace sup diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index b89cece7d93a51260b005155aa18cd37948d85aa..439a1034ffa11e848d4fe29c432582a4509ac7f4 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -99,7 +99,6 @@ set(unit_sources test_span.cpp test_spikes.cpp test_spike_store.cpp - test_spike_emitter.cpp test_stats.cpp test_strprintf.cpp test_swcio.cpp diff --git a/test/unit/test_spike_emitter.cpp b/test/unit/test_spike_emitter.cpp deleted file mode 100644 index a66812773861296398c2b3f75c35e4d421eb3fe3..0000000000000000000000000000000000000000 --- a/test/unit/test_spike_emitter.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "../gtest.h" - -#include <sstream> -#include <string> -#include <vector> - -#include <arbor/spike.hpp> -#include <sup/spike_emitter.hpp> - -TEST(spike_emitter, formatting) { - std::stringstream out; - auto callback = sup::spike_emitter(out); - - std::vector<arb::spike> spikes = { - { { 0, 0 }, 0.0 }, - { { 0, 0 }, 0.1 }, - { { 1, 0 }, 1.0 }, - { { 1, 0 }, 1.1 } - }; - - callback(spikes); - - std::string expected = - "0 0.0000\n" - "0 0.1000\n" - "1 1.0000\n" - "1 1.1000\n"; - - EXPECT_EQ(expected, out.str()); -}