From ac272785dc444c8444b085d121f08b7575bb6647 Mon Sep 17 00:00:00 2001 From: Nicolas Cornu Date: Thu, 12 Jan 2023 23:40:29 +0100 Subject: [PATCH] Add tests for BEFORE/AFTER block (#979) --- src/language/nmodl.yaml | 2 +- test/unit/codegen/codegen_cpp_visitor.cpp | 157 ++++++++++++++++++++++ 2 files changed, 158 insertions(+), 1 deletion(-) diff --git a/src/language/nmodl.yaml b/src/language/nmodl.yaml index 77607044f4..58a8b3bb49 100644 --- a/src/language/nmodl.yaml +++ b/src/language/nmodl.yaml @@ -834,7 +834,7 @@ brief: "Represents a `BREAKPOINT` block in NMODL" description: | The `BREAKPOINT` block is used to update current and conductance. - at each time step. Here is an example of `BEFORE` : + at each time step. Here is an example of `BREAKPOINT` : \code{.mod} BREAKPOINT { diff --git a/test/unit/codegen/codegen_cpp_visitor.cpp b/test/unit/codegen/codegen_cpp_visitor.cpp index 36750a91b1..5182c38488 100644 --- a/test/unit/codegen/codegen_cpp_visitor.cpp +++ b/test/unit/codegen/codegen_cpp_visitor.cpp @@ -423,6 +423,163 @@ SCENARIO("Check code generation for TABLE statements", "[codegen][array_variable } } +SCENARIO("Check that BEFORE/AFTER block are well generated", "[codegen][before/after]") { + GIVEN("A mod file full of BEFORE/AFTER of all kinds") { + std::string const nmodl_text = R"( + NEURON { + SUFFIX ba1 + } + BEFORE BREAKPOINT { + init_before_breakpoint() + inc = 0 + } + AFTER SOLVE { + init_after_solve() + inc = 0 + } + BEFORE INITIAL { + init_before_initial() + inc = 0 + } + AFTER INITIAL { + init_after_initial() + inc = 0 + } + BEFORE STEP { + init_before_step() + inc = 0 + } + )"; + THEN("They should be well registered") { + auto const generated = get_cpp_code(nmodl_text); + // 11: BEFORE BREAKPOINT + { + REQUIRE_THAT(generated, + Contains("hoc_reg_ba(mech_type, nrn_before_after_0_ba1, 11);")); + std::string generated_code = R"( + #pragma ivdep + #pragma omp simd + for (int id = 0; id < nodecount; id++) { + int node_id = node_index[id]; + double v = voltage[node_id]; + #if NRN_PRCELLSTATE + inst->v_unused[id] = v; + #endif + { + init_before_breakpoint(); + inc = 0.0; + } + })"; + auto const expected = generated_code; + REQUIRE_THAT(generated, Contains(expected)); + } + // 23: AFTER SOLVE + { + REQUIRE_THAT(generated, + Contains("hoc_reg_ba(mech_type, nrn_before_after_1_ba1, 22);")); + std::string generated_code = R"( + #pragma ivdep + #pragma omp simd + for (int id = 0; id < nodecount; id++) { + int node_id = node_index[id]; + double v = voltage[node_id]; + #if NRN_PRCELLSTATE + inst->v_unused[id] = v; + #endif + { + init_after_solve(); + inc = 0.0; + } + })"; + auto const expected = generated_code; + REQUIRE_THAT(generated, Contains(expected)); + } + // 11: BEFORE INITIAL + { + REQUIRE_THAT(generated, + Contains("hoc_reg_ba(mech_type, nrn_before_after_2_ba1, 13);")); + std::string generated_code = R"( + #pragma ivdep + #pragma omp simd + for (int id = 0; id < nodecount; id++) { + int node_id = node_index[id]; + double v = voltage[node_id]; + #if NRN_PRCELLSTATE + inst->v_unused[id] = v; + #endif + { + init_before_initial(); + inc = 0.0; + } + })"; + auto const expected = generated_code; + REQUIRE_THAT(generated, Contains(expected)); + } + // 21: AFTER INITIAL + { + REQUIRE_THAT(generated, + Contains("hoc_reg_ba(mech_type, nrn_before_after_3_ba1, 23);")); + std::string generated_code = R"( + #pragma ivdep + #pragma omp simd + for (int id = 0; id < nodecount; id++) { + int node_id = node_index[id]; + double v = voltage[node_id]; + #if NRN_PRCELLSTATE + inst->v_unused[id] = v; + #endif + { + init_after_initial(); + inc = 0.0; + } + })"; + auto const expected = generated_code; + REQUIRE_THAT(generated, Contains(expected)); + } + // 13: BEFORE STEP + { + REQUIRE_THAT(generated, + Contains("hoc_reg_ba(mech_type, nrn_before_after_4_ba1, 14);")); + std::string generated_code = R"( + #pragma ivdep + #pragma omp simd + for (int id = 0; id < nodecount; id++) { + int node_id = node_index[id]; + double v = voltage[node_id]; + #if NRN_PRCELLSTATE + inst->v_unused[id] = v; + #endif + { + init_before_step(); + inc = 0.0; + } + })"; + auto const expected = generated_code; + REQUIRE_THAT(generated, Contains(expected)); + } + } + } + + GIVEN("A mod file with several time same BEFORE or AFTER block") { + std::string const nmodl_text = R"( + NEURON { + SUFFIX ba1 + } + BEFORE STEP {} + AFTER SOLVE {} + BEFORE STEP {} + AFTER SOLVE {} + )"; + THEN("They should be all registered") { + auto const generated = get_cpp_code(nmodl_text); + REQUIRE_THAT(generated, Contains("hoc_reg_ba(mech_type, nrn_before_after_0_ba1, 14);")); + REQUIRE_THAT(generated, Contains("hoc_reg_ba(mech_type, nrn_before_after_1_ba1, 22);")); + REQUIRE_THAT(generated, Contains("hoc_reg_ba(mech_type, nrn_before_after_2_ba1, 14);")); + REQUIRE_THAT(generated, Contains("hoc_reg_ba(mech_type, nrn_before_after_3_ba1, 22);")); + } + } +} + SCENARIO("Check CONSTANT variables are added to global variable structure", "[codegen][global_variables]") { GIVEN("A MOD file that use CONSTANT variables") {