Skip to content

Commit

Permalink
corrected and re-factored connParams with multideminsional rule (mult…
Browse files Browse the repository at this point in the history
…iple conns with fromListConn plus multiple synMech + synsPerConn>1)
  • Loading branch information
vvbragin committed Jan 7, 2025
1 parent 960f490 commit 64423c9
Show file tree
Hide file tree
Showing 4 changed files with 235 additions and 198 deletions.
32 changes: 32 additions & 0 deletions netpyne/cell/cell.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,38 @@ def _shapeStim(self, isi=1, variation=0, width=0.05, weight=10, start=0, finish=
stimvecs = deepcopy([fulltime, fulloutput, events]) # Combine vectors into a matrix

return stimvecs

def _connWeightsAndDelays(self, params, netStimParams):
from .. import sim

# Scale factor for connection weights
if netStimParams:
scaleFactor = sim.net.params.scaleConnWeightNetStims
else:
connWeights = sim.net.params.scaleConnWeightModels
if isinstance(connWeights, dict) and (self.tags['cellModel'] in connWeights):
# use scale factor specific for this cell model
scaleFactor = connWeights[self.tags['cellModel']]
else:
scaleFactor = sim.net.params.scaleConnWeight # use global scale factor

synsPerConn = params['synsPerConn']

# Weights
if isinstance(params['weight'], list):
assert len(params['weight']) == synsPerConn, 'Number of weights must match synsPerConn'
weights = [scaleFactor * w for w in params['weight']]
else:
weights = [scaleFactor * params['weight']] * synsPerConn

# Delays
if isinstance(params['delay'], list):
assert len(params['delay']) == synsPerConn, 'Number of delays must match synsPerConn'
delays = params['delay']
else:
delays = [params['delay']] * synsPerConn

return weights, delays

def addNetStim(self, params, stimContainer=None):
from .. import sim
Expand Down
227 changes: 109 additions & 118 deletions netpyne/cell/compartCell.py
Original file line number Diff line number Diff line change
Expand Up @@ -852,8 +852,9 @@ def addConn(self, params, netStimParams=None):
params['delay'] = sim.net.params.defaultDelay # if no delay, set default
if params.get('preLoc') is None:
params['preLoc'] = 0.5 # if no preLoc, set default
if params.get('loc') is None:
params['loc'] = 0.5 # if no loc, set default

# same logic for `loc` is no longer here because we want to differ default case from explicitly stating 0.5 by user

if params.get('synsPerConn') is None:
params['synsPerConn'] = 1 # if no synsPerConn, set default

Expand All @@ -880,15 +881,10 @@ def addConn(self, params, netStimParams=None):
)
return # if self-connection return

# Weight
weights = self._setConnWeights(params, netStimParams, secLabels)
weightIndex = 0 # set default weight matrix index
# Weights and delays:
weights, delays = self._connWeightsAndDelays(params, netStimParams)

# Delays
if isinstance(params['delay'], list):
delays = params['delay']
else:
delays = [params['delay']] * params['synsPerConn']
weightIndex = 0 # set default weight matrix index

# Check if target is point process (artificial cell) with V not in section
pointp, weightIndex = self._setConnPointP(params, secLabels, weightIndex)
Expand Down Expand Up @@ -918,6 +914,7 @@ def addConn(self, params, netStimParams=None):
if pointerParams:
if isPreToPostPointerConn:
# generate new ids
# TODO: will it even works with synsPerConn > 1? (in particular, loc in params now can be None)
preToPostPointerId, postToPrePointerId = self.__generatePointerIds(pointerParams, params)
else:
# use pre-generated
Expand Down Expand Up @@ -1573,30 +1570,6 @@ def _setConnSections(self, params):

return secLabels

def _setConnWeights(self, params, netStimParams, secLabels):
from .. import sim

if netStimParams:
scaleFactor = sim.net.params.scaleConnWeightNetStims
elif (
isinstance(sim.net.params.scaleConnWeightModels, dict)
and sim.net.params.scaleConnWeightModels.get(self.tags['cellModel'], None) is not None
):
scaleFactor = sim.net.params.scaleConnWeightModels[
self.tags['cellModel']
] # use scale factor specific for this cell model
else:
scaleFactor = sim.net.params.scaleConnWeight # use global scale factor

if isinstance(params['weight'], list):
weights = [scaleFactor * w for w in params['weight']]
if len(weights) == 1:
weights = [weights[0]] * params['synsPerConn']
else:
weights = [scaleFactor * params['weight']] * params['synsPerConn']

return weights

def _setConnPointP(self, params, secLabels, weightIndex):
from .. import sim

Expand Down Expand Up @@ -1631,109 +1604,122 @@ def _setConnPointP(self, params, secLabels, weightIndex):

def _setConnSynMechs(self, params, secLabels):
from .. import sim

distributeSynsUniformly = params.get('distributeSynsUniformly', sim.cfg.distributeSynsUniformly)
connRandomSecFromList = params.get('connRandomSecFromList', sim.cfg.connRandomSecFromList)
distributeSynsUniformly = params.get('distributeSynsUniformly', sim.cfg.distributeSynsUniformly)

synsPerConn = params['synsPerConn']
if not params.get('synMech'):
if sim.net.params.synMechParams: # if no synMech specified, but some synMech params defined
synLabel = list(sim.net.params.synMechParams.keys())[
0
] # select first synMech from net params and add syn
# select first synMech from net params and add syn:
synLabel = list(sim.net.params.synMechParams.keys())[0]
params['synMech'] = synLabel
if sim.cfg.verbose:
print(
' Warning: no synaptic mechanisms specified for connection to cell gid=%d so using %s '
% (self.gid, synLabel)
)
else: # if no synaptic mechanism specified and no synMech params available
if sim.cfg.verbose:
print(' Error: no synaptic mechanisms available to add conn on cell gid=%d ' % (self.gid))
return -1 # if no Synapse available print error and exit
_ensure(False, params, f"no synaptic mechanisms available to add conn on cell gid={self.gid}")

# if desired synaptic mechanism specified in conn params
if synsPerConn > 1: # if more than 1 synapse
if len(secLabels) == 1: # if single section, create all syns there
synMechSecs = [secLabels[0]] * synsPerConn # same section for all
if isinstance(params['loc'], list):
if len(params['loc']) == synsPerConn:
synMechLocs = params['loc']
else:
if sim.cfg.verbose:
print(
"Error: The length of the list of locations does not match synsPerConn (distributing uniformly)"
)
synMechSecs, synMechLocs = self._distributeSynsUniformly(
secList=secLabels, numSyns=synsPerConn
)
else:
synMechLocs = [i * (1.0 / synsPerConn) + 1.0 / synsPerConn / 2 for i in range(synsPerConn)]
else:
# if multiple sections, distribute syns uniformly
if distributeSynsUniformly:
synMechSecs, synMechLocs = self._distributeSynsUniformly(secList=secLabels, numSyns=synsPerConn)
else:
# have list of secs that matches num syns
if not connRandomSecFromList and synsPerConn == len(secLabels):
synMechSecs = secLabels
if isinstance(params['loc'], list):
if len(params['loc']) == synsPerConn: # list of locs matches num syns
synMechLocs = params['loc']
else: # list of locs does not match num syns
print("Error: The length of the list of locations does not match synsPerConn (with distributeSynsUniformly = False)")
return
else: # single loc
synMechLocs = [params['loc']] * synsPerConn
else:
synMechSecs = secLabels
synMechLocs = params['loc'] if isinstance(params['loc'], list) else [params['loc']]

# randomize the section to connect to and move it to beginning of list
if connRandomSecFromList and len(synMechSecs) >= synsPerConn:
if len(synMechLocs) == 1:
synMechLocs = [params['loc']] * synsPerConn
rand = h.Random()
preGid = params['preGid'] if isinstance(params['preGid'], int) else 0
rand.Random123(sim.hashStr('connSynMechsSecs'), self.gid, preGid) # initialize randomizer

randSecPos = sim.net.randUniqueInt(rand, synsPerConn, 0, len(synMechSecs) - 1)
synMechSecs = [synMechSecs[i] for i in randSecPos]

if isinstance(params['loc'], list):
randLocPos = sim.net.randUniqueInt(rand, synsPerConn, 0, len(synMechLocs) - 1)
synMechLocs = [synMechLocs[i] for i in randLocPos]
else:
rand.uniform(0, 1)
synMechLocs = [rand.repick() for i in range(synsPerConn)]
else:
print("\nError: The length of the list of sections needs to be greater or equal to the synsPerConn (with connRandomSecFromList = True)")
return
# make difference between loc explicitly specified by user vs set by default
if params.get('loc') is None:
params['loc'] = 0.5
isExplicitLoc = False
else:
isExplicitLoc = True # keep track is loc was statet explicitly (for proper error/warning handling)

if synsPerConn > 1: # if more than 1 synapse
synMechSecs, synMechLocs = self._secsAndLocsForMultisynapse(params, isExplicitLoc, secLabels, connRandomSecFromList, distributeSynsUniformly)
else: # if 1 synapse
# by default place on 1st section of list and location available
synMechSecs = secLabels
synMechLocs = params['loc'] if isinstance(params['loc'], list) else [params['loc']]

# randomize the section to connect to and move it to beginning of list
if connRandomSecFromList and len(synMechSecs) > 1:
rand = h.Random()
preGid = params['preGid'] if isinstance(params['preGid'], int) else 0
rand.Random123(sim.hashStr('connSynMechsSecs'), self.gid, preGid) # initialize randomizer
pos = int(rand.discunif(0, len(synMechSecs) - 1))
synMechSecs[pos], synMechSecs[0] = synMechSecs[0], synMechSecs[pos]
if len(synMechLocs) > 1:
synMechLocs[pos], synMechLocs[0] = synMechLocs[0], synMechLocs[pos]
synMechSecs, synMechLocs = self._secsAndLocsForSingleSynapse(params, isExplicitLoc, secLabels, connRandomSecFromList)

# add synaptic mechanism to section based on synMechSecs and synMechLocs (if already exists won't be added unless nonLinear set to True)
synMechs = [
self.addSynMech(
synLabel=params['synMech'], secLabel=synMechSecs[i], loc=synMechLocs[i], preLoc=params['preLoc']
)
for i in range(synsPerConn)
]
synMechs = []
for i in range(synsPerConn):
synMech = self.addSynMech(synLabel=params['synMech'], secLabel=synMechSecs[i], loc=synMechLocs[i], preLoc=params['preLoc'])
synMechs.append(synMech)
return synMechs, synMechSecs, synMechLocs

def _secsAndLocsForSingleSynapse(self, params, isExplicitLoc, secLabels, connRandomSecFromList):

# by default place on 1st section of list and location available
synMechSecs = secLabels
loc = params['loc']
synMechLocs = loc if isinstance(loc, list) else [loc]

# randomize the section to connect to and move it to beginning of list
if connRandomSecFromList and len(synMechSecs) > 1:
if isExplicitLoc: # if loc was specified explicitly by user, they should've provided correct number of locs
_ensure(len(synMechSecs) == len(synMechLocs), params, "With connRandomSecFromList == True and synsPerConn == 1 (defaults), the lengths of the list of locations and the list of sections must be the same, in order to use the same randomly generated index for both")
else: # if using defaults, adjust it to match the number of sections
synMechLocs = synMechLocs * len(synMechSecs)

rand = h.Random()
preGid = params['preGid'] if isinstance(params['preGid'], int) else 0
rand.Random123(sim.hashStr('connSynMechsSecs'), self.gid, preGid) # initialize randomizer
pos = int(rand.discunif(0, len(synMechSecs) - 1))
synMechSecs = [synMechSecs[pos]]
synMechLocs = [synMechLocs[pos]]
return synMechSecs, synMechLocs

def _secsAndLocsForMultisynapse(self, params, isExplicitLoc, secLabels, connRandomSecFromList, distributeSynsUniformly):

synsPerConn = params['synsPerConn']
loc = params['loc']

if len(secLabels) == 1: # if single section, create all syns there
synMechSecs = [secLabels[0]] * synsPerConn # same section for all
if isinstance(loc, list):
_ensure(len(loc) == synsPerConn, params, "The length of the list of locations does not match synsPerConn")
synMechLocs = loc
else: # single value or no value
_ensure(isExplicitLoc == False, params, f"specifiyng the `loc` as single value when synsPerConn > 1 ({synsPerConn} in your case) is deprecated. To silence this warning, remove `loc` from the connection parameters or provide a list of {synsPerConn} values (per each synMech if they are several).")
synMechLocs = [i / synsPerConn + 1 / synsPerConn / 2 for i in range(synsPerConn)]
else:
# if multiple sections, distribute syns uniformly
if distributeSynsUniformly:
_ensure(isExplicitLoc == False, params, f"specifiyng the `loc` explicitly when distributeSynsUniformly is True and multiple sections provided is deprecated. To silence this warning, remove `loc` from the connection parameters or set distributeSynsUniformly to False.")
synMechSecs, synMechLocs = self._distributeSynsUniformly(secList=secLabels, numSyns=synsPerConn)
else:
if connRandomSecFromList:
synMechSecs, synMechLocs = self._randomSecAndLocFromList(params, synsPerConn, secLabels, loc, isExplicitLoc)
else:
# Deterministic. Need to have lists of secs and locs that matches num syns
if not isinstance(loc, list):
loc = [loc] * synsPerConn

_ensure(synsPerConn == len(secLabels), params,
f"With connRandomSecFromList = False, the length of the list of sections should match synsPerConn")
_ensure(synsPerConn == len(loc), params,
f"The length of the list of locations does not match synsPerConn (with distributeSynsUniformly = False, connRandomSecFromList = False)")

synMechSecs = secLabels
synMechLocs = loc
return synMechSecs, synMechLocs

def _randomSecAndLocFromList(self, params, synsPerConn, secLabels, loc, isExplicitLoc):
rand = h.Random()
preGid = params['preGid'] if isinstance(params['preGid'], int) else 0
rand.Random123(sim.hashStr('connSynMechsSecs'), self.gid, preGid) # initialize randomizer

from ..network.conn import randInt
maxval = len(secLabels) - 1
isUnique = synsPerConn <= maxval + 1
randSecPos = randInt(rand, N=synsPerConn, vmin=0, vmax=maxval, unique=isUnique)
synMechSecs = [secLabels[i] for i in randSecPos]

if isinstance(loc, list):
maxval = len(loc) - 1
isUnique = synsPerConn <= maxval + 1
randLocPos = randInt(rand, N=synsPerConn, vmin=0, vmax=maxval, unique=isUnique)
synMechLocs = [loc[i] for i in randLocPos]
else:
_ensure(isExplicitLoc == False, params, f"specifiyng the `loc` explicitly when distributeSynsUniformly is False and connRandomSecFromList is True (with multiple sections provided) is deprecated. To silence this warning, remove `loc` from the connection parameters.")

rand.uniform(0, 1)
synMechLocs = h.Vector(synsPerConn).setrand(rand).to_python()
return synMechSecs, synMechLocs

def _distributeSynsUniformly(self, secList, numSyns):
from .. import sim

Expand Down Expand Up @@ -1904,3 +1890,8 @@ def originSecName(self):

def originSec(self):
return self.secs[self.originSecName()]

def _ensure(condition, params, message):
connLabel = params.get('label')
connLabelStr = f'[{connLabel}]' if connLabel else ''
assert condition, f" Error in connParams{connLabelStr}: {message}"
31 changes: 2 additions & 29 deletions netpyne/cell/pointCell.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,27 +351,6 @@ def associateGid(self, threshold=None):
del nc # discard netcon
sim.net.gid2lid[self.gid] = len(sim.net.gid2lid)

def _setConnWeights(self, params, netStimParams):
from .. import sim

if netStimParams:
scaleFactor = sim.net.params.scaleConnWeightNetStims
elif (
isinstance(sim.net.params.scaleConnWeightModels, dict)
and sim.net.params.scaleConnWeightModels.get(self.tags['cellModel'], None) is not None
):
scaleFactor = sim.net.params.scaleConnWeightModels[
self.tags['cellModel']
] # use scale factor specific for this cell model
else:
scaleFactor = sim.net.params.scaleConnWeight # use global scale factor

if isinstance(params['weight'], list):
weights = [scaleFactor * w for w in params['weight']]
else:
weights = [scaleFactor * params['weight']] * params['synsPerConn']

return weights

def addConn(self, params, netStimParams=None):
from .. import sim
Expand All @@ -393,19 +372,13 @@ def addConn(self, params, netStimParams=None):
)
return # if self-connection return

# Weight
weights = self._setConnWeights(params, netStimParams)
# Weights and delays
weights, delays = self._connWeightsAndDelays(params, netStimParams)

if params.get('weightIndex') is None:
params['weightIndex'] = 0 # set default weight matrix index
weightIndex = params.get('weightIndex') # note that loop below will overwrite the weights value in weights[i]

# Delays
if isinstance(params['delay'], list):
delays = params['delay']
else:
delays = [params['delay']] * params['synsPerConn']

# Create connections
for i in range(params['synsPerConn']):

Expand Down
Loading

0 comments on commit 64423c9

Please sign in to comment.