Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solve simple ODE. #1119

Merged
merged 15 commits into from
Dec 13, 2023
11 changes: 11 additions & 0 deletions .github/workflows/nmodl-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ jobs:
# Hyphens here will be replaced with commas before the value is
# passed to NMODL_SANITIZERS
sanitizer: address-leak
- config:
os: ubuntu-22.04
enable_usecases: On
- config:
flag_warnings: ON
os: ubuntu-22.04
Expand Down Expand Up @@ -82,6 +85,11 @@ jobs:
python3 -m pip install -U pip setuptools
python3 -m pip install --user -r requirements.txt
- name: Install neuron-nightly
if: ${{matrix.config.enable_usecases == 'On'}}
run: |
python3 -m pip install neuron-nightly
- name: Register compiler warning problem matcher
if: ${{matrix.config.flag_warnings == 'ON'}}
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
Expand All @@ -106,6 +114,9 @@ jobs:
-Wno-sign-compare \
-Wno-overloaded-virtual")
fi
if [[ -n "${{matrix.config.enable_usecases}}" ]]; then
cmake_args+=(-DNMODL_ENABLE_USECASES=${{matrix.config.enable_usecases}})
fi
if [[ -n "${{matrix.config.sanitizer}}" ]]; then
cmake_args+=(-DCMAKE_BUILD_TYPE=Custom \
-DCMAKE_CXX_FLAGS="-O1 -g" \
Expand Down
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
# =============================================================================
option(NMODL_ENABLE_PYTHON_BINDINGS "Enable pybind11 based python bindings" ON)
option(NMODL_ENABLE_TESTS "Enable build of tests" ON)
option(NMODL_ENABLE_USECASES
1uc marked this conversation as resolved.
Show resolved Hide resolved
"If building tests, additionally enable build of usecase tests. Requires neuron." OFF)
set(NMODL_EXTRA_CXX_FLAGS
""
CACHE STRING "Add extra compile flags for NMODL sources")
Expand Down Expand Up @@ -207,6 +209,10 @@ if(NOT NMODL_AS_SUBPROJECT AND NMODL_ENABLE_TESTS)
include(CTest)
add_subdirectory(test/unit)
add_subdirectory(test/integration)

if(NMODL_ENABLE_USECASES)
add_subdirectory(test/usecases)
endif()
endif()

# =============================================================================
Expand Down
200 changes: 166 additions & 34 deletions src/codegen/codegen_neuron_cpp_visitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,21 @@
/// TODO: Edit for NEURON
1uc marked this conversation as resolved.
Show resolved Hide resolved
std::string CodegenNeuronCppVisitor::float_variable_name(const SymbolType& symbol,
bool use_instance) const {
return symbol->get_name();
auto name = symbol->get_name();
auto dimension = symbol->get_length();
// auto position = position_of_float_var(name);
1uc marked this conversation as resolved.
Show resolved Hide resolved
if (symbol->is_array()) {
if (use_instance) {
return fmt::format("(inst.{}+id*{})", name, dimension);
}
throw std::runtime_error("Printing non-instance variables is not implemented.");

Check warning on line 209 in src/codegen/codegen_neuron_cpp_visitor.cpp

View check run for this annotation

Codecov / codecov/patch

src/codegen/codegen_neuron_cpp_visitor.cpp#L209

Added line #L209 was not covered by tests
// return fmt::format("(data + {}*pnodecount + id*{})", position, dimension);
1uc marked this conversation as resolved.
Show resolved Hide resolved
}
if (use_instance) {
return fmt::format("inst.{}[id]", name);
}
throw std::runtime_error("Not implemented.");

Check warning on line 215 in src/codegen/codegen_neuron_cpp_visitor.cpp

View check run for this annotation

Codecov / codecov/patch

src/codegen/codegen_neuron_cpp_visitor.cpp#L215

Added line #L215 was not covered by tests
1uc marked this conversation as resolved.
Show resolved Hide resolved
// return fmt::format("data[{}*pnodecount + id]", position);
1uc marked this conversation as resolved.
Show resolved Hide resolved
}


Expand All @@ -218,10 +232,70 @@
}


/// TODO: Edit for NEURON
std::string CodegenNeuronCppVisitor::get_variable_name(const std::string& name,
bool use_instance) const {
return name;
// const std::string& varname = update_if_ion_variable_name(name);
const std::string& varname = name;
1uc marked this conversation as resolved.
Show resolved Hide resolved

auto symbol_comparator = [&varname](const SymbolType& sym) {
return varname == sym->get_name();
};

auto index_comparator = [&varname](const IndexVariableInfo& var) {
return varname == var.symbol->get_name();
};

// float variable
auto f = std::find_if(codegen_float_variables.begin(),
codegen_float_variables.end(),
symbol_comparator);
if (f != codegen_float_variables.end()) {
return float_variable_name(*f, use_instance);
}

// integer variable
auto i =
std::find_if(codegen_int_variables.begin(), codegen_int_variables.end(), index_comparator);
if (i != codegen_int_variables.end()) {
return int_variable_name(*i, varname, use_instance);

Check warning on line 260 in src/codegen/codegen_neuron_cpp_visitor.cpp

View check run for this annotation

Codecov / codecov/patch

src/codegen/codegen_neuron_cpp_visitor.cpp#L260

Added line #L260 was not covered by tests
}

// global variable
auto g = std::find_if(codegen_global_variables.begin(),
codegen_global_variables.end(),
symbol_comparator);
if (g != codegen_global_variables.end()) {
return global_variable_name(*g, use_instance);

Check warning on line 268 in src/codegen/codegen_neuron_cpp_visitor.cpp

View check run for this annotation

Codecov / codecov/patch

src/codegen/codegen_neuron_cpp_visitor.cpp#L268

Added line #L268 was not covered by tests
}

if (varname == naming::NTHREAD_DT_VARIABLE) {
return std::string("_nt->_") + naming::NTHREAD_DT_VARIABLE;
}

// t in net_receive method is an argument to function and hence it should
// be used instead of nt->_t which is current time of thread
if (varname == naming::NTHREAD_T_VARIABLE && !printing_net_receive) {
return std::string("_nt->_") + naming::NTHREAD_T_VARIABLE;

Check warning on line 278 in src/codegen/codegen_neuron_cpp_visitor.cpp

View check run for this annotation

Codecov / codecov/patch

src/codegen/codegen_neuron_cpp_visitor.cpp#L277-L278

Added lines #L277 - L278 were not covered by tests
}

auto const iter =
std::find_if(info.neuron_global_variables.begin(),
info.neuron_global_variables.end(),
[&varname](auto const& entry) { return entry.first->get_name() == varname; });
if (iter != info.neuron_global_variables.end()) {
std::string ret;
if (use_instance) {
ret = "*(inst->";

Check warning on line 288 in src/codegen/codegen_neuron_cpp_visitor.cpp

View check run for this annotation

Codecov / codecov/patch

src/codegen/codegen_neuron_cpp_visitor.cpp#L284-L288

Added lines #L284 - L288 were not covered by tests
}
ret.append(varname);
if (use_instance) {
ret.append(")");

Check warning on line 292 in src/codegen/codegen_neuron_cpp_visitor.cpp

View check run for this annotation

Codecov / codecov/patch

src/codegen/codegen_neuron_cpp_visitor.cpp#L290-L292

Added lines #L290 - L292 were not covered by tests
}
return ret;

Check warning on line 294 in src/codegen/codegen_neuron_cpp_visitor.cpp

View check run for this annotation

Codecov / codecov/patch

src/codegen/codegen_neuron_cpp_visitor.cpp#L294

Added line #L294 was not covered by tests
}

// otherwise return original name
return varname;

Check warning on line 298 in src/codegen/codegen_neuron_cpp_visitor.cpp

View check run for this annotation

Codecov / codecov/patch

src/codegen/codegen_neuron_cpp_visitor.cpp#L298

Added line #L298 was not covered by tests
}


Expand Down Expand Up @@ -384,6 +458,23 @@
printer->add_line("};");
}

void CodegenNeuronCppVisitor::print_make_instance() const {
iomaganaris marked this conversation as resolved.
Show resolved Hide resolved
printer->add_newline(2);
printer->fmt_push_block("static {} make_instance_{}(_nrn_mechanism_cache_range& _ml)",
instance_struct(),
info.mod_suffix);
printer->fmt_push_block("return {}", instance_struct());

const auto codegen_float_variables_size = codegen_float_variables.size();
for (int i = 0; i < codegen_float_variables_size; ++i) {
const auto& float_var = codegen_float_variables[i];

Check warning on line 470 in src/codegen/codegen_neuron_cpp_visitor.cpp

View workflow job for this annotation

GitHub Actions / { "flag_warnings": "ON", "os": "ubuntu-22.04" }

unused variable ‘float_var’ [-Wunused-variable]

Check warning on line 470 in src/codegen/codegen_neuron_cpp_visitor.cpp

View workflow job for this annotation

GitHub Actions / { "flag_warnings": "ON", "os": "ubuntu-22.04", "sanitizer": "undefined" }

unused variable 'float_var' [-Wunused-variable]
printer->fmt_line("&_ml.template fpfield<{}>(0){}",
1uc marked this conversation as resolved.
Show resolved Hide resolved
i,
i < codegen_float_variables_size - 1 ? "," : "");
}
printer->pop_block(";");
printer->pop_block();
}

void CodegenNeuronCppVisitor::print_mechanism_register() {
/// TODO: Write this according to NEURON
Expand Down Expand Up @@ -443,48 +534,80 @@
}


void CodegenNeuronCppVisitor::print_mechanism_range_var_structure(
[[maybe_unused]] bool print_initializers) {
void CodegenNeuronCppVisitor::print_mechanism_range_var_structure(bool print_initializers) {
auto const value_initialize = print_initializers ? "{}" : "";
auto int_type = default_int_data_type();
printer->add_newline(2);
printer->add_line("/* NEURON RANGE variables macro definitions */");
for (auto i = 0; i < codegen_float_variables.size(); ++i) {
const auto float_var = codegen_float_variables[i];
if (float_var->is_array()) {
printer->add_line("#define ",
float_var->get_name(),
"(id) _ml->template data_array<",
std::to_string(i),
", ",
std::to_string(float_var->get_length()),
">(id)");
printer->add_line("/** all mechanism instance variables and global variables */");
printer->fmt_push_block("struct {} ", instance_struct());

for (auto const& [var, type]: info.neuron_global_variables) {
auto const name = var->get_name();
printer->fmt_line("{}* {}{};",

Check warning on line 546 in src/codegen/codegen_neuron_cpp_visitor.cpp

View check run for this annotation

Codecov / codecov/patch

src/codegen/codegen_neuron_cpp_visitor.cpp#L545-L546

Added lines #L545 - L546 were not covered by tests
type,
name,
print_initializers ? fmt::format("{{&coreneuron::{}}}", name)

Check warning on line 549 in src/codegen/codegen_neuron_cpp_visitor.cpp

View check run for this annotation

Codecov / codecov/patch

src/codegen/codegen_neuron_cpp_visitor.cpp#L549

Added line #L549 was not covered by tests
: std::string{});
}
for (auto& var: codegen_float_variables) {
const auto& name = var->get_name();
printer->fmt_line("double* {}{};", name, value_initialize);
}
for (auto& var: codegen_int_variables) {
const auto& name = var.symbol->get_name();
if (var.is_index || var.is_integer) {
auto qualifier = var.is_constant ? "const " : "";
printer->fmt_line("{}{}* {}{};", qualifier, int_type, name, value_initialize);

Check warning on line 560 in src/codegen/codegen_neuron_cpp_visitor.cpp

View check run for this annotation

Codecov / codecov/patch

src/codegen/codegen_neuron_cpp_visitor.cpp#L559-L560

Added lines #L559 - L560 were not covered by tests
} else {
printer->add_line("#define ",
float_var->get_name(),
"(id) _ml->template fpfield<",
std::to_string(i),
">(id)");
auto qualifier = var.is_constant ? "const " : "";
auto type = var.is_vdata ? "void*" : default_float_data_type();
printer->fmt_line("{}{}* {}{};", qualifier, type, name, value_initialize);
}
}

// printer->fmt_line("{}* {}{};",
// global_struct(),
// naming::INST_GLOBAL_MEMBER,
// print_initializers ? fmt::format("{{&{}}}", global_struct_instance())
// : std::string{});
1uc marked this conversation as resolved.
Show resolved Hide resolved
1uc marked this conversation as resolved.
Show resolved Hide resolved
printer->pop_block(";");
}


void CodegenNeuronCppVisitor::print_initial_block(const InitialBlock* node) {
// initial block
if (node != nullptr) {
const auto& block = node->get_statement_block();
print_statement_block(*block, false, false);
}
}


/// TODO: Edit for NEURON
void CodegenNeuronCppVisitor::print_global_function_common_code(BlockType type,
const std::string& function_name) {
return;
std::string method = function_name.empty() ? compute_method_name(type) : function_name;
std::string args =
"_nrn_model_sorted_token const& _sorted_token, NrnThread* _nt, Memb_list* _ml_arg, int "
"_type";
printer->fmt_push_block("void {}({})", method, args);

printer->add_line("_nrn_mechanism_cache_range _lmr{_sorted_token, *_nt, *_ml_arg, _type};");
printer->fmt_line("auto inst = make_instance_{}(_lmr);", info.mod_suffix);
printer->add_line("auto nodecount = _ml_arg->nodecount;");
}


void CodegenNeuronCppVisitor::print_nrn_init(bool skip_init_check) {
printer->add_newline(2);
printer->add_line("/** initialize channel */");

printer->fmt_line(
"static void {}(_nrn_model_sorted_token const& _sorted_token, NrnThread* _nt, Memb_list* "
"_ml_arg, int _type) {{}}",
method_name(naming::NRN_INIT_METHOD));
}
print_global_function_common_code(BlockType::Initial);

printer->push_block("for (int id = 0; id < nodecount; id++)");
print_initial_block(info.initial_node);
printer->pop_block();

printer->pop_block();
}

void CodegenNeuronCppVisitor::print_nrn_jacob() {
printer->add_newline(2);
Expand Down Expand Up @@ -531,13 +654,21 @@
}

printer->add_newline(2);
print_global_function_common_code(BlockType::State);

printer->fmt_line(
"void {}(_nrn_model_sorted_token const& _sorted_token, NrnThread* _nt, Memb_list* "
"_ml_arg, int _type) {{}}",
method_name(naming::NRN_STATE_METHOD));
printer->push_block("for (int id = 0; id < nodecount; id++)");

/// TODO: Fill in
if (info.nrn_state_block) {
info.nrn_state_block->visit_children(*this);
}

if (info.currents.empty() && info.breakpoint_node != nullptr) {
auto block = info.breakpoint_node->get_statement_block();
print_statement_block(*block, false, false);

Check warning on line 667 in src/codegen/codegen_neuron_cpp_visitor.cpp

View check run for this annotation

Codecov / codecov/patch

src/codegen/codegen_neuron_cpp_visitor.cpp#L666-L667

Added lines #L666 - L667 were not covered by tests
}

printer->pop_block();
printer->pop_block();
}


Expand Down Expand Up @@ -668,6 +799,7 @@
void CodegenNeuronCppVisitor::print_data_structures(bool print_initializers) {
print_mechanism_global_var_structure(print_initializers);
print_mechanism_range_var_structure(print_initializers);
print_make_instance();
}


Expand Down
13 changes: 12 additions & 1 deletion src/codegen/codegen_neuron_cpp_visitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@
#include <string_view>
#include <utility>

#include "codegen/codegen_cpp_visitor.hpp"
#include "codegen/codegen_info.hpp"
#include "codegen/codegen_naming.hpp"
#include "printer/code_printer.hpp"
#include "symtab/symbol_table.hpp"
#include "utils/logger.hpp"
#include "visitors/ast_visitor.hpp"
#include <codegen/codegen_cpp_visitor.hpp>


/// encapsulates code generation backend implementations
Expand Down Expand Up @@ -83,6 +83,12 @@ class CodegenNeuronCppVisitor: public CodegenCppVisitor {
*/
virtual std::string backend_name() const override;

/**
* Name of structure that wraps range variables
*/
std::string instance_struct() const {
return fmt::format("{}_Instance", info.mod_suffix);
}

/****************************************************************************************/
/* Common helper routines accross codegen functions */
Expand Down Expand Up @@ -381,6 +387,8 @@ class CodegenNeuronCppVisitor: public CodegenCppVisitor {
*/
void print_nrn_init(bool skip_init_check = true);

/** Print the initial block. */
void print_initial_block(const ast::InitialBlock* node);

/**
* Print nrn_constructor function definition
Expand Down Expand Up @@ -527,6 +535,9 @@ class CodegenNeuronCppVisitor: public CodegenCppVisitor {
*/
void print_data_structures(bool print_initializers) override;

/** Print `make_*_instance`.
*/
void print_make_instance() const;

/**
* Set v_unused (voltage) for NRN_PRCELLSTATE feature
Expand Down
Loading
Loading