diff --git a/modcc/cprinter.cpp b/modcc/cprinter.cpp index d6b1e5370083637c3d34d9a12d40c6535856b31d..3d4b01d4a4fe608da52f83a26699a5e206604edf 100644 --- a/modcc/cprinter.cpp +++ b/modcc/cprinter.cpp @@ -305,12 +305,9 @@ CPrinter::CPrinter(Module &m, bool o) ////////////////////////////////////////////// auto proctest = [] (procedureKind k) { - return - k == procedureKind::normal - || k == procedureKind::api - || k == procedureKind::net_receive; + return is_in(k, {procedureKind::normal, procedureKind::api, procedureKind::net_receive}); }; - for(auto &var : m.symbols()) { + for(auto const& var: m.symbols()) { auto isproc = var.second->kind()==symbolKind::procedure; if(isproc ) { @@ -461,10 +458,6 @@ void CPrinter::visit(BlockExpression *e) { } } if(names.size()>0) { - //for(auto it=names.begin(); it!=names.end(); ++it) { - // text_.add_gutter() << "value_type " << *it; - // text_.end_line("{0};"); - //} text_.add_gutter() << "value_type " << *(names.begin()); for(auto it=names.begin()+1; it!=names.end(); ++it) { text_ << ", " << *it; @@ -498,8 +491,9 @@ void CPrinter::visit(IfExpression *e) { text_ << "}"; } +// NOTE: net_receive() is classified as a ProcedureExpression void CPrinter::visit(ProcedureExpression *e) { - // ------------- print prototype ------------- // + // print prototype text_.add_gutter() << "void " << e->name() << "(int i_"; for(auto& arg : e->args()) { text_ << ", value_type " << arg->is_argument()->name(); @@ -518,19 +512,18 @@ void CPrinter::visit(ProcedureExpression *e) { e->location()); } + // print body increase_indentation(); - e->body()->accept(this); - // ------------- close up ------------- // + // close the function body decrease_indentation(); text_.add_line("}"); text_.add_line(); - return; } void CPrinter::visit(APIMethod *e) { - // ------------- print prototype ------------- // + // print prototype text_.add_gutter() << "void " << e->name() << "() override {"; text_.end_line(); @@ -566,7 +559,7 @@ void CPrinter::visit(APIMethod *e) { } } - // ------------- get loop dimensions ------------- // + // get loop dimensions text_.add_line("int n_ = node_index_.size();"); // hand off printing of loops to optimized or unoptimized backend @@ -578,14 +571,12 @@ void CPrinter::visit(APIMethod *e) { } } - // ------------- close up ------------- // + // close up the loop body text_.add_line("}"); text_.add_line(); } void CPrinter::print_APIMethod_unoptimized(APIMethod* e) { - //text_.add_line("START_PROFILE"); - // there can not be more than 1 instance of a density channel per grid point, // so we can assert that aliasing will not occur. if(optimize_) text_.add_line("#pragma ivdep"); diff --git a/modcc/cprinter.hpp b/modcc/cprinter.hpp index e669c25f02e71da10e9f4622ad07651bbd558e36..ef47977c05fe13e1b6f3206bcffecf344855d355 100644 --- a/modcc/cprinter.hpp +++ b/modcc/cprinter.hpp @@ -44,6 +44,9 @@ public: void decrease_indentation(){ text_.decrease_indentation(); } + void clear_text() { + text_.clear(); + } private: void print_APIMethod_optimized(APIMethod* e); diff --git a/modcc/cudaprinter.cpp b/modcc/cudaprinter.cpp index e5103ddf3a4a78dbd0fd0db48bb8f62f7d3caa9d..175781a203df3351ccc62051813c24e0a1e8262b 100644 --- a/modcc/cudaprinter.cpp +++ b/modcc/cudaprinter.cpp @@ -1,5 +1,6 @@ #include <algorithm> +#include "cprinter.hpp" // needed for printing net_receive method #include "cudaprinter.hpp" #include "lexer.hpp" @@ -114,27 +115,11 @@ CUDAPrinter::CUDAPrinter(Module &m, bool o) text_.decrease_indentation(); text_.add_line("}"); text_.add_line(); - /* - text_.add_line("__device__"); - text_.add_line("inline double atomicSub(double* address, double val) {"); - text_.increase_indentation(); - text_.add_line("return atomicAdd(address, -val);"); - text_.decrease_indentation(); - text_.add_line("}"); - text_.add_line(); - text_.add_line("__device__"); - text_.add_line("inline float atomicSub(float* address, float val) {"); - text_.increase_indentation(); - text_.add_line("return atomicAdd(address, -val);"); - text_.decrease_indentation(); - text_.add_line("}"); - text_.add_line(); - */ // forward declarations of procedures for(auto const &var : m.symbols()) { - if( var.second->kind()==symbolKind::procedure - && var.second->is_procedure()->kind() == procedureKind::normal) + if( var.second->kind()==symbolKind::procedure && + var.second->is_procedure()->kind() == procedureKind::normal) { print_procedure_prototype(var.second->is_procedure()); text_.end_line(";"); @@ -144,11 +129,10 @@ CUDAPrinter::CUDAPrinter(Module &m, bool o) // print stubs that call API method kernels that are defined in the // kernels::name namespace - auto proctest = [] (procedureKind k) {return k == procedureKind::normal - || k == procedureKind::api; }; for(auto const &var : m.symbols()) { if (var.second->kind()==symbolKind::procedure && - proctest(var.second->is_procedure()->kind())) + is_in(var.second->is_procedure()->kind(), + {procedureKind::normal, procedureKind::api})) { var.second->accept(this); } @@ -428,11 +412,9 @@ CUDAPrinter::CUDAPrinter(Module &m, bool o) ////////////////////////////////////////////// ////////////////////////////////////////////// - - auto proctest = [] (procedureKind k) {return k == procedureKind::api;}; for(auto const &var : m.symbols()) { - if( var.second->kind()==symbolKind::procedure - && proctest(var.second->is_procedure()->kind())) + if( var.second->kind()==symbolKind::procedure && + var.second->is_procedure()->kind()==procedureKind::api) { auto proc = var.second->is_api_method(); auto name = proc->name(); @@ -450,6 +432,29 @@ CUDAPrinter::CUDAPrinter(Module &m, bool o) text_.add_line("}"); text_.add_line(); } + else if( var.second->kind()==symbolKind::procedure && + var.second->is_procedure()->kind()==procedureKind::net_receive) + { + auto proc = var.second->is_procedure(); + auto name = proc->name(); + text_.add_line("void " + name + "(int i_, value_type weight) {"); + text_.increase_indentation(); + + // Print the body of the net_receive block. + // Use the same body as would be generated with the cprinter. + // This is not omptimal, because each read and write will require + // a copy between host and device memory, so we will need a + // GPU-specific implementation + auto cprinter = CPrinter(*module_); + cprinter.clear_text(); + cprinter.set_gutter(text_.get_gutter()); + proc->body()->accept(&cprinter); + text_ << cprinter.text(); + + text_.decrease_indentation(); + text_.add_line("}"); + text_.add_line(); + } } ////////////////////////////////////////////// @@ -648,28 +653,26 @@ void CUDAPrinter::visit(ProcedureExpression *e) { e->location()); } - // ------------- print prototype ------------- // + // print prototype print_procedure_prototype(e); text_.end_line(" {"); - // ------------- print body ------------- // + // print body increase_indentation(); text_.add_line("using value_type = T;"); - text_.add_line("using iarray = I;"); text_.add_line(); e->body()->accept(this); - // ------------- close up ------------- // + // close up decrease_indentation(); text_.add_line("}"); text_.add_line(); - return; } void CUDAPrinter::visit(APIMethod *e) { - // ------------- print prototype ------------- // + // print prototype text_.add_gutter() << "template <typename T, typename I>\n"; text_.add_line( "__global__"); text_.add_gutter() << "void " << e->name() @@ -702,7 +705,8 @@ void CUDAPrinter::visit(APIMethod *e) { text_.add_line("}"); decrease_indentation(); - text_.add_line("}\n"); + text_.add_line("}"); + text_.add_line(); } void CUDAPrinter::print_APIMethod_body(APIMethod* e) { diff --git a/modcc/textbuffer.cpp b/modcc/textbuffer.cpp index 5c8af1df5df85a1f72e241c0b3f461892a65edaa..658d20c4714e698967034de295327c20bb082702 100644 --- a/modcc/textbuffer.cpp +++ b/modcc/textbuffer.cpp @@ -28,6 +28,9 @@ void TextBuffer::set_gutter(int width) { indent_ = width; gutter_ = std::string(indent_, ' '); } +int TextBuffer::get_gutter() { + return indent_; +} void TextBuffer::increase_indentation() { indent_ += indentation_width_; @@ -47,3 +50,7 @@ void TextBuffer::decrease_indentation() { std::stringstream& TextBuffer::text() { return text_; } + +void TextBuffer::clear() { + text_.str(""); +} diff --git a/modcc/textbuffer.hpp b/modcc/textbuffer.hpp index cdb3fad3daacece05c39f88a7b5e13f0c95aa779..55b6da678daa5ebebc5bc373bf91864984a4686e 100644 --- a/modcc/textbuffer.hpp +++ b/modcc/textbuffer.hpp @@ -18,11 +18,14 @@ public: std::string str() const; void set_gutter(int width); + int get_gutter(); void increase_indentation(); void decrease_indentation(); std::stringstream &text(); + void clear(); + private: int indent_ = 0; diff --git a/src/backends/fvm_multicore.hpp b/src/backends/fvm_multicore.hpp index 73a0d98874909d78cbb9fbcc3f59a0005f8be8fd..71a0ba0d06f370ed09f5ce6513fce16223477bc9 100644 --- a/src/backends/fvm_multicore.hpp +++ b/src/backends/fvm_multicore.hpp @@ -132,7 +132,7 @@ struct backend { static bool has_mechanism(const std::string& name) { return mech_map_.count(name)>0; } static std::string name() { - return "multicore"; + return "cpu"; } private: diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5fd3493290cff53f87d5c1b5a1d6a620d4b16bc4..7036ee30616a0941bb0b1cf95e84dfff1a5d16e1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,8 +1,5 @@ # google test framework add_library(gtest gtest-all.cpp) -# tests look for gtest.h here -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) - # Unit tests add_subdirectory(unit) diff --git a/tests/global_communication/mpi_listener.hpp b/tests/global_communication/mpi_listener.hpp index e33aaebb5cea2168baead70e3418567c10bcdd6e..18d245e4dd2cb3f3752e4fe22a342a28bfa305bd 100644 --- a/tests/global_communication/mpi_listener.hpp +++ b/tests/global_communication/mpi_listener.hpp @@ -1,12 +1,12 @@ #pragma once #include <cstdio> -#include <ostream> +#include <fstream> #include <stdexcept> #include <communication/global_policy.hpp> -#include "gtest.h" +#include "../gtest.h" /// A specialized listener desinged for printing test results with MPI. /// diff --git a/tests/global_communication/test.cpp b/tests/global_communication/test.cpp index 1ddb6d41baf5d84cefc5b7f4e542a7cf79d2598c..fae2502972c9f8f1025112ca15b069861d4476a8 100644 --- a/tests/global_communication/test.cpp +++ b/tests/global_communication/test.cpp @@ -3,7 +3,7 @@ #include <numeric> #include <vector> -#include "gtest.h" +#include "../gtest.h" #include "mpi_listener.hpp" diff --git a/tests/global_communication/test_communicator.cpp b/tests/global_communication/test_communicator.cpp index f79d4e2d6e42b382bc4b54e16d29187ea531b7c0..b6bcc03404322b6a7b32eda1afaa83b459056982 100644 --- a/tests/global_communication/test_communicator.cpp +++ b/tests/global_communication/test_communicator.cpp @@ -1,4 +1,4 @@ -#include "gtest.h" +#include "../gtest.h" #include <cstdio> #include <fstream> diff --git a/tests/global_communication/test_exporter_spike_file.cpp b/tests/global_communication/test_exporter_spike_file.cpp index 4a85b0784801df6f91c72db70b44b69b36337f2b..027a315bf05aeac72055d1fe64deb64bf9fbc911 100644 --- a/tests/global_communication/test_exporter_spike_file.cpp +++ b/tests/global_communication/test_exporter_spike_file.cpp @@ -1,4 +1,4 @@ -#include "gtest.h" +#include "../gtest.h" #include <cstdio> #include <fstream> diff --git a/tests/global_communication/test_mpi_gather_all.cpp b/tests/global_communication/test_mpi_gather_all.cpp index b5ecf73fa7088357e8bdbcc851d44f6f190d7b7b..f67df15ac159f40df6741ca8edfa0dff68f8e415 100644 --- a/tests/global_communication/test_mpi_gather_all.cpp +++ b/tests/global_communication/test_mpi_gather_all.cpp @@ -1,7 +1,7 @@ -#include "gtest.h" - #ifdef WITH_MPI +#include "../gtest.h" + #include <cstring> #include <vector> diff --git a/tests/modcc/test.hpp b/tests/modcc/test.hpp index d3de72506d2ef679227fcc71f0d76aab141b3a9c..45dced6442094dd73ad0aac80b51d743c43c2750 100644 --- a/tests/modcc/test.hpp +++ b/tests/modcc/test.hpp @@ -1,6 +1,6 @@ #pragma once -#include <gtest.h> +#include "../gtest.h" #include "parser.hpp" #include "modccutil.hpp" diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 2dff23105bf24ae85cbca57d9db48b8f1220db03..75c46c46b55db64f158cc85d739d67762698d835 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -1,4 +1,5 @@ set(TEST_CUDA_SOURCES + test_cell_group.cu test_matrix.cu test_vector.cu diff --git a/tests/unit/test_cell_group.cu b/tests/unit/test_cell_group.cu new file mode 100644 index 0000000000000000000000000000000000000000..16bc124dec87108f97071c7f3e13c193c02402aa --- /dev/null +++ b/tests/unit/test_cell_group.cu @@ -0,0 +1,36 @@ +#include "../gtest.h" + +#include <cell_group.hpp> +#include <common_types.hpp> +#include <fvm_multicell.hpp> +#include <util/rangeutil.hpp> + +#include "../test_common_cells.hpp" + +using namespace nest::mc; + +using fvm_cell = + fvm::fvm_multicell<nest::mc::gpu::backend>; + +nest::mc::cell make_cell() { + using namespace nest::mc; + + cell c = make_cell_ball_and_stick(); + + c.add_detector({0, 0}, 0); + c.segment(1)->set_compartments(101); + + return c; +} + +TEST(cell_group, test) +{ + using cell_group_type = cell_group<fvm_cell>; + auto group = cell_group_type{0, util::singleton_view(make_cell())}; + + group.advance(50, 0.01); + + // the model is expected to generate 4 spikes as a result of the + // fixed stimulus over 50 ms + EXPECT_EQ(4u, group.spikes().size()); +} diff --git a/tests/unit/test_filter.cpp b/tests/unit/test_filter.cpp index 0d357edd3c53fc62c1618f4173935bec27179af6..d8ca4e64e6ca465abcd1486ab3e3275ae1555845 100644 --- a/tests/unit/test_filter.cpp +++ b/tests/unit/test_filter.cpp @@ -1,5 +1,3 @@ -#include "gtest.h" - #include <cstring> #include <list> @@ -8,6 +6,8 @@ #include <util/filter.hpp> #include <util/transform.hpp> +#include "../gtest.h" + #include "common.hpp" using namespace nest::mc; diff --git a/tests/validation/CMakeLists.txt b/tests/validation/CMakeLists.txt index a5d217b27a0e54e85d1cc744a810bfdc629a3fd4..d9e16533bc8dcc082211a08b85522a5c248361e5 100644 --- a/tests/validation/CMakeLists.txt +++ b/tests/validation/CMakeLists.txt @@ -13,27 +13,38 @@ set(VALIDATION_SOURCES validate.cpp ) +set(VALIDATION_CUDA_SOURCES + # unit tests + validate_soma.cu + validate_ball_and_stick.cu + validate_synapses.cu + + # support code + validation_data.cpp + trace_analysis.cpp + + # unit test driver + validate.cpp +) + if(VALIDATION_DATA_DIR) add_definitions("-DDATADIR=\"${VALIDATION_DATA_DIR}\"") endif() -add_executable(validate.exe ${VALIDATION_SOURCES} ${HEADERS}) +add_executable(validate.exe ${VALIDATION_SOURCES}) set(TARGETS validate.exe) -foreach(target ${TARGETS}) - target_link_libraries(${target} LINK_PUBLIC nestmc gtest) +if(WITH_CUDA) + cuda_add_executable(validate_cuda.exe ${VALIDATION_CUDA_SOURCES}) + list(APPEND TARGETS validate_cuda.exe) + target_link_libraries(validate_cuda.exe LINK_PUBLIC gpu) +endif() - if(WITH_TBB) - target_link_libraries(${target} LINK_PUBLIC ${TBB_LIBRARIES}) - endif() - if(WITH_CUDA) - target_link_libraries(${target} LINK_PUBLIC ${CUDA_LIBRARIES}) - endif() +foreach(target ${TARGETS}) + target_link_libraries(${target} LINK_PUBLIC nestmc gtest) - if(WITH_UNWIND) - target_link_libraries(${target} LINK_PUBLIC ${UNWIND_LIBRARIES}) - endif() + target_link_libraries(${target} LINK_PUBLIC ${EXTERNAL_LIBRARIES}) if(WITH_MPI) target_link_libraries(${target} LINK_PUBLIC ${MPI_C_LIBRARIES}) diff --git a/tests/validation/convergence_test.hpp b/tests/validation/convergence_test.hpp index e536a0f1408f53ccfd6b7c4e1f5329e7c83572ee..0561e7d76a9088b011b4bbd79f11e273f891b389 100644 --- a/tests/validation/convergence_test.hpp +++ b/tests/validation/convergence_test.hpp @@ -2,10 +2,11 @@ #include <util/filter.hpp> #include <util/rangeutil.hpp> +#include <cell.hpp> #include <json/json.hpp> -#include "gtest.h" +#include "../gtest.h" #include "trace_analysis.hpp" #include "validation_data.hpp" diff --git a/tests/validation/tinyopt.hpp b/tests/validation/tinyopt.hpp index 85a2e4a7dae008819827f79319fd32badd99b01e..90eb145f312511460786fa7f5a004604c5c54b8e 100644 --- a/tests/validation/tinyopt.hpp +++ b/tests/validation/tinyopt.hpp @@ -6,7 +6,7 @@ #include <stdexcept> #include <string> -#include "gtest.h" +#include "../gtest.h" #include <communication/global_policy.hpp> diff --git a/tests/validation/trace_analysis.cpp b/tests/validation/trace_analysis.cpp index 78ef5ada3ff39e8155aa9db97181274fb0fef118..b83d41a2ca9ce76d79d63dd84744294366a56c18 100644 --- a/tests/validation/trace_analysis.cpp +++ b/tests/validation/trace_analysis.cpp @@ -4,7 +4,7 @@ #include <json/json.hpp> -#include "gtest.h" +#include "../gtest.h" #include <math.hpp> #include <simple_sampler.hpp> diff --git a/tests/validation/trace_analysis.hpp b/tests/validation/trace_analysis.hpp index 493a15f7bc205b90589e22a379363bddc29276c5..8b0976237bc1790dc13141ee86c625cf196fc4d4 100644 --- a/tests/validation/trace_analysis.hpp +++ b/tests/validation/trace_analysis.hpp @@ -2,7 +2,7 @@ #include <vector> -#include "gtest.h" +#include "../gtest.h" #include <simple_sampler.hpp> #include <math.hpp> diff --git a/tests/validation/validate.cpp b/tests/validation/validate.cpp index 9f071aa2ed719d0de39bafb6009ecd5415618651..a2f2f8322cc9c63e03eddf41957521e5bbdffb99 100644 --- a/tests/validation/validate.cpp +++ b/tests/validation/validate.cpp @@ -4,10 +4,10 @@ #include <string> #include <exception> -#include "gtest.h" - #include <communication/global_policy.hpp> +#include "../gtest.h" + #include "tinyopt.hpp" #include "validation_data.hpp" diff --git a/tests/validation/validate_ball_and_stick.cpp b/tests/validation/validate_ball_and_stick.cpp index 01c9bbaaf2d500444e117f4940a17b6f2bcc912c..0e31bcaad33723829317a02d183ba9f40bb20f76 100644 --- a/tests/validation/validate_ball_and_stick.cpp +++ b/tests/validation/validate_ball_and_stick.cpp @@ -1,159 +1,22 @@ -#include <json/json.hpp> - -#include <cell.hpp> -#include <common_types.hpp> -#include <fvm_multicell.hpp> -#include <model.hpp> -#include <recipe.hpp> -#include <simple_sampler.hpp> -#include <util/path.hpp> - #include "../gtest.h" +#include "validate_ball_and_stick.hpp" -#include "../test_common_cells.hpp" -#include "convergence_test.hpp" -#include "trace_analysis.hpp" -#include "validation_data.hpp" - -using namespace nest::mc; - -template < - typename lowered_cell, - typename SamplerInfoSeq -> -void run_ncomp_convergence_test( - const char* model_name, - const util::path& ref_data_path, - const cell& c, - SamplerInfoSeq& samplers, - float t_end=100.f) -{ - auto max_ncomp = g_trace_io.max_ncomp(); - auto dt = g_trace_io.min_dt(); - - nlohmann::json meta = { - {"name", "membrane voltage"}, - {"model", model_name}, - {"dt", dt}, - {"sim", "nestmc"}, - {"units", "mV"} - }; - - auto exclude = stimulus_ends(c); - - convergence_test_runner<int> R("ncomp", samplers, meta); - R.load_reference_data(ref_data_path); - - for (int ncomp = 10; ncomp<max_ncomp; ncomp*=2) { - for (auto& seg: c.segments()) { - if (!seg->is_soma()) { - seg->set_compartments(ncomp); - } - } - model<lowered_cell> m(singleton_recipe{c}); - - R.run(m, ncomp, t_end, dt, exclude); - } - R.report(); - R.assert_all_convergence(); -} - -TEST(ball_and_taper, neuron_ref) { - using lowered_cell = fvm::fvm_multicell<multicore::backend>; - - cell c = make_cell_ball_and_stick(); - add_common_voltage_probes(c); +#include <fvm_multicell.hpp> - float sample_dt = 0.025f; - sampler_info samplers[] = { - {"soma.mid", {0u, 0u}, simple_sampler(sample_dt)}, - {"dend.mid", {0u, 1u}, simple_sampler(sample_dt)}, - {"dend.end", {0u, 2u}, simple_sampler(sample_dt)} - }; +using lowered_cell = nest::mc::fvm::fvm_multicell<nest::mc::multicore::backend>; - run_ncomp_convergence_test<lowered_cell>( - "ball_and_stick", - "neuron_ball_and_stick.json", - c, - samplers); +TEST(ball_and_stick, neuron_ref) { + validate_ball_and_stick<lowered_cell>(); } TEST(ball_and_3stick, neuron_ref) { - using lowered_cell = fvm::fvm_multicell<multicore::backend>; - - cell c = make_cell_ball_and_3stick(); - add_common_voltage_probes(c); - - float sample_dt = 0.025f; - sampler_info samplers[] = { - {"soma.mid", {0u, 0u}, simple_sampler(sample_dt)}, - {"dend1.mid", {0u, 1u}, simple_sampler(sample_dt)}, - {"dend1.end", {0u, 2u}, simple_sampler(sample_dt)}, - {"dend2.mid", {0u, 3u}, simple_sampler(sample_dt)}, - {"dend2.end", {0u, 4u}, simple_sampler(sample_dt)}, - {"dend3.mid", {0u, 5u}, simple_sampler(sample_dt)}, - {"dend3.end", {0u, 6u}, simple_sampler(sample_dt)} - }; - - run_ncomp_convergence_test<lowered_cell>( - "ball_and_3stick", - "neuron_ball_and_3stick.json", - c, - samplers); + validate_ball_and_3stick<lowered_cell>(); } TEST(rallpack1, numeric_ref) { - using lowered_cell = fvm::fvm_multicell<multicore::backend>; - - cell c = make_cell_simple_cable(); - - // three probes: left end, 30% along, right end. - c.add_probe({{1, 0.0}, probeKind::membrane_voltage}); - c.add_probe({{1, 0.3}, probeKind::membrane_voltage}); - c.add_probe({{1, 1.0}, probeKind::membrane_voltage}); - - float sample_dt = 0.025f; - sampler_info samplers[] = { - {"cable.x0.0", {0u, 0u}, simple_sampler(sample_dt)}, - {"cable.x0.3", {0u, 1u}, simple_sampler(sample_dt)}, - {"cable.x1.0", {0u, 2u}, simple_sampler(sample_dt)}, - }; - - run_ncomp_convergence_test<lowered_cell>( - "rallpack1", - "numeric_rallpack1.json", - c, - samplers, - 250.f); + validate_rallpack1<lowered_cell>(); } TEST(ball_and_squiggle, neuron_ref) { - using lowered_cell = fvm::fvm_multicell<multicore::backend>; - - cell c = make_cell_ball_and_squiggle(); - add_common_voltage_probes(c); - - float sample_dt = 0.025f; - sampler_info samplers[] = { - {"soma.mid", {0u, 0u}, simple_sampler(sample_dt)}, - {"dend.mid", {0u, 1u}, simple_sampler(sample_dt)}, - {"dend.end", {0u, 2u}, simple_sampler(sample_dt)} - }; - -#if 0 - // *temporarily* disabled: compartment division policy will - // be moved into backend policy classes. - - run_ncomp_convergence_test<lowered_cell_div<div_compartment_sampler>>( - "ball_and_squiggle_sampler", - "neuron_ball_and_squiggle.json", - c, - samplers); -#endif - - run_ncomp_convergence_test<lowered_cell>( - "ball_and_squiggle_integrator", - "neuron_ball_and_squiggle.json", - c, - samplers); + validate_ball_and_squiggle<lowered_cell>(); } diff --git a/tests/validation/validate_ball_and_stick.cu b/tests/validation/validate_ball_and_stick.cu new file mode 100644 index 0000000000000000000000000000000000000000..b753b6b5d744c822aef7e65fc41e88b7dbeeeafb --- /dev/null +++ b/tests/validation/validate_ball_and_stick.cu @@ -0,0 +1,22 @@ +#include "../gtest.h" +#include "validate_ball_and_stick.hpp" + +#include <fvm_multicell.hpp> + +using lowered_cell = nest::mc::fvm::fvm_multicell<nest::mc::gpu::backend>; + +TEST(ball_and_stick, neuron_ref) { + validate_ball_and_stick<lowered_cell>(); +} + +TEST(ball_and_3stick, neuron_ref) { + validate_ball_and_3stick<lowered_cell>(); +} + +TEST(rallpack1, numeric_ref) { + validate_rallpack1<lowered_cell>(); +} + +TEST(ball_and_squiggle, neuron_ref) { + validate_ball_and_squiggle<lowered_cell>(); +} diff --git a/tests/validation/validate_ball_and_stick.hpp b/tests/validation/validate_ball_and_stick.hpp new file mode 100644 index 0000000000000000000000000000000000000000..bed16d4d59663d7d3bcd8bf069358a386a53b2bd --- /dev/null +++ b/tests/validation/validate_ball_and_stick.hpp @@ -0,0 +1,165 @@ +#include <json/json.hpp> + +#include <cell.hpp> +#include <common_types.hpp> +#include <fvm_multicell.hpp> +#include <model.hpp> +#include <recipe.hpp> +#include <simple_sampler.hpp> +#include <util/path.hpp> + +#include "../gtest.h" + +#include "../test_common_cells.hpp" +#include "convergence_test.hpp" +#include "trace_analysis.hpp" +#include "validation_data.hpp" + +template < + typename LoweredCell, + typename SamplerInfoSeq +> +void run_ncomp_convergence_test( + const char* model_name, + const nest::mc::util::path& ref_data_path, + const nest::mc::cell& c, + SamplerInfoSeq& samplers, + float t_end=100.f) +{ + using namespace nest::mc; + + auto max_ncomp = g_trace_io.max_ncomp(); + auto dt = g_trace_io.min_dt(); + + nlohmann::json meta = { + {"name", "membrane voltage"}, + {"model", model_name}, + {"dt", dt}, + {"sim", "nestmc"}, + {"units", "mV"}, + {"backend", LoweredCell::backend::name()} + }; + + auto exclude = stimulus_ends(c); + + convergence_test_runner<int> runner("ncomp", samplers, meta); + runner.load_reference_data(ref_data_path); + + for (int ncomp = 10; ncomp<max_ncomp; ncomp*=2) { + for (auto& seg: c.segments()) { + if (!seg->is_soma()) { + seg->set_compartments(ncomp); + } + } + model<LoweredCell> m(singleton_recipe{c}); + + runner.run(m, ncomp, t_end, dt, exclude); + } + runner.report(); + runner.assert_all_convergence(); +} + + +template <typename LoweredCell> +void validate_ball_and_stick() { + using namespace nest::mc; + + cell c = make_cell_ball_and_stick(); + add_common_voltage_probes(c); + + float sample_dt = 0.025f; + sampler_info samplers[] = { + {"soma.mid", {0u, 0u}, simple_sampler(sample_dt)}, + {"dend.mid", {0u, 1u}, simple_sampler(sample_dt)}, + {"dend.end", {0u, 2u}, simple_sampler(sample_dt)} + }; + + run_ncomp_convergence_test<LoweredCell>( + "ball_and_stick", + "neuron_ball_and_stick.json", + c, + samplers); +} + +template <typename LoweredCell> +void validate_ball_and_3stick() { + using namespace nest::mc; + + cell c = make_cell_ball_and_3stick(); + add_common_voltage_probes(c); + + float sample_dt = 0.025f; + sampler_info samplers[] = { + {"soma.mid", {0u, 0u}, simple_sampler(sample_dt)}, + {"dend1.mid", {0u, 1u}, simple_sampler(sample_dt)}, + {"dend1.end", {0u, 2u}, simple_sampler(sample_dt)}, + {"dend2.mid", {0u, 3u}, simple_sampler(sample_dt)}, + {"dend2.end", {0u, 4u}, simple_sampler(sample_dt)}, + {"dend3.mid", {0u, 5u}, simple_sampler(sample_dt)}, + {"dend3.end", {0u, 6u}, simple_sampler(sample_dt)} + }; + + run_ncomp_convergence_test<LoweredCell>( + "ball_and_3stick", + "neuron_ball_and_3stick.json", + c, + samplers); +} + +template <typename LoweredCell> +void validate_rallpack1() { + using namespace nest::mc; + + cell c = make_cell_simple_cable(); + + // three probes: left end, 30% along, right end. + c.add_probe({{1, 0.0}, probeKind::membrane_voltage}); + c.add_probe({{1, 0.3}, probeKind::membrane_voltage}); + c.add_probe({{1, 1.0}, probeKind::membrane_voltage}); + + float sample_dt = 0.025f; + sampler_info samplers[] = { + {"cable.x0.0", {0u, 0u}, simple_sampler(sample_dt)}, + {"cable.x0.3", {0u, 1u}, simple_sampler(sample_dt)}, + {"cable.x1.0", {0u, 2u}, simple_sampler(sample_dt)}, + }; + + run_ncomp_convergence_test<LoweredCell>( + "rallpack1", + "numeric_rallpack1.json", + c, + samplers, + 250.f); +} + +template <typename LoweredCell> +void validate_ball_and_squiggle() { + using namespace nest::mc; + + cell c = make_cell_ball_and_squiggle(); + add_common_voltage_probes(c); + + float sample_dt = 0.025f; + sampler_info samplers[] = { + {"soma.mid", {0u, 0u}, simple_sampler(sample_dt)}, + {"dend.mid", {0u, 1u}, simple_sampler(sample_dt)}, + {"dend.end", {0u, 2u}, simple_sampler(sample_dt)} + }; + +#if 0 + // *temporarily* disabled: compartment division policy will + // be moved into backend policy classes. + + run_ncomp_convergence_test<lowered_cell_div<div_compartment_sampler>>( + "ball_and_squiggle_sampler", + "neuron_ball_and_squiggle.json", + c, + samplers); +#endif + + run_ncomp_convergence_test<LoweredCell>( + "ball_and_squiggle_integrator", + "neuron_ball_and_squiggle.json", + c, + samplers); +} diff --git a/tests/validation/validate_compartment_policy.cpp b/tests/validation/validate_compartment_policy.cpp index e03f800c27b340efd211d5e79ddc9f33d68ce66b..4848ea12a14c9da2bce2dff0fd28ff4f042b4bd5 100644 --- a/tests/validation/validate_compartment_policy.cpp +++ b/tests/validation/validate_compartment_policy.cpp @@ -11,7 +11,7 @@ #include <simple_sampler.hpp> #include <util/rangeutil.hpp> -#include "gtest.h" +#include "../gtest.h" #include "../test_common_cells.hpp" #include "../test_util.hpp" diff --git a/tests/validation/validate_soma.cpp b/tests/validation/validate_soma.cpp index f7dcf4dc8b5e74d7fce3b331ffa7ad7878cdcf95..e4e58e7b665c05b0e2afdc99f76e0c4c545e905a 100644 --- a/tests/validation/validate_soma.cpp +++ b/tests/validation/validate_soma.cpp @@ -1,61 +1,9 @@ -#include <fstream> -#include <utility> - -#include <json/json.hpp> - -#include <common_types.hpp> -#include <cell.hpp> -#include <fvm_multicell.hpp> -#include <model.hpp> -#include <recipe.hpp> -#include <simple_sampler.hpp> -#include <util/rangeutil.hpp> +#include "validate_soma.hpp" #include "../gtest.h" -#include "../test_common_cells.hpp" -#include "convergence_test.hpp" -#include "trace_analysis.hpp" -#include "validation_data.hpp" - -using namespace nest::mc; +using lowered_cell = nest::mc::fvm::fvm_multicell<nest::mc::multicore::backend>; TEST(soma, numeric_ref) { - using lowered_cell = fvm::fvm_multicell<multicore::backend>; - - cell c = make_cell_soma_only(); - add_common_voltage_probes(c); - model<lowered_cell> m(singleton_recipe{c}); - - float sample_dt = .025f; - sampler_info samplers[] = {{"soma.mid", {0u, 0u}, simple_sampler(sample_dt)}}; - - nlohmann::json meta = { - {"name", "membrane voltage"}, - {"model", "soma"}, - {"sim", "nestmc"}, - {"units", "mV"} - }; - - convergence_test_runner<float> R("dt", samplers, meta); - R.load_reference_data("numeric_soma.json"); - - float t_end = 100.f; - - // use dt = 0.05, 0.025, 0.01, 0.005, 0.0025, ... - double max_oo_dt = std::round(1.0/g_trace_io.min_dt()); - for (double base = 100; ; base *= 10) { - for (double multiple: {5., 2.5, 1.}) { - double oo_dt = base/multiple; - if (oo_dt>max_oo_dt) goto end; - - m.reset(); - float dt = float(1./oo_dt); - R.run(m, dt, t_end, dt); - } - } -end: - - R.report(); - R.assert_all_convergence(); + validate_soma<lowered_cell>(); } diff --git a/tests/validation/validate_soma.cu b/tests/validation/validate_soma.cu new file mode 100644 index 0000000000000000000000000000000000000000..35355ab93d66715fcf79ce27d064d2cdd119df07 --- /dev/null +++ b/tests/validation/validate_soma.cu @@ -0,0 +1,9 @@ +#include "validate_soma.hpp" + +#include "../gtest.h" + +using lowered_cell = nest::mc::fvm::fvm_multicell<nest::mc::gpu::backend>; + +TEST(soma, numeric_ref) { + validate_soma<lowered_cell>(); +} diff --git a/tests/validation/validate_soma.hpp b/tests/validation/validate_soma.hpp new file mode 100644 index 0000000000000000000000000000000000000000..52bc7d5e087ed575372aa524812d9b23ad38fc33 --- /dev/null +++ b/tests/validation/validate_soma.hpp @@ -0,0 +1,56 @@ +#include <json/json.hpp> + +#include <common_types.hpp> +#include <cell.hpp> +#include <fvm_multicell.hpp> +#include <model.hpp> +#include <recipe.hpp> +#include <simple_sampler.hpp> +#include <util/rangeutil.hpp> + +#include "../test_common_cells.hpp" +#include "convergence_test.hpp" +#include "trace_analysis.hpp" +#include "validation_data.hpp" + +template <typename LoweredCell> +void validate_soma() { + using namespace nest::mc; + + cell c = make_cell_soma_only(); + add_common_voltage_probes(c); + model<LoweredCell> model(singleton_recipe{c}); + + float sample_dt = .025f; + sampler_info samplers[] = {{"soma.mid", {0u, 0u}, simple_sampler(sample_dt)}}; + + nlohmann::json meta = { + {"name", "membrane voltage"}, + {"model", "soma"}, + {"sim", "nestmc"}, + {"units", "mV"}, + {"backend", LoweredCell::backend::name()} + }; + + convergence_test_runner<float> runner("dt", samplers, meta); + runner.load_reference_data("numeric_soma.json"); + + float t_end = 100.f; + + // use dt = 0.05, 0.025, 0.01, 0.005, 0.0025, ... + double max_oo_dt = std::round(1.0/g_trace_io.min_dt()); + for (double base = 100; ; base *= 10) { + for (double multiple: {5., 2.5, 1.}) { + double oo_dt = base/multiple; + if (oo_dt>max_oo_dt) goto end; + + model.reset(); + float dt = float(1./oo_dt); + runner.run(model, dt, t_end, dt); + } + } +end: + + runner.report(); + runner.assert_all_convergence(); +} diff --git a/tests/validation/validate_synapses.cpp b/tests/validation/validate_synapses.cpp index e90fd494d03420edbff7e58b9e71a5253be740f5..23413cc91c44a8c890ee9635e6deada92db95e10 100644 --- a/tests/validation/validate_synapses.cpp +++ b/tests/validation/validate_synapses.cpp @@ -1,81 +1,16 @@ -#include <json/json.hpp> - -#include <cell.hpp> -#include <cell_group.hpp> #include <fvm_multicell.hpp> -#include <model.hpp> -#include <recipe.hpp> -#include <simple_sampler.hpp> -#include <util/path.hpp> #include "../gtest.h" +#include "validate_synapses.hpp" -#include "../test_common_cells.hpp" -#include "convergence_test.hpp" -#include "trace_analysis.hpp" -#include "validation_data.hpp" - -using namespace nest::mc; - -void run_synapse_test( - const char* syn_type, - const util::path& ref_data_path, - float t_end=70.f, - float dt=0.001) -{ - using lowered_cell = fvm::fvm_multicell<multicore::backend>; - - auto max_ncomp = g_trace_io.max_ncomp(); - nlohmann::json meta = { - {"name", "membrane voltage"}, - {"model", syn_type}, - {"sim", "nestmc"}, - {"units", "mV"} - }; - - cell c = make_cell_ball_and_stick(false); // no stimuli - parameter_list syn_default(syn_type); - c.add_synapse({1, 0.5}, syn_default); - add_common_voltage_probes(c); - - // injected spike events - postsynaptic_spike_event<float> synthetic_events[] = { - {{0u, 0u}, 10.0, 0.04}, - {{0u, 0u}, 20.0, 0.04}, - {{0u, 0u}, 40.0, 0.04} - }; - - // exclude points of discontinuity from linf analysis - std::vector<float> exclude = {10.f, 20.f, 40.f}; - - float sample_dt = 0.025f; - sampler_info samplers[] = { - {"soma.mid", {0u, 0u}, simple_sampler(sample_dt)}, - {"dend.mid", {0u, 1u}, simple_sampler(sample_dt)}, - {"dend.end", {0u, 2u}, simple_sampler(sample_dt)} - }; - - convergence_test_runner<int> R("ncomp", samplers, meta); - R.load_reference_data(ref_data_path); - - for (int ncomp = 10; ncomp<max_ncomp; ncomp*=2) { - c.cable(1)->set_compartments(ncomp); - model<lowered_cell> m(singleton_recipe{c}); - m.group(0).enqueue_events(synthetic_events); - - R.run(m, ncomp, t_end, dt, exclude); - } - R.report(); - R.assert_all_convergence(); -} +using lowered_cell = nest::mc::fvm::fvm_multicell<nest::mc::multicore::backend>; TEST(simple_synapse, expsyn_neuron_ref) { SCOPED_TRACE("expsyn"); - run_synapse_test("expsyn", "neuron_simple_exp_synapse.json"); + run_synapse_test<lowered_cell>("expsyn", "neuron_simple_exp_synapse.json"); } TEST(simple_synapse, exp2syn_neuron_ref) { SCOPED_TRACE("exp2syn"); - run_synapse_test("exp2syn", "neuron_simple_exp2_synapse.json"); + run_synapse_test<lowered_cell>("exp2syn", "neuron_simple_exp2_synapse.json"); } - diff --git a/tests/validation/validate_synapses.cu b/tests/validation/validate_synapses.cu new file mode 100644 index 0000000000000000000000000000000000000000..0dedd584268f77011908aa593886a5534965a482 --- /dev/null +++ b/tests/validation/validate_synapses.cu @@ -0,0 +1,16 @@ +#include <fvm_multicell.hpp> + +#include "../gtest.h" +#include "validate_synapses.hpp" + +using lowered_cell = nest::mc::fvm::fvm_multicell<nest::mc::gpu::backend>; + +TEST(simple_synapse, expsyn_neuron_ref) { + SCOPED_TRACE("expsyn"); + run_synapse_test<lowered_cell>("expsyn", "neuron_simple_exp_synapse.json"); +} + +TEST(simple_synapse, exp2syn_neuron_ref) { + SCOPED_TRACE("exp2syn"); + run_synapse_test<lowered_cell>("exp2syn", "neuron_simple_exp2_synapse.json"); +} diff --git a/tests/validation/validate_synapses.hpp b/tests/validation/validate_synapses.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a6ee35e90f271866563a69d33d8ff62d3320cb95 --- /dev/null +++ b/tests/validation/validate_synapses.hpp @@ -0,0 +1,70 @@ +#include <json/json.hpp> + +#include <cell.hpp> +#include <cell_group.hpp> +#include <fvm_multicell.hpp> +#include <model.hpp> +#include <recipe.hpp> +#include <simple_sampler.hpp> +#include <util/path.hpp> + +#include "../gtest.h" + +#include "../test_common_cells.hpp" +#include "convergence_test.hpp" +#include "trace_analysis.hpp" +#include "validation_data.hpp" + +template <typename LoweredCell> +void run_synapse_test( + const char* syn_type, + const nest::mc::util::path& ref_data_path, + float t_end=70.f, + float dt=0.001) +{ + using namespace nest::mc; + + auto max_ncomp = g_trace_io.max_ncomp(); + nlohmann::json meta = { + {"name", "membrane voltage"}, + {"model", syn_type}, + {"sim", "nestmc"}, + {"units", "mV"}, + {"backend", LoweredCell::backend::name()} + }; + + cell c = make_cell_ball_and_stick(false); // no stimuli + parameter_list syn_default(syn_type); + c.add_synapse({1, 0.5}, syn_default); + add_common_voltage_probes(c); + + // injected spike events + postsynaptic_spike_event<float> synthetic_events[] = { + {{0u, 0u}, 10.0, 0.04}, + {{0u, 0u}, 20.0, 0.04}, + {{0u, 0u}, 40.0, 0.04} + }; + + // exclude points of discontinuity from linf analysis + std::vector<float> exclude = {10.f, 20.f, 40.f}; + + float sample_dt = 0.025f; + sampler_info samplers[] = { + {"soma.mid", {0u, 0u}, simple_sampler(sample_dt)}, + {"dend.mid", {0u, 1u}, simple_sampler(sample_dt)}, + {"dend.end", {0u, 2u}, simple_sampler(sample_dt)} + }; + + convergence_test_runner<int> runner("ncomp", samplers, meta); + runner.load_reference_data(ref_data_path); + + for (int ncomp = 10; ncomp<max_ncomp; ncomp*=2) { + c.cable(1)->set_compartments(ncomp); + model<LoweredCell> m(singleton_recipe{c}); + m.group(0).enqueue_events(synthetic_events); + + runner.run(m, ncomp, t_end, dt, exclude); + } + runner.report(); + runner.assert_all_convergence(); +}