Source code for netpyne.network.conn

"""
Module for creating network connections

"""

try:
    basestring
except NameError:
    basestring = str

import numpy as np
from array import array as arrayFast
from numbers import Number
from tqdm import tqdm

# -----------------------------------------------------------------------------
# Connect Cells
# -----------------------------------------------------------------------------
[docs] def connectCells(self): """ Function for/to <short description of `netpyne.network.conn.connectCells`> Parameters ---------- self : <type> <Short description of self> **Default:** *required* """ from .. import sim # Instantiate network connections based on the connectivity rules defined in params sim.timing('start', 'connectTime') if sim.rank == 0: print('Making connections...') if sim.nhosts > 1: # Gather tags from all cells allCellTags = sim._gatherAllCellTags() else: allCellTags = {cell.gid: cell.tags for cell in self.cells} allPopTags = { -i: pop.tags for i, pop in enumerate(self.pops.values()) } # gather tags from pops so can connect NetStim pops if self.params.subConnParams: # do not create NEURON objs until synapses are distributed based on subConnParams origCreateNEURONObj = bool(sim.cfg.createNEURONObj) origAddSynMechs = bool(sim.cfg.addSynMechs) sim.cfg.createNEURONObj = False sim.cfg.addSynMechs = False hasPointerConns = self.params.synMechParams.hasPointerConns() for connParamLabel, connParamTemp in self.params.connParams.items(): # for each conn rule or parameter set connParam = connParamTemp.copy() connParam['label'] = connParamLabel # find pre and post cells that match conditions preCellsTags, postCellsTags = self._findPrePostCellsCondition( allCellTags, connParam['preConds'], connParam['postConds'] ) # if conn function not specified, select based on params if 'connFunc' not in connParam: if 'probability' in connParam: connParam['connFunc'] = 'probConn' # probability based func elif 'convergence' in connParam: connParam['connFunc'] = 'convConn' # convergence function elif 'divergence' in connParam: connParam['connFunc'] = 'divConn' # divergence function elif 'connList' in connParam: connParam['connFunc'] = 'fromListConn' # from list function else: connParam['connFunc'] = 'fullConn' # convergence function connFunc = getattr(self, connParam['connFunc']) # get function name from params # process string-based funcs and call conn function if preCellsTags and postCellsTags: # initialize randomizer in case used in string-based function (see issue #89 for more details) self.rand.Random123( sim.hashStr('conn_' + connParam['connFunc']), sim.hashList(sorted(preCellsTags) + sorted(postCellsTags)), sim.cfg.seeds['conn'], ) self._connStrToFunc( preCellsTags, postCellsTags, connParam ) # convert strings to functions (for the delay, and probability params) connFunc(preCellsTags, postCellsTags, connParam) # call specific conn function # check if gap junctions in any of the conn rules (deprecated) if 'gapJunction' in connParam: hasPointerConns = True if sim.cfg.printSynsAfterRule: nodeSynapses = sum([len(cell.conns) for cell in sim.net.cells]) print( ( ' Number of synaptic contacts on node %i after conn rule %s: %i ' % (sim.rank, connParamLabel, nodeSynapses) ) ) # add pointer conns targeting presynaptic cells if hasPointerConns: # distribute info across nodes if not getattr(sim.net, 'preCellPointerConns', False): sim.net.preCellPointerConns = [] data = [sim.net.preCellPointerConns] * sim.nhosts # send cells data to other nodes data[sim.rank] = None gather = sim.pc.py_alltoall(data) # collect cells data from other nodes (required to generate connections) sim.pc.barrier() for dataNode in gather: if dataNode: sim.net.preCellPointerConns.extend(dataNode) # add connections (need to do separately because could be in different ranks) for preGapParams in getattr(sim.net, 'preCellPointerConns', []): if preGapParams['gid'] in self.gid2lid: # only cells in this rank cell = self.cells[self.gid2lid[preGapParams['gid']]] cell.addConn(preGapParams) # apply subcellular connectivity params (distribution of synaspes) if self.params.subConnParams: self.subcellularConn(allCellTags, allPopTags) sim.cfg.createNEURONObj = origCreateNEURONObj # set to original value sim.cfg.addSynMechs = origAddSynMechs # set to original value cellsUpdate = [c for c in sim.net.cells if c.tags.get('cellModel', None) not in ['NetStim', 'VecStim']] if sim.cfg.createNEURONObj: for cell in cellsUpdate: # Add synMechs, stim and conn NEURON objects cell.addStimsNEURONObj() # cell.addSynMechsNEURONObj() cell.addConnsNEURONObj() nodeSynapses = sum([len(cell.conns) for cell in sim.net.cells]) if sim.cfg.createPyStruct: nodeConnections = sum([len(set([conn['preGid'] for conn in cell.conns])) for cell in sim.net.cells]) else: nodeConnections = nodeSynapses print((' Number of connections on node %i: %i ' % (sim.rank, nodeConnections))) if nodeSynapses != nodeConnections: print((' Number of synaptic contacts on node %i: %i ' % (sim.rank, nodeSynapses))) sim.pc.barrier() sim.timing('stop', 'connectTime') if sim.rank == 0 and sim.cfg.timing: print((' Done; cell connection time = %0.2f s.' % sim.timingData['connectTime'])) return [cell.conns for cell in self.cells]
# ----------------------------------------------------------------------------- # Find pre and post cells matching conditions # ----------------------------------------------------------------------------- def _findPrePostCellsCondition(self, allCellTags, preConds, postConds): # try: preCellsTags = dict(allCellTags) # initialize with all presyn cells (make copy) postCellsTags = None for condKey, condValue in preConds.items(): # Find subset of cells that match presyn criteria if condKey in ['x', 'y', 'z', 'xnorm', 'ynorm', 'znorm']: preCellsTags = { gid: tags for (gid, tags) in preCellsTags.items() if condValue[0] <= tags.get(condKey, None) < condValue[1] } # dict with pre cell tags else: if isinstance(condValue, list): preCellsTags = { gid: tags for (gid, tags) in preCellsTags.items() if tags.get(condKey, None) in condValue } # dict with pre cell tags else: preCellsTags = { gid: tags for (gid, tags) in preCellsTags.items() if tags.get(condKey, None) == condValue } # dict with pre cell tags if preCellsTags: # only check post if there are pre postCellsTags = allCellTags for condKey, condValue in postConds.items(): # Find subset of cells that match postsyn criteria if condKey in ['x', 'y', 'z', 'xnorm', 'ynorm', 'znorm']: postCellsTags = { gid: tags for (gid, tags) in postCellsTags.items() if condValue[0] <= tags.get(condKey, None) < condValue[1] } # dict with post Cell objects} # dict with pre cell tags elif isinstance(condValue, list): postCellsTags = { gid: tags for (gid, tags) in postCellsTags.items() if tags.get(condKey, None) in condValue } # dict with post Cell objects else: postCellsTags = { gid: tags for (gid, tags) in postCellsTags.items() if tags.get(condKey, None) == condValue } # dict with post Cell objects # except: # return None, None return preCellsTags, postCellsTags # ----------------------------------------------------------------------------- # Convert connection param string to function # ----------------------------------------------------------------------------- def _connStrToFunc(self, preCellsTags, postCellsTags, connParam): # list of params that have a function passed in as a string paramsStrFunc = [ param for param in self.connStringFuncParams + ['probability', 'convergence', 'divergence'] if param in connParam and isinstance(connParam[param], basestring) ] # dict to store correspondence between string and actual variable dictVars = {} dictVars['pre_x'] = lambda preConds, postConds: preConds['x'] dictVars['pre_y'] = lambda preConds, postConds: preConds['y'] dictVars['pre_z'] = lambda preConds, postConds: preConds['z'] dictVars['pre_xnorm'] = lambda preConds, postConds: preConds['xnorm'] dictVars['pre_ynorm'] = lambda preConds, postConds: preConds['ynorm'] dictVars['pre_znorm'] = lambda preConds, postConds: preConds['znorm'] dictVars['post_x'] = lambda preConds, postConds: postConds['x'] dictVars['post_y'] = lambda preConds, postConds: postConds['y'] dictVars['post_z'] = lambda preConds, postConds: postConds['z'] dictVars['post_xnorm'] = lambda preConds, postConds: postConds['xnorm'] dictVars['post_ynorm'] = lambda preConds, postConds: postConds['ynorm'] dictVars['post_znorm'] = lambda preConds, postConds: postConds['znorm'] dictVars['dist_x'] = lambda preConds, postConds: abs(preConds['x'] - postConds['x']) dictVars['dist_y'] = lambda preConds, postConds: abs(preConds['y'] - postConds['y']) dictVars['dist_z'] = lambda preConds, postConds: abs(preConds['z'] - postConds['z']) dictVars['dist_3D'] = lambda preConds, postConds: np.sqrt( (preConds['x'] - postConds['x']) ** 2 + (preConds['y'] - postConds['y']) ** 2 + (preConds['z'] - postConds['z']) ** 2 ) dictVars['dist_3D_border'] = lambda preConds, postConds: np.sqrt( (abs(preConds['x'] - postConds['x']) - postConds['borderCorrect'][0]) ** 2 + (abs(preConds['y'] - postConds['y']) - postConds['borderCorrect'][1]) ** 2 + (abs(preConds['z'] - postConds['z']) - postConds['borderCorrect'][2]) ** 2 ) dictVars['dist_2D'] = lambda preConds, postConds: np.sqrt( (preConds['x'] - postConds['x']) ** 2 + (preConds['z'] - postConds['z']) ** 2 ) dictVars['dist_xnorm'] = lambda preConds, postConds: abs(preConds['xnorm'] - postConds['xnorm']) dictVars['dist_ynorm'] = lambda preConds, postConds: abs(preConds['ynorm'] - postConds['ynorm']) dictVars['dist_znorm'] = lambda preConds, postConds: abs(preConds['znorm'] - postConds['znorm']) dictVars['dist_norm3D'] = lambda preConds, postConds: np.sqrt( (preConds['xnorm'] - postConds['xnorm']) ** 2 + np.sqrt(preConds['ynorm'] - postConds['ynorm']) + np.sqrt(preConds['znorm'] - postConds['znorm']) ) dictVars['dist_norm2D'] = lambda preConds, postConds: np.sqrt( (preConds['xnorm'] - postConds['xnorm']) ** 2 + np.sqrt(preConds['znorm'] - postConds['znorm']) ) dictVars['rand'] = lambda unused1, unused2: self.rand # add netParams variables for k, v in self.params.__dict__.items(): if isinstance(v, Number): dictVars[k] = v # for each parameter containing a function, calculate lambda function and arguments from netpyne.specs.utils import generateStringFunction for paramStrFunc in paramsStrFunc: strFunc = connParam[paramStrFunc] # string containing function lambdaFunc, strVars = generateStringFunction(strFunc, list(dictVars.keys())) if paramStrFunc in ['probability']: # replace function with dict of values derived from function (one per pre+post cell) connParam[paramStrFunc + 'Func'] = { (preGid, postGid): lambdaFunc( **{ strVar: dictVars[strVar] if isinstance(dictVars[strVar], Number) else dictVars[strVar](preCellTags, postCellTags) for strVar in strVars } ) for preGid, preCellTags in preCellsTags.items() for postGid, postCellTags in postCellsTags.items() } elif paramStrFunc in ['convergence']: # replace function with dict of values derived from function (one per post cell) connParam[paramStrFunc + 'Func'] = { postGid: lambdaFunc( **{ strVar: dictVars[strVar] if isinstance(dictVars[strVar], Number) else dictVars[strVar](None, postCellTags) for strVar in strVars } ) for postGid, postCellTags in postCellsTags.items() } elif paramStrFunc in ['divergence']: # replace function with dict of values derived from function (one per post cell) connParam[paramStrFunc + 'Func'] = { preGid: lambdaFunc( **{ strVar: dictVars[strVar] if isinstance(dictVars[strVar], Number) else dictVars[strVar](preCellTags, None) for strVar in strVars } ) for preGid, preCellTags in preCellsTags.items() } else: # store lambda function and func vars in connParam (for weight, delay and synsPerConn since only calculated for certain conns) connParam[paramStrFunc + 'Func'] = lambdaFunc connParam[paramStrFunc + 'FuncVars'] = {strVar: dictVars[strVar] for strVar in strVars} # ----------------------------------------------------------------------------- # Disynaptic bias for probability # ----------------------------------------------------------------------------- def _disynapticBiasProb(self, origProbability, bias, prePreGids, postPreGids, disynCounter, maxImbalance=10): probability = float(origProbability) factor = bias / origProbability # bias = min(bias, origProbability) # don't modify more than orig, so can compensate if not set(prePreGids).isdisjoint(postPreGids) and disynCounter < maxImbalance: probability = min(origProbability + bias, 1.0) disynCounter += factor # 1 elif disynCounter > -maxImbalance: probability = max(origProbability - (min(origProbability + bias, 1.0) - origProbability), 0.0) disynCounter -= 1 # print disynCounter, origProbability, probability return probability, disynCounter # ----------------------------------------------------------------------------- # Disynaptic bias for probability (version 2) # bis = min fraction of conns that will be disynaptic # ----------------------------------------------------------------------------- def _disynapticBiasProb2(self, probMatrix, allRands, bias, prePreGids, postPreGids): connGids = [] # calculate which conns are disyn vs disynMatrix = { (preGid, postGid): not set(prePreGids[preGid]).isdisjoint(postPreGids[postGid]) for preGid, postGid in list(probMatrix.keys()) } # calculate which conns are going to be created connCreate = { (preGid, postGid): probMatrix[(preGid, postGid)] >= allRands[(preGid, postGid)] for preGid, postGid in list(probMatrix.keys()) } numConns = len([c for c in list(connCreate.values()) if c]) # change % bias of conns from non-disyn to disyn (start with low, high probs respectively) disynConn, nonDisynConn, disynNotConn = [], [], [] for (pre, post), disyn in disynMatrix.items(): if disyn and connCreate[(pre, post)]: disynConn.append((pre, post)) elif not disyn and connCreate[(pre, post)]: nonDisynConn.append((pre, post)) elif disyn and not connCreate[(pre, post)]: disynNotConn.append((pre, post)) disynNumNew = int(float(bias) * numConns) disynAdd = disynNumNew - len(disynConn) if disynAdd > 0: # sort by low/high probs nonDisynConn = sorted(nonDisynConn, key=lambda k: probMatrix[k]) disynNotConn = sorted(disynNotConn, key=lambda k: probMatrix[k], reverse=True) # replaced nonDisynConn with disynNotConn for i in range(min(disynAdd, nonDisynConn, disynNotConn)): connCreate[nonDisynConn[i]] = False connCreate[disynNotConn[i]] = True connGids = [(pre, post) for (pre, post), c in connCreate.items() if c] return connGids # ----------------------------------------------------------------------------- # Full connectivity # -----------------------------------------------------------------------------
[docs] def fullConn(self, preCellsTags, postCellsTags, connParam): """ Function for/to <short description of `netpyne.network.conn.fullConn`> Parameters ---------- self : <type> <Short description of self> **Default:** *required* preCellsTags : <type> <Short description of preCellsTags> **Default:** *required* postCellsTags : <type> <Short description of postCellsTags> **Default:** *required* connParam : <type> <Short description of connParam> **Default:** *required* """ from .. import sim if sim.cfg.verbose: print('Generating set of all-to-all connections (rule: %s) ...' % (connParam['label'])) if sim.rank == 0 and not sim.cfg.verbose: pbar = tqdm(total=len(postCellsTags.items()), ascii=True, desc=' ' + connParam['label'], position=0, leave=True, bar_format= '{l_bar}{bar}| Creating synaptic connections for {n_fmt}/{total_fmt} postsynaptic cells on node %i (all-to-all connectivity)' % sim.rank) # get list of params that have a lambda function paramsStrFunc = [param for param in [p + 'Func' for p in self.connStringFuncParams] if param in connParam] for paramStrFunc in paramsStrFunc: # replace lambda function (with args as dict of lambda funcs) with list of values connParam[paramStrFunc[:-4] + 'List'] = { (preGid, postGid): connParam[paramStrFunc]( **{ k: v if isinstance(v, Number) else v(preCellTags, postCellTags) for k, v in connParam[paramStrFunc + 'Vars'].items() } ) for preGid, preCellTags in preCellsTags.items() for postGid, postCellTags in postCellsTags.items() } for postCellGid in postCellsTags: # for each postsyn cell if sim.rank == 0 and not sim.cfg.verbose: pbar.update(1) if postCellGid in self.gid2lid: # check if postsyn is in this node's list of gids for preCellGid, preCellTags in preCellsTags.items(): # for each presyn cell self._addCellConn(connParam, preCellGid, postCellGid, preCellsTags) # add connection if sim.rank == 0 and not sim.cfg.verbose: pbar.close()
# ----------------------------------------------------------------------------- # Generate random values for all pre and post cells (to use in prob conn) # -----------------------------------------------------------------------------
[docs] def generateRandsPrePost(self, pre, post): """ Function for/to <short description of `netpyne.network.conn.generateRandsPrePost`> Parameters ---------- self : <type> <Short description of self> **Default:** *required* pre : <type> <Short description of pre> **Default:** *required* post : <type> <Short description of post> **Default:** *required* """ from .. import sim sortedPre = sorted(pre) sortedPost = sorted(post) # initialize randomizer using unique hash of pre and post gids and global conn seed self.rand.Random123(sim.hashList(sortedPre), sim.hashList(sortedPost), sim.cfg.seeds['conn']) # # obtain rand value for pre,post pairs lenPre = len(pre) lenPost = len(post) vec = sim.h.Vector(lenPre * lenPost) # create Vector self.rand.uniform(0, 1) # set unfiform distribution vecList = list(vec.setrand(self.rand)) # fill in vector allRands = { (preGid, postGid): vecList[(ipre * lenPost) + ipost] for ipre, preGid in enumerate(sortedPre) for ipost, postGid in enumerate(sortedPost) } # convert to dict return allRands
# ----------------------------------------------------------------------------- # Probabilistic connectivity # -----------------------------------------------------------------------------
[docs] def probConn(self, preCellsTags, postCellsTags, connParam): """ Function for/to <short description of `netpyne.network.conn.probConn`> Parameters ---------- self : <type> <Short description of self> **Default:** *required* preCellsTags : <type> <Short description of preCellsTags> **Default:** *required* postCellsTags : <type> <Short description of postCellsTags> **Default:** *required* connParam : <type> <Short description of connParam> **Default:** *required* """ from .. import sim if sim.cfg.verbose: print('Generating set of probabilistic connections (rule: %s) ...' % (connParam['label'])) if sim.rank == 0 and not sim.cfg.verbose: pbar = tqdm(total=len(postCellsTags.items()), ascii=True, desc=' ' + str(connParam['label']), position=0, leave=True, bar_format= '{l_bar}{bar}| Creating synaptic connections for {n_fmt}/{total_fmt} postsynaptic cells on node %i (probabilistic connectivity)' % sim.rank) allRands = self.generateRandsPrePost(preCellsTags, postCellsTags) # get list of params that have a lambda function paramsStrFunc = [param for param in [p + 'Func' for p in self.connStringFuncParams] if param in connParam] # copy the vars into args immediately and work out which keys are associated with lambda functions only once per method funcKeys = {} for paramStrFunc in paramsStrFunc: connParam[paramStrFunc + 'Args'] = connParam[paramStrFunc + 'Vars'].copy() funcKeys[paramStrFunc] = [ key for key in connParam[paramStrFunc + 'Vars'] if callable(connParam[paramStrFunc + 'Vars'][key]) ] # probabilistic connections with disynapticBias (deprecated) if isinstance(connParam.get('disynapticBias', None), Number): allPreGids = sim._gatherAllCellConnPreGids() prePreGids = {gid: allPreGids[gid] for gid in preCellsTags} postPreGids = {gid: allPreGids[gid] for gid in postCellsTags} probMatrix = { (preCellGid, postCellGid): connParam['probabilityFunc'][preCellGid, postCellGid] if 'probabilityFunc' in connParam else connParam['probability'] for postCellGid, postCellTags in postCellsTags.items() # for each postsyn cell for preCellGid, preCellTags in preCellsTags.items() # for each presyn cell if postCellGid in self.gid2lid } # check if postsyn is in this node connGids = self._disynapticBiasProb2( probMatrix, allRands, connParam['disynapticBias'], prePreGids, postPreGids ) for preCellGid, postCellGid in connGids: if sim.rank == 0 and not sim.cfg.verbose: pbar.update(1) for paramStrFunc in paramsStrFunc: # call lambda functions to get weight func args connParam[paramStrFunc + 'Args'] = { k: v if isinstance(v, Number) else v(preCellsTags[preCellGid], postCellsTags[postCellGid]) for k, v in connParam[paramStrFunc + 'Vars'].items() } self._addCellConn(connParam, preCellGid, postCellGid, preCellsTags) # add connection if sim.rank == 0 and not sim.cfg.verbose: pbar.close() # standard probabilistic conenctions else: # print('rank %d'%(sim.rank)) # print(connParam) # calculate the conn preGids of the each pre and post cell # for postCellGid,postCellTags in sorted(postCellsTags.items()): # for each postsyn cell for postCellGid, postCellTags in postCellsTags.items(): # for each postsyn cell # for each postsyn cell if sim.rank==0: pbar.update(1) if postCellGid in self.gid2lid: # check if postsyn is in this node for preCellGid, preCellTags in preCellsTags.items(): # for each presyn cell probability = ( connParam['probabilityFunc'][preCellGid, postCellGid] if 'probabilityFunc' in connParam else connParam['probability'] ) if probability >= allRands[preCellGid, postCellGid]: for paramStrFunc in paramsStrFunc: # call lambda functions to get weight func args # update the relevant FuncArgs dict where lambda functions are known to exist in the corresponding FuncVars dict for funcKey in funcKeys[paramStrFunc]: connParam[paramStrFunc + 'Args'][funcKey] = connParam[paramStrFunc + 'Vars'][funcKey]( preCellTags, postCellTags ) # connParam[paramStrFunc+'Args'] = {k:v if isinstance(v, Number) else v(preCellTags,postCellTags) for k,v in connParam[paramStrFunc+'Vars'].items()} self._addCellConn(connParam, preCellGid, postCellGid, preCellsTags) # add connection if sim.rank == 0 and not sim.cfg.verbose: pbar.close()
# ----------------------------------------------------------------------------- # Generate random unique integers # -----------------------------------------------------------------------------
[docs] def randUniqueInt(self, r, N, vmin, vmax): """ Function for/to <short description of `netpyne.network.conn.randUniqueInt`> Parameters ---------- self : <type> <Short description of self> **Default:** *required* r : <type> <Short description of r> **Default:** *required* N : <type> <Short description of N> **Default:** *required* vmin : <type> <Short description of vmin> **Default:** *required* vmax : <type> <Short description of vmax> **Default:** *required* """ r.discunif(vmin, vmax) out = [] while len(out) < N: x = int(r.repick()) if x not in out: out.append(x) return out
# ----------------------------------------------------------------------------- # Convergent connectivity # -----------------------------------------------------------------------------
[docs] def convConn(self, preCellsTags, postCellsTags, connParam): """ Function for/to <short description of `netpyne.network.conn.convConn`> Parameters ---------- self : <type> <Short description of self> **Default:** *required* preCellsTags : <type> <Short description of preCellsTags> **Default:** *required* postCellsTags : <type> <Short description of postCellsTags> **Default:** *required* connParam : <type> <Short description of connParam> **Default:** *required* """ from .. import sim if sim.cfg.verbose: print('Generating set of convergent connections (rule: %s) ...' % (connParam['label'])) if sim.rank == 0 and not sim.cfg.verbose: pbar = tqdm(total=len(postCellsTags.items()), ascii=True, desc=' ' + connParam['label'], position=0, leave=True, bar_format= '{l_bar}{bar}| Creating synaptic connections for {n_fmt}/{total_fmt} postsynaptic cells on node %i (convergent connectivity)' % sim.rank) # get list of params that have a lambda function paramsStrFunc = [param for param in [p + 'Func' for p in self.connStringFuncParams] if param in connParam] # copy the vars into args immediately and work out which keys are associated with lambda functions only once per method funcKeys = {} for paramStrFunc in paramsStrFunc: connParam[paramStrFunc + 'Args'] = connParam[paramStrFunc + 'Vars'].copy() funcKeys[paramStrFunc] = [ key for key in connParam[paramStrFunc + 'Vars'] if callable(connParam[paramStrFunc + 'Vars'][key]) ] # converted to list only once preCellsTagsKeys = sorted(preCellsTags) # calculate hash for post cell gids hashPreCells = sim.hashList(preCellsTagsKeys) for postCellGid, postCellTags in postCellsTags.items(): # for each postsyn cell if sim.rank == 0 and not sim.cfg.verbose: pbar.update(1) if postCellGid in self.gid2lid: # check if postsyn is in this node convergence = ( connParam['convergenceFunc'][postCellGid] if 'convergenceFunc' in connParam else connParam['convergence'] ) # num of presyn conns / postsyn cell convergence = max(min(int(round(convergence)), len(preCellsTags) - 1), 0) self.rand.Random123(hashPreCells, postCellGid, sim.cfg.seeds['conn']) # init randomizer randSample = self.randUniqueInt(self.rand, convergence + 1, 0, len(preCellsTags) - 1) # note: randSample[divergence] is an extra value used only if one of the random postGids coincided with the preGid preCellsSample = { preCellsTagsKeys[randSample[convergence]] if preCellsTagsKeys[i] == postCellGid else preCellsTagsKeys[i]: 0 for i in randSample[0:convergence] } # dict of selected gids of postsyn cells with removed post gid preCellsConv = { k: v for k, v in preCellsTags.items() if k in preCellsSample } # dict of selected presyn cells tags for preCellGid, preCellTags in preCellsConv.items(): # for each presyn cell for paramStrFunc in paramsStrFunc: # call lambda functions to get weight func args # update the relevant FuncArgs dict where lambda functions are known to exist in the corresponding FuncVars dict for funcKey in funcKeys[paramStrFunc]: connParam[paramStrFunc + 'Args'][funcKey] = connParam[paramStrFunc + 'Vars'][funcKey]( preCellTags, postCellTags ) if preCellGid != postCellGid: # if not self-connection self._addCellConn(connParam, preCellGid, postCellGid, preCellsTags) # add connection if sim.rank == 0 and not sim.cfg.verbose: pbar.close()
# ----------------------------------------------------------------------------- # Divergent connectivity # -----------------------------------------------------------------------------
[docs] def divConn(self, preCellsTags, postCellsTags, connParam): """ Function for/to <short description of `netpyne.network.conn.divConn`> Parameters ---------- self : <type> <Short description of self> **Default:** *required* preCellsTags : <type> <Short description of preCellsTags> **Default:** *required* postCellsTags : <type> <Short description of postCellsTags> **Default:** *required* connParam : <type> <Short description of connParam> **Default:** *required* """ from .. import sim if sim.cfg.verbose: print('Generating set of divergent connections (rule: %s) ...' % (connParam['label'])) if sim.rank == 0 and not sim.cfg.verbose: pbar = tqdm(total=len(preCellsTags.items()), ascii=True, desc=' ' + connParam['label'], position=0, leave=True, bar_format= '{l_bar}{bar}| Creating synaptic connections for {n_fmt}/{total_fmt} presynaptic cells on node %i (divergent connectivity)' % sim.rank) # get list of params that have a lambda function paramsStrFunc = [param for param in [p + 'Func' for p in self.connStringFuncParams] if param in connParam] # copy the vars into args immediately and work out which keys are associated with lambda functions only once per method funcKeys = {} for paramStrFunc in paramsStrFunc: connParam[paramStrFunc + 'Args'] = connParam[paramStrFunc + 'Vars'].copy() funcKeys[paramStrFunc] = [ key for key in connParam[paramStrFunc + 'Vars'] if callable(connParam[paramStrFunc + 'Vars'][key]) ] # converted to list only once postCellsTagsKeys = sorted(postCellsTags) # calculate hash for post cell gids hashPostCells = sim.hashList(postCellsTagsKeys) for preCellGid, preCellTags in preCellsTags.items(): # for each presyn cell if sim.rank == 0 and not sim.cfg.verbose: pbar.update(1) divergence = ( connParam['divergenceFunc'][preCellGid] if 'divergenceFunc' in connParam else connParam['divergence'] ) # num of presyn conns / postsyn cell divergence = max(min(int(round(divergence)), len(postCellsTags) - 1), 0) self.rand.Random123(hashPostCells, preCellGid, sim.cfg.seeds['conn']) # init randomizer randSample = self.randUniqueInt(self.rand, divergence + 1, 0, len(postCellsTags) - 1) # note: randSample[divergence] is an extra value used only if one of the random postGids coincided with the preGid postCellsSample = { postCellsTagsKeys[randSample[divergence]] if postCellsTagsKeys[i] == preCellGid else postCellsTagsKeys[i]: 0 for i in randSample[0:divergence] } # dict of selected gids of postsyn cells with removed pre gid for postCellGid in [c for c in postCellsSample if c in self.gid2lid]: postCellTags = postCellsTags[postCellGid] for paramStrFunc in paramsStrFunc: # call lambda functions to get weight func args # update the relevant FuncArgs dict where lambda functions are known to exist in the corresponding FuncVars dict for funcKey in funcKeys[paramStrFunc]: connParam[paramStrFunc + 'Args'][funcKey] = connParam[paramStrFunc + 'Vars'][funcKey]( preCellTags, postCellTags ) if preCellGid != postCellGid: # if not self-connection self._addCellConn(connParam, preCellGid, postCellGid, preCellsTags) # add connection if sim.rank == 0 and not sim.cfg.verbose: pbar.close()
# ----------------------------------------------------------------------------- # From list connectivity # -----------------------------------------------------------------------------
[docs] def fromListConn(self, preCellsTags, postCellsTags, connParam): """ Function for/to <short description of `netpyne.network.conn.fromListConn`> Parameters ---------- self : <type> <Short description of self> **Default:** *required* preCellsTags : <type> <Short description of preCellsTags> **Default:** *required* postCellsTags : <type> <Short description of postCellsTags> **Default:** *required* connParam : <type> <Short description of connParam> **Default:** *required* """ from .. import sim if sim.cfg.verbose: print('Generating set of connections from list (rule: %s) ...' % (connParam['label'])) if sim.rank == 0 and not sim.cfg.verbose: pbar = tqdm(total=len(connParam['connList']), ascii=True, desc=' ' + connParam['label'], position=0, leave=True, bar_format= '{l_bar}{bar}| Creating synaptic connections for {n_fmt}/{total_fmt} pairs of neurons on node %i (from list)' % sim.rank) orderedPreGids = sorted(preCellsTags) orderedPostGids = sorted(postCellsTags) # list of params that can have a lambda function paramsStrFunc = [param for param in [p + 'Func' for p in self.connStringFuncParams] if param in connParam] for paramStrFunc in paramsStrFunc: # replace lambda function (with args as dict of lambda funcs) with list of values connParam[paramStrFunc[:-4] + 'List'] = { (orderedPreGids[preId], orderedPostGids[postId]): connParam[paramStrFunc]( **{ k: v if isinstance(v, Number) else v(preCellsTags[orderedPreGids[preId]], postCellsTags[orderedPostGids[postId]]) for k, v in connParam[paramStrFunc + 'Vars'].items() } ) for preId, postId in connParam['connList'] } if 'weight' in connParam and isinstance(connParam['weight'], list): connParam['weightFromList'] = list(connParam['weight']) # if weight is a list, copy to weightFromList if 'delay' in connParam and isinstance(connParam['delay'], list): connParam['delayFromList'] = list(connParam['delay']) # if delay is a list, copy to delayFromList if 'loc' in connParam and isinstance(connParam['loc'], list): connParam['locFromList'] = list(connParam['loc']) # if delay is a list, copy to locFromList if connParam['synsPerConn'] == 1: if isinstance(connParam.get('sec'), list): connParam['secFromList'] = list(connParam['sec']) else: pass # TODO: needs consistent handling # for pointer connections (e.g. gap junctions) only: if isinstance(connParam.get('preLoc'), list): connParam['preLocFromList'] = list(connParam['preLoc']) if isinstance(connParam.get('preSec'), list): connParam['preSecFromList'] = list(connParam['preSec']) for iconn, (relativePreId, relativePostId) in enumerate(connParam['connList']): # for each postsyn cell if sim.rank == 0 and not sim.cfg.verbose: pbar.update(1) preCellGid = orderedPreGids[relativePreId] postCellGid = orderedPostGids[relativePostId] if postCellGid in self.gid2lid: # check if postsyn is in this node's list of gids if 'weightFromList' in connParam: connParam['weight'] = connParam['weightFromList'][iconn] if 'delayFromList' in connParam: connParam['delay'] = connParam['delayFromList'][iconn] if 'locFromList' in connParam: connParam['loc'] = connParam['locFromList'][iconn] if 'secFromList' in connParam: connParam['sec'] = connParam['secFromList'][iconn] if 'preLocFromList' in connParam: connParam['preLoc'] = connParam['preLocFromList'][iconn] if 'preSecFromList' in connParam: connParam['preSec'] = connParam['preSecFromList'][iconn] # TODO: consider cfg.allowSelfConns? if preCellGid != postCellGid: # if not self-connection self._addCellConn(connParam, preCellGid, postCellGid, preCellsTags) # add connection if sim.rank == 0 and not sim.cfg.verbose: pbar.close()
# ----------------------------------------------------------------------------- # Set parameters and create connection # ----------------------------------------------------------------------------- def _addCellConn(self, connParam, preCellGid, postCellGid, preCellsTags={}): from .. import sim from ..specs.netParams import SynMechParams # set final param values paramStrFunc = self.connStringFuncParams finalParam = {} # Set final parameter values; initialize randomizer for string-based funcs that use rand to ensue replicability # Note: could potentially speed up by generating list of values for all rand funcs used (e.g. rand.uniform()) # and then selecting a value from list based of pre- and post- gid -- that way only seed once at beginning in connectCells() # Howeve, not clear if faster in all cases since need to generate values for len(pre)*len(post), whereas here only a subset randSeeded = False for param in paramStrFunc: if param + 'List' in connParam: finalParam[param] = connParam[param + 'List'][preCellGid, postCellGid] elif param + 'Func' in connParam: if not randSeeded and 'rand' in connParam[param + 'FuncArgs']: self.rand.Random123(preCellGid, postCellGid, sim.cfg.seeds['conn']) randSeeded = True finalParam[param] = connParam[param + 'Func'](**connParam[param + 'FuncArgs']) else: finalParam[param] = connParam.get(param) # get Cell object postCell = self.cells[self.gid2lid[postCellGid]] # convert synMech param to list (if not already) if not isinstance(connParam.get('synMech'), list): connParam['synMech'] = [connParam.get('synMech')] # generate dict with final params for each synMech paramPerSynMech = ['weight', 'delay', 'loc'] for i, synMech in enumerate(connParam.get('synMech')): for param in paramPerSynMech: finalParam[param + 'SynMech'] = finalParam.get(param) if len(connParam['synMech']) > 1: if isinstance(finalParam.get(param), list): # get weight from list for each synMech finalParam[param + 'SynMech'] = finalParam[param][i] elif 'synMech' + param.title() + 'Factor' in connParam: # adapt weight for each synMech finalParam[param + 'SynMech'] = ( finalParam[param] * connParam['synMech' + param.title() + 'Factor'][i] ) params = { 'preGid': preCellGid, 'sec': connParam.get('sec'), 'loc': finalParam['locSynMech'], 'synMech': synMech, 'weight': finalParam['weightSynMech'], 'delay': finalParam['delaySynMech'], 'synsPerConn': finalParam['synsPerConn'], } # if 'threshold' in connParam: params['threshold'] = connParam.get('threshold') # deprecated, use threshold in preSyn cell sec if 'shape' in connParam: params['shape'] = connParam.get('shape') if 'plast' in connParam: params['plast'] = connParam.get('plast') if 'weightIndex' in connParam: params['weightIndex'] = connParam.get('weightIndex') if 'distributeSynsUniformly' in connParam: params['distributeSynsUniformly'] = connParam['distributeSynsUniformly'] if 'connRandomSecFromList' in connParam: params['connRandomSecFromList'] = connParam['connRandomSecFromList'] isGapJunction = 'gapJunction' in connParam # deprecated way of defining gap junction if self.params.synMechParams.isPointerConn(params['synMech']) or isGapJunction: params['preLoc'] = connParam.get('preLoc') params['preSec'] = connParam.get('preSec', 'soma') if isGapJunction: params['gapJunction'] = connParam['gapJunction'] # TODO: synMech can be None here (meaning 'use default'). Then need to use default label while checking below elif SynMechParams.stringFuncsReferPreLoc(synMech): # save synapse pre-cell location to be used in stringFunc for synMech. # for optimization purpose, do it only if preLoc is referenced for a given synMech cellType = preCellsTags[preCellGid].get('cellType') if cellType: from ..cell import CompartCell secs = self.params.cellParams[cellType].secs loc, _ = CompartCell.spikeGenLocAndSec(secs) params['preLoc'] = loc if sim.cfg.includeParamsLabel: params['label'] = connParam.get('label') postCell.addConn(params=params)