Modelling the effects of short and random proto-neural elongations (de Wiljes et al 2017)

 Download zip file 
Help downloading and running models
Accession:231859
"To understand how neurons and nervous systems first evolved, we need an account of the origins of neural elongations: why did neural elongations (axons and dendrites) first originate, such that they could become the central component of both neurons and nervous systems? Two contrasting conceptual accounts provide different answers to this question. Braitenberg's vehicles provide the iconic illustration of the dominant input-output (IO) view. Here, the basic role of neural elongations is to connect sensors to effectors, both situated at different positions within the body. For this function, neural elongations are thought of as comparatively long and specific connections, which require an articulated body involving substantial developmental processes to build. Internal coordination (IC) models stress a different function for early nervous systems. Here, the coordination of activity across extended parts of a multicellular body is held central, in particular, for the contractions of (muscle) tissue. An IC perspective allows the hypothesis that the earliest proto-neural elongations could have been functional even when they were initially simple, short and random connections, as long as they enhanced the patterning of contractile activity across a multicellular surface. The present computational study provides a proof of concept that such short and random neural elongations can play this role. ..."
Reference:
1 . de Wiljes OO, van Elburg RAJ, Keijzer FA (2017) Modelling the effects of short and random proto-neural elongations. J R Soc Interface [PubMed]
Model Information (Click on a link to find other models with that property)
Model Type:
Brain Region(s)/Organism:
Cell Type(s): Abstract integrate-and-fire leaky neuron;
Channel(s):
Gap Junctions:
Receptor(s):
Gene(s):
Transmitter(s):
Simulation Environment: Brian 2; Python;
Model Concept(s): Early evolution;
Implementer(s): de Wiljes, O. O. [otdewiljes at gmail.com];
# -*- coding: utf-8 -*-
"""
Created on Wed Sep 24 00:22:34 2014

TODO:
* parallelize

@author: Oddman
"""

## import builtins whole
import os, collections, itertools, json, time, shutil, logging, zipfile
## ... or with an alias
import cPickle as pkl
## ... or partly
from multiprocessing import Pool
## Import brian
from brian2 import *
## Import packaged dependencies
from scipy.spatial import distance
#import visual as vp
## import local script dependencies
#import povexport

#==============================================================================
# Globals
#==============================================================================
FILE_LOG_LEVEL = logging.DEBUG
CONSOLE_LOG_LEVEL = logging.DEBUG
PARALLEL = True
CPUS = 2
codegen.target = 'cython'
#==============================================================================
# Define namedtuples
#==============================================================================
Link = collections.namedtuple(
            'Link',
            [
                'fromCell',
                'toCell',
                'fromCellIndex',
                'toCellIndex',
                'linkType',
                'linkWeight',
                'rhosum' ## actual distance over elongations
            ]
)

#def characterizer(
#        runProfile,
#    ):
#    x = 
##    print x
#    print json.dumps(x)

#==============================================================================
# Define functions
#==============================================================================

def dictifyArray(indices,spikeTimes,totalCells):
    '''Turns a pair of arrays containing spiketimes and indices into a dict
    with indices for keys and their spikes as values.'''
    targetDict = dict((i,[]) for i in range(totalCells))
#    print [indices,spikeTimes,totalCells]
    for i in range(len(indices)):
        targetDict[indices[i]].append(spikeTimes[i])
    return targetDict

def productProfiler(multiprofileDict):
    return None
    

def spawnTriangularGridTubularCells(
        length,
        circumference,
        excWeight,
        pacemakerType = None,
        excMikadoDensity = 0.,
        excMikadoDistance = None,
        inhibMikadoDensity = 0.,
        inhibMikadoDistance = None,
        inhibWeight = 0.
    ):
    cellTypes = {}
    cellTypeCount = 0
    inCellTypeIndices = {}
    c = 0
    l = 0
    nCells = length * circumference
    assert excMikadoDensity + inhibMikadoDensity <= 1.
    for i in range(nCells):
        if pacemakerType == 'singleCellExc' and i == 0:
            cellType = 'activeExcitatory'
#            inhib = False
            weight = excWeight
        elif pacemakerType == 'ringExc' and i < circumference:
            cellType = 'activeExcitatory'
#            inhib = False
            weight = excWeight
        else:
            cellType = 'passiveExcitatory'
            weight = excWeight
        mikadoRoll = rand()
        if mikadoRoll < excMikadoDensity:
            connectivity = 'excMikado'
            mikadoOrientation = (rand()*pi*2) - pi#(random.randint(-36,35) / 36.) * pi
            mikadoDistance = excMikadoDistance            
            weight = excWeight
        elif mikadoRoll < excMikadoDensity + inhibMikadoDensity:
            connectivity = 'inhibMikado'
            mikadoOrientation = (rand()*pi*2) - pi#(random.randint(-36,35) / 36.) * math.pi
            mikadoDistance = inhibMikadoDistance            
            weight = inhibWeight
        else:
            connectivity = None
            mikadoOrientation = None
            weight = excWeight
            mikadoDistance = None
        circumferenceIndex = c
        lengthIndex = l
        c += 1
        if c == circumference:
            c = 0
            l += 1
        try:
            cellTypeIndex = cellTypes[cellType]
        except KeyError:
            cellTypes[cellType] = cellTypeCount
            cellTypeIndex = cellTypes[cellType]
            cellTypeCount += 1
        try:
            inCellTypeIndices[cellType] += 1
        except KeyError:
            inCellTypeIndices[cellType] = 0
        radius = circumference / (2 * pi)  
        angleProp = (circumferenceIndex / float(circumference))
        angle = angleProp * 2 * pi
        if lengthIndex % 2 == 1:
            angle += (2 * pi) / (circumference * 2)
        x = sin(angle) * radius
        y = cos(angle) * radius
        z = lengthIndex * sqrt(.75)
        coordinates = (x,y,z)
        flatX = lengthIndex * sqrt(.75)
        flatY = circumferenceIndex
        if lengthIndex % 2 == 1:
            flatY += sqrt(.75) * .5 
        flatCoordinates = (flatX,flatY)
        cell = Cell(
                i,
                weight,
                coordinates,
                flatCoordinates = flatCoordinates,
                cellType = cellType,
                connectivity = connectivity, 
                mikadoOrientation = mikadoOrientation,
                mikadoDistance = mikadoDistance,
                cellTypeIndex = cellTypeIndex, 
                inCellTypeIndex = inCellTypeIndices[cellType]
            )
        yield cell

def modelRunWorker(cellModelParameters,networkParameters,_runParameters,_runCntr,_topologyCachePath,_outputDir,_useCache,_metadataPickler):
    '''Multiprocessing worker function to execute a SkinBrain model.'''
    thisRunMetadata = collections.OrderedDict()          
#    cellModelParameters = _runProfile[0]._asdict()
#    print cellModelParameters.keys()
#    networkParameters = _runProfile[1]._asdict()
    cellModelType = cellModelParameters['cellModelType']            
    networkType = networkParameters['networkType']
    ## set up some metadata for ease of file identification
    thisRunMetadata['cellModelParameters'] = cellModelParameters
    thisRunMetadata['networkParameters'] = networkParameters     
    thisRunMetadata['runParameters'] = _runParameters         
    networkTopology = NetworkTopology(
        networkType,
        cacheDir = _topologyCachePath
    )
    networkTopology.generate(networkParameters,cache=_useCache)
    thisRunMetadata['networkTopologyFileName'] = networkTopology.fileName
    thisRunMetadata['cacheDir'] = networkTopology.cacheDir
    cellModelImplementation = BrianCellMechanismImplementation(
        networkTopology,
        cellModelType,
        cellModelParameters,
        logger = None
    )
    json.encoder.FLOAT_REPR = lambda o: format(o, '.3f')
    spikeFilePath = _outputDir + 'spikefile_%s.json'%_runCntr
    spikeZipFilePath = _outputDir + 'spikefile_%s.zip'%_runCntr
    indices,spikeTimes = cellModelImplementation.run(_runParameters)#.items()
    runOut = dictifyArray(indices,spikeTimes,len(networkTopology.cells))
    runOut = dict((key,np.array(val)) for key,val in runOut.items())
    with open(spikeFilePath,'wb') as spikeFile:
        json.dump(
            [
                (i,list(spikeArray*1000))
                for i,spikeArray 
                in runOut.items()
            ],
            spikeFile
        )
    with zipfile.ZipFile(spikeZipFilePath,'w',compression=zipfile.ZIP_DEFLATED) as zipSpikeFile:
        zipSpikeFile.write(spikeFilePath,'spikefile_%s.json'%_runCntr)
    os.remove(spikeFilePath)
    print thisRunMetadata
#    successFile = open(_outputDir+'last_successful_run_index','w')
#    successFile.write(str(_runCntr))
#    successFile.close()
    _metadataPickler.dumpMetadata(_runCntr,thisRunMetadata)
    return _runCntr
    

#==============================================================================
# Define classes
#==============================================================================
#class MetadataContainer(collections.OrderedDict):
#    def setDumpFilename(self,dumpFilename):
#        self.dumpFilename = dumpFilename
#        
#    def updateMetadata(self,key,val):
#        self.__setitem__(key,val)
#        self.dumpJSON()
#        
#    def dumpJSON(self):
#        with open(self.dumpFilename,'wb') as metadatafile:
#            metadatafile.write('')
#        with open(self.dumpFilename,'wb') as metadatafile:
#            json.dump(self,metadatafile,indent=4)
            
class MetadataPickler:
    def __init__(self,dumpFilenameBase):
        self.dumpFilenameBase = dumpFilenameBase
       
    def dumpMetadata(self,runCntr,thisRunMetadata):
        runNum = ('0000'+str(runCntr))[-5:]
        with open(self.dumpFilenameBase+runNum+'.pkl','wb') as outfile:
            pkl.dump((runCntr,thisRunMetadata),outfile)
        
#    def dumpJSON(self):
#        with open(self.dumpFilename,'wb') as metadatafile:
#            metadatafile.write('')
#        with open(self.dumpFilename,'wb') as metadatafile:
#            json.dump(self,metadatafile,indent=4)
        

class Cell:
    def __init__(self, 
         overallIndex, weight, coordinates, flatCoordinates = None, cellType = None, 
         inhib = False, connectivity = None, mikadoOrientation = None,
         mikadoDistance = None, cellTypeIndex = None, inCellTypeIndex = None
    ):
        self.overallIndex = overallIndex
        self.coordinates = coordinates
        [self.x,self.y,self.z] = self.coordinates
        self.flatCoordinates = flatCoordinates
        self.cellType = cellType
        self.connectivity = connectivity
        self.mikadoOrientation = mikadoOrientation
        self.mikadoDistance = mikadoDistance
        self.cellTypeIndex = cellTypeIndex
        self.inCellTypeIndex = inCellTypeIndex
        self.weight = weight
#        for k,v in self.__dict__.items():
#            print [k,v]


class NetworkTopology:
    def __init__(self,networkType, cacheDir = './'):
        self.networkType = networkType
        self.cacheDir = cacheDir.rstrip('/') + '/'
        
    def loadFromFile(self,cacheDir,fileName):
        print "Loading cached network topology from: " + cacheDir + fileName+'.zip'
        self.pathToCacheFile = cacheDir+fileName+'.zip'
        with zipfile.ZipFile(cacheDir+fileName+'.zip','r') as openZip:
            openFile = openZip.open(fileName+'.pkl')
            [
                    loadedNetworkType,
                    self.networkParameters,
                    self.cells,
                    self.links
            ] = pkl.load(openFile) 
            openFile.close()
        assert loadedNetworkType == self.networkType
        
    def generate(self,networkParameters, cache = True, cacheDir = None, fileName = None,createCache = True):
        self.networkParameters = networkParameters
        if fileName == None:
            self.fileName = [
                (k[:4] + str(v)).replace('.','') 
                for k,v in sorted(networkParameters.items())
            ]
            self.fileName = (
                'NetImp_' + self.networkType + '_' + 
                '_'.join(self.fileName)
            )
            assert len(self.fileName) <= 255
        else: self.fileName = fileName
        currentCacheDir = [cacheDir,self.cacheDir][cacheDir == None]
            
        if cache and os.path.exists(currentCacheDir + self.fileName+'.zip'):
            ## try loading previous version.
            self.loadFromFile(currentCacheDir,self.fileName)
        else:
            ## no cache or no cache found? run it :)
             self.buildTopology()
             ## and then build a cache file
             if createCache:
                 self.serialize()
          
    def buildTopology(self):
        if self.networkType == 'triangularGridTubular':
            ## turn the network parameters into object parameters of this
            ## NetworkTopologyImplementation.
            self.__dict__.update(self.networkParameters)
            [self.cells, self.links] = self.generateTriangularGridTubularNetwork()

                
    def generateTriangularGridTubularNetwork(self):
        #======================================================================
        # First, generate the nodes / cells.
        #======================================================================
        cellBuildingBlocks = []
        overallIndex = 0
        seed(self.networkDummySeed)
        self.length = self.length_circumference[0]
        self.circumference = self.length_circumference[1]
        cells = [
            i for i in 
            spawnTriangularGridTubularCells(
                self.length, self.circumference, self.excSynapseWeight,
                pacemakerType = self.pacemakerStructure,                
                excMikadoDensity = self.excMikadoDensity, 
                excMikadoDistance = self.excMikadoDistance,
                inhibMikadoDensity = self.inhibMikadoDensity,
                inhibMikadoDistance = self.inhibMikadoDistance,
                inhibWeight = self.inhibSynapseWeight
            )
        ]
        #======================================================================
        # Nodes done? Do the links / synapses.
        #======================================================================
        links = []
        for fromCellIndex,fromCell in enumerate(cells):
            for toCellIndex,toCell in enumerate(cells):
                autapse = fromCellIndex == toCellIndex     ## no autapses
                doubleCheck = toCellIndex < fromCellIndex  ## no double checking
                if not autapse and not doubleCheck:
                    rowDist = absolute(fromCell.z - toCell.z)
                    if rowDist <= self.connectionDistance:
                        linkDistance = distance.euclidean(
                                fromCell.coordinates,toCell.coordinates)
                        if linkDistance <= self.connectionDistance:
                            links.append(
                                Link(
                                    fromCell,
                                    toCell,
                                    fromCellIndex,
                                    toCellIndex,
                                    'pancake',
                                    fromCell.weight,
                                    1 ## distance measure
                                )
                            )
                            links.append(
                                Link(
                                    toCell,
                                    fromCell,
                                    toCellIndex,
                                    fromCellIndex,
                                    'pancake',
                                    toCell.weight,
                                    1 ## distance measure
                                )
                            )
                    #==========================================================
                    # Add the mikado-links.
                    #==========================================================   
                    if (    fromCell.connectivity in ['excMikado','inhibMikado'] and 
                            toCell.connectivity in ['excMikado','inhibMikado']
                    ):
                        mikadoLinks = self.mikadoIze(
                            fromCell,
                            toCell)
                        if mikadoLinks != None:
                            links.extend(mikadoLinks)
        return [cells,links]
        
    def serialize(self): 
        if not os.path.exists(self.cacheDir):
            os.mkdir(self.cacheDir)
        self.pathToCacheFile = self.cacheDir + self.fileName+'.zip'
        with open(self.cacheDir + self.fileName+'.pkl','wb') as openFile:
            pkl.dump(
                [
                    self.networkType,
                    self.networkParameters,
                    self.cells,
                    self.links
                ],
                openFile
            )
        with zipfile.ZipFile(self.pathToCacheFile,'w',compression=zipfile.ZIP_DEFLATED) as zipCache:
            zipCache.write(self.cacheDir + self.fileName+'.pkl',self.fileName+'.pkl')
        os.remove(self.cacheDir + self.fileName+'.pkl')
        
        
            
    def mikadoIze(self,fromCell,toCell):
        weight = False
        maxWinding=int(max([fromCell.mikadoDistance,toCell.mikadoDistance])/self.circumference)+1
        if fromCell.overallIndex < toCell.overallIndex:
            pass
        else:
            fromCell,toCell = toCell,fromCell
        fromCellDistance = fromCell.mikadoDistance
        toCellDistance = toCell.mikadoDistance#[self.excMikadoDistance,self.inhibMikadoDistance][toCell.connectivity == 'inhibMikado']
        totalDistance = fromCellDistance + toCellDistance
        fromCellX = fromCell.flatCoordinates[0]
        fromCellY = fromCell.flatCoordinates[1]
        fromCellPhi = fromCell.mikadoOrientation
        toCellX = toCell.flatCoordinates[0]
        toCellY = toCell.flatCoordinates[1]
        toCellPhi = toCell.mikadoOrientation
        xDistance = toCellX - fromCellX
        yDistance = toCellY - fromCellY
#        print 'distances: '+repr([xDistance,yDistance])
        for winding in range(-maxWinding,maxWinding+1,1):
            distance = sqrt((yDistance+(winding*self.circumference))**2 + xDistance**2)
            phid = arctan2(yDistance+(winding*self.circumference),xDistance)
#            phid = math.atan2(xDistance,yDistance+(winding*self.circumference))
            ## Only ever do anything if distance < 2 * mikadoDistance
            if distance < totalDistance:
                 ##analyse degenerate cases separately
                if (    (toCellPhi == (fromCellPhi - pi)) or 
                        (toCellPhi == (fromCellPhi + pi)) or
                        (toCellPhi == fromCellPhi) 
                ):
#                    print 'degenerate case'
                    if (    (phid == fromCellPhi - pi) or 
                            (phid == fromCellPhi + pi)
                    ):
                        if (    (   (phid == toCellPhi - pi) or 
                                    (phid == toCellPhi + pi)
                                ) and 
                                distance < fromCellDistance 
                        ):
                            weight = True
                            cache_rhosum = distance	
                    elif (phid == fromCellPhi):
                        if (distance < self.excMikadoDistance):
                            weight = True
                            cache_rhosum = distance
                        elif (  (   (phid == toCellPhi - pi) or 
                                    (phid == toCellPhi + pi)
                                ) and distance < totalDistance
                        ):
                            weight = True
                            cache_rhosum = distance
                else:
#                    print 'non-degenerate case.'
                    rho1 = (
                        (distance * sin(phid - toCellPhi)) 
                        / 
                        (sin(toCellPhi - fromCellPhi))
                    )
                    rho2 = (
                        (distance * sin(phid - fromCellPhi)) 
                        / 
                        (sin(toCellPhi - fromCellPhi))
                    )
#                    print 'rhos: '+repr([rho1,rho2])
                    if (    (rho1 < fromCellDistance) 
                            and 
                            (rho2 < toCellDistance)
                        ):
                        ## Check whether crossing is on the cylinder
                        if(-0.5 <= fromCellX+rho1*cos(toCellPhi) <= (self.length-1)*sqrt(0.75)+0.5): 
                            weight = True
                            cache_rhosum = abs(rho1)+abs(rho2)	
        if weight != False:      
#            print 'some result.'  
            return [Link(
                    fromCell,
                    toCell,
                    fromCell.overallIndex,
                    toCell.overallIndex,
                    'mikado',
                    fromCell.weight,
                    cache_rhosum
            ),
                Link(
                    toCell,
                    fromCell,
                    toCell.overallIndex,
                    fromCell.overallIndex,
                    'mikado',
                    toCell.weight,
                    cache_rhosum
            ),
            ]
#        else:
##            print 'No dice.'
#            pass
        
        
class BrianCellMechanismImplementation:
    def __init__(
            self,
            networkTopology,
            cellMechanismType,
            cellMechanismParameters,
            logger = None
    ):
        self.cellMechanismType = cellMechanismType
        self.networkTopology = networkTopology
        self.cellMechanismParameters = cellMechanismParameters
        if logger == None:
            self.logger = logging.getLogger('SkinBrian_2')
        else:
            self.logger = logger
            
    def run(self,runParameters):
        if self.cellMechanismType == 'uniformHH':
            spikeMonitor = self.uniformHH(self.cellMechanismParameters, runParameters)
        if self.cellMechanismType == 'IF':
            spikeMonitor = self.IF(self.cellMechanismParameters, runParameters)
#        print spikeMonitor.t
#        print 
        return [np.array(spikeMonitor.i),np.array(spikeMonitor.t)]

    #==========================================================================
    # HH functions
    #==========================================================================
    def uniformHH(self,cellMechanismParameters,uniformHHRunParameters):
        ## clear up the environment.
        clear(erase=True)
        k = MagicNetwork(verbose=False)
        k.reinit()
        # test whether parameters get passed
#        print cellMechanismParameters['cellModelDummySeed']
        area=1257*umetre**2
        Cm=(1.*ufarad*cm**-2)*area ## == 12.57 pF
        gl=(3e-5*siemens*cm**-2)*area
        El=-54.3*mV
        EK=-77*mV
        ENa=50*mV
        g_na=(120*msiemens*cm**-2)*area
        g_kd=(36*msiemens*cm**-2)*area
        VT=-63*mV
        # Time constants
        taue=2*ms
        taui=10*ms
        # Reversal potentials
        Ee=0*mV
        Ei=-80*mV
        we=6*nS # excitatory synaptic weight (voltage)
        wi=67*nS # inhibitory synaptic weight
        # The model
        eqs=Equations('''
dv/dt = (gl*(El-v)+ge*(Ee-v)+gi*(Ei-v)-g_na*(m*m*m)*h*(v-ENa)-g_kd*(n*n*n*n)*(v-EK))/Cm : volt
dm/dt = alpham*(1-m)-betam*m : 1
dn/dt = alphan*(1-n)-betan*n : 1
dh/dt = alphah*(1-h)-betah*h : 1
dge/dt = -ge*(1./taue) : siemens
dgi/dt = -gi*(1./taui) : siemens
alpham = 0.32*(mV**-1)*(13*mV-v+VT)/(exp((13*mV-v+VT)/(4*mV))-1.)/ms : Hz
betam = 0.28*(mV**-1)*(v-VT-40*mV)/(exp((v-VT-40*mV)/(5*mV))-1)/ms : Hz
alphah = 0.128*exp((17*mV-v+VT)/(18*mV))/ms : Hz
betah = 4./(1+exp((40*mV-v+VT)/(5*mV)))/ms : Hz
alphan = 0.032*(mV**-1)*(15*mV-v+VT)/(exp((15*mV-v+VT)/(5*mV))-1.)/ms : Hz
betan = .5*exp((10*mV-v+VT)/(40*mV))/ms : Hz
        ''')
        ## set up the cells in Brian
        ## (uniform, so only one group)
        self.cellGroup = NeuronGroup(
                len(self.networkTopology.cells), 
                model = eqs,
                threshold = EmpiricalThreshold(
                        threshold=-20*mV,
                        refractory=3*ms
                ),
                implicit=True,
                freeze=True
        )            
        ## set up the connections
        ## starts empty, so this is nothing yet
        self.cellConnections = Connection(
                self.cellGroup, 
                self.cellGroup, 
                'ge', 
#                weight=we, 
                delay = 3.0 * ms
            )  
        ## fill in the connections according to the topology
        for link in self.networkTopology.links:
            self.cellConnections[link.fromCellIndex, link.toCellIndex] = (
                we * link.linkWeight
            )
        ## set the starting values to something random
        self.cellGroup.v = El+(randn(len(self.cellGroup))*5-5)*mV
        self.cellGroup.ge = (randn(len(self.cellGroup))*1.5+4)*10.*nS
        self.cellGroup.gi = (randn(len(self.cellGroup))*12+20)*10.*nS 
        ## set up a poisson noise generator and connect it
        poissonNoiseGenerator = PoissonGroup(
            len(self.networkTopology.cells),
            rates = self.cellMechanismParameters['noise'] * hertz, 
        )
        poissonConnections = Connection(
                poissonNoiseGenerator, ## from
                self.cellGroup,        ## to 
                'ge'                   ## acts on
        )
        poissonConnections.connect_one_to_one(
                poissonNoiseGenerator,
                self.cellGroup,
                weight = we * self.networkTopology.networkParameters['noiseWeight']
        )
        ## set up the spike monitor
        self.spikeMonitor = SpikeMonitor(self.cellGroup)   
        
        ## set up the custom end condition, where we end when the spike count
        ## reaches a certain number.
        ## (The simulation still terminates then t_end is reached; it's 
        ## whichever condition is reached first.)
        @network_operation
        def spikeCountStop():
            maxCount = uniformHHRunParameters['maxSpikeCountPerCell'] * len(self.networkTopology.cells)
            if self.spikeMonitor.nspikes >= maxCount:
                self.network.stop()
        ## bung everything into a network
        network = Network(
                spikeCountStop,
                self.cellGroup,
                self.cellConnections,
                self.spikeMonitor,
                poissonNoiseGenerator,
                poissonConnections
        )
        ## run the network & return the spike train
        self.logger.debug('Start actual running.')
        network.run(uniformHHRunParameters['t_end']*ms)
        return self.spikeMonitor
#        raster_plot(self.spikeMonitor)
#        show() 

    def IF(self,cellMechanismParameters,IFRunParameters):
        '''
        Simple but functional.
        '''
        self.logger.debug('starting IF run')
        ## clear up the environment.
#        clear(erase=True)
#        k.remove()
#        k = MagicNetwork()
#        k.reinit()
        ## mechanism itself
        tau = 10 * msecond
        Vt = 0 * mvolt
        Vr = -10 * mvolt
        El = 1 * mvolt
#        Ac = 0
        baseW = 10 * mvolt
        cellsPerType = dict()
        for cell in self.networkTopology.cells:
#            print cell.cellType
            try:           
                cellsPerType[cell.cellType].append(cell)
            except KeyError:
                cellsPerType[cell.cellType] = [cell]
        self.logger.debug('{0} cell objects initialized'.format(len(self.networkTopology.cells)))
        cellGroupDefs = [(len(v), k) for k,v in cellsPerType.items()]
        model = '''
            dV/dt = Ac*-(V-El)/tau : volt (unless refractory)
            Ac : 1
        '''
        
#        '''
#            dv/dt  = (ge+gi-(v-El))/taum : volt (unless refractory)
#            dge/dt = -ge/taue : volt
#            dgi/dt = -gi/taui : volt
#        '''
        cellGroups = []
        typeGroupDict = {}
        allCells = NeuronGroup(
                N=sum([a for a,b in cellGroupDefs]), 
                model = model, 
                threshold = 'V > Vt', 
                reset = 'V = Vr',
                refractory = 20. * ms
            )
        
        for cell in self.networkTopology.cells:
            if cell.cellType == 'activeExcitatory': 
                cI = cell.overallIndex
                allCells[cI:cI+1].Ac = 1. ## can only slice, hence a slice of 1
        allConns = Synapses(
                allCells, 
                allCells, 
                model = 'w : volt',
                on_pre =  'V_post += w'
        )
        self.logger.debug('Synapses set up.')
#        allConns.w = psp
        
#        allConns.w = psp
#        allConns.connect_full(
#                allCells, 
#                allCells, 
#                weight = 0*psp, 
#                delay = 6.
#        )
        self.logger.debug('Setting up {0} links (synapses)'.format(len(self.networkTopology.links)))
        fromList = []
        toList = []
        for link in self.networkTopology.links:
#            print link
            fromList.append(link.fromCell.overallIndex)
            toList.append(link.toCell.overallIndex)
#            allConns.connect(link.fromCell.overallIndex, link.toCell.overallIndex)
#        print [fromList,toList]
        allConns.connect(i=fromList,j=toList)
        allConns.w = 1.01 * baseW
#        allConns.delay = 2.*msecond
        if self.networkTopology.transmissionSpeed == None:
            allConns.delay = 2.*msecond
        else:
            for link in self.networkTopology.links:
                i = link.fromCell.overallIndex
                j = link.toCell.overallIndex
                thisDelay = (
                    self.networkTopology.cellSize *
                    link.rhosum
                ) / self.networkTopology.transmissionSpeed
                allConns.delay[i,j] = 2.*msecond + thisDelay *second
#        for link in self.networkTopology.links:
#            lid = (link.fromCell.overallIndex,link.toCell.overallIndex)
#            allConns[lid].w = baseW * link.linkWeight
        self.logger.debug('Synapses connected.')
        poissonInput = PoissonInput(
            allCells, target_var = 'V', N=1,#len(self.networkTopology.cells), 
            rate=self.cellMechanismParameters['noise']*Hz,
            weight=self.networkTopology.networkParameters['noiseWeight'] * baseW
        )
        ## set up the spike monitor
        self.spikeMonitor = SpikeMonitor(allCells)
        ## set up a single cell monitor
        self.cellMonitor = StateMonitor(allCells,'V',record=[0, 1,2,3,4,5])
        
        ## set up the custom end condition, where we end when the spike count
        ## reaches a certain number.
        ## (The simulation still terminates then t_end is reached; it's 
        ## whichever condition is reached first.)
        @network_operation
        def spikeCountStop():
            if self.spikeMonitor.num_spikes >= IFRunParameters['maxSpikeCountPerCell'] * len(self.networkTopology.cells):
                self.network.stop()
        ## bung everything into a network
        self.network = Network(
                spikeCountStop,
                self.spikeMonitor,
                self.cellMonitor,
                poissonInput,
                allCells,
                allConns
        )
#        for i in cellGroups + connGroups:
#            self.network.add(i)
        ## run the network & return the spike train
        self.logger.debug('Start actual running.')
        self.network.run(IFRunParameters['t_end']*ms)
        subplot(211)
        plot(self.spikeMonitor.t/ms, self.spikeMonitor.i, '.k')
#        raster_plot(self.spikeMonitor)
        subplot(212)
        plot(self.cellMonitor.t / ms, self.cellMonitor.V[0] / mV)
        plot(self.cellMonitor.t / ms, self.cellMonitor.V[1] / mV)
        print 'should show'
        show()
        return self.spikeMonitor

#    def IF1(self,cellMechanismParameters,IFRunParameters):
#        '''
#        Simple but functional.
#        '''
#        ## clear up the environment.
#        clear(erase=True)
#        k = MagicNetwork(verbose=False)
#        k.reinit()
#        ## mechanism itself
#        tau = 10 * msecond
#        Vt = 0 * mvolt
#        Vr = -10 * mvolt
#        El = 1 * mvolt
#        Ac = 0
#        psp = 10 * mvolt
#        cellsPerType = dict()
#        for cell in self.networkTopology.cells:
##            print cell.cellType
#            try:           
#                cellsPerType[cell.cellType].append(cell)
#            except KeyError:
#                cellsPerType[cell.cellType] = [cell]
#        cellGroupDefs = [(len(v), k) for k,v in cellsPerType.items()]
#        model = '''
#            dV/dt = Ac*-(V-El)/tau : volt
#            Ac : 1
#        '''
#        cellGroups = []
#        typeGroupDict = {}
#        allCells = NeuronGroup(
#                N=sum([a for a,b in cellGroupDefs]), 
#                model = model, 
#                threshold = Vt, 
#                reset = Vr,
#                refractory = 20. * ms
#            )
#        
#        for cell in self.networkTopology.cells:
#            if cell.cellType == 'activeExcitatory': 
#                allCells[cell.overallIndex].Ac = 1.
#        allConns = DelayConnection(
#                allCells, 
#                allCells, 
#                'V',
#                delay = 3.0*msecond,
#                maxDelay = 6.*msecond
#        )
#        allConns.connect_full(
#                allCells, 
#                allCells, 
#                weight = 0*psp, 
#                delay = 6.
#        )
#        for link in self.networkTopology.links:
##            print link
#            allConns[link.fromCell.overallIndex, link.toCell.overallIndex] = (
#                psp * link.linkWeight
#            )
#        poissonInput = PoissonInput(
#            allCells, N=1,#len(self.networkTopology.cells), 
#            rate=self.cellMechanismParameters['noise'],
#            weight=self.networkTopology.networkParameters['noiseWeight'] * psp,
#            state='V'
#        )
#        ## set up the spike monitor
#        self.spikeMonitor = SpikeMonitor(allCells)
#        ## set up a single cell monitor
#        self.cellMonitor = StateMonitor(allCells,'V',record=[0, 1])
#        
#        ## set up the custom end condition, where we end when the spike count
#        ## reaches a certain number.
#        ## (The simulation still terminates then t_end is reached; it's 
#        ## whichever condition is reached first.)
#        @network_operation
#        def spikeCountStop():
#            if self.spikeMonitor.nspikes >= IFRunParameters['maxSpikeCountPerCell'] * len(self.networkTopology.cells):
#                self.network.stop()
#        ## bung everything into a network
#        self.network = Network(
#                spikeCountStop,
#                self.spikeMonitor,
#                self.cellMonitor,
#                poissonInput,
#                allCells,
#                allConns
#        )
##        for i in cellGroups + connGroups:
##            self.network.add(i)
#        ## run the network & return the spike train
#        self.network.run(IFRunParameters['t_end']*ms)
#        subplot(211)
#        raster_plot(self.spikeMonitor)
#        subplot(212)
#        plot(self.cellMonitor.times / ms, self.cellMonitor[0] / mV)
#        plot(self.cellMonitor.times / ms, self.cellMonitor[1] / mV)
#        show()
#        return self.spikeMonitor

class NetworkRun3dVisualizer:
    def __init__(self,networkTopology,spikes = None, cellRadius = .5,
                 cylinderRadius = .01, stepSize = 2, showLinks = False, 
                 flatCamera = False, opacity = .8, output = False, 
                 targetFolder = None):
        self.name = networkTopology.fileName
        nodes = networkTopology.cells
        links = networkTopology.links
#        print len(nodes)
        zippedCoordinates = zip(*[node.coordinates for node in nodes])
        [maxX,maxY,maxZ] = [max(coord) for coord in zippedCoordinates]
        [minX,minY,minZ] = [min(coord) for coord in zippedCoordinates]
        print [ [maxX,maxY,maxZ], [minX,minY,minZ]]
        zippedCoordinates = zip(*[node.coordinates for node in nodes])
        [maxX,maxY,maxZ] = [max(coord) for coord in zippedCoordinates]
        [minX,minY,minZ] = [min(coord) for coord in zippedCoordinates]
        print [ [maxX,maxY,maxZ], [minX,minY,minZ]]
        ## nobody cares about x; we want to know the deltaY / deltaZ proportion
        deltaY = maxY - minY
        deltaZ = maxZ - minZ
        [propY,propZ] = [i/float(max([deltaY,deltaZ])) for i in [deltaY,deltaZ]]
        print [propY,propZ]
        self.stepSize = stepSize
        self.cellRadius = cellRadius
        self.scene = vp.scene
        self.scene.width = 1000 #int(1000*propZ)
        self.scene.height = 1000 #int(1000*propY)
        self.scene.autocenter = False
        self.scene.background = vp.vector(1,1,1)##vp.vector(.8,.8,.8)        
        self.scene.forward = vp.vector(-1,0.,0.)
        self.scene.center = vp.vector(0,0,deltaZ*.5)
        self.scene.range = max([deltaY,deltaZ])
        self.activeNodeColour = vp.vector(1.,0.,0.)
        self.inactiveNodeColour = vp.vector(1.,1.,1.)
        self.opacity = opacity
        self.output = output
        self.targetFolder = targetFolder
        self.nodeDict = dict(
            (i,
            vp.sphere(
                pos = (vp.vector(node.coordinates)),
                opacity = opacity,
                radius = self.cellRadius))
            for i,node
            in enumerate(nodes)
        )
        links = [(link[0].overallIndex, link[1].overallIndex) for link in links]
        self.linkdict = dict()
        if showLinks == True:
            for link in links:
                self.linkdict[link] = vp.cylinder(
                    pos = self.nodeDict[list(link)[0]].pos,
                    axis = self.nodeDict[list(link)[1]].pos - self.nodeDict[list(link)[0]].pos,
                    opacity = opacity,
                    radius = cylinderRadius)
                    
    def alignEvents(self,spikes):
        ## the format of spikes produced by brian is a list of
        ## arrays, spike times of cells.
        ## the time of the last spike in ms/binsize, rounded up
        self.cellsfiringpermoment = dict((i,[]) for i in range(self.maxtime))
        ## for every spike, put the cellindex in the appropriate time-bin
#        for cellindex,spikeTrain in spikes.items():
#            print max(spikeTrain)
#            for spiketime in spikeTrain:
#                print max()
#                self.cellsfiringpermoment[int(spiketime * 1000.)].append(cellindex)       
        [
            [
                self.cellsfiringpermoment[int(spiketime)].append(cellindex)
                for spiketime
                in spikeTrain
            ]
            for cellindex,spikeTrain
            in spikes.items()
        ]
        print self.cellsfiringpermoment

    def step(self):
        print 'curtime (ms): ' + str(self.curtime)
        self.adjustColor(self.curtime)
        self.curtime += self.stepSize
        if self.output == True:
            vp.scene.visible = False
#            vp.scene.title = 
            vp.scene.visible = True
            ## take a picture
            povexport.export(display=vp.scene,filename=("viz_shot_" + str(self.curtime).rjust(3,'0')+'.pov'), include_list = ['colors.inc'],xy_ratio=1)
            povexport.export()

    def adjustColor(self,curTime):
#        print 'adjusting colors!'
#        print self.cellsfiringpermoment[curTime]
        ## reset stuff to inactive
        [
            node.__setattr__('color',self.inactiveNodeColour) 
            for node in self.nodeDict.values()
        ]
        [
            node.__setattr__('opacity',self.opacity) 
            for node in self.nodeDict.values()
        ]
#        print [self.nodeDict[cellidx] for cellidx in self.cellsfiringpermoment[curTime]]
        try:
            firings = [self.cellsfiringpermoment[t] for t in range(curTime,curTime+self.stepSize,1)]
            activeCells = []
            for f in firings:
                activeCells.extend(f)
        except KeyError:
           activeCells = []
#        print activeCells
        [
            self.nodeDict[cellidx].__setattr__('opacity',1.) 
            for cellidx in activeCells
        ]
        [
            self.nodeDict[cellidx].__setattr__('color',self.activeNodeColour) 
            for cellidx in activeCells
        ]
#        if self.links:
#            [link.__setattr__('color',self.linkcolour) for link in self.linkdict.values()]
#            [self.linkdict[link].__setattr__('color',self.colourdict[link]) for link in self.linksfiringpermoment[time]]

    def run(self,spikeFilePath,mintime=0,maxtime=None,stepSize = 10.):
        with open(spikeFilePath,'r') as spikeFile:
            spikes = dict(json.load(spikeFile))
#        try:
        self.maxMs = max([max(spikeTrain+[0]) for cell_i,spikeTrain in spikes.items()])
#        except ValueError:
#            self.maxMs = 0
#        self.maxtime = int(max([max(i) for i in spikes])/self.binsize + 1) 
        self.maxtime = int(self.maxMs) + 1
        print self.maxtime
        self.alignEvents(spikes)
#        if self.movie == False:
#            self.linegraph(mintime,maxtime,plotbinsize)
        self.curtime = mintime
        if maxtime != None and maxtime < self.maxtime:
             maxtime = maxtime
        else:
            maxtime = self.maxtime
        print str(self.curtime) + ' < ' + str(maxtime)
        while self.curtime < maxtime:
            time.sleep(.2)
#            vp.sleep(.2)
            self.step()
#        while True:
#            vp.sleep(.2)
#            self.scene.autoscale = False
    def MOOOVIE(self):
        pass
        ## C:\Program Files\ImageMagick-6.9.1-Q16

class ModelRunner:
    def __init__(self,dataDirectoryPath,topologyCachePath,pathToCaller):
        #======================================================================
        # Output and cache directories. Create them if they don't exist.
        #======================================================================
        if os.path.exists(dataDirectoryPath):
            pass
        else:
            os.mkdir(dataDirectoryPath)
        self.dataDirectoryPath = dataDirectoryPath
        if os.path.exists(topologyCachePath):
            pass
        else:
            os.mkdir(topologyCachePath)
        self.topologyCachePath = topologyCachePath
        assert os.path.exists(pathToCaller), "The model needs to know which script is calling it. Use os.path.abspath(__file__) to generate this argument." 
        self.pathToCaller = pathToCaller.replace('\\','/')
        self.pathToModule = os.path.abspath(__file__).replace('\\','/')
   
    def setup(self,
                  networkParameters,
                  cellModelParameters,
                  useCache,
                  continueFrom = None,
                  loglevel = logging.DEBUG
        ):
        '''Create the network topologies according to given parameters.
        Pass the distilled network parameters (which cell connects to which,
        and so on) to the cell mechanism implementation.
        '''
        self.useCache = useCache
        #======================================================================
        # Set up a folder for this run.
        #======================================================================
        self.runTitle = time.strftime("%Y%m%d_%H%M%S", time.gmtime())
        if continueFrom != None:
            self.runTitle = continueFrom
        self.outputDir = self.dataDirectoryPath.rstrip('/')+'/'+self.runTitle+'/'
        self.metadataPickler = MetadataPickler(self.outputDir + 'metadata')
        ## given that the moment, down to the second, is in the file name, it
        ## is reasonable to assume that the directory does not exist yet.
        if continueFrom == None:
            os.mkdir(self.outputDir)
        ## Copy both the script and the module to the target dir for reference.
        print (self.pathToCaller,self.pathToModule)##os.path.abspath(__file__)
        callerFilename = self.pathToCaller.split('/')[-1]
        shutil.copyfile(self.pathToCaller,self.outputDir + callerFilename)
        moduleFilename = self.pathToModule.split('/')[-1]
        if self.pathToCaller != self.pathToModule:
            shutil.copyfile(self.pathToModule,self.outputDir + moduleFilename)
#        print (self.pathToCaller,self.pathToModule)
        #==============================================================================
        # Setting up the logger
        #==============================================================================
        self.logger = logging.getLogger('SkinBrian_2')
        self.logger.setLevel(loglevel)
        ## and a formatter
        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        ## set file handler which records according to FILE_LOG_LEVEL
        ## (also create a new log file)
        logname = time.strftime(self.outputDir+"./%Y-%m-%d %H:%M:%S", time.gmtime()) + '.log'
        f = open(logname,'wb'); f.close()
        fh = logging.FileHandler(logname)
        fh.setLevel(FILE_LOG_LEVEL)
        fh.setFormatter(formatter)
        self.logger.addHandler(fh)
        ## set console handler which displays according to CONSOLE_LOG_LEVEL
        ch = logging.StreamHandler()
        ch.setLevel(CONSOLE_LOG_LEVEL)
        ch.setFormatter(formatter)
        self.logger.addHandler(ch)
        self.logger.info('Logger initialized. Setting up ModelRunner...')
        #======================================================================
        # create a single network profile for every individual possible
        # instance
        #======================================================================
        networkParameterNames = networkParameters.keys()
        NetworkProfile = collections.namedtuple(
                'NetworkProfile',networkParameterNames)
        iterableNetworkParameters = [
            name 
            for name,value 
            in networkParameters.items() 
            if type(value) == list
        ]
        uniterableNetworkParameters = [
            (k,v) for k,v in networkParameters.items() 
            if k not in iterableNetworkParameters
        ]
        self.networkProfiles = [
            dict(
                zip(iterableNetworkParameters,profileProduct) + 
                uniterableNetworkParameters
            )
            for profileProduct
            in itertools.product(*[
                networkParameters[iterableName]
                for iterableName
                in iterableNetworkParameters
            ])
        ]
        self.logger.debug('List network profiles:')
        for prf in self.networkProfiles:
            self.logger.debug(str(prf))
#        print self.networkProfiles
        self.networkProfiles = [
            NetworkProfile(**npDict)
            for npDict in self.networkProfiles
        ]
        self.logger.debug('----------------------------------------- List end')
        #======================================================================
        # create a single cell model profile for every individual possible
        # instance
        #======================================================================
        cellModelParameterNames = cellModelParameters.keys()
        CellModelProfile = collections.namedtuple(
                'CellModelProfile',cellModelParameterNames)
        iterableCellModelParameters = [
            name 
            for name,value 
            in cellModelParameters.items() 
            if type(value) == list
        ]
        uniterableCellModelParameters = [
            (k,v) for k,v in cellModelParameters.items() 
            if k not in iterableCellModelParameters
        ]
        self.cellModelProfiles = [
            dict(
                zip(iterableCellModelParameters,profileProduct) + 
                uniterableCellModelParameters
            )
            for profileProduct
            in itertools.product(*[
                cellModelParameters[iterableName]
                for iterableName
                in iterableCellModelParameters
            ])
        ]
        self.cellModelProfiles = [
            CellModelProfile(**cmpDict)
            for cmpDict in self.cellModelProfiles
        ]
        self.runProfiles = [i for i in itertools.product(
            self.cellModelProfiles,self.networkProfiles)]
        
#        print self.networkProfiles[0]._asdict()
#        oneNetwork =     
#==============================================================================
#         testing code follows.
#==============================================================================
#        print self.networkProfiles[1]
#        networkTopology = NetworkTopology(
#                self.networkProfiles[1]._asdict()['networkType'],
#                cacheDir = self.topologyCachePath
#            )
#        networkTopology.generate(self.networkProfiles[1]._asdict(),cache=self.useCache)
#        viz = NetworkRun3dVisualizer(networkTopology)
        self.logger.info('ModelRunner setup (including topology generation) done.')
            
    def run(self,runParameters):
        '''
        Iterate over all the topologies and parameters and generate output.
        '''
        runCntr=0
#        metadata = collections.OrderedDict()
        processPool = Pool(processes=CPUS)
        doneRunPaths = self.getSuccessfulMetadataFilePaths()
        doneRunIndices = [int(path[-9:][:5]) for path in doneRunPaths]
        print doneRunIndices
        metadataResultObjects = []
        done = []
        for runProfile in self.runProfiles:
            if runCntr not in doneRunIndices:
                self.logger.info('Starting run {0}. RunProfile: {1}'.format(runCntr,str(runProfile)))
                cellModelParameters = runProfile[0]._asdict()
                networkParameters = runProfile[1]._asdict()            
                if not PARALLEL:
                    thisRunMetadata = modelRunWorker(cellModelParameters,networkParameters,runParameters,runCntr,self.topologyCachePath,self.outputDir,self.useCache,self.metadataPickler)
                    self.metadataPickler.dumpMetadata(runCntr,thisRunMetadata)
                else:
                    metadataResultObjects.append(
                        (
                            runCntr,
                            processPool.apply_async(
                                modelRunWorker,
                                (   
                                    cellModelParameters,networkParameters,runParameters,runCntr,
                                    self.topologyCachePath, self.outputDir,self.useCache,self.metadataPickler
                                 )
                             )
                         )
                    )
            runCntr+=1
        if PARALLEL:
            for rC,robj in metadataResultObjects:
                done.append(robj.get())
                print done
#        self.successfullyConcludedMetadata.dumpJSON()

        ## needed: rebuid all of the metadata.
        ## Read in all the metadata pkl files, put them in an OrderedDict and 
        ## JSON-sump the orderedDict.
        self.reconstitute()
        
    def getSuccessfulMetadataFilePaths(self):
        outputFiles = os.listdir(self.outputDir)
        metadatafiles = sorted([
            fn for fn in outputFiles 
            if (fn[-4:] == '.pkl' and fn[:8] == 'metadata')
        ])
        return metadatafiles
        
    def reconstitute(self):
        metadatafiles = self.getSuccessfulMetadataFilePaths()
        successfulRunMetadata = collections.OrderedDict()
        for metadatafilePath in metadatafiles:
            with open(self.outputDir+metadatafilePath,'rb') as metadatafile:
                runIndex,runMetadata = pkl.load(metadatafile)
            successfulRunMetadata[runIndex] = runMetadata
        
        with open(self.outputDir + 'metadata.json','wb') as metadatafile:
            json.dump(successfulRunMetadata,metadatafile,indent=4)
            

class VPVisualizer:
    def __init__(self,targetFolder,topologyCachePath):
#        os.listdir(targetFolder)
        self.targetFolder = targetFolder
        self.topologyCachePath = topologyCachePath
        metadataPath = self.targetFolder.strip('/') + '/metadata.json'
        with open(metadataPath,'r') as metadataFile:
            self.metadata = json.load(metadataFile)
#        print self.metadata['0']['cellModelParameters']
            
    def vizSingle(self,index,vizType='balls',output=False):
        key = str(index)
        networkParameters = self.metadata[key]['networkParameters']
        networkType = networkParameters['networkType']
        networkTopology = NetworkTopology(
                networkType,
                cacheDir = self.topologyCachePath
        )
        networkTopology.generate(
                networkParameters,
                cache=True
        )
        if vizType == 'balls':
            single3dViz = NetworkRun3dVisualizer(networkTopology,
                     cellRadius = .5, showLinks = False, opacity = .8,
                     output = output, targetFolder = self.targetFolder)
        elif vizType == 'links':
            single3dViz = NetworkRun3dVisualizer(networkTopology,
                     cellRadius = .1, showLinks = True, opacity = .4,
                     output = output, targetFolder = self.targetFolder)
        spikeFilePath = self.targetFolder.strip('/') + '/spikefile_'+str(index)+'.json'
        single3dViz.run(spikeFilePath)
    
    def vizAxes(self):
        pass
        
        
if __name__ == '__main__':
#    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!    
#    def __init__(self, **entries): 
#        self.__dict__.update(entries)    
    mr = ModelRunner('./output/','./topologyCaches/',os.path.abspath(__file__))
    randomTubularParameters = {
        'acceptableDistanceFactor': .45,
        'cellDensity': 10.,
        'length': [1,2,3,4], 
        'circumference': [.2, .3, .4]
    }
    triangularGridTubularParameters = {
        'networkType':'triangularGridTubular', ## mandatoryl
        'length_circumference': [(32,8),(64,16),(128,32),(256,64)],
#        'length': 256, 
#        'circumference': 64,
        'connectionDistance': 1.1, ## connects to all cells within ~ circ
        'excMikadoDistance': [0.,1.5,2,2.5,3,3.5,4,6,10],
        'excMikadoDensity': [.02,.05,.1,.2,.5,1.],
#        'excMikadoDistance': 0.,
#        'excMikadoDensity': .0,
        'inhibMikadoDistance': None,
        'inhibMikadoDensity': 0.,
#        'inhibitoryDensity': 0.,
        'excSynapseWeight': 1.01, ## just above threshold
        'inhibSynapseWeight': 0., ## negative but small
        'networkDummySeed': [4, 14, 25, 38, 44, 51, 60, 76, 83, 95],#, 106, 120, 127, 131, 150, 154, 165, 176, 190, 195],
#        'networkDummySeed': [4,],
#        'cellTypeUniform': 'genericCell',
#        'pacemakerStructure':'singleCellExc',
#        'pacemakerStructure':'ringExc',
        'pacemakerStructure':None,
        'noiseWeight': 1.01
    }
    
    triangularGridTubularMaxtestParameters = {
        'networkType':'triangularGridTubular', ## mandatoryl
        'length_circumference': [(256,64)],
#        'length': 256, 
#        'circumference': 64,
        'connectionDistance': 1.1, ## connects to all cells within ~ circ
        'excMikadoDistance': [10],
        'excMikadoDensity': [1.],
#        'excMikadoDistance': 0.,
#        'excMikadoDensity': .0,
        'inhibMikadoDistance': None,
        'inhibMikadoDensity': 0.,
#        'inhibitoryDensity': 0.,
        'excSynapseWeight': 1.01, ## just above threshold
        'inhibSynapseWeight': 0., ## negative but small
        'networkDummySeed': [83, 95],#, 106, 120, 127, 131, 150, 154, 165, 176, 190, 195],
#        'networkDummySeed': [4,],
#        'cellTypeUniform': 'genericCell',
#        'pacemakerStructure':'singleCellExc',
#        'pacemakerStructure':'ringExc',
        'pacemakerStructure':None,
        'noiseWeight': 1.01
    }

    triangularGridTubularMikadolessParameters = {
        'networkType':'triangularGridTubular', ## mandatory
        'length_circumference': [(32,8),(64,16),(128,32),(256,64)],
#        'length': 256, 
#        'circumference': 64,
        'connectionDistance': 1.1, ## connects to all cells within ~ circ
#        'excMikadoDistance': [1.5,2,2.5,3,3.5,4,6,10],
#        'excMikadoDensity': [.05,.1,.2,.3,.4,.5,1.],
        'excMikadoDistance': 0.,
        'excMikadoDensity': .0,
        'inhibMikadoDistance': None,
        'inhibMikadoDensity': 0.,
#        'inhibitoryDensity': 0.,
        'excSynapseWeight': 1.01, ## just above threshold
        'inhibSynapseWeight': 0., ## negative but small
        'networkDummySeed': 19,
#        'cellTypeUniform': 'genericCell',
#        'pacemakerStructure':'singleCellExc',
#        'pacemakerStructure':'ringExc',
        'pacemakerStructure':None,
        'noiseWeight': 1.01
    } 
    
    triangularGridTubular5Parameters = {
        'networkType':'triangularGridTubular', ## mandatory
        'length_circumference': [(128,32)], 
#        'circumference': 32,
        'connectionDistance': 1.1, ## connects to all cells within ~ circ
        'excMikadoDistance': [0.,1.5,2.,2.5,3.],
        'excMikadoDensity': .5,
        'inhibMikadoDistance': None,
        'inhibMikadoDensity': 0.,
#        'inhibitoryDensity': 0.,
        'excSynapseWeight': 1.01, ## just above threshold
        'inhibSynapseWeight': 0., ## negative but small
        'networkDummySeed': [19],
#        'cellTypeUniform': 'genericCell',
#        'pacemakerStructure':'singleCellExc',
#        'pacemakerStructure':'ringExc',
        'pacemakerStructure':None,
        'noiseWeight': 1.01
    } 
   
    triangularGridTubular3Parameters = {
        'networkType':'triangularGridTubular', ## mandatory
        'length_circumference': [(128,32)], 
#        'circumference': 32,
        'connectionDistance': 1.1, ## connects to all cells within ~ circ
        'excMikadoDistance': [0.,2.,4.],
        'excMikadoDensity': .5,
        'inhibMikadoDistance': None,
        'inhibMikadoDensity': 0.,
#        'inhibitoryDensity': 0.,
        'excSynapseWeight': 1.01, ## just above threshold
        'inhibSynapseWeight': 0., ## negative but small
        'networkDummySeed': [19],
#        'cellTypeUniform': 'genericCell',
#        'pacemakerStructure':'singleCellExc',
#        'pacemakerStructure':'ringExc',
        'pacemakerStructure':None,
        'noiseWeight': 1.01
    }    
    
    triangularGridTubular3x4Parameters = {
        'networkType':'triangularGridTubular', ## mandatory
        'length_circumference': [(32,8),(64,16),(128,32),(256,64)], 
#        'circumference': 32,
        'connectionDistance': 1.1, ## connects to all cells within ~ circ
        'excMikadoDistance': [0.,2.,4.],
        'excMikadoDensity': .5,
        'inhibMikadoDistance': None,
        'inhibMikadoDensity': 0.,
#        'inhibitoryDensity': 0.,
        'excSynapseWeight': 1.01, ## just above threshold
        'inhibSynapseWeight': 0., ## negative but small
        'networkDummySeed': [25],
#        'cellTypeUniform': 'genericCell',
#        'pacemakerStructure':'singleCellExc',
#        'pacemakerStructure':'ringExc',
        'pacemakerStructure':None,
        'noiseWeight': 1.01
    }
    
    triangularGridTubular3x3x4Parameters = {
        'networkType':'triangularGridTubular', ## mandatory
        'length_circumference': [(32,8),(64,16),(128,32)], 
#        'circumference': 32,
        'connectionDistance': 1.1, ## connects to all cells within ~ circ
        'excMikadoDistance': [0.,2.,4.],
        'excMikadoDensity': .5,
        'inhibMikadoDistance': None,
        'inhibMikadoDensity': 0.,
#        'inhibitoryDensity': 0.,
        'excSynapseWeight': 1.01, ## just above threshold
        'inhibSynapseWeight': 0., ## negative but small
        'networkDummySeed': [90578, 30542, 44346, 2234],
#        'cellTypeUniform': 'genericCell',
#        'pacemakerStructure':'singleCellExc',
#        'pacemakerStructure':'ringExc',
        'pacemakerStructure':None,
        'noiseWeight': 1.01
    }    
    
    triangularGridTubular3x3x2Parameters = {
        'networkType':'triangularGridTubular', ## mandatory
        'length_circumference': [(32,8),(64,16),(128,32)], 
#        'circumference': 32,
        'connectionDistance': 1.1, ## connects to all cells within ~ circ
        'excMikadoDistance': [0.,2.,4.],
        'excMikadoDensity': [.1,.5],
        'inhibMikadoDistance': None,
        'inhibMikadoDensity': 0.,
        'transmissionSpeed': 1, ## m/s
        'cellSize': 50*10**-6, ## m
#        'inhibitoryDensity': 0.,
        'excSynapseWeight': 1.01, ## just above threshold
        'inhibSynapseWeight': 0., ## negative but small
        'networkDummySeed': 2234,
#        'cellTypeUniform': 'genericCell',
#        'pacemakerStructure':'singleCellExc',
#        'pacemakerStructure':'ringExc',
        'pacemakerStructure':None,
        'noiseWeight': 1.01
    }    
    
    triangularGridTubularTransmissionSpeedtestParameters = {
        'networkType':'triangularGridTubular', ## mandatory
        'length_circumference': [(128,32)], 
#        'circumference': 32,
        'connectionDistance': 1.1, ## connects to all cells within ~ circ
        'excMikadoDistance': 10.,
        'excMikadoDensity': [.5],
        'inhibMikadoDistance': None,
        'inhibMikadoDensity': 0.,
        'transmissionSpeed': [.01,.1,1.,10.], ## m/s
        'cellSize': 50*10**-6, ## m
#        'inhibitoryDensity': 0.,
        'excSynapseWeight': 1.01, ## just above threshold
        'inhibSynapseWeight': 0., ## negative but small
        'networkDummySeed': [17,563,2234],
#        'cellTypeUniform': 'genericCell',
#        'pacemakerStructure':'singleCellExc',
#        'pacemakerStructure':'ringExc',
        'pacemakerStructure':None,
        'noiseWeight': 1.01
    }    
    
    triangularGridTubularTS3x4Parameters = {
        'networkType':'triangularGridTubular', ## mandatory
        'length_circumference': [(256,64)], 
#        'circumference': 32,
        'connectionDistance': 1.1, ## connects to all cells within ~ circ
        'excMikadoDistance': [0.,2.,4.],
        'excMikadoDensity': .5,
        'inhibMikadoDistance': None,
        'inhibMikadoDensity': 0.,
#        'inhibitoryDensity': 0.,
        'transmissionSpeed': [.01,.1,1.,10.], ## m/s
        'cellSize': 50*10**-6, ## m
        'excSynapseWeight': 1.01, ## just above threshold
        'inhibSynapseWeight': 0., ## negative but small
        'networkDummySeed': [25],
#        'cellTypeUniform': 'genericCell',
#        'pacemakerStructure':'singleCellExc',
#        'pacemakerStructure':'ringExc',
        'pacemakerStructure':None,
        'noiseWeight': 1.01
    }
    
    triangularGridTubularTSParameters = {
        'networkType':'triangularGridTubular', ## mandatory
        'length_circumference': [(32,8),(64,16),(128,32),(256,64)], 
#        'circumference': 32,
        'connectionDistance': 1.1, ## connects to all cells within ~ circ
        'excMikadoDistance': [0.,2.,4.],
        'excMikadoDensity': .5,
        'inhibMikadoDistance': None,
        'inhibMikadoDensity': 0.,
#        'inhibitoryDensity': 0.,
        'transmissionSpeed': [.01,.1,1.,10.,None], ## m/s
        'cellSize': 50*10**-6, ## m
        'excSynapseWeight': 1.01, ## just above threshold
        'inhibSynapseWeight': 0., ## negative but small
        'networkDummySeed': [19],
#        'cellTypeUniform': 'genericCell',
#        'pacemakerStructure':'singleCellExc',
#        'pacemakerStructure':'ringExc',
        'pacemakerStructure':None,
        'noiseWeight': 1.01
    }
    

    triangularGridTubularTSSmallParameters = {
        'networkType':'triangularGridTubular', ## mandatory
        'length_circumference': [(64,16)], 
#        'circumference': 32,
        'connectionDistance': 1.1, ## connects to all cells within ~ circ
        'excMikadoDistance': [0.],
        'excMikadoDensity': .5,
        'inhibMikadoDistance': None,
        'inhibMikadoDensity': 0.,
#        'inhibitoryDensity': 0.,
        'transmissionSpeed': [.01,.1,1.,10.], ## m/s
        'cellSize': 50*10**-6, ## m
        'excSynapseWeight': 1.01, ## just above threshold
        'inhibSynapseWeight': 0., ## negative but small
        'networkDummySeed': [4, 14, 25, 38, 44, 51, 60, 76, 83, 95],
#        'cellTypeUniform': 'genericCell',
#        'pacemakerStructure':'singleCellExc',
#        'pacemakerStructure':'ringExc',
        'pacemakerStructure':None,
        'noiseWeight': 1.01
    }
    
   
    triangularGridTubularMVSParameters = {
        'networkType':'triangularGridTubular', ## mandatory
        'length_circumference': [(32,8),(64,16),(128,32),(256,64)], 
#        'circumference': 32,
        'connectionDistance': 1.1, ## connects to all cells within ~ circ
        'excMikadoDistance': [0.,1.5,2,2.5,3,3.5,4,6,10],
        'excMikadoDensity': [.1,.5],
        'inhibMikadoDistance': None,
        'inhibMikadoDensity': 0.,
#        'inhibitoryDensity': 0.,
        'excSynapseWeight': 1.01, ## just above threshold
        'inhibSynapseWeight': 0., ## negative but small
        'networkDummySeed': [4, 14, 25, 38],
#        'cellTypeUniform': 'genericCell',
#        'pacemakerStructure':'singleCellExc',
#        'pacemakerStructure':'ringExc',
        'pacemakerStructure':None,
        'noiseWeight': 1.01
    }    
    
    triangularGridTubularSingleParameters = {
        'networkType':'triangularGridTubular', ## mandatory
        'length_circumference': [(256,64)], 
        'connectionDistance': 1.1, ## connects to all cells within ~ circ
        'excMikadoDistance': 6,
        'excMikadoDensity': .5,
        'inhibMikadoDistance': 3.0,
        'inhibMikadoDensity': 0.0,
#        'inhibitoryDensity': 0.,
        'excSynapseWeight': 1.01, ## just above threshold
        'inhibSynapseWeight': -.2, ## negative but small
        'networkDummySeed': 19,
#        'cellTypeUniform': 'genericCell',
#        'pacemakerStructure':'singleCellExc',
#        'pacemakerStructure':'ringExc',
        'pacemakerStructure':None,
        'noiseWeight': 1.01
    } 
    uniformHHParameters = {
        'cellModelType': 'uniformHH', ## mandatory
        'noise': [0.1] ## in hertz (units defined in implementation method)
    }
    IFParameters = {
        'cellModelType': 'IF', ## mandatory
#        'noise': [.01,.1,1.] ## in hertz (units defined in implementation method)
        'noise': .1
    }
    genericRunParameters = {
        'maxSpikeCountPerCell': 100,
        't_end': 10000 ## in ms (units defined in implementation method)
    }
    localtime = time.time()
    mr.setup(
        triangularGridTubularTSParameters,
        IFParameters,
        useCache=False
        ,continueFrom = 'TS_incNone'
    )
    mr.run(genericRunParameters)
    lastRunFolder = './output/'+max(os.listdir('./output/'))
    print lastRunFolder
    print 'Run duration: {0} s'.format(time.time()-localtime)
#    viz = VPVisualizer('./output/20150203_210508','./topologyCaches/')
#    viz = VPVisualizer(lastRunFolder,'./topologyCaches/')
#    viz.vizSingle(0,vizType='balls',output=False)

#    q = [i for i in spawnCellBuildingBlock(4,20,'ringExc',.2,.2)]
    
    

Loading data, please wait...