20 #include "utils/logger.hpp"
34 const std::shared_ptr<const ast::Ast>& procedure_node) {
35 const auto& solve_block = std::dynamic_pointer_cast<const ast::SolveBlock>(solve_node);
36 const auto& method = solve_block->get_method();
40 const auto& method_name = method->get_node_name();
42 return procedure_node->get_node_name() == solve_block->get_block_name()->get_node_name() &&
70 std::sort(symbols.begin(),
73 return first->get_id() > second->get_id();
77 std::sort(symbols.begin(),
80 return first->get_name()[0] < second->get_name()[0];
94 std::vector<std::string> ion_vars;
95 std::vector<std::string> read_ion_vars;
96 std::vector<std::string> write_ion_vars;
97 std::map<std::string, double> valences;
99 for (
const auto& ion_node: ion_nodes) {
100 const auto& ion = std::dynamic_pointer_cast<const ast::Useion>(ion_node);
101 auto ion_name = ion->get_node_name();
102 ion_vars.push_back(ion_name);
103 for (
const auto&
var: ion->get_readlist()) {
104 read_ion_vars.push_back(
var->get_node_name());
106 for (
const auto&
var: ion->get_writelist()) {
107 write_ion_vars.push_back(
var->get_node_name());
110 if (ion->get_valence() !=
nullptr) {
111 valences[ion_name] = ion->get_valence()->get_value()->to_double();
120 auto ion_variable = [](
const std::string&
var,
const std::string& ion) ->
bool {
121 auto len =
var.size() - 1;
122 return (
var.substr(1, len) == ion ||
var.substr(0, len) == ion);
126 for (
auto& ion_name: ion_vars) {
128 for (
auto& read_var: read_ion_vars) {
129 if (ion_variable(read_var, ion_name)) {
130 ion.
reads.push_back(read_var);
133 for (
auto& write_var: write_ion_vars) {
134 if (ion_variable(write_var, ion_name)) {
135 ion.
writes.push_back(write_var);
138 info.write_concentration =
true;
142 if (
auto it = valences.find(ion_name); it != valences.end()) {
150 auto vars = psymtab->get_variables_with_properties(NmodlType::nonspecific_cur_var);
151 for (
auto&
var: vars) {
152 info.currents.push_back(
var->get_name());
154 vars = psymtab->get_variables_with_properties(NmodlType::electrode_cur_var);
155 for (
auto&
var: vars) {
156 info.currents.push_back(
var->get_name());
158 for (
auto& ion:
info.ions) {
159 for (
auto&
var: ion.writes) {
160 if (ion.is_ionic_current(
var)) {
167 for (
const auto& ion:
info.ions) {
168 for (
const auto&
var: ion.writes) {
169 if (!ion.is_ionic_current(
var) && !ion.is_rev_potential(
var)) {
170 info.require_wrote_conc =
true;
187 const auto& breakpoint_nodes =
collect_nodes(
node, {AstNodeType::BREAKPOINT_BLOCK});
190 if (breakpoint_nodes.empty()) {
195 assert(breakpoint_nodes.size() == 1);
197 const auto& breakpoint_node = std::dynamic_pointer_cast<const ast::BreakpointBlock>(
198 breakpoint_nodes[0]);
201 const auto& kinetic_or_derivative_nodes =
202 collect_nodes(
node, {AstNodeType::KINETIC_BLOCK, AstNodeType::DERIVATIVE_BLOCK});
205 const auto& procedure_nodes =
collect_nodes(
node, {AstNodeType::PROCEDURE_BLOCK});
208 const auto& solve_nodes =
collect_nodes(*breakpoint_node, {AstNodeType::SOLVE_BLOCK});
213 solve_nodes.begin(), solve_nodes.end(), [&procedure_nodes](
const auto& solve_node) {
214 return std::any_of(procedure_nodes.begin(),
215 procedure_nodes.end(),
216 [&solve_node](const auto& procedure_node) {
217 return check_procedure_has_cvode(solve_node, procedure_node);
224 if (solve_nodes.size() == 1 && (kinetic_or_derivative_nodes.size() ||
using_cvode)) {
225 logger->debug(
"Will emit code for CVODE");
226 info.emit_cvode = enable_cvode;
251 std::string variables;
254 for (
auto&
var: vars) {
256 var->mark_thread_safe();
259 variables +=
" " +
var->get_name();
273 auto with = NmodlType::param_assign;
274 auto without = NmodlType::range_var
275 | NmodlType::assigned_definition
276 | NmodlType::global_var
277 | NmodlType::pointer_var
278 | NmodlType::bbcore_pointer_var
279 | NmodlType::read_ion_var
280 | NmodlType::write_ion_var;
283 for (
auto&
var: vars) {
287 var->has_any_property(NmodlType::extern_neuron_variable)) {
294 var->mark_thread_safe();
346 for (
auto& variable: primes) {
351 auto properties = NmodlType::pointer_var | NmodlType::bbcore_pointer_var;
355 properties = NmodlType::random_var;
359 properties = NmodlType::assigned_definition | NmodlType::param_assign;
361 for (
auto&
var: vars) {
426 return first->get_definition_order() < second->get_definition_order();
431 vars.erase(std::remove_if(vars.begin(),
442 secondary.erase(std::remove_if(secondary.begin(),
445 return std::find_if(primary.begin(),
450 return tosearch->get_name() ==
461 auto with = NmodlType::range_var
462 | NmodlType::param_assign;
463 auto without = NmodlType::global_var
464 | NmodlType::pointer_var
465 | NmodlType::bbcore_pointer_var
466 | NmodlType::state_var;
477 with = NmodlType::range_var
478 | NmodlType::assigned_definition;
479 without = NmodlType::global_var
480 | NmodlType::pointer_var
481 | NmodlType::bbcore_pointer_var
482 | NmodlType::state_var
483 | NmodlType::param_assign;
498 with = NmodlType::state_var;
499 without = NmodlType::global_var
500 | NmodlType::pointer_var
501 | NmodlType::bbcore_pointer_var;
514 with = NmodlType::assigned_definition
515 | NmodlType::read_ion_var
516 | NmodlType::write_ion_var;
517 without = NmodlType::global_var
518 | NmodlType::pointer_var
519 | NmodlType::bbcore_pointer_var
520 | NmodlType::extern_neuron_variable;
523 for (
const auto& variable: variables) {
524 if (!variable->has_any_property(without)) {
541 auto property = NmodlType::table_statement_var;
543 property = NmodlType::table_assigned_var;
549 using pair = std::pair<const char*, const char*>;
551 pair{
"secondorder",
"int"},
552 pair{
"pi",
"double"}}) {
554 if (sym && (sym->get_read_count() || sym->get_write_count())) {
562 const auto&
type =
node.get_type()->get_node_name();
584 node.visit_children(*
this);
590 node.visit_children(*
this);
596 node.visit_children(*
this);
604 node.visit_children(*
this);
611 node.visit_children(*
this);
623 node.visit_children(*
this);
630 node.visit_children(*
this);
635 node.visit_children(*
this);
641 node.visit_children(*
this);
651 node.visit_children(*
this);
670 const auto new_unique_functor_name =
"functor_" +
info.
mod_suffix +
"_" +
674 node.visit_children(*
this);
680 node.visit_children(*
this);
695 const auto& ion =
node.get_ion();
696 const auto& variable =
node.get_conductance();
697 std::string ion_name;
699 ion_name = ion->get_node_name();
727 const auto& statements =
node.get_statements();
728 for (
auto& statement: statements) {
729 statement->accept(*
this);
734 if (symbol !=
nullptr) {
735 auto is_prime = symbol->has_any_property(NmodlType::prime_name);
736 auto from_state = symbol->has_any_status(Status::from_state);
737 if (is_prime || from_state) {
744 [&](
auto const& sym) {
745 return sym->get_name() == symbol->get_name();
763 if (
node.get_op().eval() ==
"=") {
766 node.get_lhs()->accept(*
this);
767 node.get_rhs()->accept(*
this);
787 node.visit_children(*
this);
804 auto blocks =
node.get_blocks();
805 for (
auto& block: blocks) {
807 if (block->is_verbatim()) {
811 node.visit_children(*
this);
844 const auto&
text =
node.get_statement()->eval();
848 const auto& tokens =
driver.all_tokens();
851 for (
auto& token: tokens) {
853 if (symbol !=
nullptr) {
869 const std::string& var_name) {
870 const auto& compartment_block =
node.get_compartment_statements();
871 for (
const auto& stmt: compartment_block->get_statements()) {
872 auto comp = std::dynamic_pointer_cast<ast::Compartment>(stmt);
874 auto species = comp->get_species();
875 auto it = std::find_if(species.begin(), species.end(), [&var_name](
auto var) {
876 return var->get_node_name() == var_name;
879 if (it != species.end()) {
889 auto longitudinal_diffusion_block =
node.get_longitudinal_diffusion_statements();
890 for (
auto stmt: longitudinal_diffusion_block->get_statements()) {
891 auto diffusion = std::dynamic_pointer_cast<ast::LonDiffuse>(stmt);
892 auto rate_index_name =
diffusion->get_index_name();
896 auto process_compartment = [](
const std::shared_ptr<ast::Compartment>& compartment)
897 -> std::pair<std::shared_ptr<ast::Name>, std::shared_ptr<ast::Expression>> {
898 std::shared_ptr<ast::Expression> volume_expr;
899 std::shared_ptr<ast::Name> volume_index_name;
901 volume_index_name =
nullptr;
902 volume_expr = std::make_shared<ast::Double>(
"1.0");
904 volume_index_name = compartment->get_index_name();
905 volume_expr = std::shared_ptr<ast::Expression>(compartment->get_volume()->clone());
910 for (
auto var: species) {
911 std::string state_name =
var->get_value()->get_value();
913 auto [volume_index_name, volume_expr] = process_compartment(compartment);
918 std::shared_ptr<ast::Expression>(volume_expr),
920 std::shared_ptr<ast::Expression>(rate_expr->clone()))});
Auto generated AST classes declaration.
Represents a AFTER block in NMODL.
Represents BBCOREPOINTER statement in NMODL.
Represents a BEFORE block in NMODL.
Represents binary expression in the NMODL.
Represents a BREAKPOINT block in NMODL.
Represents CONDUCTANCE statement in NMODL.
Represents a CONSTRUCTOR block in the NMODL.
Represents a block used for variable timestep integration (CVODE) of DERIVATIVE blocks.
Represents DERIVATIVE block in the NMODL.
Represent a callback to NEURON's derivimplicit solver.
Represents a DESTRUCTOR block in the NMODL.
Represent linear solver solution block based on Eigen.
Represent newton solver solution block based on Eigen.
Represents ELECTRODE_CURRENT variables statement in NMODL.
Represents a INITIAL block in the NMODL.
Represents LINEAR block in the NMODL.
Extracts information required for LONGITUDINAL_DIFFUSION for each KINETIC block.
Represents NONLINEAR block in the NMODL.
Represents the coreneuron nrn_state callback function.
Represents top level AST node for whole NMODL input.
Represents block encapsulating list of statements.
Represents SUFFIX statement in NMODL.
Represents TABLE statement in NMODL.
Represents THREADSAFE statement in NMODL.
Statement to indicate a change in timestep in a given block.
Represents a C code block.
Represent WATCH statement in NMODL.
static void sort_with_mod2c_symbol_order(std::vector< SymbolType > &symbols)
How symbols are stored in NEURON? See notes written in markdown file.
void visit_derivimplicit_callback(const ast::DerivimplicitCallback &node) override
visit node of type ast::DerivimplicitCallback
void visit_derivative_block(const ast::DerivativeBlock &node) override
visit node of type ast::DerivativeBlock
void check_cvode_codegen(const ast::Program &node)
Find whether or not we need to emit CVODE-related code for NEURON Notes: we generate CVODE-related co...
void visit_non_linear_block(const ast::NonLinearBlock &node) override
visit node of type ast::NonLinearBlock
void visit_breakpoint_block(const ast::BreakpointBlock &node) override
visit node of type ast::BreakpointBlock
void visit_thread_safe(const ast::ThreadSafe &) override
visit node of type ast::ThreadSafe
bool table_statement_used
table statement found
void visit_before_block(const ast::BeforeBlock &node) override
visit node of type ast::BeforeBlock
void visit_update_dt(const ast::UpdateDt &node) override
visit node of type ast::UpdateDt
void visit_discrete_block(const ast::DiscreteBlock &node) override
visit node of type ast::DiscreteBlock
void visit_nrn_state_block(const ast::NrnStateBlock &node) override
visit node of type ast::NrnStateBlock
void visit_function_table_block(const ast::FunctionTableBlock &node) override
visit node of type ast::FunctionTableBlock
void visit_function_call(const ast::FunctionCall &node) override
visit node of type ast::FunctionCall
bool under_derivative_block
if visiting derivative block
void visit_linear_block(const ast::LinearBlock &node) override
visit node of type ast::LinearBlock
void visit_longitudinal_diffusion_block(const ast::LongitudinalDiffusionBlock &node) override
visit node of type ast::LongitudinalDiffusionBlock
void visit_eigen_linear_solver_block(const ast::EigenLinearSolverBlock &node) override
visit node of type ast::EigenLinearSolverBlock
void visit_conductance_hint(const ast::ConductanceHint &node) override
visit node of type ast::ConductanceHint
void find_table_variables()
bool under_breakpoint_block
if visiting breakpoint block
void visit_after_block(const ast::AfterBlock &node) override
visit node of type ast::AfterBlock
std::shared_ptr< ast::Expression > assign_lhs
lhs of assignment in derivative block
void find_neuron_global_variables()
void find_ion_variables(const ast::Program &node)
Find all ions used in mod file.
void visit_table_statement(const ast::TableStatement &node) override
visit node of type ast::TableStatement
void visit_suffix(const ast::Suffix &node) override
visit node of type ast::Suffix
void visit_verbatim(const ast::Verbatim &node) override
visit verbatim block and find all symbols used
void visit_constructor_block(const ast::ConstructorBlock &node) override
visit node of type ast::ConstructorBlock
void visit_eigen_newton_solver_block(const ast::EigenNewtonSolverBlock &node) override
visit node of type ast::EigenNewtonSolverBlock
codegen::CodegenInfo analyze(const ast::Program &node)
run visitor and return information for code generation
void visit_electrode_current(const ast::ElectrodeCurrent &node) override
visit node of type ast::ElectrodeCurrent
void visit_factor_def(const ast::FactorDef &node) override
visit node of type ast::FactorDef
void visit_statement_block(const ast::StatementBlock &node) override
Visit statement block and find prime symbols appear in derivative block.
void visit_net_receive_block(const ast::NetReceiveBlock &node) override
visit node of type ast::NetReceiveBlock
std::shared_ptr< symtab::Symbol > SymbolType
void visit_watch_statement(const ast::WatchStatement &node) override
visit node of type ast::WatchStatement
std::vector< std::shared_ptr< symtab::Symbol > > SymbolVectorType
void find_range_variables()
Find range variables i.e.
void visit_watch(const ast::Watch &node) override
visit node of type ast::Watch
symtab::SymbolTable * psymtab
symbol table for the program
void visit_program(const ast::Program &node) override
visit node of type ast::Program
codegen::CodegenInfo info
holds all codegen related information
void visit_function_block(const ast::FunctionBlock &node) override
visit node of type ast::FunctionBlock
void find_non_range_variables()
Find non-range variables i.e.
void visit_binary_expression(const ast::BinaryExpression &node) override
visit node of type ast::BinaryExpression
void visit_for_netcon(const ast::ForNetcon &node) override
visit node of type ast::ForNetcon
void visit_procedure_block(const ast::ProcedureBlock &node) override
visit node of type ast::ProcedureBlock
bool under_net_receive_block
if visiting net receive block
void visit_bbcore_pointer(const ast::BbcorePointer &node) override
visit node of type ast::BbcorePointer
void visit_initial_block(const ast::InitialBlock &node) override
visit node of type ast::InitialBlock
void visit_destructor_block(const ast::DestructorBlock &node) override
visit node of type ast::DestructorBlock
void visit_cvode_block(const ast::CvodeBlock &node) override
visit node of type ast::CvodeBlock
Information required to print LONGITUDINAL_DIFFUSION callbacks.
Class that binds all pieces together for parsing C verbatim blocks.
std::vector< std::shared_ptr< Symbol > > get_variables(syminfo::NmodlType with=syminfo::NmodlType::empty, syminfo::NmodlType without=syminfo::NmodlType::empty) const
get variables
std::vector< std::shared_ptr< Symbol > > get_variables_with_properties(syminfo::NmodlType properties, bool all=false) const
get variables with properties
std::shared_ptr< Symbol > lookup(const std::string &name) const
check if symbol with given name exist in the current table (but not in parents)
Helper visitor to gather AST information to help code generation.
Auto generated AST classes declaration.
double var(InputIterator begin, InputIterator end)
void move(Item *q1, Item *q2, Item *q3)
static constexpr char AREA_VARIABLE[]
similar to node_area but user can explicitly declare it as area
static constexpr char POINT_PROCESS[]
point process keyword in nmodl
static constexpr char NET_EVENT_METHOD[]
net_event function call in nmodl
static constexpr char DIAM_VARIABLE[]
inbuilt neuron variable for diameter of the compartment
static constexpr char ARTIFICIAL_CELL[]
artificial cell keyword in nmodl
static constexpr char CVODE_T_METHOD[]
cvode_t method in nmodl
static constexpr char NET_SEND_METHOD[]
net_send function call in nmodl
static constexpr char CELSIUS_VARIABLE[]
global temperature variable
static constexpr char CVODE_T_V_METHOD[]
cvode_t_v method in nmodl
static constexpr char AFTER_CVODE_METHOD[]
cvode method in nmodl
static bool check_procedure_has_cvode(const std::shared_ptr< const ast::Ast > &solve_node, const std::shared_ptr< const ast::Ast > &procedure_node)
Check whether a given SOLVE block solves a PROCEDURE with any of the CVode methods.
static std::shared_ptr< ast::Compartment > find_compartment(const ast::LongitudinalDiffusionBlock &node, const std::string &var_name)
Status
state during various compiler passes
std::string to_string(const T &obj)
NmodlType
NMODL variable properties.
encapsulates code generation backend implementations
std::vector< std::shared_ptr< const ast::Ast > > collect_nodes(const ast::Ast &node, const std::vector< ast::AstNodeType > &types)
traverse node recursively and collect nodes of given types
static Node * node(Object *)
Represent information collected from AST for code generation.
int thread_var_data_size
sum of length of thread promoted variables
std::vector< SymbolType > range_assigned_vars
range variables which are assigned variables as well
std::vector< std::pair< SymbolType, std::string > > neuron_global_variables
[Core]NEURON global variables used (e.g. celsius) and their types
bool bbcore_pointer_used
if bbcore pointer is used
std::vector< const ast::FactorDef * > factor_definitions
all factors defined in the mod file
std::vector< SymbolType > assigned_vars
remaining assigned variables
const ast::CvodeBlock * cvode_block
the CVODE block
std::vector< SymbolType > range_state_vars
state variables excluding such useion read/write variables that are not ionic currents.
bool is_ion_variable(const std::string &name) const noexcept
if either read or write variable
int num_equations
number of equations (i.e.
bool artificial_cell
if mod file is artificial cell
std::vector< const ast::FunctionTableBlock * > function_tables
all functions tables defined in the mod file
std::vector< SymbolType > pointer_variables
pointer or bbcore pointer variables
bool point_process
if mod file is point process
bool electrode_current
if electrode current specified
std::vector< ast::Node * > top_blocks
all top level global blocks
bool diam_used
if diam is used
std::unordered_map< const ast::EigenNewtonSolverBlock *, std::string > functor_names
unique functor names for all the EigenNewtonSolverBlock s
std::vector< SymbolType > global_variables
global variables
int thread_data_index
thread_data_index indicates number of threads being allocated.
bool vectorize
true if mod file is vectorizable (which should be always true for coreneuron) But there are some bloc...
bool net_event_used
if net_event function is used
const ast::BreakpointBlock * breakpoint_node
derivative block
bool net_send_used
if net_send function is used
std::vector< const ast::WatchStatement * > watch_statements
all watch statements
bool declared_thread_safe
A mod file can be declared to be thread safe using the keyword THREADSAFE.
bool thread_callback_register
if thread thread call back routines need to register
int num_primes
number of primes (all state variables not necessary to be prime)
const ast::DestructorBlock * destructor_node
destructor block only for point process
std::vector< SymbolType > external_variables
external variables
std::vector< const ast::ProcedureBlock * > procedures
all procedures defined in the mod file
const ast::NrnStateBlock * nrn_state_block
nrn_state block
const ast::InitialBlock * net_receive_initial_node
initial block within net receive block
std::vector< SymbolType > thread_variables
thread variables (e.g. global variables promoted to thread)
bool eigen_newton_solver_exist
true if eigen newton solver is used
std::vector< SymbolType > constant_variables
constant variables
std::vector< ast::Node * > top_verbatim_blocks
all top level verbatim blocks
int num_net_receive_parameters
number of arguments to net_receive block
std::vector< const ast::DerivimplicitCallback * > derivimplicit_callbacks
derivimplicit callbacks need to be emited
bool is_ionic_current(const std::string &name) const noexcept
if given variable is a ionic current
std::vector< const ast::Block * > before_after_blocks
all before after blocks
bool derivimplicit_used() const
if legacy derivimplicit solver from coreneuron to be used
int table_count
number of table statements
std::vector< SymbolType > table_statement_variables
table variables
std::vector< const ast::Block * > functions_with_table
function or procedures with table statement
std::vector< SymbolType > random_variables
RANDOM variables.
std::vector< SymbolType > top_local_variables
local variables in the global scope
const ast::NetReceiveBlock * net_receive_node
net receive block for point process
std::vector< SymbolType > range_parameter_vars
range variables which are parameter as well
std::vector< const ast::FunctionBlock * > functions
all functions defined in the mod file
int top_local_thread_id
Top local variables are those local variables that appear in global scope.
int derivimplicit_var_thread_id
thread id for derivimplicit variables
bool eigen_linear_solver_exist
true if eigen linear solver is used
int thread_var_thread_id
thread id for thread promoted variables
int primes_size
sum of length of all prime variables
std::map< std::string, LongitudinalDiffusionInfo > longitudinal_diffusion_info
for each state, the information needed to print the callbacks.
int watch_count
number of watch expressions
std::vector< Conductance > conductances
represent conductance statements used in mod file
std::vector< SymbolType > prime_variables_by_order
this is the order in which they appear in derivative block this is required while printing them in in...
bool area_used
if area is used
std::string mod_suffix
name of the suffix
std::string changed_dt
updated dt to use with steadystate solver (in initial block) empty string means no change in dt
int derivimplicit_list_num
slist/dlist id for derivimplicit block
bool for_netcon_used
if for_netcon is used
const ast::ConstructorBlock * constructor_node
constructor block
std::vector< SymbolType > state_vars
all state variables
std::unordered_set< std::string > variables_in_verbatim
all variables/symbols used in the verbatim block
std::vector< SymbolType > table_assigned_variables
const ast::InitialBlock * initial_node
initial block
int top_local_thread_size
total length of all top local variables
Represent ions used in mod file.
bool need_style
if style semantic needed
bool is_intra_cell_conc(const std::string &text) const
Check if variable name is internal cell concentration.
std::optional< double > valence
ion valence
bool is_extra_cell_conc(const std::string &text) const
Check if variable name is external cell concentration.
std::vector< std::string > reads
ion variables that are being read
std::vector< std::string > writes
ion variables that are being written
nmodl::parser::UnitDriver driver
Utility functions for visitors implementation.