#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This program creates a Bhalla and Bower 1993 (upgraded to genesis 2 by Beeman) mitral cell model along with tables to pull data
import sys
import math
# The PYTHONPATH should contain the location of moose.py and _moose.so
# files. Putting ".." with the assumption that moose.py and _moose.so
# has been generated in ${MOOSE_SOURCE_DIRECTORY}/pymoose/ (as default
# pymoose build does) and this file is located in
# ${MOOSE_SOURCE_DIRECTORY}/pymoose/examples
# sys.path.append('../..')
import moose
from mooseConstants import *
from globalConstants import *
from pylab import * # part of matplotlib that depends on numpy but not scipy
import random
import pickle
EREST = -65.0e-3 # V
############# Set these such that 100 ORNs at approx 50Hz make the mitral cell fire in the middle of its linear range.
SYN_EXC_G = 1 * 8.6516e-9 # Siemens
SYN_INH_G = 1 * 2.2126e-9 # Siemens
class BBMitral:
def __init__(self, moosename='/mitral', table=False):
self.context = moose.PyMooseBase.getContext()
self.path = moosename
self.setupClocks()
self.loadCell()
if table:
self.setupTables()
self.addSynapses()
self.connectORNs()
# print self._mitral.method ######## By default Cell object uses hsolve method
print("<< "+moosename+" fully loaded >>")
def loadCell(self):
self.context.readCell('mit_aditya_davison_reduced.p',self.path)
self._mitral = moose.Cell(self.path)
self._mitralSoma = moose.Compartment(self.path+'/soma')
self._mitralGlom = moose.Compartment(self.path+'/glom')
self._mitralDend = moose.Compartment(self.path+'/dend')
self._mitralDendNa = moose.HHChannel(self.path+'/dend/Na_mit_usb')
self._mitralSomaNa = moose.HHChannel(self.path+'/soma/Na_mit_usb')
self._mitralSomaCaPool = moose.CaConc(self.path+'/soma/Ca_mit_conc')
self._mitralSomaLCa = moose.HHChannel(self.path+'/soma/LCa3_mit_usb')
self._mitralSomaKCa = moose.HHChannel(self.path+'/soma/Kca_mit_usb')
# Connect the LCa current to the Ca Pool
self._mitralSomaLCa.connect('IkSrc',self._mitralSomaCaPool,'current')
# Connect the KCa channel to the Ca concentration of Ca Pool
self._mitralSomaCaPool.connect('concSrc',self._mitralSomaKCa,'concen')
def addSynapses(self):
##### Excitatory + Inhibitory Synpase combo taken from the paper Djurisic etal 2008 JNeurosci.
##### Actually it's only an excitatory synapse, but they have used the inhibitory one to model the later time course.
##### Though this might be needed to account for PG cell inhibition?
##### Gbar-s have been set to ensure 16mV EPSP at the glom tuft as done in the paper.
##### Paper's defaults give only 8mV EPSP peak at glom tuft. So here multiplied by two. Cannot use supplemental table values as no cytoplasmic resistivity Ri in this model. Only axial resistance from glom to prim which doesn't matter much [maybe it does - loading rather than input resistance?]. Makes sense only if dendritic tree with many compartments.
##### Also no idea of how much to change the inhibitory part without Ri, so multiplied that also by 2
self._ExcORNSyn = moose.SynChan(self.path+"/ExcSyn")
self._ExcORNSyn.Ek = EREST + 0.07 # Volts, 70mV above EREST
self._ExcORNSyn.Gbar = 0.3 * SYN_EXC_G # Siemens
### The delay and weight can be set only after connecting a spike event generator.
### delay and weight are arrays: multiple event messages can be connected to a single synapse
self._ExcORNSyn.tau1 = 1.6094e-3 # seconds
self._ExcORNSyn.tau2 = 1.6094e-3 # seconds
self._InhORNSyn = moose.SynChan(self.path+"/InhSyn")
self._InhORNSyn.Ek = EREST - 0.01 # Volts, 10mV below EREST
self._InhORNSyn.Gbar = 0.3 * SYN_INH_G # Siemens
### The delay and weight can be set only after connecting a spike event generator.
### delay and weight are arrays: multiple event messages can be connected to a single synapse
self._InhORNSyn.tau1 = 5.6631e-3 # seconds
self._InhORNSyn.tau2 = 5.6631e-3 # seconds
self._mitralGlom.connect("channel", self._ExcORNSyn, "channel")
self._mitralGlom.connect("channel", self._InhORNSyn, "channel")
def connectORNs(self):
self.spiketable = moose.TimeTable(self.path+'/tt')
#### SynChan's synapse MsgDest takes time as its argument. Thus spiketable should contain a list of spike times.
self.spiketable.connect("event", self._ExcORNSyn,"synapse")
self.spiketable.connect("event", self._InhORNSyn,"synapse")
self._ExcORNSyn.setWeight(0, 1) # 0th element in synaptic array set to weight 1
self._InhORNSyn.setDelay(0, 7.6337e-3) # seconds
self._InhORNSyn.setWeight(0, 1) # 0th element in synaptic array set to weight 1
def setupTables(self):
self._data = moose.Neutral(self.path+"/data")
# Setup the tables to pull data
self._vmTableSoma = moose.Table("vmTableSoma", self._data)
self._vmTableSoma.stepMode = TAB_BUF #TAB_BUF: table acts as a buffer.
self._vmTableSoma.connect("inputRequest", self._mitralSoma, "Vm")
self._vmTableSoma.useClock(PLOTCLOCK)
self._vmTableGlom = moose.Table("vmTableGlom", self._data)
self._vmTableGlom.stepMode = TAB_BUF #TAB_BUF: table acts as a buffer.
self._vmTableGlom.connect("inputRequest", self._mitralGlom, "Vm")
self._vmTableGlom.useClock(PLOTCLOCK)
self._vmTableDend = moose.Table("vmTableDend", self._data)
self._vmTableDend.stepMode = TAB_BUF #TAB_BUF: table acts as a buffer.
self._vmTableDend.connect("inputRequest", self._mitralDend, "Vm")
self._vmTableDend.useClock(PLOTCLOCK)
def setupClocks(self):
###### I suppose by default all elements use clock 0 the global clock. Not sure, Niraj checked that hsolve uses clock 1
self.context.setClock(0, SIMDT, 0)
self.context.setClock(1, SIMDT, 0) #### The hsolve and ee methods use clock 1
self.context.setClock(2, SIMDT, 0) #### hsolve uses clock 2 for mg_block, nmdachan and others.
self.context.setClock(PLOTCLOCK, PLOTDT, 0)
def testMitral():
mitral = BBMitral() ## Use the default randomly generated synConns
mitral.context.reset()
mitral.context.step(RUNTIME)
plot(mitral._vmTableSoma,label='Soma Vm')
plot(mitral._vmTableGlom,label='Glom Vm')
show()
if __name__ == "__main__":
random.seed() ##### If no parameter is given, it uses current system time
testMitral()