Skip to content

Latest commit

 

History

History
371 lines (266 loc) · 15.4 KB

File metadata and controls

371 lines (266 loc) · 15.4 KB

LinearMechanism

.. tab:: Python


    Syntax:
        ``lm = n.LinearMechanism(c, g, y, [y0], b)``

        ``lm = n.LinearMechanism(c, g, y, [y0], b, x, sec=section)``

        ``lm = n.LinearMechanism(c, g, y, [y0], b, sl, xvec, [layervec])``

        ``lm = n.LinearMechanism(pycallable, c, g, y, ...)``


    Description:
        Adds linear equations to the tree matrix current balance equations.
        I.e. the equations are solved
        simultaneously with the current balance equations.
        These equations may modify current balance equations and involve
        membrane potentials as dependent variables.

        The equations added are of the differential-algebraic form
        :math:`c \frac{dy}{dt} + g y = b`
        with initial conditions specified by the optional y0 vector argument.
        c and g must be square matrices of the same rank as the y and b vectors.
        The implementation is more efficient if c is a sparse matrix since
        at every time step c*y/dt must be computed.

        When a LinearMechanism is created, all the potentially non-zero elements
        for the c and g matrices must be actually non-zero so that
        the mathematical topology of the matrices is known in advance.
        After creation, elements can be set to 0 if desired.

        The arguments after the b vector specify which voltages and current
        balance equations are coupled to this system. The scalar form, x, with
        the specified `section` means that the first equation
        is added to the current balance equation at this location and the first
        dependent variable is a copy of the membrane potential. If the
        system is coupled to more than one location, then  sl must be a SectionList
        and xvec a Vector of relative positions (0 ... 1) specifying the
        locations. In this case, the first xvec.size equations are added to the
        corresponding current balance equations and the first xvec.size dependent
        y variables are copies of the membrane potentials at this location.
        If the optional layervec argument is present then the values must be
        0, 1, or 2 (or up to however many layers are defined in :file:`src/nrnoc/options.h`)
        0 refers to the internal potential (equal to the membrane potential when
        the extracellular mechanism is not inserted), and higher numbers refer
        to the \ ``vext[layer-1]`` layer (or ground if the extracellular mechanism is
        not inserted).

        If some y variables correspond to membrane potential, the corresponding
        initial values in the y0 vector are ignored and the initial values come
        from the values of v during the normal :func:`finitialize` call. If you change
        the value of v after finitialize, then you should also change the
        corresponding y values if the linear system involves derivatives of v.

        Note that current balance equations of sections when 0 < x < 1 have dimensions
        of milliamp/cm2 and positive terms are outward. Thus
        c elements involving voltages in mV
        have dimensions of 1000 :math:`\mathrm{\mu{}F/cm^2}` (so a value of .001 corresponds to
        1  :math:`\mathrm{\mu{}F/cm^2}`), g elements have dimensions of :math:`\mathrm{S/cm^2}`, and b elements have
        dimensions of outward current in :math:`\mathrm{milliamp/cm^2}`. The current balance
        equations for the zero area nodes at the beginning and end
        of a section (x = 0 and x = 1) have terms with the dimensions of
        nanoamps. Thus c elements involving voltages in mV have dimensions
        of nF and g elements have dimensions of :math:`\mathrm{\mu{}S}`.

        The existence of one or more LinearMechanism switches the gaussian elimination
        solver to the general sparse linear equation solver written by
        Kenneth S. Kundert and available from
        http://www.netlib.org/sparse/index.html
        Although, even with no added equations, the solving of m*x=b takes more
        than twice as long as the original default solver, there is no restriction
        to a tree topology.

    Example:

        .. code-block::
            python

            from neuron import n

            tstop = 5

            soma = n.Section("soma")
            soma.insert(n.hh)

            # ideal voltage clamp.
            c = n.Matrix(2, 2, 2) # sparse - no elements used
            g = n.Matrix(2, 2)
            y = n.Vector([0, 0])       # y[1] is injected current
            b = n.Vector([0, 10])      # b[1] is voltage clamp level
            g.setval(0, 1, -1)
            g.setval(1, 0, 1)

            model = n.LinearMechanism(c, g, y, b, 0.5, sec=soma)

            n.finitialize(-65)
            while n.t < tstop:
                print(f't={n.t:<8g} v={soma(0.5).v:<8g} y[1]={y[1]:<8g}')
                n.fadvance()



    .. warning::

        Does not work with the CVODE integrator but does work with the
        differential-algebraic solver IDA. Note that if the standard
        run system is loaded, ``n.cvode_active(True)`` will automatically
        choose the correct variable step integrator.

    .. warning::

            Does not allow changes to coupling locations.
        Is not notified when matrices, vectors, or segments it depends on
        disappear.

    Description (continued):
        If the pycallable argument (A Python Callable object) is present
        it is called just before the b Vector is used during a simulation. The
        callable can change the elements of b and g (but do not introduce new
        elements into g) as a function of time and states. It may be useful for
        stability and performance to place the linearized part of b into g.
        Consider the following pendulum.py with equations

.. method:: LinearMechanism.dforce

    Syntax:
        ``lm.dforce(bdot)``

        ``lm.dforce(dforce_callable, bdot)``

    Description:
        Supplies :math:`db/dt` for IDA consistent initialization when
        :meth:`CVode.dae_init_mode` is 3 (forcing :math:`t^+` info). The
        ``bdot`` Vector must have the same size as ``b``.

        With a callable, that function is invoked at each IDA reinit with
        ``t`` set to the IC time; it should fill ``bdot``. Without a
        callable, ``bdot`` is used as-is (the user may update it before
        ``re_init``).

        If neither ``dforce`` nor continuous :meth:`Vector.play` into ``b``
        provides :math:`b'`, but a force callable was passed to the
        constructor, a one-sided finite difference of that callable is used
        as a fallback.

        Example (series :math:`C`–:math:`R` with sinusoid current into node 0):

        .. code-block::
            python

            import math
            from neuron import n

            A, w = 1.0, 2 * math.pi
            c = n.Matrix(2, 2)
            g = n.Matrix(2, 2)
            y = n.Vector(2)
            b = n.Vector(2)
            bdot = n.Vector(2)
            c.setval(0, 0, 1); c.setval(0, 1, -1)
            c.setval(1, 0, -1); c.setval(1, 1, 1)
            g.setval(1, 1, 1)

            def force():
                b.x[0] = A * math.sin(w * n.t)

            def dforce():
                bdot.x[0] = A * w * math.cos(w * n.t)

            lm = n.LinearMechanism(force, c, g, y, b)
            lm.dforce(dforce, bdot)
            n.CVode().active(True)
            n.CVode().use_daspk(True)
            n.CVode().dae_init_mode(3)
            n.finitialize(0)

    See also:
        :meth:`CVode.dae_init_mode`, :meth:`CVode.dae_init_audit`

Description (continued, pendulum):

Example:

\frac{d\theta}{dt} = \omega
\frac{d\omega}{dt} = -\frac{g}{L} \sin(\theta) \text{ with } \frac{g}{L}=1
from neuron import n, gui
from math import sin

cmat = n.Matrix(2, 2, 2).ident()

gmat = n.Matrix(2, 2, 2)
gmat.setval(0, 1, -1)

y = n.Vector(2)
y0 = n.Vector(2)
b = n.Vector(2)

def callback():
  b[1] = -sin(y[0])

nlm = n.LinearMechanism(callback, cmat, gmat, y, y0, b)

dummy = n.Section("dummy")
trajec = n.Vector().record(y._ref_x[0])
tvec = n.Vector().record(n._ref_t)

graph = n.Graph()
n.tstop=50

def prun(theta0, omega0):
  graph.erase()
  y0[0] = theta0
  y0[1] = omega0
  n.run()
  trajec.line(graph, tvec)

n.dt /= 10
n.cvode.atol(1e-5)
n.cvode_active(True)
prun(0, 1.9999) # 2.0001 will keep it rotating
graph.exec_menu("View = plot")
../../images/linmod.png
.. tab:: HOC


    Syntax:
        ``lm = new LinearMechanism(c, g, y, [y0], b)``


        ``section lm = new LinearMechanism(c, g, y, [y0], b, x)``


        ``lm = new LinearMechanism(c, g, y, [y0], b, sl, xvec, [layervec])``


    Description:
        Adds linear equations to the tree matrix current balance equations.
        I.e. the equations are solved
        simultaneously with the current balance equations.
        These equations may modify current balance equations and involve
        membrane potentials as dependent variables.


        The equations added are of the differential-algebraic form
        :math:`c \frac{dy}{dt} + g y = b`
        with initial conditions specified by the optional y0 vector argument.
        c and g must be square matrices of the same rank as the y and b vectors.
        The implementation is more efficient if c is a sparse matrix since
        at every time step c*y/dt must be computed.


        When a LinearMechanism is created, all the potentially non-zero elements
        for the c and g matrices must be actually non-zero so that
        the mathematical topology of the matrices is known in advance.
        After creation, elements can be set to 0 if desired.


        The arguments after the b vector specify which voltages and current
        balance equations are coupled to this system. The scalar form, x, with
        a currently accessed section means that the first equation
        is added to the current balance equation at this location and the first
        dependent variable is a copy of the membrane potential. If the
        system is coupled to more than one location, then  sl must be a SectionList
        and xvec a Vector of relative positions (0 ... 1) specifying the
        locations. In this case, the first xvec.size equations are added to the
        corresponding current balance equations and the first xvec.size dependent
        y variables are copies of the membrane potentials at this location.
        If the optional layervec argument is present then the values must be
        0, 1, or 2 (or up to however many layers are defined in :file:`src/nrnoc/options.h`)
        0 refers to the internal potential (equal to the membrane potential when
        the extracellular mechanism is not inserted), and higher numbers refer
        to the \ ``vext[layer-1]`` layer (or ground if the extracellular mechanism is
        not inserted).


        If some y variables correspond to membrane potential, the corresponding
        initial values in the y0 vector are ignored and the initial values come
        from the values of v during the normal :func:`finitialize` call. If you change
        the value of v after finitialize, then you should also change the
        corresponding y values if the linear system involves derivatives of v.


        Note that current balance equations of sections when 0 < x < 1 have dimensions
        of milliamp/cm2 and positive terms are outward. Thus
        c elements involving voltages in mV
        have dimensions of 1000 :math:`\mathrm{\mu{}F/cm^2}` (so a value of .001 corresponds to
        1  :math:`\mathrm{\mu{}F/cm^2}`), g elements have dimensions of :math:`\mathrm{S/cm^2}`, and b elements have
        dimensions of outward current in :math:`\mathrm{milliamp/cm^2}`. The current balance
        equations for the zero area nodes at the beginning and end
        of a section (x = 0 and x = 1) have terms with the dimensions of
        nanoamps. Thus c elements involving voltages in mV have dimensions
        of nF and g elements have dimensions of :math:`\mathrm{\mu{}S}`.


        The existence of one or more LinearMechanism switches the gaussian elimination
        solver to the general sparse linear equation solver written by
        Kenneth S. Kundert and available from
        http://www.netlib.org/sparse/index.html
        Although, even with no added equations, the solving of m*x=b takes more
        than twice as long as the original default solver, there is no restriction
        to a tree topology.


    Example:


        .. code-block::
            none


            load_file("nrngui.hoc")


            create soma
            soma { insert hh }


            //ideal voltage clamp.
            objref c, g, y, b, model
            c = new Matrix(2,2,2) //sparse - no elements used
            g = new Matrix(2,2)
            y = new Vector(2) // y.x[1] is injected current
            b = new Vector(2)
            g.x[0][1] = -1
            g.x[1][0] = 1
            b.x[1] = 10 // voltage clamp level


            soma model = new LinearMechanism(c, g, y, b, .5)


            proc advance() {
                printf("t=%g v=%g y.x[1]=%g\n", t, soma.v(.5), y.x[1])
                fadvance()
            }
            run()


    .. warning::


          Does not work with the CVODE integrator but does work with the
          differential-algebraic solver IDA. Note that if the standard
          run system is loaded, ``cvode_active(1)`` will automatically
          choose the correct variable step integrator.
          Does not allow changes to coupling locations.
          Is not notified when matrices, vectors, or segments it depends on
          disappear.