-
Notifications
You must be signed in to change notification settings - Fork 15
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
Add CvodeBlock
and CvodeVisitor
#1467
base: master
Are you sure you want to change the base?
Conversation
DerivativeOriginalFunctionBlock
and DerivativeVisitor
DerivativeOriginalFunctionBlock
and DerivativeOriginalVisitor
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two comments:
- The
DerivativeOriginalBlock
is advertised as an unmodified copy. However, it's immediately during the process it's being modified. - There's no code demonstrating how this works, i.e. no tests or anything similar.
class DerivativeOriginalVisitor: public AstVisitor { | ||
private: | ||
/// The copy of the derivative block we are solving | ||
ast::DerivativeBlock* der_block_function = nullptr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this a _function
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since there's two blocks that will be added: one for Dx = f(x)
(the _function
one), and the other one for Dx = Dx / (1 - dt * J(f))
(the _jacobian
, will be added in next breakdown of the original PR). I've debated about only adding one block, but the codegen would then require parsing the AST and modifying it, which I feel shouldn't be done at the codegen stage, hence the "two blocks, one visitor" design (the one visitor is here only because it felt pointless to make another one which does almost the same thing).
src/language/codegen.yaml
Outdated
@@ -87,7 +87,30 @@ | |||
type: StatementBlock | |||
- finalize_block: | |||
brief: "Statement block to be executed after calling linear solver" | |||
type: StatementBlock | |||
type: StatementBlock | |||
- DerivativeOriginalFunctionBlock: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the Function
in DerivativeOriginalFunctionBlock
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NMODL doesn't allow two blocks with the same type (doesn't matter that they may not have the same name), and we will need another block for the transformation involving the Jacobian, so it's basically with that in mind that there's the additional Function
. Open to suggestions on how to make it shorter though!
`DERIVATIVE` blocks can't have array variables in NOCMODL by default, so let's go with that.
DerivativeOriginalFunctionBlock
and DerivativeOriginalVisitor
CvodeBlock
and CvodeVisitor
*/ | ||
|
||
/** | ||
* \class DerivativeOriginalVisitor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's still a couple of places where the old term DerivativeOriginal
exists (including filenames).
class CvodeVisitor: public AstVisitor { | ||
private: | ||
/// The copy of the derivative block we are solving | ||
std::shared_ptr<ast::DerivativeBlock> der_block = nullptr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The abbreviation is slightly jarring.
std::shared_ptr<ast::DerivativeBlock> der_block = nullptr; | ||
|
||
/// true while visiting differential equation | ||
bool differential_equation = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are the names for differential_equation
and derivative_block
idiomatic? Could they have a better name? Something the hints better at what they are: inside_*
, beneath_*
, is_*
, printing_*
auto ast = run_cvode_visitor(nmodl_text); | ||
THEN("CVODE block is added") { | ||
auto block = collect_nodes(*ast, {ast::AstNodeType::CVODE_BLOCK}); | ||
REQUIRE(!block.empty()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It has too be exactly one I think. At least it looks like that's the assumption further down.
)"; | ||
auto ast = run_cvode_visitor(nmodl_text); | ||
THEN("CVODE block is added") { | ||
auto block = collect_nodes(*ast, {ast::AstNodeType::CVODE_BLOCK}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a vector of all CVODE_BLOCK
s. Hence plural, blocks
(or cvode_blocks
); then later you'd be free to use block = block[0]
(not much use).
} | ||
|
||
// re-visit the AST since we now inserted the DERIVATIVE_ORIGINAL block | ||
node.visit_children(*this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to revisit them again?
program_symtab = node.get_symbol_table(); | ||
node.visit_children(*this); | ||
if (der_block) { | ||
auto der_node = new ast::CvodeBlock(der_block->get_name(), | ||
der_block->get_statement_block(), | ||
der_block->get_statement_block()); | ||
node.emplace_back_node(der_node); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you don't like the pattern that you need to toggle two booleans there's a way out. The code I marked essentially does a:
auto blocks = collect_nodes(*ast, {ast::AstNodeType::DERIVATIVE_BLOCK});
Then all you need to do is run the {}' -> d{}
replacement visitor (which consists of the visit_binary_expression
) on each block and put them into CVodeBlock
s and add them to the program.
Then there's no more boolean toggling; and it'll be more explicit about handling multiple DERIVATIVE blocks. BTW, the name for toggling being inside a cvode block is now rather misleading.
Uses finite differences
Part 1 of #1399.
Adds the original DERIVATIVE block since NMODL solves it in-place. Also adds a visitors which actually replaces statements of the form
x' = f(x)
intoDx = f(x)
.