1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998
|
.. _hoc_nmodl:
NMODL
-----
This document describes how to use the NBSR model description language
to add membrane mechanisms to NEURON.
NEURON's extensions to the NBSR language are described in:
.. toctree:: :maxdepth: 1
nmodl2.rst
.. _hoc_modeldescriptionlanguage:
Model Description Language
==========================
Introduction
~~~~~~~~~~~~
The kinds of mechanisms that can
be added are:
- Channels in which the model consists of current-voltage relationships.
- Calculation of internal and external
ionic concentration changes due to currents carried
by specific ions.
Many user defined mechanisms can be simultaneously "insert"ed into
sections in NEURON; NEURON will keep track of the total current for
each ionic species used and the effect of that current on the membrane
potential. For example, suppose a calcium pump, sodium-calcium exchanger,
calcium channel, radial calcium diffusion, and calcium activated potassium
mechanisms are inserted into a cable section. Then the total calcium current
is calculated
as the sum of the individual currents from the calcium pump, exchanger,
and channel. The internal calcium concentration just under the membrane
is calculated from the total calcium current and diffusion away from the
surface.
The potassium current through the cagk channel is calculated
from the internal calcium concentration next to the membrane and the
membrane potential. And the membrane potential is calculated from the
total current. (The above is only a partial list of the interactions
among these channels. The point is that the ionic current, membrane voltage,
and concentration computations are consistent regardless of the channels
inserted into the cable section.)
Mechanisms are normally *local*. That is they do not depend on
what is happening at other places on the neuron.
However, a method exists for writing mechanisms that depend on variables of
mechanisms at other locations. For example
the calcium concentration at a presynaptic
mechanism can be used to calculate the conductance change at a postsynaptic
mechanism. (See, Importing variables from other mechanisms.)
Also, FUNCTION's written in a model are global and may be used in other
models if they do not involve range variables.
History
"""""""
MODL (model description language) was originally developed at
the NBSR (National Biomedical Simulation
Resource) to specify models for simulation with SCoP (Simulation Control
Program). With MODL one specifies a physical model in terms of
simultaneous nonlinear algebraic equations, differential equations, or
kinetic schemes. MODL translates the specification into the C language
which is then compiled and linked with the SCoP program. It turned out
that only modest extensions to the MODL syntax were necessary to
allow it to translate
model descriptions into a form suitable for compiling and linking
with NEURON V2. The extended version was called NMODL. In NEURON V3
the advent of the object oriented interpreter, OC, allowed Point Processes to
be treated as objects instead of parallel arrays of variables. The
model description translator that emits code suitable for NEURON V3 is
called NOCMODL. NMODL and NOCMODL handle identical input model descriptions,
they differ merely in the output interface code. A prototype model description
translator has been written to generate code suitable for linking with GENESIS.
This document discusses only the differences between NMODL and MODL.
A complete user manual for the standard model description language is
available from NBSR. A brief description of MODL is in the document entitled,
"SCoP Language Summary".
Usage
"""""
The easiest way to write membrane mechanisms is by analogy with the
examples. The example files come in pairs with a .mod and .hoc extension.
Models (membrane mechanisms) are linked into neuron with the command:
.. code-block::
none
nrnivmodl file1 file2 file3 ...
In the list of :file:`.mod` files you do *not* type the extension, only the prefix.
If there are no files specified then nrnivmodl will use all the
mod files in the current working directory. When :program:`nrnivmodl` is finished, there
will exist a version of NEURON called :program:`special` which contains those
membrane mechanisms described in the files. :file:`special` should be renamed
to something more suitable. The associated :file:`.hoc` files can be executed by
:program:`special` to test various aspects of the models.
It is extremely important that mechanisms have consistent units. To ensure
this use the command:
.. code-block::
none
modlunit file
leaving off the file extension. For more information about units click here.
Rationale
"""""""""
Our first nerve simulation program, :program:`CABLE`, contained several built-in
membrane mechanisms, including radial calcium diffusion, calcium channel,
calcium activated potassium channel, calcium pump, etc. However, in practice,
only the Hodgkin-Huxley squid channels were enough of a standard to be used
"as is" across more than one series of simulations. The other channels
all required some type of modification to be useful as new situations arose.
Sometimes the modifications were minor, such as changing the coordinate
system for radial calcium diffusion so that there were more compartments
near the membrane, but often we were forced to add an entirely new
mechanism from scratch such as Frankenhaeuser-Huxley channels for
Xenopus node. The problem was greatly compounded for other users of
CABLE who needed to add new channels but were not familiar with the numerical
issues or the detailed interface requirements. NMODL with NEURON
is a significant improvement over CABLE with regard to adding new membrane
mechanisms:
- Interface details are handled automatically.
- Consistency of units is ensured. (By checking with modlunit.)
- Mechanisms described by a kinetic scheme are written with a syntax
in which the reactions are clearly apparent.
- There is often a great increase in clarity since statements are
directly related to discourse at the model level instead of the C
programming level.
- The high level description language often provides a great deal
of leverage in that one model statement can get translated into very
many C statements. For example, kinetic reaction statements get translated
into statements which explicitly calculate sparse
jacobian matrix coefficients.
At the same time, since the model description is translated into C, the
computation speed remains the same or better than a hand coded mechanism
in CABLE.
General Paradigm
~~~~~~~~~~~~~~~~
Membrane mechanisms deal with currents, concentrations,
potentials, and state variables
and it is helpful to know how NEURON treats these variables in order to
correctly write a new membrane mechanism.
NEURON integrates its equations using the function :hoc:func:`fadvance`.
During a call to this function the value of the global time variable, :hoc:data:`t`,
is increased by the value of :hoc:data:`dt` ``(t = t + dt)``,
and all the voltages, currents,
concentrations, etc. are changed to new values appropriate to the new
value of time. The default numerical method used by NEURON produces
values which have an error proportional to :hoc:data:`dt`. That is, it makes
no sense to ask at what time in the interval are the values most accurate.
However, by setting the global variable
:hoc:data:`secondorder` equal to 2, the values produced by ``fadvance`` have
errors proportional to ``dt^2`` and it is important to realize that
- membrane potential is second order correct at time, :hoc:data:`t`.
- currents are second order correct at time, ``t - dt/2``.
- channel states are second order correct at time, ``t + dt/2``;.
- concentrations are second order correct at time, :hoc:data:`t`.
:hoc:func:`fadvance` goes about its business by first setting up the current
conservation matrix equation to be used in the calculation of membrane
potential. To do this it calls the current functions for each mechanism
in each segment which compute conductance using the old values of states
and current using the old values of states and membrane potential.
The value of time when the BREAKPOINT block is called is t+dt/2 so models
which depend explicitly on time will be second order correct if they use
the value of :hoc:data:`t`.
:hoc:func:`fadvance` then solves the matrix equation for the new value of the membrane
potential. Depending on the value of :hoc:data:`secondorder` it then
may re-call these current functions with the average of the new and old
membrane potentials to get an accurate final value of the current.
It then calls the state integrator functions using the new
value of the membrane potential and the second order correct currents
to calculate the new values of the states. The details of this method
can be gleaned from the file :file:`nrn/src/nrnoc/fadvance.c`.
It is therefore necessary for NMODL to divide up the statements properly
into a current function and a state function. It also has to create
the interface between model variables and NEURON and create a memory
allocation function so that segments have separate copies of each variable.
Finally, it has to make sure that local model currents get added to the
correct global ionic currents.
Note: This simulation method is very effective and
highly efficient when currents depend on
membrane potential and ionic concentrations do not change on the
same time scale as the membrane potential. When these conditions
are not met, however, such as in a calcium pump mechanism in which
the current depends on the concentrations of calcium next to the
membrane, one must be careful to use a ``dt`` small enough to
prevent the occurrence of numerical instabilities. (Or else using a single
model to describe both the pump current and that current's effect on concentration
so that the concentrations and pump states may be computed simultaneously.
An example of such a model is in nrn/demo/release/cabpump.mod)
A future version of
NEURON will have the option (slightly less efficient) of calculating
all state variables simultaneously so that numerical stability is
guaranteed.
Further discussion of the numerical methods used by NEURON are found
here.
Basic NMODL Statements
~~~~~~~~~~~~~~~~~~~~~~
Only a small part of the full model description language is relevant to
neuron mechanisms. The important concepts held in common are
the declaration of all variables as
TITLE
"""""
Description:
Title of the mechanism. Doesn't play any role to the code generation.
COMMENT
"""""""
Description:
Comments of the code. ``COMMENT`` blocks start with ``COMMENT`` and end with ``ENDCOMMENT``.
For example:
.. code-block::
none
COMMENT
Some text here.
ENDCOMMENT
Single line comments can be added to the mod file also with ``:`` or ``?``.
For example:
.. code-block::
none
NEURON {
: This is a single line comment
? This is a single line comment as well
GLOBAL a
}
DEFINE
""""""
Description:
Defines an integer macro variable. The name of the variable can be used in the rest of the mod
file and its name will be replaced by its value during parsing of the mod file. Syntax is:
.. code-block::
none
DEFINE <variable_name> <integer_value>
UNITS
"""""
Description:
The statements in the UNITS block define new names for units in terms of existing names in
the UNIX units database. This can increase legibility and convenience, and is helpful both as a
reminder to the user and as a means for automating the process of checking for consistency of
units.
The UNIX units database taken into account is defined in the `nrnunits.lib file <https://github.com/neuronsimulator/nrn/blob/master/share/lib/nrnunits.lib.in>`_.
This file includes two versions of the units due to the updates in the values of their base
units. Currently there are legacy and modern units that contain the changes after the updates
introduced on 2019 to the nist constants. The selection between those two versions can be done
using the ``NRN_DYNAMIC_UNITS_USE_LEGACY`` CMake variable or a call to
``h.nrnunit_use_legacy(bool)`` during runtime.
New units can be defined in terms of default units and previously defined units by placing
definitions in the UNITS block. e.g.
.. code-block::
none
UNITS {
(uF) = (microfarad)
(Mohms) = (megohms)
(V) = (volt)
(molar) = (/liter)
(mM) = (millimolar)
}
and it is more convenient to define ``CONSTANT`` constants in the UNITS block rather than in the
``CONSTANTS`` block --- there is less chance of a typo, and they do not appear in SCoP where
they can be inadvertently changed.
For example:
.. code-block::
none
UNITS {
F = (faraday) (coulomb)
PI = (pi) (1)
e = (e) (coulomb)
R = (k-mole) (joule/degC)
C = (c) (cm/sec)
}
Here, ``C`` is the speed of light in cm/sec and ``R`` is the Gas constant.
Constant factors are defined in the UNITS block in the following manner.
.. code-block::
none
UNITS {
F = 96520 (coul)
PI = 3.14159 ()
foot2inch = 12 (inch/foot)
}
``TODO``: Add existing example mod file
.. _hoc_nmodl_parameter:
PARAMETER
"""""""""
Description:
These are variables which are set by
the user
and not changed by the model itself. In a NEURON context some of these
parameters need to be range variables which can vary with position and some
are more useful as global variables. Special variables to NEURON such as
:hoc:data:`celsius`, :hoc:data:`area`, :hoc:data:`v`, etc. if used in a model
should be declared as
parameters. (and you should not assign values to them in the model).
Ionic concentrations, currents, and potentials
that are used but not set
in this particular model should be declared as parameters.
NMODL does not enforce the "constantness" of parameters but stylistically
it is a good rule to follow since there is a special field editor widget in NEURON's
graphical user interface which makes it easier to modify a PARAMETER's value.
There is an unfortunate restriction on PARAMETER's in that they cannot declare
arrays. Even if an array is conceptually a PARAMETER, it must be declared
as an ASSIGNED variable. In NMODL, PARAMETERS and ASSIGNED variables are
practically synonyms. They substantively differ only in that when a
panel of variables is automatically created, PARAMETERS are displayed in
augmented field editors which make it easier to change values whereas ASSIGNED
variables are displayed in field editors in which the only way to change the
value is to type it from the keyboard. (see :hoc:func:`xvalue`).
STATE
"""""
Description:
These are variables which are the unknowns in differential
and algebraic equations.
They are normally the variables to be "SOLVE"ed for within the
BREAKPOINT block.
For example, in HH channels the states are m, h, and n.
In a NEURON context they are always range variables.
Ionic concentration is a state only if the concentration is being
calculated within that specific model (mechanism). ERRORS in the simulation
would occur if concentrations were computed in more than one mechanism inserted
at the same location. Membrane potential, ``v``, is *never*
a state since
only NEURON itself is allowed to calculate that value.
ASSIGNED
""""""""
Description:
These are variables which can be computed directly
by assignment statements and are important enough that you may wish
to know their value during a simulation. In a NEURON context you will wish
to divide them between range variables and global variables.
CONSTANT
""""""""
Description:
These are variables that cannot be changed during the simulation. Better to use ``UNITS`` to
define those variables.
LOCAL
"""""
Description:
These are equivalent to C static variables ie shared
between all instances of a given mechanism.
INDEPENDENT
"""""""""""
Description:
This specifies the mathematical independent variable.
For NMODL this statement is unnecessary since the independent variable
is always time, :hoc:data:`t`.
POINTER
"""""""
Basically what is needed is a way to implement the hoc statement
.. code-block::
none
section1.var1_mech1(x1) = section2.var2_mech2(x2)
efficiently from within a mechanism without having to explicitly connect them
through assignment at the HOC level everytime the :samp:`{var2}` might change.
First of all, the variables which point to the values in some other mechanism
are declared within the NEURON block via
.. code-block::
none
NEURON {
POINTER var1, var2, ...
}
These variables are used exactly like normal variables in the sense that
they can be used on the left or right hand side of assignment statements
and used as arguments in function calls. They can also be accessed from HOC
just like normal variables.
It is essential that the user set up the pointers to point to the correct
variables. This is done by first making sure that the proper mechanisms
are inserted into the sections and the proper point processes are actually
"located" in a section. Then, at the hoc level each POINTER variable
that exists should be set up via the command:
.. code-block::
none
setpointer pointer, variable
where pointer and variable have enough implicit/explicit information to
determine their exact segment and mechanism location. For a continuous
mechanism, this means the section and location information. For a point
process it means the object. The variable may also be any hoc variable
or voltage, v.
For example, consider a synapse which requires a presynaptic potential
in order to calculate the amount of transmitter release. Assume the
declaration in the presynaptic model
.. code-block::
none
NEURON { POINTPROCESS Syn POINTER vpre }
Then
.. code-block::
none
objref syn
somedendrite {syn = new Syn(.8)}
setpointer syn.vpre, axon.v(1)
will allow the syn object to know the voltage at the distal end of the axon
section. As a variation on that example, if one supposed that the synapse
needed the presynaptic transmitter concentration (call it tpre) calculated
from a point process model called "release" (with object reference
rel, say) then the
statement would be
.. code-block::
none
setpointer syn.tpre, rel.AcH_release
The caveat is that tight coupling between states in different models
may cause numerical instability. When this happens,
merging models into one larger
model may eliminate the instability, unless the model is so simple that time
does not appear, such as a passive channel. In that case, ``v`` is normally
chosen as the independent variable. MODL required this statement but NMODL
will implicitly generate one for you.
When currents and ionic potentials are calculated in a particular model they
are declared either as STATE, or ASSIGNED depending on the nature
of the calculation or whether they are important enough to save. If a variable
value needs to persist only between entry and exit of an instance
one may declare it as LOCAL, but in that case the model cannot be vectorized
and different instances cannot be called in parallel.
INCLUDE
"""""""
Description:
The INCLUDE statement replaces itself with the contents of the indicated file.
eg.
.. code-block::
none
INCLUDE "units.inc"
If the full path to the file is not given, the file is first looked
for in the current working directory, then in the directory where the
original .mod file was located,
and then
in the directories specified by the colon separated list in the
environment variable MODL_INCLUDES. Notice that the INCLUDE filename
explicitly requires a complete file name --- don't leave off the
suffix, if any.
Note that if one is redefined in the included file or the file that includes
another one, then the generated code has the corresponding code to both blocks with the order of
their inclusion.
``TODO``: Add existing example mod file
Other blocks which play similar roles in NMODL and MODL are
BREAKPOINT
""""""""""
Description:
This is the main computation block of the model. Any
states are integrated by a SOLVE statement. Currents are set with
assignment statements at the end of this block. Think of this block
as making sure that on exit, all variables are consistent at time, :hoc:data:`t`.
The reason this block is named BREAKPOINT is because in SCoP it was
called for each value of the INDEPENDENT variable at which the user desired
to plot something. It was responsible for making all variables consistent
at that value of the INDEPENDENT variable (which usually required integrating
states from their values at the previous call using SOLVE statements).
In NMODL, this block is usually called twice every time step (with voltage
equal to v+.001 and voltage equal to v) in order to
calculate the conductance from the currents. Often, errors result if one
computes values for states in this block. All states depending explicitly or
implicitly on time should
only be changed in a block called by a SOLVE statement.
DERIVATIVE
""""""""""
Description:
If the states are governed by differential equations,
this block is used to assign values to the derivatives of the states.
Such statements are of the form :samp:`y' = {expr}`. These equations
are normally integrated from the old values of the states to
their new values at time, :hoc:data:`t`, via a SOLVE statement in the BREAKPOINT block.
The expression may explicitly involve time. The SOLVE statement for a DERIVATIVE
block should explicitly invoke either
.. code-block::
none
SOLVE deriv METHOD euler
or
SOLVE deriv METHOD runge
or
SOLVE deriv METHOD derivimplicit
because the default integration method
is a variable time step runge-kutta method which cannot work in a NEURON context.
The first two methods above are computationally cheap but are
numerically unstable when equations are stiff (states vary a lot within
a :hoc:data:`dt` step).
HH type mechanisms have state equations which are particularly
simple and extra efficiency and accuracy is easily obtained by integrating
the states analytically. The :file:`hh2.mod` example shows how to do this.
NET_RECEIVE
"""""""""""
Description:
The NET_RECEIVE block is called by the NetCon event delivery system when an event arrives at
this postsynaptic point process.
For example:
.. code-block::
none
STATE { g (microsiemens) }
NET_RECEIVE(weight (microsiemens)) {
g = g + weight
}
In this case the value of the weight is specified by the particular NetCon object delivering the
event, and this value increments the conductance state.
``TODO``: Add existing example mod file
WATCH
~~~~~
Description:
``TODO``: Add description and existing example mod file
CONSTRUCTOR
"""""""""""
Description:
``TODO``: Add description and existing example mod file
DESTRUCTOR
""""""""""
Description:
``TODO``: Add description and existing example mod file
LINEAR
""""""
Description:
``TODO``: Add description and existing example mod file
NONLINEAR
"""""""""
Description:
This block solves simultaneous equations in the form
of a list of statements with the syntax,
.. code-block::
none
~ expr = expr
When this block is called by the SOLVE
statement, the values of the states are computed so that the equations are
true. The default method used is Newton's method. These kinds of equations
can also appear within a DERIVATIVE block.
KINETIC
"""""""
Description:
This block specifies a sequence of chemical reactions.
The default method used is backwards euler which is very stable but only
first order correct. If the SOLVE statement specifies
a "METHOD sparse" the method is still backwards euler but
the computation may be much faster.
CONSERVE
""""""""
Description:
This statement's fundamental idea is to systematically account for conservation of material.
When there is neither a source nor a sink reaction for a STATE , the
differential equations are not linearly independent when calculating steady states (dt
approaches infinity). Steady states can be approximated by integrating for several steps from
any initial condition with large dt, but roundoff error can be a problem if the Jacobian matrix
is nearly singular. To solve the equations while maintaining strict numerical conservation
throughout the simulation (no accumulation of roundoff error), the user is allowed to explicitly
specify conservation equations with the CONSERVE statement. The CONSERVE statement does not add
to the information content of a kinetic scheme and should be considered only as a hint to the
translator. The NMODL translator uses this algebraic equation to replace the ODE for the last
STATE on the left side of the equal sign. If one of the STATE names is an array, the
conservation equation will contain an implicit sum over the array. If the last STATE is an
array, then the ODE for the last STATE array element will be replaced by the algebraic equation.
The choice of which STATE ODE is replaced by the algebraic equation is implementation-dependent
and does not affect the solution (to within roundoff error). If a CONSERVEd STATE is relative
to a compartment size, then compartment size is implicitly taken into account for the STATEs on
the left hand side of the CONSERVE equation. The right hand side is merely an expression, in
which any necessary compartment sizes must be included explicitly.
``TODO``: Add existing example mod file
COMPARTMENT
"""""""""""
Description:
The compartment volumes needed by the KINETIC scheme are given using the ``COMPARTMENT``
keyword. The syntax of this construct is:
.. code-block::
none
COMPARTMENT volume {state1 state2 . . . }
where the STATE s named in the braces have the same compartment volume given by the volume
expression after the COMPARTMENT keyword.
In case a mechanism involves many compartments whose relative volumes are specified by the
elements of an array the syntax is:
.. code-block::
none
COMPARTMENT index, volume [ index ] { state1 state2 . . . }
where the STATEs that are diffusing are listed inside the braces.
LONGITUDINAL_DIFFUSION
""""""""""""""""""""""
Description:
This statement specifies that this mechanism includes nonlocal diffusion, i.e. longitudinal
diffusion along a section and into connecting sections. The syntax for scalar STATEs is:
.. code-block::
none
LONGITUDINAL_DIFFUSION flux_expr { state1 state2 . . . }
where ``flux_expr`` is the product of the diffusion constant and the cross-sectional area
between adjacent compartments. Units of the ``flux_expr`` must be (:math:`micron^4 /ms`), i.e.
the diffusion constant has units of (:math:`micron^2 /ms`) and the cross-sectional area has
units of (:math:`micron^2`). For cylindrical shell compartments, the cross-sectional area is
just the volume per unit length. If the states are arrays then all elements are assumed to
diffuse between corresponding volumes in adjacent segments and the iteration variable must be
specified as in:
.. code-block::
none
LONGITUDINAL_DIFFUSION index , flux_expr ( index ) { state1 state2 . . . }
PROCEDURE
"""""""""
Description:
Procedures normally do not return a value but are
called for their side effects, eg, the setting of variables. Procedures
are callable from NEURON by the user.
However if a procedure is called
by the user, and it makes use of any range variables, then the user is
responsible for telling the mechanism from what location it should get
its range variable data. This is done with the hoc :hoc:function:
.. code-block::
none
setdata_mechname(x)
where mechname is the mechanism name. For range variables there must
of course be a currently accessed section. In the case of Point processes,
one calls procedures using the object notation
.. code-block::
none
pp_objref.procname()
In this case procname uses the instance data of the point process referenced
by pp_objref.
Sometimes, state equations are so simple, e.g.
HH states, that significant efficiency gains and extra accuracy are
obtainable by a special integration procedure. In this case the
procedure can be called by a SOLVE statement and actually integrates the
states (but don't call it directly at the user level!).
If a PROCEDURE is solved by a SOLVE statement it may return an error code
(By default it returns an error code of 0 which denotes success.) To return
a non-zero error code use the idiom
.. code-block::
none
VERBATIM
return ...;
ENDVERBATIM
FUNCTION
""""""""
Description:
This block can be called at either the user level or from
within the model description. Functions return a double precision value.
Functions can also be called from other models. When the calling model is
translated a warning will be generated. Just be sure to load all needed
models. Use the suffix of the model where the function is declared.
The user level caveats stated for procedures apply.
TABLE
"""""
Description:
The TABLE statement is very useful in a NEURON context because of
the potentially great increase in speed of simulation. Often rate functions are
complicated functions of the voltage and it is very expensive to calculate
their values over and over at every segment. By using tables of rate
coefficients, it is not uncommon to improve simulation speed by a factor
of 5.
In the context of a procedure taking one argument, TABLE has the syntax
.. code-block::
none
TABLE variables DEPEND dependencies FROM lowest TO highest WITH tablesize
where:
variables is a list of variable names each of which will have its
own table,
dependencies is a list of parameters that, when any of them changes their
value, cause the tables to be recalculated,
lowest is the least arg value for the first table entry,
highest is the greatest arg value for the last table entry, and
table size is the number of elements in each table.
Each model that has a table also has a flag associated with it that
can be changed by the user called
usetable_suffix
which specifies that the tables are to be used (1, default) or not used (0).
With usetable_suffix = 0, when the procedure is called it ignores the tables
and just computes the values using the assignment statements as any normal
procedure.
With usetable_suffix = 1, when the procedure is called, the
arg value is used to assign values to the "variables" by looking them up
in the tables; the time normally spent executing the assignment statements
is saved. If the tables are out of date (a "dependency" has a different
value from its value the last time the tables were constructed) or have never
been created, the tables are created.
Note that updating tables with :samp:`{tablesize}=200` is equivalent to calling
the procedure 200 times with different values of the argument. This
investment is only repaid if the tables remain valid for many more than
200 subsequent calls to the procedure and if the calculation takes more
time than an interpolated table lookup.
INITIAL
"""""""
Description:
The INITIAL block is called when the user executes the finitialize() function
from hoc. Just prior to executing the user code in the INITIAL block (and
if an INITIAL block does not exist) all
states are set to the values in the state0 variables (default 0). It may
be useful to declare some state0 variables as GLOBAL or RANGE in the NEURON
block in order to give some user control over the default initialization
of states. In the INITIAL block these or any other variables may be set
to calculated values. Note that
states can also be initialized explicitly by the user at the hoc level.
The case where an ionic variable is also a STATE requires some care to
deal properly with it in the INITIALIZE block. The problem is that
the ionic variable, eg. cai, is actually the value of a local copy of the
ionic variable which is located in the variable named _ion_cai. Because of
the order of copying and default initialization, cai is always initialized
to 0 regardless of the global value of cai and on exit the global value of
cai is then set to 0 as well. The way to avoid this is either to make sure
the state0 variable, cai0, is set properly or (I believe more preferably),
set the local cai variable explicitly using the global cai variable with
a VERBATIM statement within the INITIAL block. The idiom is:
.. code-block::
none
VERBATIM
cai = _ion_cai;
ENDVERBATIM
Many other features of the model description language, such as DISCRETE blocks, and sensitivity analysis,
optimization are not relevant in the NEURON context and may or may not
produce meaningful translations. Since NMODL produces a c file, it is
possible for the highly motivated to modify that file in order to do
something implementation dependent. In this regard, the VERBATIM block
can be used to place c code within the model description file.
DISCRETE
""""""""
Description:
``TODO``: Add description
FUNCTION_TABLE
~~~~~~~~~~~~~~
Description:
This keyword defines function tables whose values are given by vectors prior to the simulation.
For example let's say we have the following declaration in a ΝMODL file:
.. code-block::
none
FUNCTION_TABLE tau1(v(mV)) (ms)
This means that there is a function `tau1` that takes as argument a variable `v` (voltage). Its
values can be then passed from HOC/Python using the following call:
.. code-block::
none
table_tau1_<MOD_SUFFIX>(tau1_vec, v_vec)
Then whenever tau1(x) is called in the NMODL file, or tau1_k3st(x) is called from hoc, the
interpolated value of the array is returned.
A useful feature of FUNCTION_TABLEs is that prior to developing the Vector database, they can
be attached to a scalar value as in
.. code-block::
none
table_tau1_<MOD_SUFFIX>(100)
effectively becoming constant functions. Also FUNCTION_TABLEs can be declared with two
arguments and doubly dimensioned hoc arrays attached to them. The latter is useful, for example,
with voltage- and calcium-sensitive rates. In this case the table is linearly interpolated in
both dimensions.
SWEEP
~~~~~
Description:
``TODO``: Add description and new example mod file
CONDUCTANCE
~~~~~~~~~~~
Description:
``TODO``: Add description and new example mod file
WHILE
~~~~~
Description:
``TODO``: Add description and new example mod file
IF / ELSE IF / ELSE
~~~~~~~~~~~~~~~~~~
Description:
If-statement for mod files.
``TODO``: Add new example mod file (iclamp1.mod)
LAG
~~~
Description:
``TODO``: Add description and new example mod file
|