//genesis - LFPfuncs.g
/* Functions for calculating local field potentials, EEG, and ECoG
potentials. Uses an efield2 object and can be used with hsolve.
Will be included in the main script if calc_LFP = 1.
The global string variable 'solvepath' is defined in the main script
to give the name that is being used for the hsolve element, e.g. "solver".
Output clock will be clock 1 (out_dt)
function make_electrode(name, x, y, z, cellpath) sums over all pyr cells,
is most often used to sum over all pyrmidal cells.
*/
/* When recording field potentials from many cells, it may be
useful to record only synaptic currents rather than include
transmembrane currents generated by action potential, leak,
and capacitive currents.
The global variable 'use_syn_currents' is used to allow this option.
set in main script:
int use_syn_currents = 1 // calculate the efield using only synchan currents
Typical usage:
make_electrode "Electrode_1" 0.0 0.0 0.001 {cellpath} // Lower Left: cell [0]
make_electrode "Electrode_2" 0.00096 0.00064 0.001 {cellpath} // over pyr_4[792]
To include all currents, including capacitive currents, one can use
make_electrode without hsolve and use_syn_currents = 0. This will use
the axial currents Im, which are equal to the total membrane and
capacitive Cm*(dCvm/dt) currents. The hsolve does not include the
capacitive currents in the calculation of Im.
Alternatively, use hsolve and the function make_electrode_cells.
This creates an efield_cells object that correctly calculates Im
and the resulting field. It also places the Im value in the disabled
object that was taken over by the solver, where it is accessible for use
by efield or efield2 as if it were not hsolved.
*/
// This function uses efield2 to correctly set the distance to hsolved elements
// It is to be executed by output_node
function make_electrode(name, x, y, z) // sums over all cells in path
str name // electrode name
float x, y, z // electrode position
if (calc_LFP == 0)
return
end
if (!{exists /electrodes})
create neutral /electrodes
end
pushe /electrodes
if ({exists {name}})
delete {name}
end
float scale // scale factor for currents
if (use_syn_currents)
scale = -0.32 // invert sign of trans-membrane currents
else // Use Im to give axial currents
scale = 0.32 // positive - axial currents are positive-in
end
create efield2 {name}
setfield {name} x {x} y {y} z {z}
setfield {name} scale {scale}
pope
useclock /electrodes/{name} 1 // clock at out_dt
// In order to output the results, use function do_electrodes_out
end // function make_electrode
function make_electrode_messages(name, cellpath) // executed by worker nodes
str name // electrode name
str cellpath // path to cells producing the field
float x, y, z // electrode position
x = {getfield@{output_node} /electrodes/{name} x}
y = {getfield@{output_node} /electrodes/{name} y}
z = {getfield@{output_node} /electrodes/{name} z}
float cx, cy, cz // channel position
float distance
str compt, chan, src
int i
for (i = 0; i < Ex_cells_per_slice; i = i + 1)
src = {cellpath} @ "[" @ {i} @ "]"
if({hflag} && {hsolve_chanmode > 1})
foreach compt ({el {src}/#[OBJECT=compartment]})
if (use_syn_currents)
foreach chan ({el {compt}/#[OBJECT=synchan]})
cx = {getfield {chan} x}
cy = {getfield {chan} y}
cz= {getfield {chan} z}
distance = {sqrt { {pow {{cx} - {x}} 2.0} + \
{pow {{cy} - {y}} 2.0} + \
{pow {{cz} - {z}} 2.0} }}
if(debug_level > 1)
echo {getfield {compt} name} {getfield {chan} name} \
"distance = " {distance}
end
raddmsg {src}/{solvepath} /electrodes/{name}@{output_node} \
CURRENT {findsolvefield {src}/{{solvepath}} {chan} Ik} \
{distance}
end // foreach
else // Use Im to give axial currents
/* Assume that efield_cells has updated hsolved compt Im */
raddmsg {compt} /electrodes/{name}@{output_node} CURRENT Im 0.0
end
end // loop over compts
else // not hsolve - Ileak is not calculated
foreach compt ({el {src}/#[OBJECT=compartment]})
if(use_syn_currents)
foreach chan ({el {compt}/#[OBJECT=synchan]})
raddmsg {src}/{synpath} /electrodes/{name}@{output_node} Ik 0.0
end // foreach chan
else
raddmsg {compt} /electrodes/{name}@{output_node} CURRENT Im 0.0
end
end // loop over compts
end // if({hflag} && {hsolve_chanmode > 1})
end // loop over cells
end
/* A variation that calculates the Efield for only a specified synpath
e.g. "apical3/AMPA_pyr", or {Ex_ex_synpath}
*/
function make_electrode_synpath(name, x, y, z)
str name // electrode name
str synpath // path to compartment/synchan
float x, y, z // electrode position
str cellpath // path to cells
str chan // full path to the particular synchan
float cx, cy, cz // channel position
float distance
if (calc_LFP == 0)
return
end
if (!{exists /electrodes})
create neutral /electrodes
end
pushe /electrodes
if ({exists {name}})
delete {name}
end
create efield2 {name}
setfield {name} x {x} y {y} z {z}
setfield {name} scale -0.32 // membrane currents should be 'negative-in'
pope
useclock /electrodes/{name} 1 // clock at out_dt
call /electrodes/{name} RECALC // calculate the distances to the compartments
// In order to output the results, use function do_electrodes_out
end // function make_electrode_synpath
function make_electrode_synpath_messages(name, cellpath, synpath)
str name // electrode name
str synpath // path to compartment/synchan
float x, y, z // electrode position
str cellpath // path to cells
str chan // full path to the particular synchan
x = {getfield@{output_node} /electrodes/{name} x}
y = {getfield@{output_node} /electrodes/{name} y}
z = {getfield@{output_node} /electrodes/{name} z}
float cx, cy, cz // channel position
float distance
str src
int i
for (i = 0; i < {Ex_cells_per_slice}; i = i + 1)
src = {cellpath} @ "[" @ {i} @ "]"
if({hflag} && {hsolve_chanmode > 1})
// need to provide the distance to the electrode
chan = {src} @ "/" @ {synpath}
cx = {getfield {chan} x}
cy = {getfield {chan} y}
cz= {getfield {chan} z}
distance = {sqrt { {pow {{cx} - {x}} 2.0} + \
{pow {{cy} - {y}} 2.0} + \
{pow {{cz} - {z}} 2.0} }}
raddmsg {src}/{solvepath} /electrodes/{name}@{output_node} CURRENT \
{findsolvefield {src}/{solvepath} {synpath} Ik} {distance}
else // not hsolve
raddmsg {src}/{synpath} /electrodes/{name}@{output_node} CURRENT Ik 0.0
end // if({hflag} && {hsolve_chanmode > 1})
end // loop over cells
end
function make_electrode_cells(name, cellpath, x, y, z)
str name // electrode name
str cellpath // here cellpath is {cellpath}[]
str worker_name // name used for worker electrodes
/* Example:
make_electrode_cells "Electrode_cells_Im" {cellpath}[] \
{(Ex_NX-1)*Ex_SEP_X/2.0} {39.5*Ex_SEP_Y} 0.001 // use efield_cells
*/
float x, y, z // electrode position
if (calc_LFP == 0)
return
end
if (i_am_worker_node)
if (!{exists /electrodes})
create neutral /electrodes
end
worker_name = {name} @ "_" @ {mynode}
pushe /electrodes
if ({exists {worker_name}})
delete {worker_name}
end
create efield_cells {worker_name}
setfield {worker_name} x {x} y {y} z {z}
setfield {worker_name} cellpath {cellpath}
setfield {worker_name} solvepath {solvepath} // global variable
setfield {worker_name} scale 0.32
setfield {worker_name} debug_level 0
pope
useclock /electrodes/{worker_name} 1 // clock at out_dt
end // if (i_am_worker_node)
if (i_am_output_node)
if (!{exists /electrodes})
create neutral /electrodes
end
create calculator /electrodes/{name}
useclock /electrodes/{name} 1 // clock at out_dt
end
end // function make_electrode_cells
function make_electrode_cells_messages(name)
str name, worker_name
if (i_am_worker_node)
worker_name = {name} @ "_" @ {mynode}
raddmsg /electrodes/{worker_name} /electrodes/{name}@{output_node} SUM field
end
end
function do_electrodes_out
str name, path
foreach path ({el /electrodes/#[OBJECT=efield],/electrodes/#[OBJECT=efield2]})
/* create an asc_file to output the LFP to a file
{name} @ "_" @ {RUNID} @ ".txt". Here, the asc_file element
will be /{name} and the electrode will be /electrodes/{name}
*/
name = {getpath {path} -tail}
make_output {name}
addmsg /electrodes/{name} {name} SAVE field
end
end
function do_electrodes_cells_out
str name, path
foreach path ({el /electrodes/#[OBJECT=calculator]})
name = {getpath {path} -tail}
make_output {name}
addmsg /electrodes/{name} {name} SAVE output
end
end
/********** graphics functions *********/
extern makegraphscale
function make_LFPplot
str graph_form = "/electrode_graphs"
str name, path, title_str
float x, y, z
floatformat %0.4g // limit precision of displayed x, y, z
create xform {graph_form} [280,0,400,800]
pushe {graph_form}
foreach path ({el /electrodes/#[OBJECT=efield_cells],/electrodes/#[OBJECT=efield],/electrodes/#[OBJECT=efield2]})
name = {getpath {path} -tail}
x = {getfield {path} x}; y = {getfield {path} y}; z = {getfield {path} z}
title_str = {name} @ " at " @ {x} @ " " @ {y} @ " " @ {z}
// make the graph
create xgraph {name} -hgeom 33% -title {title_str}
setfield {name} XUnits sec YUnits V
setfield {name} xmax {tmax} ymin -0.00030 ymax 0.000005
end // making electrode graphs
floatformat %0.10g // restore default precision
if (calc_EPSCsum)
create xgraph EPSCsum -hgeom 25% -title "Summed Ex_ex Currents"
setfield EPSCsum XUnits sec YUnits Amp
setfield EPSCsum xmax {tmax} ymin 0 ymax 3e-6
end
pope
// e.g. makegraphscale {graph_form}/Electrode_3
foreach path ({el /electrodes/#[OBJECT=efield_cells],/electrodes/#[OBJECT=efield],/electrodes/#[OBJECT=efield2]})
name = {getpath {path} -tail}
makegraphscale {graph_form}/{name}
end
if (calc_EPSCsum)
makegraphscale {graph_form}/EPSCsum
end
useclock {graph_form} 2
xshow {graph_form}
end
extern colors
function make_LFPplot_messages
str name, path, col_name
int col_num = 0
str graph_form = "/electrode_graphs"
foreach path ({el /electrodes/#[OBJECT=efield_cells],/electrodes/#[OBJECT=efield],/electrodes/#[OBJECT=efield2]})
name = {getpath {path} -tail}
col_name = {colors {col_num}}
addmsg /electrodes/{name} {graph_form}/{name} \
PLOT field *{name} *{col_name}
col_num = col_num + 1
end // loop over electrodes
if (calc_EPSCsum)
addmsg {data_source} {graph_form}/EPSCsum \
PLOT output *EPSC_sum *magenta
end
end