15 #include "utils/logger.hpp"
36 logger->debug(
"KineticBlockVisitor :: adding non-state fflux[{}] \"{}\"",
41 logger->debug(
"KineticBlockVisitor :: adding non-state bflux[{}] \"{}\"",
49 int i_statevar = it->second;
53 logger->debug(
"KineticBlockVisitor :: nu_L[{}][{}] += {}",
60 logger->debug(
"KineticBlockVisitor :: nu_R[{}][{}] += {}",
81 if (compartment_factor.empty()) {
93 "KineticBlockVisitor :: Error : CONSERVE statement should only contain state vars "
94 "on LHS, but found {}",
101 std::shared_ptr<ast::Expression>
create_expr(
const std::string& str_expr) {
103 auto expr = std::dynamic_pointer_cast<ast::ExpressionStatement>(statement)->get_expression();
104 return std::dynamic_pointer_cast<ast::BinaryExpression>(expr)->get_rhs();
122 node.visit_children(*
this);
140 auto expr = std::dynamic_pointer_cast<ast::Conserve>(statement);
142 node.set_react(expr->get_react());
144 node.set_expr(expr->get_expr());
151 throw std::runtime_error(
"Setting compartment volume twice.");
155 logger->debug(
"KineticBlockVisitor :: COMPARTMENT factor {} for state var {} (index {})",
163 const auto& var_name =
name.get_node_name();
166 int var_index = it->second;
167 auto expr =
node.get_volume();
168 std::string expression =
to_nmodl(expr);
173 "KineticBlockVisitor :: COMPARTMENT specified volume for non-state variable {}",
180 auto array_var_name =
name.get_node_name();
181 auto index_name =
node.get_index_name()->get_node_name();
183 auto pattern = fmt::format(
"^{}\\[([0-9]*)\\]$", array_var_name);
184 std::regex re(pattern);
187 for (
size_t var_index = 0; var_index <
state_var.size(); ++var_index) {
188 auto matches = std::regex_match(
state_var[var_index], m, re);
191 int index_value = std::stoi(m[1]);
192 auto volume_expr =
node.get_volume();
193 auto expr = std::shared_ptr<ast::Expression>(volume_expr->clone());
196 std::string expression =
to_nmodl(*expr);
206 logger->debug(
"KineticBlockVisitor :: COMPARTMENT expr: {}",
to_nmodl(
node.get_volume()));
207 for (
const auto& name_ptr:
node.get_species()) {
208 if (
node.get_index_name() ==
nullptr) {
220 auto reaction_op =
node.get_value();
235 int count =
node.get_value() ?
node.get_value()->eval() : 1;
254 auto reaction_op =
node.get_op().get_value();
264 const auto& lhs =
node.get_reaction1();
267 bool single_state_var =
true;
268 if (lhs->is_react_var_name()) {
269 auto value = std::dynamic_pointer_cast<ast::ReactVarName>(lhs)->get_value();
271 single_state_var =
false;
274 if (!lhs->is_react_var_name() || !single_state_var) {
275 throw std::runtime_error(fmt::format(
276 "KineticBlockVisitor :: LHS of \"<<\" reaction statement must be a single state "
277 "var, but instead found {}: ignoring this statement",
280 const auto&
rhs =
node.get_expression1();
281 std::string varname =
to_nmodl(lhs);
285 int var_index = it->second;
292 logger->debug(
"KineticBlockVisitor :: '<<' reaction statement: {}' += {}",
300 const auto& kf =
node.get_expression1();
302 const auto& kb =
node.get_expression2();
330 node.visit_children(*
this);
339 std::string multiply_var = std::string(
"*").append(
state_var[
j]);
379 if (
node.get_expression()->is_name()) {
380 auto var_name = std::dynamic_pointer_cast<ast::Name>(
node.get_expression());
381 if (var_name->get_node_name() ==
"f_flux") {
383 logger->debug(
"KineticBlockVisitor :: replacing f_flux with {}",
to_nmodl(expr));
385 }
else if (var_name->get_node_name() ==
"b_flux") {
387 logger->debug(
"KineticBlockVisitor :: replacing b_flux with {}",
to_nmodl(expr));
391 node.visit_children(*
this);
397 node.visit_children(*
this);
420 node.visit_children(*
this);
429 for (
int j = 0;
j < Nj; ++
j) {
432 for (
int i = 0;
i < Ni; ++
i) {
436 if (!ode_rhs.empty()) {
440 ode_rhs += fmt::format(
"({}*({}))", delta_nu,
fflux[
i]);
441 }
else if (
fflux[
i].empty()) {
442 ode_rhs += fmt::format(
"({}*(-{}))", delta_nu,
bflux[
i]);
444 ode_rhs += fmt::format(
"({}*({}-{}))", delta_nu,
fflux[
i],
bflux[
i]);
453 if (!ode_rhs.empty()) {
455 std::string var_str = state_var_split[0];
456 std::string index_str;
457 if (state_var_split.size() > 1) {
458 index_str =
"[" + state_var_split[1];
460 odes.push_back(fmt::format(
"{}'{} = {}", var_str, index_str, ode_rhs));
465 logger->debug(
"KineticBlockVisitor :: ode : {}",
ode);
468 const auto& kinetic_statement_block =
node.get_statement_block();
473 logger->debug(
"KineticBlockVisitor :: -> adding statement: {}",
ode);
487 std::string unmangled_name = fmt::format(
"{}{}_", stem,
n_equations);
488 std::string mangled_name = unmangled_name;
490 size_t mangle_attempt = 0;
492 mangled_name = fmt::format(
"{}{:04d}", unmangled_name, mangle_attempt++);
494 if (mangle_attempt >= 10000) {
495 throw std::runtime_error(
"Failed to find unique local name.");
499 auto name = std::make_shared<ast::Name>(std::make_shared<ast::String>(mangled_name));
554 const std::shared_ptr<ast::Name>&
name,
555 const std::shared_ptr<ast::Expression>& expression) {
556 auto local = std::make_shared<ast::BinaryExpression>(
name,
559 return std::make_shared<ast::ExpressionStatement>(local);
562 template <
class Node>
564 return std::shared_ptr<Node>(
node.clone());
569 auto stmt_block =
node.get_statement_block();
573 node.visit_children(*
this);
579 for (
const auto& local: locals) {
587 node.visit_children(*
this);
590 const auto& statements =
node.get_statements();
591 for (
auto iter = statements.begin(); iter != statements.end(); ++iter) {
592 if ((*iter)->is_reaction_statement()) {
593 auto reaction_equation = std::dynamic_pointer_cast<ast::ReactionStatement>(*iter);
594 auto op = reaction_equation->get_op();
598 auto local_expr1 = reaction_equation->get_expression1();
599 auto local_expr2 = reaction_equation->get_expression2();
601 std::shared_ptr<ast::Name> expr1_name =
nullptr;
602 std::shared_ptr<ast::Name> expr2_name =
nullptr;
614 reaction_equation->get_expression1());
615 localized_statements.push_back(assignment);
616 local_expr1 =
clone(*expr1_name);
621 reaction_equation->get_expression2());
622 localized_statements.push_back(assignment);
623 local_expr2 =
clone(*expr2_name);
626 auto local_reaction =
627 std::make_shared<ast::ReactionStatement>(reaction_equation->get_reaction1(),
628 reaction_equation->get_op(),
629 reaction_equation->get_reaction2(),
632 localized_statements.push_back(local_reaction);
634 iter =
node.erase_statement(iter);
635 for (
const auto& stmt: localized_statements) {
638 iter = ++
node.insert_statement(iter, stmt);
653 for (
const auto&
ii: kineticBlockNodes) {
654 ii->accept(const_folder);
668 for (
const auto&
ii: kineticBlockNodes) {
669 ii->accept(unroller);
674 for (
const auto&
ii: kineticBlockNodes) {
675 ii->accept(const_folder);
679 node.accept(visitor);
694 if (
auto symtab =
node.get_symbol_table()) {
695 auto statevars = symtab->get_variables_with_properties(NmodlType::state_var);
696 for (
const auto&
v: statevars) {
697 std::string var_name =
v->get_name();
703 for (
int i = 0;
i <
v->get_length(); ++
i) {
705 logger->debug(
"KineticBlockVisitor :: state_var_index[{}] = {}",
712 logger->debug(
"KineticBlockVisitor :: state_var_index[{}] = {}",
723 for (
const auto&
ii: kineticBlockNodes) {
728 auto blocks =
node.get_blocks();
730 for (
auto it = blocks.begin(); it != blocks.end(); ++it) {
731 if (it->get() == kinetic_block) {
733 std::make_shared<ast::DerivativeBlock>(kinetic_block->get_name(),
734 kinetic_block->get_statement_block());
736 dblock->set_token(tok);
Auto generated AST classes declaration.
Represent token returned by scanner.
Operator used in ast::BinaryExpression.
Represent COMPARTMENT statement in NMODL.
Represent CONSERVE statement in NMODL.
Base class for all AST node.
Represents top level AST node for whole NMODL input.
Represents block encapsulating list of statements.
StatementVector::const_iterator erase_statement(StatementVector::const_iterator first)
Erase member to statements.
Wrap any other expression type.
Represent symbol table for a NMODL block.
std::shared_ptr< Symbol > lookup_in_scope(const std::string &name) const
check if symbol with given name exist in the current table (including all parents)
Concrete visitor for all AST classes.
void visit_expression(ast::Expression &node) override
visit node of type ast::Expression
Perform constant folding of integer/float/double expressions.
Helper visitor to replace index of array variable with integer.
int state_var_count
number of state variables
void visit_kinetic_block(ast::KineticBlock &node) override
visit node of type ast::KineticBlock
std::string modfile_fflux
current expressions for the fflux, bflux variables that can be used in the mod file and that are dete...
void visit_reaction_operator(ast::ReactionOperator &node) override
visit node of type ast::ReactionOperator
struct nmodl::visitor::KineticBlockVisitor::RateEqs rate_eqs
void compute_compartment_factor(ast::Compartment &node, const ast::Name &name)
void visit_reaction_statement(ast::ReactionStatement &node) override
visit node of type ast::ReactionStatement
int i_statement
current statement index
void visit_react_var_name(ast::ReactVarName &node) override
visit node of type ast::ReactVarName
bool in_conserve_statement
true if we are visiting a CONSERVE statement
std::string modfile_bflux
std::string conserve_equation_str
conserve statement equation as string
std::vector< std::string > non_state_var_bflux
std::vector< ast::KineticBlock * > kinetic_blocks
vector of kinetic block nodes
std::vector< std::string > fflux
generated set of fluxes and ODEs
int conserve_statement_count
counts the number of CONSERVE statements in Kinetic blocks
void unroll_kinetic_blocks(ast::Program &node)
Unroll loops in KINETIC blocks.
void visit_statement_block(ast::StatementBlock &node) override
visit node of type ast::StatementBlock
std::unordered_map< std::string, int > array_state_var_size
unordered_map from array state variable to its size (for summing over each element of any array state...
std::vector< std::string > compartment_factors
multiplicative factors for ODEs from COMPARTMENT statements
std::vector< std::string > additive_terms
additive constant terms for ODEs from reaction statements like ~ x << (a)
std::unordered_set< ast::Statement * > statements_to_remove
statements to remove from block
void visit_conserve(ast::Conserve &node) override
visit node of type ast::Conserve
void visit_wrapped_expression(ast::WrappedExpression &node) override
visit node of type ast::WrappedExpression
std::vector< std::string > odes
void visit_compartment(ast::Compartment &node) override
visit node of type ast::Compartment
void process_conserve_reac_var(const std::string &varname, int count=1)
update CONSERVE statement with reaction var term
void visit_program(ast::Program &node) override
visit node of type ast::Program
void compute_indexed_compartment_factor(ast::Compartment &node, const ast::Name &name)
std::string conserve_equation_factor
conserve statement: current state var multiplicative factor being processed
std::string conserve_equation_statevar
conserve statement: current state variable being processed
void set_compartment_factor(int var_index, const std::string &factor)
ast::StatementBlock * current_statement_block
current statement block being visited
std::unordered_map< std::string, int > state_var_index
unordered_map from state variable to corresponding index
void process_reac_var(const std::string &varname, int count=1)
update stoichiometric matrices with reaction var term
std::vector< std::string > bflux
std::vector< std::string > non_state_var_fflux
multiplicate constant terms for fluxes from non-state vars as reactants e.g.
bool in_reaction_statement_lhs
true if we are visiting the left hand side of reaction statement
std::vector< std::string > state_var
state variables vector
bool in_reaction_statement
true if we are visiting a reaction statement
std::pair< std::shared_ptr< ast::Name >, std::shared_ptr< ast::Name > > generate_rate_names()
std::shared_ptr< ast::Name > generate_source_name()
LocalRateNames(LocalRateNames &&)=default
static constexpr auto kf_stem
LocalRateNames & operator=(const LocalRateNames &)=default
std::shared_ptr< ast::Name > generate_forward_rate_name()
static constexpr auto source_stem
std::shared_ptr< ast::Name > generate_local_name(const std::string &stem)
std::vector< std::string > local_names
static constexpr auto kb_stem
LocalRateNames & operator=(LocalRateNames &&)=default
LocalRateNames(symtab::SymbolTable const *symtab)
std::vector< std::string > get_local_variable_names()
symtab::SymbolTable const * symtab
LocalRateNames(const LocalRateNames &)=default
void visit_kinetic_block(ast::KineticBlock &node)
visit node of type ast::KineticBlock
LocalRateNames local_names
void visit_statement_block(ast::StatementBlock &node)
visit node of type ast::StatementBlock
std::shared_ptr< ast::ExpressionStatement > localize_expression(const std::shared_ptr< ast::Name > &name, const std::shared_ptr< ast::Expression > &expression)
std::shared_ptr< Node > clone(const Node &node)
Unroll for loop in the AST.
Perform constant folding of integer/float/double expressions.
@ KINETIC_BLOCK
type of ast::KineticBlock
std::vector< std::shared_ptr< Statement > > StatementVector
static std::vector< std::string > split_string(const std::string &text, char delimiter)
Split a text in a list of words, using a given delimiter character.
Visitor for kinetic block statements
Unroll for loop in the AST.
void move(Item *q1, Item *q2, Item *q3)
std::string to_string(const T &obj)
NmodlType
NMODL variable properties.
LocalVar * add_local_variable(StatementBlock &node, Identifier *varname)
std::shared_ptr< Statement > create_statement(const std::string &code_statement)
Convert given code statement (in string format) to corresponding ast node.
std::shared_ptr< ast::Expression > create_expr(const std::string &str_expr)
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
std::string to_nmodl(const ast::Ast &node, const std::set< ast::AstNodeType > &exclude_types)
Given AST node, return the NMODL string representation.
static Node * node(Object *)
Implement string manipulation functions.
std::vector< std::vector< int > > nu_L
std::vector< std::string > k_b
std::vector< std::string > k_f
std::vector< std::vector< int > > nu_R
Implement class to represent a symbol in Symbol Table.
Utility functions for visitors implementation.