diff --git a/.github/workflows/nmodl-ci.yml b/.github/workflows/nmodl-ci.yml index c5c6c397c2..394104e9ff 100644 --- a/.github/workflows/nmodl-ci.yml +++ b/.github/workflows/nmodl-ci.yml @@ -50,6 +50,13 @@ jobs: sanitizer: undefined fail-fast: true steps: + - name: Fix kernel mmap rnd bits + # Asan in llvm 14 provided in ubuntu 22.04 is incompatible with + # high-entropy ASLR in much newer kernels that GitHub runners are + # using leading to random crashes: https://reviews.llvm.org/D148280 + run: sudo sysctl vm.mmap_rnd_bits=28 + if: matrix.config.os == 'ubuntu-22.04' + - name: Setup cmake uses: jwlawson/actions-setup-cmake@v2 with: diff --git a/.gitignore b/.gitignore index 852a697f1e..2f1752b201 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,4 @@ venv.bak/ # Generated files test/usecases/*/x86_64 test/usecases/*/amd64 +test/usecases/*/arm64 diff --git a/ext/catch2 b/ext/catch2 index 3f0283de7a..8ac8190e49 160000 --- a/ext/catch2 +++ b/ext/catch2 @@ -1 +1 @@ -Subproject commit 3f0283de7a9c43200033da996ff9093be3ac84dc +Subproject commit 8ac8190e494a381072c89f5e161b92a08d98b37b diff --git a/ext/cli11 b/ext/cli11 index b9be5b9444..f4d0731ceb 160000 --- a/ext/cli11 +++ b/ext/cli11 @@ -1 +1 @@ -Subproject commit b9be5b9444772324459989177108a6a65b8b2769 +Subproject commit f4d0731cebb123ff0ace712c099dffbcd2c58e5a diff --git a/ext/json b/ext/json index 4f8fba1406..9cca280a4d 160000 --- a/ext/json +++ b/ext/json @@ -1 +1 @@ -Subproject commit 4f8fba14066156b73f1189a2b8bd568bde5284c5 +Subproject commit 9cca280a4d0ccf0c08f47a99aa71d1b0e52f8d03 diff --git a/ext/pybind11 b/ext/pybind11 index 914c06fb25..8a099e44b3 160000 --- a/ext/pybind11 +++ b/ext/pybind11 @@ -1 +1 @@ -Subproject commit 914c06fb252b6cc3727d0eedab6736e88a3fcb01 +Subproject commit 8a099e44b3d5f85b20f05828d919d2332a8de841 diff --git a/ext/spdlog b/ext/spdlog index 7e635fca68..7c02e204c9 160000 --- a/ext/spdlog +++ b/ext/spdlog @@ -1 +1 @@ -Subproject commit 7e635fca68d014934b4af8a1cf874f63989352b7 +Subproject commit 7c02e204c92545f869e2f04edaab1f19fe8b19fd diff --git a/src/codegen/codegen_neuron_cpp_visitor.cpp b/src/codegen/codegen_neuron_cpp_visitor.cpp index 829afff315..17380af463 100644 --- a/src/codegen/codegen_neuron_cpp_visitor.cpp +++ b/src/codegen/codegen_neuron_cpp_visitor.cpp @@ -507,7 +507,7 @@ std::string CodegenNeuronCppVisitor::float_variable_name(const SymbolType& symbo std::string CodegenNeuronCppVisitor::int_variable_name(const IndexVariableInfo& symbol, const std::string& name, bool use_instance) const { - auto position = position_of_int_var(name); + // auto position = position_of_int_var(name); if (symbol.is_index) { if (use_instance) { throw std::runtime_error("Not implemented. [wiejo]"); @@ -785,7 +785,8 @@ void CodegenNeuronCppVisitor::print_mechanism_global_var_structure(bool print_in } - for (const auto& f: info.function_tables) { + // for (const auto& f: info.function_tables) { + if (!info.function_tables.empty()) { throw std::runtime_error("Not implemented, global function tables."); } @@ -1033,7 +1034,6 @@ void CodegenNeuronCppVisitor::print_mechanism_register() { for (int i = 0; i < codegen_int_variables_size; ++i) { const auto& int_var = codegen_int_variables[i]; - const auto& name = int_var.symbol->get_name(); if (i != info.semantics[i].index) { throw std::runtime_error("Broken logic."); } @@ -1149,7 +1149,6 @@ void CodegenNeuronCppVisitor::print_make_instance() const { } void CodegenNeuronCppVisitor::print_node_data_structure(bool print_initializers) { - auto const value_initialize = print_initializers ? "{}" : ""; printer->add_newline(2); printer->fmt_push_block("struct {} ", node_data_struct()); diff --git a/src/main.cpp b/src/main.cpp index 70a26a66ae..0a678789d2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -69,7 +69,7 @@ int main(int argc, const char* argv[]) { std::vector mod_files; /// true if debug logger statements should be shown - std::string verbose("info"); + std::string verbose("warning"); /// true if code is to be generated for NEURON bool neuron_code(false); diff --git a/src/visitors/kinetic_block_visitor.cpp b/src/visitors/kinetic_block_visitor.cpp index a8d78dc4c4..88d53023c6 100644 --- a/src/visitors/kinetic_block_visitor.cpp +++ b/src/visitors/kinetic_block_visitor.cpp @@ -8,11 +8,14 @@ #include "kinetic_block_visitor.hpp" #include "ast/all.hpp" +#include "index_remover.hpp" #include "symtab/symbol.hpp" #include "utils/logger.hpp" #include "utils/string_utils.hpp" #include "visitor_utils.hpp" +#include + namespace nmodl { namespace visitor { @@ -141,24 +144,69 @@ void KineticBlockVisitor::visit_conserve(ast::Conserve& node) { logger->debug("KineticBlockVisitor :: --> {}", to_nmodl(node)); } +void KineticBlockVisitor::set_compartment_factor(int var_index, const std::string& factor) { + if (compartment_factors[var_index] != "") { + throw std::runtime_error("Setting compartment volume twice."); + } + + compartment_factors[var_index] = factor; + logger->debug("KineticBlockVisitor :: COMPARTMENT factor {} for state var {} (index {})", + factor, + state_var[var_index], + var_index); +} + +void KineticBlockVisitor::compute_compartment_factor(ast::Compartment& node, + const ast::Name& name) { + const auto& var_name = name.get_node_name(); + const auto it = state_var_index.find(var_name); + if (it != state_var_index.cend()) { + int var_index = it->second; + auto expr = node.get_expression(); + std::string expression = to_nmodl(expr); + + set_compartment_factor(var_index, expression); + } else { + logger->debug( + "KineticBlockVisitor :: COMPARTMENT specified volume for non-state variable {}", + var_name); + } +} + +void KineticBlockVisitor::compute_indexed_compartment_factor(ast::Compartment& node, + const ast::Name& name) { + auto array_var_name = name.get_node_name(); + auto index_name = node.get_name()->get_node_name(); + + auto pattern = fmt::format("^{}\\[([0-9]*)\\]$", array_var_name); + std::regex re(pattern); + std::smatch m; + + for (size_t var_index = 0; var_index < state_var.size(); ++var_index) { + auto matches = std::regex_match(state_var[var_index], m, re); + + if (matches) { + int index_value = std::stoi(m[1]); + auto volume_expr = node.get_expression(); + auto expr = std::shared_ptr(node.get_expression()->clone()); + IndexRemover(index_name, index_value).visit_expression(*expr); + + std::string expression = to_nmodl(*expr); + set_compartment_factor(var_index, expression); + } + } +} + void KineticBlockVisitor::visit_compartment(ast::Compartment& node) { // COMPARTMENT block has an expression, and a list of state vars it applies to. // For each state var, the rhs of the differential eq should be divided by the expression. // Here we store the expressions in the compartment_factors vector - auto expr = node.get_expression(); - std::string expression = to_nmodl(expr); - logger->debug("KineticBlockVisitor :: COMPARTMENT expr: {}", expression); + logger->debug("KineticBlockVisitor :: COMPARTMENT expr: {}", to_nmodl(node.get_expression())); for (const auto& name_ptr: node.get_names()) { - const auto& var_name = name_ptr->get_node_name(); - const auto it = state_var_index.find(var_name); - if (it != state_var_index.cend()) { - int var_index = it->second; - compartment_factors[var_index] = expression; - logger->debug( - "KineticBlockVisitor :: COMPARTMENT factor {} for state var {} (index {})", - expression, - var_name, - var_index); + if (node.get_name() == nullptr) { + compute_compartment_factor(node, *name_ptr); + } else { + compute_indexed_compartment_factor(node, *name_ptr); } } // add COMPARTMENT state to list of statements to remove @@ -226,7 +274,6 @@ void KineticBlockVisitor::visit_reaction_statement(ast::ReactionStatement& node) "KineticBlockVisitor :: LHS of \"<<\" reaction statement must be a single state " "var, but instead found {}: ignoring this statement", to_nmodl(lhs))); - return; } const auto& rhs = node.get_expression1(); std::string varname = to_nmodl(lhs); diff --git a/src/visitors/kinetic_block_visitor.hpp b/src/visitors/kinetic_block_visitor.hpp index 0f67260594..7c2fae5c4d 100644 --- a/src/visitors/kinetic_block_visitor.hpp +++ b/src/visitors/kinetic_block_visitor.hpp @@ -52,6 +52,10 @@ class KineticBlockVisitor: public AstVisitor { /// update CONSERVE statement with reaction var term void process_conserve_reac_var(const std::string& varname, int count = 1); + void set_compartment_factor(int var_index, const std::string& factor); + void compute_compartment_factor(ast::Compartment& node, const ast::Name& name); + void compute_indexed_compartment_factor(ast::Compartment& node, const ast::Name& name); + /// stochiometric matrices nu_L, nu_R /// forwards/backwards fluxes k_f, k_b /// (see kinetic_schemes.ipynb notebook for details) diff --git a/src/visitors/semantic_analysis_visitor.cpp b/src/visitors/semantic_analysis_visitor.cpp index ff83a36ead..ef46605945 100644 --- a/src/visitors/semantic_analysis_visitor.cpp +++ b/src/visitors/semantic_analysis_visitor.cpp @@ -97,7 +97,6 @@ void SemanticAnalysisVisitor::visit_name(const ast::Name& node) { // There are only two contexts where a random_var is allowed. As the first arg of a random // function or as an item in the RANDOM declaration. // Only the former needs checking. - bool ok = true; auto name = node.get_node_name(); // only check for variables exist in the symbol table (e.g. SUFFIX has type Name but it's not diff --git a/src/visitors/semantic_analysis_visitor.hpp b/src/visitors/semantic_analysis_visitor.hpp index 93c0958cef..bcf69f204c 100644 --- a/src/visitors/semantic_analysis_visitor.hpp +++ b/src/visitors/semantic_analysis_visitor.hpp @@ -12,6 +12,12 @@ * \brief \copybrief nmodl::visitor::SemanticAnalysisVisitor */ +#include "ast/ast.hpp" +#include "visitors/ast_visitor.hpp" + +namespace nmodl { +namespace visitor { + /** * \addtogroup visitor_classes * \{ @@ -19,7 +25,7 @@ /** * \class SemanticAnalysisVisitor - * \brief %Visitor to check some semantic rules on the ast + * \brief %Visitor to check some semantic rules on the AST * * Current checks: * @@ -34,11 +40,6 @@ * 8. Check that at most one derivative block is present. * 9. Check that RANDOM variable is mentioned only as first arg in random function. */ -#include "ast/ast.hpp" -#include "visitors/ast_visitor.hpp" - -namespace nmodl { -namespace visitor { class SemanticAnalysisVisitor: public ConstAstVisitor { private: diff --git a/test/unit/visitor/kinetic_block.cpp b/test/unit/visitor/kinetic_block.cpp index 7d52ae86bb..abcf1f89aa 100644 --- a/test/unit/visitor/kinetic_block.cpp +++ b/test/unit/visitor/kinetic_block.cpp @@ -239,6 +239,26 @@ SCENARIO("Convert KINETIC to DERIVATIVE using KineticBlock visitor", "[kinetic][ REQUIRE(result[0] == reindent_text(output_nmodl_text)); } } + GIVEN("KINETIC block with -> reaction statement, indexed COMPARTMENT") { + std::string input_nmodl_text = R"( + STATE { + x[2] + } + KINETIC states { + COMPARTMENT i, vol[i] { x } + ~ x[0] + x[1] -> (f(v)) + })"; + std::string output_nmodl_text = R"( + DERIVATIVE states { + x'[0] = ((-1*(f(v)*x[0]*x[1])))/(vol[0]) + x'[1] = ((-1*(f(v)*x[0]*x[1])))/(vol[1]) + })"; + THEN("Convert to equivalent DERIVATIVE block") { + auto result = run_kinetic_block_visitor(input_nmodl_text); + CAPTURE(input_nmodl_text); + REQUIRE(result[0] == reindent_text(output_nmodl_text)); + } + } GIVEN("KINETIC block with one reaction statement, 1 state var, 1 non-state var, flux vars") { // Here c is NOT a state variable // see 9.9.2.1 of NEURON book diff --git a/test/usecases/generate_references.sh b/test/usecases/generate_references.sh index ef21a838ea..5a41ef9661 100755 --- a/test/usecases/generate_references.sh +++ b/test/usecases/generate_references.sh @@ -8,21 +8,20 @@ if [[ $# -eq 3 ]] then output_dir="$3" else - script_dir="$(dirname "$(realpath "$0")")" + script_dir="$(cd "$(dirname "$0")"; pwd -P)" output_dir="${script_dir}/references/$(basename "$2")" fi function sanitize() { for f in "${1}"/*.cpp do - if [[ "$(uname)" == 'Darwin' ]] - then - sed_cmd="sed -i''" + if [[ "$(uname)" == 'Darwin' ]]; then + sed_cmd=("sed" "-i" "") else - sed_cmd="sed -i" + sed_cmd=("sed" "-i") fi - ${sed_cmd} "s/Created : .*$/Created : DATE/" "$f" - ${sed_cmd} "s/NMODL Compiler : .*$/NMODL Compiler : VERSION/" "$f" + "${sed_cmd[@]}" "s/Created : .*$/Created : DATE/" "$f" + "${sed_cmd[@]}" "s/NMODL Compiler : .*$/NMODL Compiler : VERSION/" "$f" done }