--#!/usr/bin/env luajit
--[[
-- Trial variant of the double-cable model.
-- Will have model nodes, standard internodes and paranodes
--
-- version with explicit MYSA. More stiff
--
--
--]]
--require "profiler"
module(...,package.seeall)
require 'lib'
require 'el_ph' -- auxilary routines and electrophysiology
require 'ode' -- ODE solvers
function ficks_flux(C_neigh, C_this, D, L)
-- expects C in mM, D in cm^2/s, L in cm
-- returns J in mM*cm/ms
-- multiply by 1e-3 to convert seconds to milliseconds
return 1e-3 * D * (C_neigh - C_this)/L
end
function g_link(g_neigh, g_this)
return 2/(1/g_this + (g_neigh and 1/g_neigh or 0))
end
format = string.format
---------------------------------------------------
--function ghk_node(dv,s,p)
---- ghk Na current
--local iNa = p.P_Na * el_ph.ghk(p.Na_i, p.Na_o, s.V_a, p.T)*s.m1^3*s.h1
--local iNap = p.P_Nap * el_ph.ghk(p.Na_i, p.Na_o, s.V_a, p.T)*s.p^3
-- ghk K current (slow potassium current)
--local iK = p.P_K * el_ph.ghk(p.K_i, p.K_o, s.V_a, p.T)*s.n*s.n
--local iKs = p.P_Ks * el_ph.ghk(p.K_i, p.K_o, s.V_a, p.T)*s.s
--end
function set_q10c(gating_particles, temp)
for k,gp in pairs(gating_particles) do
if not gp.q10c then
gp.q10c = gp.q10^((temp - gp.tref)/10)
end
end
return gating_particles
end
function tanhp1(x)
return 1 + math.tanh(20*x)
end
function apply_current(t, istim)
local ia,tx,L
ia = 0
for _,iappl in ipairs(istim) do
local p = iappl
if (t > p.start - 2*p.width) and (t < p.stop + 2*p.width) then
tx = (t - p.start) % p.int
ia = ia + p.amp*.0625 * tanhp1(tx) * tanhp1((p.width - tx)) * tanhp1((t - p.start)) * tanhp1((p.stop-t))
end
end
return ia
end
function update_gps(gps, V, s, dv, vid)
for k,gp in pairs(gps) do
dv[vid[k]] =
gp.q10c*(gp.alpha(V)*(1 - s[vid[k]])
- gp.beta(V)*s[vid[k]])
end
end
function hh_iv(T, z)
return function (V, Ci, Co)
return (V - el_ph.nernst(Ci, Co, T, z))
end
end
function ghk_iv(T, z)
return function (V, Ci, Co)
return el_ph.ghk(Ci, Co, V, T, z)
end
end
----------------------------
--- Compartment `class' ---
----------------------------
Compartment = lib.inheritFrom(nil) -- table for a new class
function Compartment:new(phase,params,virtuals,tag)
local new_inst = {} -- new instance
setmetatable(new_inst, new_inst)
new_inst.__index = new_inst
new_inst.v0 = lib.deepcopy(phase)
new_inst.p = lib.deepcopy(params)
new_inst.virt = lib.deepcopy(virtuals)
new_inst.memoized = {}
self.base_tag = tag
return new_inst
end
-- Compartment methods --
function Compartment:type()
return "compartment"
end
--function Compartment:set_tag(base_tag)
-- self.tag = base_tag..'-'..self.type()
--end
function Compartment:set_right(rcomp) self.right = rcomp end -- set right link
function Compartment:set_left(lcomp) self.left = lcomp end -- set left link
--function Compartment:apply_phase(phase) self.v = phase end
function Compartment:apply_parameters(pars) self.p = pars end
function Compartment:erase_memoized() self.memoized = {} end
function Compartment:chain_link(addcomp)
self:set_right(addcomp)
addcomp:set_left(self)
end
function Compartment:get_var(key, phase)
return (self.vid[key] and phase[self.vid[key]]) or self.virt[key]
end
function Compartment:set_var(key,val)
if self.v0[key] then self.v0[key] = val
else self.virt[key] = val
end
end
function Compartment:cc_dist(neigh)
-- center to center distance
if neigh then
return .5*(neigh.p.l + self.p.l)
else
return .5*self.p.l
end
end
function Compartment:axial_current(neigh, phase)
return ((neigh:get_Vi(phase) - self:get_Vi(phase))*
g_link(neigh.p.G_a, self.p.G_a))
end
function Compartment:longit_current(neigh, phase, func)
if neigh then
return func(self, neigh, phase)
else
return 0
end
end
function Compartment:longit_current2(phase, func)
return (self:longit_current(self.left, phase,func) +
self:longit_current(self.right, phase,func))
end
-- Review dimensions: I have D in cm^2/s, Concentration in mmole/l, which is eqv. to mole/m^3,
-- time in ms, lenght in cm, flux in mmole/s
--
-- 10^-4 m^2 mole 1 1 mole
-- (S/V)*D*J*dc/dx = ----------- * ------- * -------- * -------- = ---------- = 10^3 mM/ms
-- s m^3 10^-2 m 10^-2 m s * m^3
function Compartment:ion_exchange_maker(neigh, ion_name, D, sect_name)
if neigh then
local dist = self:cc_dist(neigh)
local csect = self:mean_csect(neigh, sect_name)
return function (phase)
local flux -- mM*cm^3/ms
flux = ficks_flux(phase[neigh.vid[ion_name]],
phase[self.vid[ion_name]],
D, dist)
return flux * self:mean_csect(neigh, sect_name)
end
end
return function(phase) return 0 end
end
function Compartment:min_csect(neigh, key)
local sect = self.p[key]
if neigh and neigh.p[key] and neigh.p[key] < sect then
sect = neigh.p[key]
end
return sect
end
function Compartment:mean_csect(neigh, key)
local sect = self.p[key]
if neigh and neigh.p[key] then
sect = 0.5*(neigh.p[key] + self.p[key])
end
return sect
end
function Compartment:Na_exchange(phase)
return (self.Na_exchange_left(phase)
+ self.Na_exchange_right(phase))/self.p.axonal_vol
end
function Compartment:K_exchange(phase)
return (self.K_exchange_left(phase)
+ self.K_exchange_right(phase))/self.p.periax_vol
end
function Compartment:setup()
--self.Iax_longit = self:Iaxial_maker()
local p = self.p
p.axonal_csect = .25 * math.pi * p.d^2
p.periax_csect = el_ph.ring_area(p.d + 2*p.h, p.d)
if self.right then
local rp = self.right.p
rp.periax_csect = el_ph.ring_area(rp.d + 2*rp.h, rp.d)
rp.axonal_csect = .25 * math.pi * rp.d^2
end
self.Na_exchange_left =
self:ion_exchange_maker(self.left,'Na_i', el_ph.Daq.Na,
'axonal_csect')
self.Na_exchange_right =
self:ion_exchange_maker(self.right,'Na_i', el_ph.Daq.Na, 'axonal_csect')
self.K_exchange_left =
self:ion_exchange_maker(self.left,'K_o', el_ph.Daq.K, 'periax_csect')
self.K_exchange_right =
self:ion_exchange_maker(self.right,'K_o', el_ph.Daq.K, 'periax_csect')
end
---------------------------------------
---------------------------------------
-- Space-clamped models
---------------------------------------
SC_simple = lib.inheritFrom(Compartment)
function SC_simple:type()
return 'scsimp'
end
function set_q10c2(gp, temp)
if not gp.q10c then
gp.q10c = gp.q10^((temp - gp.tref)/10)
end
end
function SC_simple:setup()
local p = self.p
for _,current in pairs(p.node_currents) do
set_q10c(current.gp, p.celsius)
end
for _,current in pairs(p.internode_currents) do
set_q10c(current.gp, p.celsius)
end
end
function curr_g(current, s, vid)
local g = current.G
for key,gp in pairs(current.gp) do
g = g*s[vid[key]]^gp.order
end
return g
end
function SC_simple:deriv(s,dv,t)
local vid = self.vid
local V_n = s[vid.V_n]
local V_int = s[vid.V_int]
local p = self.p
local Erest = {
Na = el_ph.nernst(p.Na_i, p.Na_o, p.T),
K = el_ph.nernst(p.K_i, p.K_o, p.T)}
local iex = apply_current(t, p.iappl)
local ilk_i = p.G_lk_i * (V_int - Erest.Na)
local vnvi = (V_n - V_int)/(p.R_il)--/s[vid.sw])
local dvn = iex - vnvi
for _,i in pairs(p.node_currents) do
dvn = dvn - curr_g(i, s, vid)*(V_n - Erest[i.ion])
update_gps(i.gp, V_n, s, dv, vid)
end
dvn = dvn/(p.C_n + p.C_my)
local dvi = vnvi + dvn*p.C_my - ilk_i
for _,i in pairs(p.internode_currents) do
dvi = dvi - curr_g(i, s, vid)*(V_int - Erest[i.ion])
update_gps(i.gp, V_int, s, dv, vid)
end
dv[vid.V_n] = dvn
dv[vid.V_int] = dvi/p.C_i
return dv
end
SC_geom = lib.inheritFrom(Compartment)
function SC_geom:type()
return 'scgeom' end
function SC_geom:setup()
local p = self.p
p.int.G_il = 1/p.int.R_il
p.node.asurf = math.pi * p.node.l * p.node.d -- axonal surface area
p.int.asurf = math.pi * p.int.l * p.int.d
p.int.asurf_p = math.pi * p.int.lpara * p.int.d
p.int.gsurf = p.int.asurf*1.1 -- glial surface facing periaxonal space
p.node.acsect = .25 * math.pi * p.node.d^2 -- axonal cross-section
p.int.acsect = .25 * math.pi * p.int.d^2
p.node.periax_csect =
el_ph.ring_area(p.node.d + 2*p.node.h, p.node.d)
p.node.gsurf = p.node.wavy*p.node.periax_csect
p.int.periax_csect =
el_ph.ring_area(p.int.d + 2*p.int.h, p.int.d)
--p.int.glia_csect =
-- el_ph.ring_area(p.int.d + 2*(p.int.h + p.int.hg),
-- p.int.h + 2*p.int.h)
p.node.ax_vol = p.node.l * p.node.acsect -- axonal volume
p.int.ax_vol = p.int.l * p.int.acsect
p.int.ax_vol_p = p.int.lpara * p.int.acsect
--p.int.glial_vol = p.int.l * p.int.glia_csect
p.node.periax_vol = p.node.l*p.node.periax_csect
p.int.periax_vol = p.int.l *p.int.periax_csect
p.int.periax_vol_p = p.int.lpara *p.int.periax_csect
for _,i in pairs(p.node.currents) do
i.G = i.g*p.node.asurf
end
for _,i in pairs(p.int.currents) do
i.G = i.g*p.int.asurf
end
p.node.G_lk = p.int.g_lk * p.int.asurf --leakage conductance
p.int.G_lk = p.int.g_lk * p.int.asurf --leakage conductance
p.int.G_lk_glia = p.int.g_lk_glia * p.int.gsurf
p.int.G_Kglia = p.int.g_Kglia*p.int.gsurf
p.int.C_glia = p.int.c_m*p.int.gsurf
--p.int.G_s=el_ph.myelin_conductance(p.int.g_s, p.int.D, p.int.d, p.int.l, p.int.Nl)
p.int.C_s=el_ph.myelin_capacitance(p.int.c_s, p.int.D, p.int.d, p.int.l, p.int.Nl)
p.node.C_m = p.node.asurf*p.node.c_m -- capacity of the axonal membrane
p.int.C_m = p.int.asurf*p.int.c_m -- capacity of the axonal membrane
-- q10c!
for _,current in pairs(p.node.currents) do
set_q10c(current.gp, p.celsius)
end
for _,current in pairs(p.int.currents) do
set_q10c(current.gp, p.celsius)
end
end
function SC_geom:deriv (s, dv, t)
local vid = self.vid
local V_n = s[vid.V_n]
local V_int = s[vid.V_int]
local p = self.p
local Erest_n = {
Na = el_ph.nernst(s[vid.Nai_n], p.Na_o, p.T),
K = el_ph.nernst(p.K_i, s[vid.Ko_n], p.T)}
local Erest_p = {
Na = el_ph.nernst(s[vid.Nai_p], p.Na_o, p.T),
K = el_ph.nernst(p.K_i, s[vid.Ko_p], p.T)}
local Erest_i = {
Na = el_ph.nernst(s[vid.Nai_i], p.Na_o, p.T),
K = el_ph.nernst(p.K_i, s[vid.Ko_i], p.T)}
local iex = apply_current(t, p.iappl)
local ilk_n = p.node.G_lk * (V_n - p.node.V_lk)
--local vnvi = (V_n - V_int)/p.int.R_il
local vnvi = (V_n - V_int)*p.int.G_il*s[vid.sw]
local fluxes_n = {K = 0, Na = 0}
local fluxes_i = {K = 0, Na = 0}
local fluxes_p = {K = 0, Na = 0}
local nakpf_a_n = el_ph.NaKpump_flux(p.K_i, s[vid.Ko_n],
s[vid.Nai_n], p.Na_o,
p.node.pump_a)
local nakpf_g_n = el_ph.NaKpump_flux(p.K_i, s[vid.Ko_n],
p.Na_i, p.Na_o,
p.nak_pump_g)
local nakpf_a_i = el_ph.NaKpump_flux(p.K_i, s[vid.Ko_i],
s[vid.Nai_i], p.Na_o,
p.nak_pump_a)
local nakpf_a_p = el_ph.NaKpump_flux(p.K_i, s[vid.Ko_p],
s[vid.Nai_p], p.Na_o,
p.nak_pump_a)
local nakpf_g_i = el_ph.NaKpump_flux(p.K_i, s[vid.Ko_i],
p.Na_i, p.Na_o,
p.nak_pump_g)
local nakpf_g_p = el_ph.NaKpump_flux(p.K_i, s[vid.Ko_p],
p.Na_i, p.Na_o,
p.nak_pump_g)
local ipump_n = el_ph.flux2i(nakpf_a_n[1])*p.node.asurf/3
local ipump_i = el_ph.flux2i(nakpf_a_i[1])*p.int.asurf/3
local ipump_p = el_ph.flux2i(nakpf_a_p[1])*p.int.asurf_p/3
local ipump_g = el_ph.flux2i(nakpf_g_i[1])*p.int.gsurf/3
exch_Na_np = 2*ficks_flux(s[vid.Nai_p], s[vid.Nai_n],
el_ph.Daq.Na,
0.5*p.int.lpara)*p.node.acsect
exch_Na_pi = 2*ficks_flux(s[vid.Nai_i], s[vid.Nai_p],
el_ph.Daq.Na, 0.25*p.int.l)*p.int.acsect
exch_K_np = 2*ficks_flux(s[vid.Ko_p], s[vid.Ko_n],
el_ph.Daq.K, 0.5*p.int.lpara)*p.int.periax_csect
exch_K_pi = 2*ficks_flux(s[vid.Ko_i], s[vid.Ko_p],
el_ph.Daq.K, 0.25*p.int.l)*p.int.periax_csect
fluxes_n.K = (nakpf_a_n[2]*p.node.asurf +
nakpf_g_n[2]*p.node.gsurf +
exch_K_np)
fluxes_p.K = (nakpf_a_i[2]*p.int.asurf_p +
nakpf_g_i[2]*p.int.asurf_p*1.1 +
exch_K_pi - exch_K_np)
fluxes_i.K = (nakpf_a_i[2]*p.int.asurf +
nakpf_g_i[2]*p.int.gsurf -
exch_K_pi)
fluxes_n.Na = nakpf_a_n[1]*p.node.asurf - exch_Na_np
fluxes_p.Na = nakpf_a_i[1]*p.int.asurf_p + exch_Na_np - exch_Na_pi
fluxes_i.Na = nakpf_a_i[1]*p.int.asurf + exch_Na_pi
local dvn = iex - (vnvi + ilk_n + ipump_n)
local x
for _,i in pairs(p.node.currents) do
x = curr_g(i, s, vid)*(V_n - Erest_n[i.ion])
fluxes_n[i.ion] = fluxes_n[i.ion] + el_ph.i2flux(x)
dvn = dvn - x
update_gps(i.gp, V_n, s, dv, vid)
end
dvn = dvn/(p.node.C_m + p.int.C_s)
local ilk_i = (1-p.int.naparaw)*p.int.G_lk * (V_int - Erest_i.Na)
local ilk_p = p.int.naparaw*p.int.G_lk * (V_int - Erest_p.Na)
local dvi = vnvi + dvn*p.int.C_s - (ilk_i + ilk_p + ipump_p + ipump_i)
fluxes_i.Na = fluxes_i.Na + el_ph.i2flux(ilk_i)
fluxes_p.Na = fluxes_p.Na + el_ph.i2flux(ilk_p)
local x,xi,xp
for iname,i in pairs(p.int.currents) do
x = curr_g(i, s, vid)
local v = p.int.kparaw*Erest_p[i.ion] + (1-p.int.kparaw)*Erest_i[i.ion]
xi = (1-p.int.kparaw)*(V_int - Erest_i[i.ion])*x
xp = p.int.kparaw * (V_int - Erest_p[i.ion])*x
if iname == "iKf" then
self.virt.iKfp = xp
self.virt.iKfi = xi
end
fluxes_i[i.ion] = fluxes_i[i.ion] + el_ph.i2flux(xi)
fluxes_p[i.ion] = fluxes_p[i.ion] + el_ph.i2flux(xp)
update_gps(i.gp, V_int, s, dv, vid)
dvi = dvi - xi - xp
end
self.virt.ipump_p = ipump_p
local iKg = p.int.G_Kglia*(s[vid.V_g] - Erest_i.K)
dv[vid.V_g] = -(iKg +
p.int.G_lk_glia*(s[vid.V_g] - p.int.V_lk_glia)
+ ipump_g)/p.int.C_m
fluxes_i.K = fluxes_i.K + el_ph.i2flux(iKg)
dv[vid.V_n] = dvn
dv[vid.V_int] = dvi/p.int.C_m
dv[vid.Nai_n] = -fluxes_n.Na/p.node.ax_vol
dv[vid.Nai_p] = -fluxes_p.Na/p.int.ax_vol_p +
(p.Na_i - s[vid.Nai_p])/self.p.int.tau_passive_Na
dv[vid.Nai_i] = -fluxes_i.Na/p.int.ax_vol +
(p.Na_i - s[vid.Nai_i])/self.p.int.tau_passive_Na
dv[vid.Ko_n] = fluxes_n.K/p.node.periax_vol +
(p.K_o - s[vid.Ko_n])/self.p.node.tau_passive
dv[vid.Ko_p] = fluxes_p.K/p.int.periax_vol_p +
(p.K_o - s[vid.Ko_p])/self.p.int.tau_passive_K
dv[vid.Ko_i] = fluxes_i.K/p.int.periax_vol +
(p.K_o - s[vid.Ko_i])/self.p.int.tau_passive_K
dv[vid.sw] = ((p.ko_sig(s[vid.Ko_p]) - s[vid.sw]) / p.int.tau_sw)
return dv
end
--------------------------
-----------------------------
--- Nerve `class' ----
-----------------------------
Nerve = {}
function Nerve:parameter_setup(obj)
local surface,volume,cross_section
local p
for i,comp in ipairs(obj.layout) do
comp:setup()
end
end
function Nerve:set_state(obj)
obj.phase0 = setmetatable({}, lib.vecmt)
obj.derivatives = setmetatable({}, lib.vecmt)
-- create a sorted list of variable names
obj.sorted_keys = {} -- with virtuals
obj.sorted_vkeys = {} -- phase only
for i, comp in ipairs(obj.layout) do
local x = {}
local xv = {} -- without virtuals (phase only)
for index,value in pairs(comp.v0) do
table.insert(x,index)
table.insert(xv, index)
end
if comp.virt then
--io.stderr:write(string.format("\n comp.virt: \n"))
for index,value in pairs(comp.virt) do
table.insert(x,index)
end
end
table.sort(x)
table.sort(xv)
table.insert(obj.sorted_keys,x)
table.insert(obj.sorted_vkeys,xv)
end
-- setup variable indices for each compartment
local j = 1
for z,comp in ipairs(obj.layout) do
comp.vid = {}
for _, key in ipairs(obj.sorted_vkeys[z]) do
comp.vid[key] = j
obj.phase0[j] = comp.v0[key]
j = j + 1
end
end
end
function Nerve:erase_memoized()
for z, comp in ipairs(self.layout) do
comp:erase_memoized()
end
end
function Nerve:derivs(t, phase) -- calculates derivatives for a state
--local dvs = setmetatable({}, lib.stmt)
-- print("Nerve.derivs: phase size = ", #phase)
self:erase_memoized()
local dvs = self.derivatives
for n,comp in ipairs(self.layout) do -- now calculate derivatives
dvs = comp:deriv(phase, dvs, t)
end
return dvs
end
function Nerve:run(t0, h, t1, stf)
-- numerically integrate from t0 to t1,
-- using step h and stepper function stf
local st,ks,n
n = 0
local save_step = 5e-3
local max_h = 2
ks = save_step > h and math.floor(save_step/h) or 1
local kp = ks*10
local stepper = ode[stf]
local t = t0
local tnext
-- phase we start from:
local U = self.phase0 + 0
-- print("Nerve.run: U[1] = ", U[1])
--local U1 = U + 0
while t <= t1 do
U, tnext, h = stepper(U, t, h, _s_, self)
if math.mod(n,ks) == 0 then
if math.mod(n,kp) == 0 then
io.stderr:write(string.format('\rmodel time: %3.3f ms',t))
end
io.stdout:write(self:pr_state(U, t))
--io.stdout:write(self:pp_state(t))
io.stdout:flush()
end
n = n+1
if h > max_h then
h = max_h
tnext = t+h
end
t = tnext
end
--io.stderr:write('\n')
--io.stdout:write('\n')
self.phase0 = U + 0
return t, U
end
function Nerve:pr_state(phase, t)
local x = string.format('%3.5e',t)
for z,comp in ipairs(self.layout) do
for i,key in ipairs(self.sorted_keys[z]) do
x = x..string.format('\t%3.5e', comp:get_var(key, phase))
end
end
return (x..'\n')
end
function Nerve:luaprint_state(phase, t)
--prints state in a lua-loadable format
--x = string.format("{time = %3.5e,\n" ,time)
x = "return {"
for z, comp in ipairs(self.layout) do
x = x..string.format('{')
for i,key in ipairs(self.sorted_keys[z]) do
x = x..string.format(' %s = %3.5e,', key, comp:get_var(key, phase))
end
x = x.."},\n"
end
return x.."}\n"
end
function Nerve:pythonprint_state(phase, t)
--prints state in a python-loadable format
--x = string.format("{time = %3.5e,\n" ,time)
x = "["
for z, comp in ipairs(self.layout) do
x = x..string.format('{')
for i,key in ipairs(self.sorted_keys[z]) do
x = x..string.format(" '%s': %3.5e,", key, comp:get_var(key, phase))
end
x = x.."},\n"
end
return x.."]\n"
end
function Nerve:pp_state(phase, t) -- pretty print state
local x = string.format("(('time . %3.5e)", t)
local j = 1
for z,comp in ipairs(self.layout) do
x = x..string.format("\n (%s-%d ", self.layout_rule.tag, z)
for i,key in ipairs(self.sorted_keys[z]) do
x = x..string.format(" (%s-%s-%d %3.5e)",
comp:type(), key, j, comp:get_var(key, phase))
j = j+1
end
x = x..")"
end
return (x..'))\n')
end
function Nerve:print_parameters()
local x = ""
for z,comp in ipairs(self.layout) do
for key,value in pairs(comp.p) do
if type(value) == "number" then
x = x..string.format('%s-%s = \t%3.5e\n', comp:type(), key, value)
end
end
end
return (x..'\n')
end
function Nerve:gp_print()
local x = ''
local j = 2
local curr_type
local types = {}
for z,comp in ipairs(self.layout) do
curr_type = comp:type()
if not types[curr_type] then types[curr_type] = 1 end
for i,key in ipairs(self.sorted_keys[z]) do
x = x..string.format("%s_%s%d_%s = %d\n",
self.layout_rule.tag,
comp:type(), types[curr_type], key, j)
j = j + 1
end
types[curr_type] = types[curr_type] + 1
end
return x..'\n'
end
function Nerve:luaload_state(fname)
local f, sts, x, j
local state
f = assert(loadfile(fname))
state = f()
j = 0
for z, comp in ipairs(self.layout) do
for key, val in pairs(state[z]) do
comp:set_var(key,val)
end
end
Nerve:set_state(self)
end
function Nerve:construct_from_rule(rule, comps)
local layout = {}
local prev
local node_count = 0
local i =1
for _,name in ipairs(rule.rule) do
--if known[name] then
local comp_type = comps[name].type and comps[name].type or name
local comp_class = getfenv()[comp_type]
layout[i] = comp_class:new(comps[name].state,
comps[name].pars,
comps[name].virtuals, '-')
if i > 1 then
layout[i-1]:chain_link(layout[i])
end
if layout[i]:type() == 'node' then
node_count = node_count + 1
layout[i].p.number = node_count
end
i = i+1
end
return layout
end
function Nerve:new(compartments,layout_rule) -- class constructor
local newn = {} -- new nerve instance
setmetatable(newn,newn)
newn.__index = self
newn.layout_rule = layout_rule
newn.layout = Nerve:construct_from_rule(layout_rule, compartments, newn.known)
Nerve:set_state(newn)
Nerve:parameter_setup(newn)
return newn
end