User Guide
nmodl_constructs.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2023 Blue Brain Project, EPFL.
3  * See the top-level LICENSE file for details.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include "nmodl_constructs.hpp"
9 
10 namespace nmodl {
11 /// custom type to represent nmodl construct for testing
12 namespace test_utils {
13 
14 /**
15  * Guidelines for adding nmodl text constructs
16  *
17  * As nmodl constructs are used to for testing ast to nmodl transformations,
18  * consider following points:
19  * - Leading whitespaces or empty lines are removed
20  * - Use string literal to define nmodl text
21  * When ast is transformed back to nmodl, each statement has newline.
22  * Hence for easy comparison, input nmodl should be null terminated.
23  * One way to use format:
24  *
25  * \code
26  * R"(
27  * TITLE nmodl title
28  * )"
29  * \endcode
30  *
31  * - Do not use extra spaces (even though it's valid)
32  *
33  * \code
34  * LOCAL a,b
35  * \endcode
36  *
37  * instead of
38  *
39  * \code
40  * LOCAL a, b, c
41  * \endcode
42  *
43  * - Use well indented blocks
44  *
45  * \code
46  * NEURON {
47  * RANGE x
48  * }
49  * \endcode
50  *
51  * instead of
52  *
53  * \code
54  * NEURON {
55  * RANGE x
56  * }
57  * \endcode
58  *
59  * If nmodl transformation is different from input, third argument could be
60  * provided with the expected nmodl.
61  */
62 
63 std::map<std::string, NmodlTestCase> const nmodl_invalid_constructs{
64  // clang-format off
65  {
66  "title_1",
67  {
68  "Title statement without any text",
69  "TITLE"
70  }
71  },
72 
73  {
74  "local_list_1",
75  {
76  "LOCAL statement without any variable",
77  "LOCAL"
78  }
79  },
80 
81  {
82  "local_list_2",
83  {
84  "LOCAL statement with empty index",
85  "LOCAL gbar[]"
86  }
87  },
88 
89  {
90  "local_list_3",
91  {
92  "LOCAL statement with invalid index",
93  "LOCAL gbar[2.0]"
94  }
95  },
96 
97  {
98  "define_1",
99  {
100  "Incomplete macro definition without value",
101  "DEFINE NSTEP"
102  }
103  },
104 
105  {
106  "verbatim_block_1",
107  {
108  "Nested verbatim blocks",
109  R"(
110  VERBATIM
111  VERBATIM
112  #include <cuda.h>
113  ENDVERBATIM
114  ENDVERBATIM
115  )"
116  }
117  },
118 
119  {
120  "comment_block_1",
121  {
122  "Nested comment blocks",
123  R"(
124  COMMENT
125  COMMENT
126  some code comment here
127  ENDCOMMENT
128  ENDCOMMENT
129  )"
130  }
131  },
132 
133  {
134  "include_statement_1",
135  {
136  "Incomplete include statements",
137  "INCLUDE "
138  }
139  },
140 
141  {
142  "parameter_block_1",
143  {
144  "Incomplete parameter declaration",
145  R"(
146  PARAMETER {
147  ampa =
148  }
149  )"
150  }
151  },
152 
153  {
154  "parameter_block_2",
155  {
156  "Invalid parameter declaration",
157  R"(
158  PARAMETER {
159  ampa = 2 (ms>
160  }
161  )"
162  }
163  },
164 
165  {
166  "neuron_block_1",
167  {
168  "Invalid CURIE statement",
169  R"(
170  NEURON {
171  REPRESENTS xx
172  }
173  )"
174  }
175  }
176 
177 
178  // clang-format on
179 };
180 
181 std::map<std::string, NmodlTestCase> const nmodl_valid_constructs{
182  // clang-format off
183  {
184  "title_1",
185  {
186  "Title statement",
187  R"(
188  TITLE nmodl title
189  )"
190  }
191  },
192 
193  {
194  "local_list_1",
195  {
196  "Standalone LOCAL statement with single scalar variable",
197  R"(
198  LOCAL gbar
199  )"
200  }
201  },
202 
203  {
204  "local_list_2",
205  {
206  "Standalone LOCAL statement with single vector variable",
207  R"(
208  LOCAL gbar[2]
209  )"
210  }
211  },
212 
213  {
214  "local_list_3",
215  {
216  "Standalone LOCAL statement with multiple variables",
217  R"(
218  LOCAL gbar, ek[2], ik
219  )"
220  }
221  },
222 
223  {
224  "local_list_4",
225  {
226  "Standalone LOCAL statement with multiple variables with/without whitespaces",
227  R"(
228  LOCAL gbar, ek[2],ik, gk
229  )",
230  R"(
231  LOCAL gbar, ek[2], ik, gk
232  )"
233  }
234  },
235 
236  {
237  "define_1",
238  {
239  "Macro definition",
240  R"(
241  DEFINE NSTEP 10
242  )"
243  }
244  },
245 
246  {
247  "statement_block_1",
248  {
249  "Statements should preserve order with blocks",
250  R"(
251  DEFINE ASTEP 10
252 
253  NEURON {
254  RANGE x
255  }
256 
257  DEFINE BSTEP 20
258  )"
259  }
260  },
261 
262  {
263  "artificial_cell_1",
264  {
265  "Artificial Statement usage",
266  R"(
267  NEURON {
268  ARTIFICIAL_CELL NSLOC
269  }
270  )"
271  }
272  },
273 
274  {
275  "verbatim_block_1",
276  {
277  "Stanadlone empty verbatim block",
278  R"(
279  VERBATIM
280  ENDVERBATIM
281  )"
282  }
283  },
284 
285  {
286  "verbatim_block_2",
287  {
288  "Standalone verbatim block",
289  R"(
290  VERBATIM
291  #include <cuda.h>
292  ENDVERBATIM
293  )"
294  }
295  },
296 
297  {
298  "comment_block_1",
299  {
300  "Standalone comment block",
301  R"(
302  COMMENT
303  some comment here
304  ENDCOMMENT
305  )"
306  }
307  },
308 
309  {
310  "unit_statement_1",
311  {
312  "Standalone unit on/off statements",
313  R"(
314  UNITSON
315 
316  UNITSOFF
317 
318  UNITSON
319 
320  UNITSOFF
321  )"
322  }
323  },
324 
325  {
326  "include_statement_1",
327  {
328  "Standalone include statements",
329  R"(
330  INCLUDE "Unit.inc"
331  )"
332  }
333  },
334 
335  {
336  "parameter_block_1",
337  {
338  "Empty parameter block",
339  R"(
340  PARAMETER {
341  }
342  )"
343  }
344  },
345 
346  {
347  "parameter_block_2",
348  {
349  "PARAMETER block with all statement types",
350  R"(
351  PARAMETER {
352  tau_r_AMPA = 10
353  tau_d_AMPA = 10.1 (mV)
354  tau_r_NMDA = 10 (mV) <1,2>
355  tau_d_NMDA = 10 (mV) <1.1,2.2>
356  Use (mV)
357  Dep[1] <1,2>
358  Fac[1] (mV) <1,2>
359  g
360  }
361  )"
362  }
363  },
364 
365  {
366  "parameter_block_3",
367  {
368  "PARAMETER statement can use macro definition as a number",
369  R"(
370  DEFINE SIX 6
371 
372  PARAMETER {
373  tau_r_AMPA = SIX
374  }
375  )"
376  }
377  },
378 
379  {
380  "parameter_block_4",
381  {
382  "PARAMETER block with inconsistent whitespaces",
383  R"(
384  PARAMETER {
385  tau_r_AMPA=10.0
386  tau_d_AMPA = 10.1(mV)
387  tau_r_NMDA = 10 (mV) <1, 2>
388  tau_d_NMDA= 10 (mV)<1.1,2.2>
389  Use (mV)
390  Dep [1] <1,2>
391  Fac[1](mV)<1,2>
392  g
393  }
394  )",
395  R"(
396  PARAMETER {
397  tau_r_AMPA = 10.0
398  tau_d_AMPA = 10.1 (mV)
399  tau_r_NMDA = 10 (mV) <1,2>
400  tau_d_NMDA = 10 (mV) <1.1,2.2>
401  Use (mV)
402  Dep[1] <1,2>
403  Fac[1] (mV) <1,2>
404  g
405  }
406  )"
407  }
408  },
409 
410  {
411  "parameter_block_5",
412  {
413  "PARAMETER block with very small/large doubles",
414  R"(
415  PARAMETER {
416  tau_r_AMPA = 1e-16
417  tau_d_AMPA = 1.7e-22
418  tau_r_NMDA = 1e+21
419  tau_d_NMDA = 1.3643e+27
420  }
421  )"
422  }
423  },
424 
425  {
426  "independent_block_1",
427  {
428  "INDEPENDENT block with all statement types",
429  R"(
430  INDEPENDENT {
431  t FROM 0 TO 1 WITH 1 (ms)
432  SWEEP u FROM 0 TO 1 WITH 1 (ms)
433  }
434  )",
435  R"(
436  : INDEPENDENT block is deprecated and has no effect in the NEURON model. Skipped!
437  )"
438  }
439  },
440 
441  {
442  "dependent_block_1",
443  {
444  "ASSIGNED block with all statement types",
445  R"(
446  ASSIGNED {
447  v
448  i_AMPA (nA)
449  i_NMDA START 2.1 (nA) <0.1>
450  A_NMDA_step[1] START 1 <0.2>
451  factor_AMPA FROM 0 TO 1
452  B_NMDA_step[2] FROM 1 TO 2 START 0 (ms) <1>
453  }
454  )"
455  }
456  },
457 
458  {
459  "neuron_block_1",
460  {
461  "NEURON block with many statement types",
462  R"(
463  NEURON {
464  SUFFIX ProbAMPANMDA
465  REPRESENTS NCIT:C17145
466  REPRESENTS [NCIT:C17145]
467  USEION na READ ena
468  USEION na READ ena, kna
469  USEION na WRITE ena, kna VALENCE 2.1
470  USEION na READ ena WRITE ina
471  USEION k READ ek WRITE ik REPRESENTS CHEBI:29103
472  USEION na READ ena WRITE ina VALENCE 3.3 REPRESENTS NCIT:C17
473  NONSPECIFIC_CURRENT i
474  NONSPECIFIC_CURRENT i, j
475  ELECTRODE_CURRENT i
476  RANGE tau_r_AMPA, tau_d_AMPA
477  GLOBAL gNa, xNa
478  POINTER rng1, rng2
479  BBCOREPOINTER rng3
480  EXTERNAL extvar
481  RANDOM r1
482  RANDOM r2, r3
483  THREADSAFE
484  }
485  )"
486  }
487  },
488 
489  {
490  "unit_block_1",
491  {
492  "UNITS block with unit definitions",
493  R"(
494  UNITS {
495  (mA) = (milliamp)
496  (mV) = (millivolt)
497  }
498  )"
499  }
500  },
501 
502  {
503  "unit_block_2",
504  {
505  "UNITS block with unit and factor definitions",
506  R"(
507  UNITS {
508  aa = 1 (bb)
509  cc = 1.1 (dd)
510  ee = (ff) (gg)
511  hh = (ii) -> (jj)
512  }
513  )"
514  }
515  },
516 
517  {
518  "unit_block_3",
519  {
520  "UNITS block with empty unit (called default unit)",
521  R"(
522  UNITS {
523  () = (millivolt)
524  }
525  )"
526  }
527  },
528 
529  {
530  "constant_block_1",
531  {
532  "CONSTANT block with all statement types",
533  R"(
534  CONSTANT {
535  xx = 1
536  yy2 = 1.1
537  ee = 1e-06 (gg)
538  }
539  )"
540  }
541  },
542 
543  {
544  "constant_block_2",
545  {
546  "CONSTANT block with signed values",
547  R"(
548  CONSTANT {
549  xx = +1
550  yy2 = -1.1
551  ee = 1e-06 (gg)
552  }
553  )",
554  R"(
555  CONSTANT {
556  xx = 1
557  yy2 = -1.1
558  ee = 1e-06 (gg)
559  }
560  )"
561  }
562  },
563 
564  {
565  "statement_list_1",
566  {
567  "Empty statement list",
568  R"(
569  INITIAL {
570  }
571  )"
572  }
573  },
574 
575  {
576  "statement_list_1",
577  {
578  "Statement list with local variables",
579  R"(
580  INITIAL {
581  LOCAL a, b
582  }
583  )"
584  }
585  },
586 
587  {
588  "fromstmt_1",
589  {
590  "From statement",
591  R"(
592  INITIAL {
593  LOCAL a, b
594  FROM i = 0 TO 1 {
595  tau[i] = 1
596  }
597  }
598  )"
599  }
600  },
601 
602  {
603  "fromstmt_2",
604  {
605  "From statement with integer expressions",
606  R"(
607  INITIAL {
608  LOCAL a, b
609  FROM i = (0+0) TO (1+b) BY X {
610  tau[i] = 1
611  }
612  }
613  )"
614  }
615  },
616 
617  {
618  "while_statement_1",
619  {
620  "Empty while statement",
621  R"(
622  CONSTRUCTOR {
623  WHILE (1) {
624  }
625  }
626  )"
627  }
628  },
629 
630  {
631  "while_statement_2",
632  {
633  "While statement with AND expression as condition",
634  R"(
635  CONSTRUCTOR {
636  WHILE ((a+1)<2 && b>100) {
637  x = 10
638  y = 20
639  }
640  }
641  )"
642  }
643  },
644 
645  {
646  "while_statement_3",
647  {
648  "While statement with OR expression as condition",
649  R"(
650  CONSTRUCTOR {
651  WHILE ((a+1)<=2 || b>=100) {
652  x = 10
653  y = 20
654  }
655  }
656  )"
657  }
658  },
659 
660  {
661  "while_statement_4",
662  {
663  "While statement with NE and NOT condition",
664  R"(
665  CONSTRUCTOR {
666  WHILE (a!=2 && !b) {
667  x = 10
668  y = 20
669  }
670  }
671  )"
672  }
673  },
674 
675  {
676  "if_statement_1",
677  {
678  "Empty if statement",
679  R"(
680  DESTRUCTOR {
681  IF (1) {
682  }
683  }
684  )"
685  }
686  },
687 
688  {
689  "if_else_statement_1",
690  {
691  "If else statement",
692  R"(
693  DESTRUCTOR {
694  IF ((2.1+1)<x) {
695  a = (a+1)/2.1
696  } ELSE {
697  b = (2.1+1)
698  }
699  }
700  )"
701  }
702  },
703 
704  {
705  "if_elseif_statement_1",
706  {
707  "If multiple else if statements",
708  R"(
709  FUNCTION test() {
710  IF ((2)<x) {
711  a = (a+1)/2.1
712  } ELSE IF (a<2) {
713  b = 1
714  } ELSE IF (b>2) {
715  c = 1.1
716  }
717  }
718  )"
719  }
720  },
721 
722  {
723  "if_elseif_else_statement_1",
724  {
725  "If with multiple else if nested statements",
726  R"(
727  FUNCTION test(v, x) {
728  IF (2<x) {
729  a = (a+1)
730  } ELSE IF (a<2) {
731  b = 1
732  } ELSE IF (b>2) {
733  c = 1.1
734  } ELSE {
735  IF (A) {
736  } ELSE {
737  x = 1
738  }
739  }
740  }
741  )"
742  }
743  },
744 
745  {
746  "solve_block_1",
747  {
748  "Solve statement without method",
749  R"(
750  BREAKPOINT {
751  SOLVE states
752  }
753  )"
754  }
755  },
756 
757  {
758  "solve_block_2",
759  {
760  "Solve statement with method",
761  R"(
762  BREAKPOINT {
763  SOLVE states METHOD cnexp
764  }
765  )"
766  }
767  },
768 
769  {
770  "solve_block_equation_1",
771  {
772  "Solve statement without method using EQUATION, generating BREAKPOINT",
773  R"(
774  EQUATION {
775  SOLVE states
776  }
777  )",
778 
779  R"(
780  BREAKPOINT {
781  SOLVE states
782  }
783  )"
784  }
785  },
786 
787  {
788  "solve_block_equation_2",
789  {
790  "Solve statement with method using EQUATION, generating BREAKPOINT",
791  R"(
792  EQUATION {
793  SOLVE states METHOD cnexp
794  }
795  )",
796  R"(
797  BREAKPOINT {
798  SOLVE states METHOD cnexp
799  }
800  )"
801 
802  }
803  },
804 
805  {
806  "solve_block_equation_3",
807  {
808  "Solve statement using EQUATION, generating BREAKPOINT",
809  R"(
810  EQUATION {
811  SOLVE states METHOD cnexp
812  {
813  a = 1
814  }
815  }
816  )",
817  R"(
818  BREAKPOINT {
819  SOLVE states METHOD cnexp
820  {
821  a = 1
822  }
823  }
824  )"
825  }
826  },
827 
828  {
829  "conduct_hint_1",
830  {
831  "Conductance statement",
832  R"(
833  BREAKPOINT {
834  CONDUCTANCE gIm
835  }
836  )"
837  }
838  },
839 
840  {
841  "conduct_hint_2",
842  {
843  "Conductance statement with ion name",
844  R"(
845  BREAKPOINT {
846  CONDUCTANCE gIm USEION k
847  }
848  )"
849  }
850  },
851 
852  {
853  "conserve_1",
854  {
855  "CONSERVE statement",
856  R"(
857  KINETIC ihkin {
858  CONSERVE C+o = 1
859  CONSERVE pump+pumpca = TotalPump*parea*(1e+10)
860  }
861  )"
862  }
863  },
864 
865  {
866  "compartment_1",
867  {
868  "COMPARTMENT statement",
869  R"(
870  KINETIC ihkin {
871  COMPARTMENT voli {cai}
872  COMPARTMENT diam*diam*PI/4 {qk}
873  COMPARTMENT (1e+10)*area1 {pump pumpca}
874  COMPARTMENT i, diam*diam*vol[i]*1(um) {ca CaBuffer Buffer}
875  }
876  )"
877  }
878  },
879 
880  {
881  "long_diffuse_1",
882  {
883  "LONGITUDINAL_DIFFUSION statement",
884  R"(
885  KINETIC ihkin {
886  LONGITUDINAL_DIFFUSION D {nai}
887  LONGITUDINAL_DIFFUSION Dk*crossSectionalArea {ko}
888  LONGITUDINAL_DIFFUSION i, DIP3*diam*diam*vrat[i] {bufm cabufm}
889  }
890  )"
891  }
892  },
893 
894  {
895  "reaction_1",
896  {
897  "REACTION statement",
898  R"(
899  KINETIC kstates {
900  ~ c1 <-> i1 (Con, Coff)
901  ~ ca[i] <-> ca[i+1] (DCa*frat[i+1], DCa*frat[i+1])
902  ~ ca[0] << (in*PI*diam*(0.1)*1(um))
903  ~ nai << (-f*ina*PI*diam*(10000)/(FARADAY))
904  ~ g -> (1/tau)
905  }
906  )"
907  }
908  },
909 
910  {
911  "lag_statement_1",
912  {
913  "LAG statement",
914  R"(
915  PROCEDURE lates() {
916  LAG ina BY tau
917  neo = lag_ina_tau
918  }
919  )"
920  }
921  },
922 
923  {
924  "linear_block_1",
925  {
926  "LINEAR block",
927  R"(
928  LINEAR some_name {
929  ~ I1*bi1+C2*b01-C1*(fi1+f01) = 0
930  ~ C1+C2+C3+C4+C5+O+I1+I2+I3+I4+I5+I6 = 1
931  }
932  )"
933  }
934  },
935 
936  {
937  "nonlinear_block_1",
938  {
939  "NONLINEAR block with solver for",
940  R"(
941  NONLINEAR some_name SOLVEFOR a,b {
942  ~ I1*bi1+C2*b01-C1*(fi1+f01) = 0
943  ~ C1+C2+C3+C4+C5+O+I1+I2+I3+I4+I5+I6 = 1
944  }
945  )"
946  }
947  },
948 
949  /// \todo : NONLIN1 (i.e. ~+) gets replaced with ~. This is not
950  /// a problem as ~ in NONLINEAR block gets replaced with
951  /// ~ anyway. But it would be good to keep same variable
952  /// for nmodl-format utility
953  {
954  "nonlinear_block_2",
955  {
956  "NONLINEAR block using symbol",
957  R"(
958  NONLINEAR some_name SOLVEFOR a,b {
959  ~+ I1*bi1+C2*b01-C1*(fi1+f01) = 0
960  ~+ C1+C2+C3+C4+C5+O+I1+I2+I3+I4+I5+I6 = 1
961  }
962  )",
963  R"(
964  NONLINEAR some_name SOLVEFOR a,b {
965  ~ I1*bi1+C2*b01-C1*(fi1+f01) = 0
966  ~ C1+C2+C3+C4+C5+O+I1+I2+I3+I4+I5+I6 = 1
967  }
968  )"
969  }
970  },
971 
972  {
973  "table_statement_1",
974  {
975  "TABLE statements",
976  R"(
977  PROCEDURE rates(v) {
978  TABLE RES FROM -20 TO 20 WITH 5000
979  TABLE einf,eexp,etau DEPEND dt,celsius FROM -100 TO 100 WITH 200
980  }
981  )"
982  }
983  },
984 
985  {
986  "watch_statement_1",
987  {
988  "WATCH statements",
989  R"(
990  NET_RECEIVE (w) {
991  IF (celltype == 4) {
992  WATCH (v>(vpeak-0.1*u)) 2
993  } ELSE {
994  WATCH (v>vpeak) 2
995  }
996  }
997  )"
998  }
999  },
1000 
1001  {
1002  "watch_statement_2",
1003  {
1004  "WATCH statements with multiple expressions",
1005  R"(
1006  NET_RECEIVE (w) {
1007  IF (celltype == 4) {
1008  WATCH (v>vpeak) 2,(v>vpeak) 3.4
1009  }
1010  }
1011  )"
1012  }
1013  },
1014 
1015  {
1016  "for_netcon_statement_1",
1017  {
1018  "FOR_NETCONS statement",
1019  R"(
1020  NET_RECEIVE (w(uS), A, tpre(ms)) {
1021  FOR_NETCONS (w1, A1, tp) {
1022  A1 = A1+(wmax-w1-A1)*p*exp((tp-t)/ptau)
1023  }
1024  }
1025  )"
1026  }
1027  },
1028 
1029  {
1030  "mutex_statement_1",
1031  {
1032  "MUTEX lock/unlock statements",
1033  R"(
1034  PROCEDURE fun(w, A, tpre) {
1035  MUTEXLOCK
1036  MUTEXUNLOCK
1037  }
1038  )"
1039  }
1040  },
1041 
1042  {
1043  "protect_statement_1",
1044  {
1045  "PROTECT statements",
1046  R"(
1047  INITIAL {
1048  PROTECT Rtau = 1/(Alpha+Beta)
1049  }
1050  )"
1051  }
1052  },
1053 
1054 
1055  {
1056  "nonlinear_equation",
1057  {
1058  "NONLINEAR block and equation",
1059  R"(
1060  NONLINEAR peak {
1061  ~ 1/taurise*exp(-tmax/taurise)-afast/taufast*exp(-tmax/taufast)-aslow/tauslow*exp(-tmax/tauslow) = 0
1062  }
1063  )"
1064  }
1065  },
1066 
1067  {
1068  "state_block_1",
1069  {
1070  "STATE block with variable names",
1071  R"(
1072  STATE {
1073  m
1074  h
1075  }
1076  )"
1077  }
1078  },
1079 
1080  {
1081  "state_block_2",
1082  {
1083  "STATE block with variable and associated unit",
1084  R"(
1085  STATE {
1086  a (microsiemens)
1087  g (uS)
1088  }
1089  )"
1090  }
1091  },
1092 
1093  {
1094  "kinetic_block_1",
1095  {
1096  "KINETIC block taken from mod file",
1097  R"(
1098  KINETIC kin {
1099  LOCAL qa
1100  qa = q10a^((celsius-22(degC))/10(degC))
1101  rates(v)
1102  ~ c <-> o (alpha, beta)
1103  ~ c <-> cac (kon*qa*ai/bf, koff*qa*b/bf)
1104  ~ o <-> cao (kon*qa*ai, koff*qa)
1105  ~ cac <-> cao (alphaa, betaa)
1106  CONSERVE c+cac+o+cao = 1
1107  }
1108  )"
1109  }
1110  },
1111 
1112  {
1113  "thread_safe_1",
1114  {
1115  "Theadsafe statement",
1116  R"(
1117  NEURON {
1118  THREADSAFE
1119  THREADSAFE
1120  }
1121  )"
1122  }
1123  },
1124 
1125  {
1126  "function_table_1",
1127  {
1128  "FUNCTION_TABLE example",
1129  R"(
1130  FUNCTION_TABLE tabmtau(v(mV)) (ms)
1131  )"
1132  }
1133  },
1134 
1135  {
1136  "discrete_block_1",
1137  {
1138  "DISCRETE block example",
1139  R"(
1140  DISCRETE test {
1141  x = 1
1142  }
1143  )"
1144  }
1145  },
1146 
1147  {
1148  "derivative_block_1",
1149  {
1150  "DERIVATIVE block example",
1151  R"(
1152  DERIVATIVE states {
1153  rates()
1154  m' = (mInf-m)/mTau
1155  h' = (hInf-h)/hTau
1156  }
1157  )"
1158  }
1159  },
1160 
1161  {
1162  "derivative_block_2",
1163  {
1164  "DERIVATIVE block with mixed equations",
1165  R"(
1166  DERIVATIVE states {
1167  cri' = ((cui-cri)/180-0.5*icr)/(1+Csqn*Kmcsqn/((cri+Kmcsqn)*(cri+Kmcsqn)))
1168  }
1169  )"
1170  }
1171  },
1172 
1173  {
1174  "function_1",
1175  {
1176  "FUNCTION definition with other function calls",
1177  R"(
1178  FUNCTION test(v, x) (ms) {
1179  IF (2<x) {
1180  hello(1, 2)
1181  }
1182  }
1183  )"
1184  }
1185  },
1186 
1187  {
1188  "before_block_1",
1189  {
1190  "BEFORE block example",
1191  R"(
1192  BEFORE BREAKPOINT {
1193  }
1194  )"
1195  }
1196  },
1197 
1198  {
1199  "after_block_1",
1200  {
1201  "AFTER block example",
1202  R"(
1203  AFTER STEP {
1204  x = 1
1205  }
1206  )"
1207  }
1208  },
1209 
1210  {
1211  "assignment_statement_1",
1212  {
1213  "Various assignement statement types",
1214  R"(
1215  AFTER STEP {
1216  x = 1
1217  y[1+2] = z
1218  a@1 = 12
1219  a@2[1+2] = 21.1
1220  }
1221  )"
1222  }
1223  },
1224 
1225  {
1226  "steadystate_statement_1",
1227  {
1228  "SOLVE statement using STEADYSTATE",
1229  R"(
1230  INITIAL {
1231  SOLVE kin STEADYSTATE sparse
1232  }
1233  )"
1234  }
1235  },
1236 
1237  {
1238  "netreceive_block_1",
1239  {
1240  "NET_RECEIVE block containing INITIAL block",
1241  R"(
1242  NET_RECEIVE (weight, weight_AMPA, weight_NMDA, Psurv, tsyn) {
1243  LOCAL result
1244  weight_AMPA = weight
1245  weight_NMDA = weight*NMDA_ratio
1246  INITIAL {
1247  tsyn = t
1248  }
1249  }
1250  )"
1251  }
1252  },
1253 
1254  /// \todo : support for comment parsing is not working
1255  {
1256  "inline_comment_1",
1257  {
1258  "Comments with ? or : are not handled yet",
1259  R"(
1260  ? comment here
1261  FUNCTION urand() {
1262  VERBATIM
1263  printf("Hello World!\n");
1264  ENDVERBATIM
1265  }
1266  )",
1267  R"(
1268  FUNCTION urand() {
1269  VERBATIM
1270  printf("Hello World!\n");
1271  ENDVERBATIM
1272  }
1273  )"
1274  }
1275  },
1276 
1277  {
1278  "inline_comment_2",
1279  {
1280  "Inline comments with ? or : are not handled yet",
1281  R"(
1282  FUNCTION urand() {
1283  a = b+c : some comment here
1284  c = d*e ? another comment here
1285  }
1286  )",
1287  R"(
1288  FUNCTION urand() {
1289  a = b+c
1290  c = d*e
1291  }
1292  )"
1293  }
1294  },
1295  {
1296  "empty_unit_declaration",
1297  {
1298  "Declaration with empty units",
1299  R"(
1300  FUNCTION ssCB(kdf(), kds()) (mM) {
1301  }
1302  )"
1303  }
1304  }
1305  // clang-format on
1306 };
1307 
1308 
1309 std::vector<DiffEqTestCase> const diff_eq_constructs{
1310  // clang-format off
1311 
1312  /// differential equations from BlueBrain mod files including latest V6 branch
1313 
1314  {
1315  "NaTs2_t.mod",
1316  "m' = (mInf-m)/mTau",
1317  "m = m+(1.0-exp(dt*((((-1.0)))/mTau)))*(-(((mInf))/mTau)/((((-1.0)))/mTau)-m)",
1318  "cnexp"
1319  },
1320 
1321  {
1322  "tmgExSyn.mod",
1323  "A' = -A/tau_r",
1324  "A = A+(1.0-exp(dt*((-1.0)/tau_r)))*(-(0.0)/((-1.0)/tau_r)-A)",
1325  "cnexp"
1326  },
1327 
1328  {
1329  "CaDynamics_DC0.mod",
1330  "cai' = -(10000)*ica*surftovol*gamma/(2*FARADAY) - (cai - minCai)/decay",
1331  "cai = cai+(1.0-exp(dt*((-((1.0))/decay))))*(-(((((-(10000))*(ica))*(surftovol))*(gamma))/(2*FARADAY)-(((-minCai)))/decay)/((-((1.0))/decay))-cai)",
1332  "cnexp"
1333  },
1334 
1335  {
1336  "CaDynamics_DC1.mod",
1337  "cai' = -(10000)*ica*surftovol*gamma/(2*FARADAY) - (cai - minCai)/decay * diamref * surftovol",
1338  "cai = cai+(1.0-exp(dt*((-((((1.0))/decay)*(diamref))*(surftovol)))))*(-(((((-(10000))*(ica))*(surftovol))*(gamma))/(2*FARADAY)-(((((-minCai)))/decay)*(diamref))*(surftovol))/((-((((1.0))/decay)*(diamref))*(surftovol)))-cai)",
1339  "cnexp"
1340  },
1341 
1342  {
1343  "DetAMPANMDA.mod",
1344  "A_AMPA' = -A_AMPA/tau_r_AMPA",
1345  "A_AMPA = A_AMPA+(1.0-exp(dt*((-1.0)/tau_r_AMPA)))*(-(0.0)/((-1.0)/tau_r_AMPA)-A_AMPA)",
1346  "cnexp"
1347  },
1348 
1349  {
1350  "StochKv.mod",
1351  "n' = a - (a + b)*n",
1352  "n = n+(1.0-exp(dt*((-((a+b))*(1.0)))))*(-(a)/((-((a+b))*(1.0)))-n)",
1353  "cnexp"
1354  },
1355 
1356  {
1357  "StochKv2.mod",
1358  "l' = al - (al + bl)*l",
1359  "l = l+(1.0-exp(dt*((-((al+bl))*(1.0)))))*(-(al)/((-((al+bl))*(1.0)))-l)",
1360  "cnexp"
1361  },
1362 
1363  {
1364  "_calcium.mod",
1365  "mcal' = ((inf-mcal)/tau)",
1366  "mcal = mcal+(1.0-exp(dt*(((((-1.0)))/tau))))*(-((((inf))/tau))/(((((-1.0)))/tau))-mcal)",
1367  "cnexp"
1368  },
1369 
1370  {
1371  "_calciumc_concentration.mod",
1372  "cai' = -(ica*surftovol/FARADAY) - cai/decay",
1373  "cai = cai+(1.0-exp(dt*((-(1.0)/decay))))*(-(-(((ica)*(surftovol))/FARADAY))/((-(1.0)/decay))-cai)",
1374  "cnexp"
1375  },
1376 
1377  {
1378  "_outside_calcium_concentration.mod",
1379  "cao' = ica*(1e8)/(fhspace*FARADAY) + (cabath-cao)/trans",
1380  "cao = cao+(1.0-exp(dt*((((-1.0)))/trans)))*(-(((ica)*((1e8)))/(fhspace*FARADAY)+((cabath))/trans)/((((-1.0)))/trans)-cao)",
1381  "cnexp"
1382  },
1383 
1384 
1385  /// glusynapse.mod for plasticity simulations
1386 
1387 
1388  /// using cnexp method
1389 
1390  {
1391  "GluSynapse.mod",
1392  "A_AMPA' = -A_AMPA/tau_r_AMPA",
1393  "A_AMPA = A_AMPA+(1.0-exp(dt*((-1.0)/tau_r_AMPA)))*(-(0.0)/((-1.0)/tau_r_AMPA)-A_AMPA)",
1394  "cnexp"
1395  },
1396 
1397  {
1398  "GluSynapse.mod",
1399  "m_VDCC' = (minf_VDCC-m_VDCC)/mtau_VDCC",
1400  "m_VDCC = m_VDCC+(1.0-exp(dt*((((-1.0)))/mtau_VDCC)))*(-(((minf_VDCC))/mtau_VDCC)/((((-1.0)))/mtau_VDCC)-m_VDCC)",
1401  "cnexp"
1402  },
1403 
1404  {
1405  "GluSynapse.mod",
1406  "cai_CR' = -(1e-9)*(ica_NMDA + ica_VDCC)*gamma_ca_CR/((1e-15)*volume_CR*2*FARADAY) - (cai_CR - min_ca_CR)/tau_ca_CR",
1407  "cai_CR = cai_CR+(1.0-exp(dt*((-((1.0))/tau_ca_CR))))*(-((((-(1e-9))*((ica_NMDA+ica_VDCC)))*(gamma_ca_CR))/((1e-15)*volume_CR*2*FARADAY)-(((-min_ca_CR)))/tau_ca_CR)/((-((1.0))/tau_ca_CR))-cai_CR)",
1408  "cnexp"
1409  },
1410 
1411  {
1412  "GluSynapse.mod",
1413  "effcai_GB' = -0.005*effcai_GB + (cai_CR - min_ca_CR)",
1414  "effcai_GB = effcai_GB+(1.0-exp(dt*((-0.005)*(1.0))))*(-((cai_CR-min_ca_CR))/((-0.005)*(1.0))-effcai_GB)",
1415  "cnexp"
1416  },
1417 
1418  {
1419  "GluSynapse.mod",
1420  "Rho_GB' = ( - Rho_GB*(1-Rho_GB)*(rho_star_GB-Rho_GB) + potentiate_GB*gamma_p_GB*(1-Rho_GB) - depress_GB* gamma_d_GB*Rho_GB ) / ((1e3)*tau_GB)",
1421  "Rho_GB = Rho_GB+(1.0-exp(dt*(((((((-1.0)*((1-Rho_GB))+(-Rho_GB)*(((-1.0)))))*((rho_star_GB-Rho_GB))+(-Rho_GB*(1-Rho_GB))*(((-1.0))))+(potentiate_GB*gamma_p_GB)*(((-1.0)))-(depress_GB*gamma_d_GB)*(1.0)))/((1e3)*tau_GB))))*(-Rho_GB)",
1422  "cnexp"
1423  },
1424 
1425  {
1426  "GluSynapse.mod",
1427  "Use_GB' = (Use_d_GB + Rho_GB*(Use_p_GB-Use_d_GB) - Use_GB) / ((1e3)*tau_Use_GB)",
1428  "Use_GB = Use_GB+(1.0-exp(dt*((((-1.0)))/((1e3)*tau_Use_GB))))*(-(((Use_d_GB+(Rho_GB)*((Use_p_GB-Use_d_GB))))/((1e3)*tau_Use_GB))/((((-1.0)))/((1e3)*tau_Use_GB))-Use_GB)",
1429  "cnexp"
1430  },
1431 
1432  /// some made-up examples to test cnexp solver implementation
1433 
1434  {
1435  "GluSynapse.mod",
1436  "A_AMPA' = fun(tau_r_AMPA)",
1437  "A_AMPA = A_AMPA-dt*(-(fun(tau_r_AMPA)))",
1438  "cnexp"
1439  },
1440 
1441  {
1442  "GluSynapse.mod",
1443  "A_AMPA' = fun(tau_r_AMPA, B_AMPA) + B_AMPA",
1444  "A_AMPA = A_AMPA-dt*(-(fun(tau_r_AMPA,B_AMPA)+B_AMPA))",
1445  "cnexp"
1446  },
1447 
1448  {
1449  "GluSynapse.mod",
1450  "A_AMPA' = tau_r_AMPA/A_AMPA",
1451  "DA_AMPA = DA_AMPA/(1.0-dt*(((tau_r_AMPA/(A_AMPA+0.001))-(tau_r_AMPA/A_AMPA))/0.001))",
1452  "cnexp"
1453  },
1454 
1455  {
1456  "GluSynapse.mod",
1457  "A_AMPA' = A_AMPA*A_AMPA",
1458  "A_AMPA = A_AMPA+(1.0-exp(dt*(((1.0)*(A_AMPA)+(A_AMPA)*(1.0)))))*(-A_AMPA)",
1459  "cnexp"
1460  },
1461 
1462  {
1463  "GluSynapse.mod",
1464  "A_AMPA' = tau_r_AMPA/A_AMPA",
1465  "DA_AMPA = DA_AMPA/(1.0-dt*(((tau_r_AMPA/(A_AMPA+0.001))-(tau_r_AMPA/A_AMPA))/0.001))",
1466  "derivimplicit"
1467  },
1468 
1469  {
1470  "GluSynapse.mod",
1471  "A_AMPA' = A_AMPA*A_AMPA",
1472  "DA_AMPA = A_AMPA*A_AMPA",
1473  "euler"
1474  },
1475 
1476 
1477  /// using derivimplicit method
1478  /// note that the equation in state block gets changed by replacing state variable with Dstate.
1479  /// below expressions are from ode_matsol1 method
1480 
1481  {
1482  "GluSynapse.mod",
1483  "A_AMPA' = -A_AMPA/tau_r_AMPA",
1484  "DA_AMPA = DA_AMPA/(1.0-dt*((-1.0)/tau_r_AMPA))",
1485  "derivimplicit"
1486  },
1487 
1488  {
1489  "GluSynapse.mod",
1490  "m_VDCC' = (minf_VDCC-m_VDCC)/mtau_VDCC",
1491  "Dm_VDCC = Dm_VDCC/(1.0-dt*((((-1.0)))/mtau_VDCC))",
1492  "derivimplicit"
1493  },
1494 
1495  {
1496  "GluSynapse.mod",
1497  "cai_CR' = -(1e-9)*(ica_NMDA + ica_VDCC)*gamma_ca_CR/((1e-15)*volume_CR*2*FARADAY) - (cai_CR - min_ca_CR)/tau_ca_CR",
1498  "Dcai_CR = Dcai_CR/(1.0-dt*((-((1.0))/tau_ca_CR)))",
1499  "derivimplicit"
1500  },
1501 
1502  {
1503  "GluSynapse.mod",
1504  "effcai_GB' = -0.005*effcai_GB + (cai_CR - min_ca_CR)",
1505  "Deffcai_GB = Deffcai_GB/(1.0-dt*((-0.005)*(1.0)))",
1506  "derivimplicit"
1507  },
1508 
1509  {
1510  "GluSynapse.mod",
1511  "Rho_GB' = ( - Rho_GB*(1-Rho_GB)*(rho_star_GB-Rho_GB) + potentiate_GB*gamma_p_GB*(1-Rho_GB) - depress_GB*gamma_d_GB*Rho_GB ) / ((1e3)*tau_GB)",
1512  "DRho_GB = DRho_GB/(1.0-dt*(((((((-1.0)*((1-Rho_GB))+(-Rho_GB)*(((-1.0)))))*((rho_star_GB-Rho_GB))+(-Rho_GB*(1-Rho_GB))*(((-1.0))))+(potentiate_GB*gamma_p_GB)*(((-1.0)))-(depress_GB*gamma_d_GB)*(1.0)))/((1e3)*tau_GB)))",
1513  "derivimplicit"
1514  },
1515 
1516  {
1517  "GluSynapse.mod",
1518  "Use_GB' = (Use_d_GB + Rho_GB*(Use_p_GB-Use_d_GB) - Use_GB) / ((1e3)*tau_Use_GB)",
1519  "DUse_GB = DUse_GB/(1.0-dt*((((-1.0)))/((1e3)*tau_Use_GB)))",
1520  "derivimplicit"
1521  },
1522 
1523 
1524  /// using euler method : solutions are same as derivimplicit method
1525 
1526  {
1527  "GluSynapse.mod",
1528  "A_AMPA' = -A_AMPA/tau_r_AMPA",
1529  "DA_AMPA = -A_AMPA/tau_r_AMPA",
1530  "euler"
1531  },
1532 
1533  {
1534  "GluSynapse.mod",
1535  "m_VDCC' = (minf_VDCC-m_VDCC)/mtau_VDCC",
1536  "Dm_VDCC = (minf_VDCC-m_VDCC)/mtau_VDCC",
1537  "euler"
1538  },
1539 
1540  {
1541  "GluSynapse.mod",
1542  "cai_CR' = -(1e-9)*(ica_NMDA + ica_VDCC)*gamma_ca_CR/((1e-15)*volume_CR*2*FARADAY) - (cai_CR - min_ca_CR)/tau_ca_CR",
1543  "Dcai_CR = -(1e-9)*(ica_NMDA + ica_VDCC)*gamma_ca_CR/((1e-15)*volume_CR*2*FARADAY) - (cai_CR - min_ca_CR)/tau_ca_CR",
1544  "euler"
1545  },
1546 
1547  {
1548  "GluSynapse.mod",
1549  "effcai_GB' = -0.005*effcai_GB + (cai_CR - min_ca_CR)",
1550  "Deffcai_GB = -0.005*effcai_GB + (cai_CR - min_ca_CR)",
1551  "euler"
1552  },
1553 
1554  {
1555  "GluSynapse.mod",
1556  "Rho_GB' = ( - Rho_GB*(1-Rho_GB)*(rho_star_GB-Rho_GB) + potentiate_GB*gamma_p_GB*(1-Rho_GB) - depress_GB*gamma_d_GB*Rho_GB ) / ((1e3)*tau_GB)",
1557  "DRho_GB = ( - Rho_GB*(1-Rho_GB)*(rho_star_GB-Rho_GB) + potentiate_GB*gamma_p_GB*(1-Rho_GB) - depress_GB*gamma_d_GB*Rho_GB ) / ((1e3)*tau_GB)",
1558  "euler"
1559  },
1560 
1561  {
1562  "GluSynapse.mod",
1563  "Use_GB' = (Use_d_GB + Rho_GB*(Use_p_GB-Use_d_GB) - Use_GB) / ((1e3)*tau_Use_GB)",
1564  "DUse_GB = (Use_d_GB + Rho_GB*(Use_p_GB-Use_d_GB) - Use_GB) / ((1e3)*tau_Use_GB)",
1565  "euler"
1566  },
1567 
1568 
1569  /// equations of nonlinear from taken from nocmodlx/test/input/usecases/nonlinear
1570  /// using derivimplicit and euler method
1571 
1572  {
1573  "wc.mod",
1574  "uu' = -uu+f(aee*uu-aie*vv-ze+i_e)",
1575  "Duu = Duu/(1.0-dt*(((-(uu+0.001)+f(aee*(uu+0.001)-aie*vv-ze+i_e))-(-uu+f(aee*uu-aie*vv-ze+i_e)))/0.001))",
1576  "derivimplicit"
1577  },
1578 
1579  {
1580  "wc.mod",
1581  "vv' = (-vv+f(aei*uu-aii*vv-zi+i_i))/tau",
1582  "Dvv = Dvv/(1.0-dt*((((-(vv+0.001)+f(aei*uu-aii*(vv+0.001)-zi+i_i))/tau)-((-vv+f(aei*uu-aii*vv-zi+i_i))/tau))/0.001))",
1583  "derivimplicit"
1584  },
1585 
1586  {
1587  "ER.mod",
1588  "caer' = -(0.001)*( Jip3(cali,caer, ip3ip, Vip3, dact, dinh, dip3, ddis)+errel(cali,caer,kerrel,kerm)-erfil(cali,caer,kerfila,kerfilb)+erlek(cali,caer,kerlek))/(rhover/fer)",
1589  "Dcaer = Dcaer/(1.0-dt*(((-(0.001)*(Jip3(cali,(caer+0.001),ip3ip,Vip3,dact,dinh,dip3,ddis)+errel(cali,(caer+0.001),kerrel,kerm)-erfil(cali,(caer+0.001),kerfila,kerfilb)+erlek(cali,(caer+0.001),kerlek))/(rhover/fer))-(-(0.001)*(Jip3(cali,caer,ip3ip,Vip3,dact,dinh,dip3,ddis)+errel(cali,caer,kerrel,kerm)-erfil(cali,caer,kerfila,kerfilb)+erlek(cali,caer,kerlek))/(rhover/fer)))/0.001))",
1590  "derivimplicit"
1591  },
1592 
1593  {
1594  "ER.mod",
1595  "Jip3h' = (Jip3hinf(ip3ip, cali, dinh, dip3, ddis)-Jip3h)/Jip3th(ip3ip, ainh, cali, dinh, dip3, ddis)",
1596  "DJip3h = DJip3h/(1.0-dt*((((-1.0)))/Jip3th(ip3ip,ainh,cali,dinh,dip3,ddis)))",
1597  "derivimplicit"
1598  },
1599 
1600  {
1601  "gr_ltp1.mod",
1602  "messenger' = -gamma*picanmda - eta*messenger",
1603  "Dmessenger = Dmessenger/(1.0-dt*((-(eta)*(1.0))))",
1604  "derivimplicit"
1605  },
1606 
1607  {
1608  "gr_ltp1.mod",
1609  "Np' = nu1*messenger - (pp - picanmda*gdel1)*Np +(Mp*Np*Np)/(Ap+Np*Np)",
1610  "DNp = DNp/(1.0-dt*(((nu1*messenger-(pp-picanmda*gdel1)*(Np+0.001)+(Mp*(Np+0.001)*(Np+0.001))/(Ap+(Np+0.001)*(Np+0.001)))-(nu1*messenger-(pp-picanmda*gdel1)*Np+(Mp*Np*Np)/(Ap+Np*Np)))/0.001))",
1611  "derivimplicit"
1612  },
1613 
1614  {
1615  "cajsracc.mod",
1616  "cri' = ((cui - cri)/180 - 0.5*icr)/(1 + Csqn*Kmcsqn/((cri + Kmcsqn)*(cri + Kmcsqn)))",
1617  "Dcri = Dcri/(1.0-dt*(((((cui-(cri+0.001))/180-0.5*icr)/(1+Csqn*Kmcsqn/(((cri+0.001)+Kmcsqn)*((cri+0.001)+Kmcsqn))))-(((cui-cri)/180-0.5*icr)/(1+Csqn*Kmcsqn/((cri+Kmcsqn)*(cri+Kmcsqn)))))/0.001))",
1618  "derivimplicit"
1619  },
1620 
1621  {
1622  "syn_bip_gan.mod",
1623  "s' = (s_inf-s)/((1-s_inf)*tau*s)",
1624  "Ds = (s_inf-s)/((1-s_inf)*tau*s)",
1625  "euler"
1626  },
1627 
1628  {
1629  "syn_rod_bip.mod",
1630  "s' = (s_inf-s)/((1-s_inf)*tau*s)",
1631  "Ds = (s_inf-s)/((1-s_inf)*tau*s)",
1632  "euler"
1633  },
1634 
1635  // clang-format on
1636 };
1637 
1638 } // namespace test_utils
1639 } // namespace nmodl
nmodl::test_utils::nmodl_valid_constructs
const std::map< std::string, NmodlTestCase > nmodl_valid_constructs
Definition: nmodl_constructs.cpp:181
nmodl
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
nmodl::test_utils::diff_eq_constructs
const std::vector< DiffEqTestCase > diff_eq_constructs
Definition: nmodl_constructs.cpp:1309
nmodl::test_utils::nmodl_invalid_constructs
const std::map< std::string, NmodlTestCase > nmodl_invalid_constructs
Guidelines for adding nmodl text constructs.
Definition: nmodl_constructs.cpp:63
nmodl_constructs.hpp