8 #include <catch2/catch_test_macros.hpp>
20 using namespace nmodl;
21 using namespace visitor;
23 using namespace test_utils;
33 std::vector<std::string> results;
40 SymtabVisitor().visit_program(*ast);
43 KineticBlockVisitor().visit_program(*ast);
47 CheckParentVisitor().check_ast(*ast);
50 const auto& blocks =
collect_nodes(*ast, {AstNodeType::DERIVATIVE_BLOCK});
51 results.reserve(blocks.size());
52 for (
const auto& block: blocks) {
58 CheckParentVisitor().check_ast(*ast);
63 SCENARIO(
"Convert KINETIC to DERIVATIVE using KineticBlock visitor",
"[kinetic][visitor]") {
64 GIVEN(
"KINETIC block with << reaction statement, 1 state var") {
65 static const std::string input_nmodl_text = R
"(
72 static const std::string output_nmodl_text = R
"(
78 THEN("Convert to equivalent DERIVATIVE block") {
80 CAPTURE(input_nmodl_text);
84 GIVEN(
"KINETIC block with << reaction statement, 1 array state var") {
85 std::string input_nmodl_text = R
"(
92 std::string output_nmodl_text = R"(
98 THEN("Convert to equivalent DERIVATIVE block") {
100 CAPTURE(input_nmodl_text);
104 GIVEN(
"KINETIC block with << reaction statement, 1 array state var, flux vars") {
105 std::string input_nmodl_text = R
"(
114 std::string output_nmodl_text = R"(
122 THEN("Convert to equivalent DERIVATIVE block") {
124 CAPTURE(input_nmodl_text);
128 GIVEN(
"KINETIC block with invalid << reaction statement with 2 state vars") {
129 std::string input_nmodl_text = R
"(
136 THEN("Fail by throwing an error.") {
140 GIVEN(
"KINETIC block with -> reaction statement, 1 state var, flux vars") {
141 std::string input_nmodl_text = R
"(
150 std::string output_nmodl_text = R"(
158 THEN("Convert to equivalent DERIVATIVE block") {
160 CAPTURE(input_nmodl_text);
164 GIVEN(
"KINETIC block with -> reaction statement, 2 state vars") {
165 std::string input_nmodl_text = R
"(
172 std::string output_nmodl_text = R"(
179 THEN("Convert to equivalent DERIVATIVE block") {
181 CAPTURE(input_nmodl_text);
185 GIVEN(
"KINETIC block with -> reaction statement, 2 state vars, CONSERVE statement") {
186 std::string input_nmodl_text = R
"(
194 std::string output_nmodl_text = R"(
202 THEN("Convert to equivalent DERIVATIVE block, rewrite CONSERVE statement") {
204 CAPTURE(input_nmodl_text);
208 GIVEN(
"KINETIC block with -> reaction statement, 2 state vars, CONSERVE & COMPARTMENT") {
209 std::string input_nmodl_text = R
"(
219 std::string output_nmodl_text = R"(
223 CONSERVE y = (1-(a*1*x))/(b*1)
224 x' = ((-1*(kf0_*x*y)))/(a)
225 y' = ((-1*(kf0_*x*y)))/(b)
228 "Convert to equivalent DERIVATIVE block, rewrite CONSERVE statement inc COMPARTMENT "
231 CAPTURE(input_nmodl_text);
235 GIVEN(
"KINETIC block with -> reaction statement, array of 2 state var") {
236 std::string input_nmodl_text = R
"(
241 ~ x[0] + x[1] -> (f(v))
243 std::string output_nmodl_text = R"(
247 x'[0] = (-1*(kf0_*x[0]*x[1]))
248 x'[1] = (-1*(kf0_*x[0]*x[1]))
250 THEN("Convert to equivalent DERIVATIVE block") {
252 CAPTURE(input_nmodl_text);
256 GIVEN(
"KINETIC block with -> reaction statement, indexed COMPARTMENT") {
257 std::string input_nmodl_text = R
"(
262 COMPARTMENT i, vol[i] { x }
263 ~ x[0] + x[1] -> (f(v))
265 std::string output_nmodl_text = R"(
269 x'[0] = ((-1*(kf0_*x[0]*x[1])))/(vol[0])
270 x'[1] = ((-1*(kf0_*x[0]*x[1])))/(vol[1])
272 THEN("Convert to equivalent DERIVATIVE block") {
274 CAPTURE(input_nmodl_text);
278 GIVEN(
"KINETIC block with one reaction statement, 1 state var, 1 non-state var, flux vars") {
284 std::string input_nmodl_text = R
"(
292 std::string output_nmodl_text = R"(
298 x' = (-1*(kf0_*x-kb0_*c))
300 THEN("Convert to equivalent DERIVATIVE block") {
302 CAPTURE(input_nmodl_text);
306 GIVEN(
"KINETIC block with one reaction statement, 2 state vars") {
307 std::string input_nmodl_text = R
"(
314 std::string output_nmodl_text = R"(
319 x' = (-1*(kf0_*x-kb0_*y))
320 y' = (1*(kf0_*x-kb0_*y))
322 THEN("Convert to equivalent DERIVATIVE block") {
324 CAPTURE(input_nmodl_text);
328 GIVEN(
"KINETIC block with one reaction statement, 2 state vars, CONSERVE statement") {
329 std::string input_nmodl_text = R
"(
337 std::string output_nmodl_text = R"(
343 x' = (-1*(kf0_*x-kb0_*y))
344 y' = (1*(kf0_*x-kb0_*y))
346 THEN("Convert to equivalent DERIVATIVE block, rewrite CONSERVE statement") {
348 CAPTURE(input_nmodl_text);
354 GIVEN(
"KINETIC block with array state vars, CONSERVE statement") {
355 std::string input_nmodl_text = R
"(
360 ~ x[0] <-> x[1] (a, b)
364 std::string output_nmodl_text = R"(
366 LOCAL kf0_, kb0_, kf1_, kb1_
371 CONSERVE x[2] = 1-y-x[0]-x[1]
372 x'[0] = (-1*(kf0_*x[0]-kb0_*x[1]))
373 x'[1] = (1*(kf0_*x[0]-kb0_*x[1]))
374 x'[2] = (-1*(kf1_*x[2]-kb1_*y))
375 y' = (1*(kf1_*x[2]-kb1_*y))
378 "Convert to equivalent DERIVATIVE block, rewrite CONSERVE statement after summing over "
379 "array elements, with last state var on LHS") {
381 CAPTURE(input_nmodl_text);
387 GIVEN(
"KINETIC block with array state vars, re-ordered CONSERVE statement") {
388 std::string input_nmodl_text = R
"(
393 ~ x[0] <-> x[1] (a, b)
397 std::string output_nmodl_text = R"(
399 LOCAL kf0_, kb0_, kf1_, kb1_
404 CONSERVE y = 1-x[0]-x[1]-x[2]
405 x'[0] = (-1*(kf0_*x[0]-kb0_*x[1]))
406 x'[1] = (1*(kf0_*x[0]-kb0_*x[1]))
407 x'[2] = (-1*(kf1_*x[2]-kb1_*y))
408 y' = (1*(kf1_*x[2]-kb1_*y))
411 "Convert to equivalent DERIVATIVE block, rewrite CONSERVE statement after summing over "
412 "array elements, with last state var on LHS") {
414 CAPTURE(input_nmodl_text);
418 GIVEN(
"KINETIC block with one reaction statement & 1 COMPARTMENT statement") {
419 std::string input_nmodl_text = R
"(
424 COMPARTMENT c-d {x y}
427 std::string output_nmodl_text = R"(
432 x' = ((-1*(kf0_*x-kb0_*y)))/(c-d)
433 y' = ((1*(kf0_*x-kb0_*y)))/(c-d)
435 THEN("Convert to equivalent DERIVATIVE block") {
437 CAPTURE(input_nmodl_text);
441 GIVEN(
"KINETIC block with two CONSERVE statements") {
442 std::string input_nmodl_text = R
"(
448 ~ c1 <-> o1 (alpha, beta)
449 ~ p0 <-> p1 (k1ca, k2)
450 ~ o1 <-> o2 (k3p, k4)
452 CONSERVE c1+o1+o2 = 1
454 std::string output_nmodl_text = R"(
456 LOCAL kf0_, kb0_, kf1_, kb1_, kf2_, kb2_
465 CONSERVE o2 = 1-c1-o1
466 c1' = (-1*(kf0_*c1-kb0_*o1))
467 o1' = (1*(kf0_*c1-kb0_*o1))+(-1*(kf2_*o1-kb2_*o2))
468 o2' = (1*(kf2_*o1-kb2_*o2))
469 p0' = (-1*(kf1_*p0-kb1_*p1))
470 p1' = (1*(kf1_*p0-kb1_*p1))
472 THEN("Convert to equivalent DERIVATIVE block, re-order both CONSERVE statements") {
474 CAPTURE(input_nmodl_text);
478 GIVEN(
"KINETIC block with one reaction statement & clashing local") {
479 std::string input_nmodl_text = R
"(
487 LOCAL kf0_0000, kb0_0000
490 std::string output_nmodl_text = R"(
492 LOCAL kf0_0000, kb0_0000, kf0_0001, kb0_
495 x' = (-1*(kf0_0001*x-kb0_*y))
496 y' = (1*(kf0_0001*x-kb0_*y))
498 THEN("Convert to equivalent DERIVATIVE block") {
500 CAPTURE(input_nmodl_text);
504 GIVEN(
"KINETIC block with one reaction statement & 2 COMPARTMENT statements") {
505 std::string input_nmodl_text = R
"(
514 std::string output_nmodl_text = R"(
519 x' = ((-1*(kf0_*x-kb0_*y)))/(cx)
520 y' = ((1*(kf0_*x-kb0_*y)))/(cy)
522 THEN("Convert to equivalent DERIVATIVE block") {
524 CAPTURE(input_nmodl_text);
528 GIVEN(
"KINETIC block with two independent reaction statements") {
529 std::string input_nmodl_text = R
"(
537 std::string output_nmodl_text = R"(
539 LOCAL kf0_, kb0_, kf1_, kb1_
544 w' = (-1*(kf1_*w-kb1_*z))
545 x' = (-1*(kf0_*x-kb0_*y))
546 y' = (1*(kf0_*x-kb0_*y))
547 z' = (1*(kf1_*w-kb1_*z))
549 THEN("Convert to equivalent DERIVATIVE block") {
551 CAPTURE(input_nmodl_text);
555 GIVEN(
"KINETIC block with two dependent reaction statements") {
556 std::string input_nmodl_text = R
"(
564 std::string output_nmodl_text = R"(
566 LOCAL kf0_, kb0_, kf1_, kb1_
571 x' = (-1*(kf0_*x-kb0_*y))
572 y' = (1*(kf0_*x-kb0_*y))+(-1*(kf1_*y-kb1_*z))
573 z' = (1*(kf1_*y-kb1_*z))
575 THEN("Convert to equivalent DERIVATIVE block") {
577 CAPTURE(input_nmodl_text);
581 GIVEN(
"KINETIC block with two dependent reaction statements, flux vars") {
582 std::string input_nmodl_text = R
"(
591 c2 = f_flux - 2*b_flux
593 std::string output_nmodl_text = R"(
595 LOCAL kf0_, kb0_, kf1_, kb1_
603 x' = (-1*(kf0_*x-kb0_*y))
604 y' = (1*(kf0_*x-kb0_*y))+(-1*(kf1_*y-kb1_*z))
605 z' = (1*(kf1_*y-kb1_*z))
607 THEN("Convert to equivalent DERIVATIVE block") {
609 CAPTURE(input_nmodl_text);
613 GIVEN(
"KINETIC block with a stoch coeff of 2") {
614 std::string input_nmodl_text = R
"(
621 std::string output_nmodl_text = R"(
626 x' = (-2*(kf0_*x*x-kb0_*y))
627 y' = (1*(kf0_*x*x-kb0_*y))
629 THEN("Convert to equivalent DERIVATIVE block") {
631 CAPTURE(input_nmodl_text);
635 GIVEN(
"KINETIC block with duplicate state vars") {
636 std::string input_nmodl_text = R
"(
643 std::string output_nmodl_text = R"(
648 x' = (-2*(kf0_*x*x-kb0_*y))
649 y' = (1*(kf0_*x*x-kb0_*y))
651 THEN("Convert to equivalent DERIVATIVE block") {
653 CAPTURE(input_nmodl_text);
657 GIVEN(
"KINETIC block with functions for reaction rates") {
659 std::string input_nmodl_text = R
"(
664 ~ mc <-> m (a(v), b(v))
666 std::string output_nmodl_text = R"(
671 mc' = (-1*(kf0_*mc-kb0_*m))
672 m' = (1*(kf0_*mc-kb0_*m))
674 THEN("Convert to equivalent DERIVATIVE block") {
676 CAPTURE(input_nmodl_text);
680 GIVEN(
"KINETIC block with stoch coeff 2, coupled pair of statements") {
682 std::string input_nmodl_text = R
"(
687 ~ 2A + B <-> C (k1, k2)
688 ~ C + D <-> A + 2B (k3, k4)
690 std::string output_nmodl_text = R"(
692 LOCAL kf0_, kb0_, kf1_, kb1_
697 A' = (-2*(kf0_*A*A*B-kb0_*C))+(1*(kf1_*C*D-kb1_*A*B*B))
698 B' = (-1*(kf0_*A*A*B-kb0_*C))+(2*(kf1_*C*D-kb1_*A*B*B))
699 C' = (1*(kf0_*A*A*B-kb0_*C))+(-1*(kf1_*C*D-kb1_*A*B*B))
700 D' = (-1*(kf1_*C*D-kb1_*A*B*B))
703 THEN("Convert to equivalent DERIVATIVE block") {
705 CAPTURE(input_nmodl_text);
709 GIVEN(
"KINETIC block with loop over array variable") {
710 std::string input_nmodl_text = R
"(
724 ~ x[i] <-> x[i+1] (b[i], c[i])
728 std::string output_nmodl_text = R"(
730 LOCAL kf0_, kb0_, kf1_, kb1_, kf2_, kb2_, kf3_, kb3_, source4_, kf5_
743 x'[0] = (source4_)+(-1*(kf0_*x[0]-kb0_*x[1]))
744 x'[1] = (1*(kf0_*x[0]-kb0_*x[1]))+(-1*(kf1_*x[1]-kb1_*x[2]))
745 x'[2] = (1*(kf1_*x[1]-kb1_*x[2]))+(-1*(kf2_*x[2]-kb2_*x[3]))
746 x'[3] = (1*(kf2_*x[2]-kb2_*x[3]))+(-1*(kf3_*x[3]-kb3_*x[4]))
747 x'[4] = (1*(kf3_*x[3]-kb3_*x[4]))+(-1*(kf5_*x[4]))
749 THEN("Convert to equivalent DERIVATIVE block") {
751 CAPTURE(input_nmodl_text);