"""
netParams.py 

High-level specifications for M1 network model using NetPyNE

Contributors: salvadordura@gmail.com
"""

from netpyne import specs
import pickle, json

netParams = specs.NetParams()   # object of class NetParams to store the network parameters

netParams.version = 48

try:
	from __main__ import cfg  # import SimConfig object with params from parent module
except:
	from cfg_unified import cfg

#------------------------------------------------------------------------------
#
# NETWORK PARAMETERS
#
#------------------------------------------------------------------------------

#------------------------------------------------------------------------------
# General network parameters
#------------------------------------------------------------------------------
netParams.scale = cfg.scale # Scale factor for number of cells
netParams.sizeX = cfg.sizeX # x-dimension (horizontal length) size in um
netParams.sizeY = cfg.sizeY # y-dimension (vertical height or cortical depth) size in um
netParams.sizeZ = cfg.sizeZ # z-dimension (horizontal depth) size in um
netParams.shape = 'cylinder' # cylindrical (column-like) volume


#------------------------------------------------------------------------------
# General connectivity parameters
#------------------------------------------------------------------------------
netParams.scaleConnWeight = 1.0 # Connection weight scale factor (default if no model specified)
netParams.scaleConnWeightModels = {'HH_simple': 1.0, 'HH_reduced': 1.0, 'HH_full': 1.0} #scale conn weight factor for each cell model
netParams.scaleConnWeightNetStims = 1.0 #0.5  # scale conn weight factor for NetStims
netParams.defaultThreshold = 0.0 # spike threshold, 10 mV is NetCon default, lower it for all cells
netParams.defaultDelay = 2.0 # default conn delay (ms)
netParams.propVelocity = 500.0 # propagation velocity (um/ms)
netParams.probLambda = 100.0  # length constant (lambda) for connection probability decay (um)

#------------------------------------------------------------------------------
# Cell parameters
#------------------------------------------------------------------------------
cellModels = ['HH_simple', 'HH_reduced', 'HH_full']
layer = {'2': [0.12,0.31], '4': [0.31,0.42], '5A': [0.42,0.52], '45A':[0.31,0.52], '5B': [0.52,0.77], '6': [0.77,1.0], 'long': [2.0,3.0]}  # normalized layer boundaries

#------------------------------------------------------------------------------
## Load cell rules previously saved using netpyne format

# if cfg.simType == 'GroupNetParams':         # cfg_cell.py
#     cellParamLabels = [ 'IT2_reduced', 
#                         'IT4_reduced', 
#                         'IT5A_reduced', 
#                         'IT5B_reduced',
#                     	'PT5B_reduced',  
#                         'IT6_reduced', 
#                         'CT6_reduced', 
#                         'PV_simple', 
#                         'SOM_simple',
#                         'IT5A_full']    #, 'PT5B_full'] #  # list of cell rules to load from file
#     loadCellParams = cellParamLabels
#     saveCellParams = True
# else:                                       # cfg.py
#     cellParamLabels = [ 'IT5A_full', 
#                         'IT2_reduced', 
#                         'IT4_reduced', 
#                         'IT5A_reduced',
#                         'IT5B_reduced',
# 	                    'PT5B_reduced',
#                         'IT6_reduced', 
#                         'CT6_reduced', 
#                         'PV_simple', 
#                         'SOM_simple']   #, 'PT5B_full'] #  # list of cell rules to load from file
#     loadCellParams = []
#     saveCellParams = False

# for ruleLabel in loadCellParams:
# 	netParams.loadCellParamsRule(label=ruleLabel, fileName='cells/'+ruleLabel+'_cellParams.pkl')

loadCellParams = []
saveCellParams = False

# #------------------------------------------------------------------------------
# # Specification of cell rules not previously loaded
# # Includes importing from hoc template or python class, and setting additional params

# #------------------------------------------------------------------------------
# if cfg.simType == 'GroupNetParams':         # cfg_cell.py
#     # Reduced cell model params (6-comp) 
#     reducedCells = {  # layer and cell type for reduced cell models
#         'IT2_reduced': 	{'layer': '2', 	'cname': 'CSTR6', 'carg': 'BS1578'}, 
#         'IT4_reduced': 	{'layer': '4', 	'cname': 'CSTR6', 'carg': 'BS1578'},
#         'IT5A_reduced': {'layer': '5A', 'cname': 'CSTR6', 'carg': 'BS1579'},
#         'IT5B_reduced': {'layer': '5B', 'cname': 'CSTR6', 'carg': 'BS1579'},
#         'PT5B_reduced': {'layer': '5B', 'cname': 'SPI6',  'carg':  None},
#         'IT6_reduced': 	{'layer': '6', 	'cname': 'CSTR6', 'carg': 'BS1579'},
#         'CT6_reduced':	{'layer': '6', 	'cname': 'CSTR6', 'carg': 'BS1578'}}

#     reducedSecList = {  # section Lists for reduced cell model
#         'alldend': 	['Adend1', 'Adend2', 'Adend3', 'Bdend'],
#         'spiny': 	['Adend1', 'Adend2', 'Adend3', 'Bdend'],
#         'apicdend': ['Adend1', 'Adend2', 'Adend3'],
#         'perisom': 	['soma']}

#     for label, p in reducedCells.items():  # create cell rules that were not loaded 
#         if label not in loadCellParams:
#             cellRule = netParams.importCellParams(label=label, conds={'cellType': label[0:2], 'cellModel': 'HH_reduced', 'ynorm': layer[p['layer']]},
#             fileName='cells/'+p['cname']+'.py', cellName=p['cname'], cellArgs={'params': p['carg']} if p['carg'] else None)
#             dendL = (layer[p['layer']][0]+(layer[p['layer']][1]-layer[p['layer']][0])/2.0) * cfg.sizeY  # adapt dend L based on layer
#             for secName in ['Adend1', 'Adend2', 'Adend3', 'Bdend']: cellRule['secs'][secName]['geom']['L'] = dendL / 3.0  # update dend L
#             for k,v in reducedSecList.items(): cellRule['secLists'][k] = v  # add secLists
#             netParams.addCellParamsWeightNorm(label, 'conn/'+label+'_weightNorm.pkl', threshold=cfg.weightNormThreshold)  # add weightNorm

#             if cfg.reduced3DGeom: # set 3D pt geom
#                 offset, prevL = 0, 0
#                 for secName, sec in netParams.cellParams[label]['secs'].items():
#                     sec['geom']['pt3d'] = []
#                     if secName in ['soma', 'Adend1', 'Adend2', 'Adend3']:  # set 3d geom of soma and Adends
#                         sec['geom']['pt3d'].append([offset+0, prevL, 0, sec['geom']['diam']])
#                         prevL = float(prevL + sec['geom']['L'])
#                         sec['geom']['pt3d'].append([offset+0, prevL, 0, sec['geom']['diam']])
#                     if secName in ['Bdend']:  # set 3d geom of Bdend
#                         sec['geom']['pt3d'].append([offset+0, 0, 0, sec['geom']['diam']])
#                         sec['geom']['pt3d'].append([offset+sec['geom']['L'], 0, 0, sec['geom']['diam']])		
#                     if secName in ['axon']:  # set 3d geom of axon
#                         sec['geom']['pt3d'].append([offset+0, 0, 0, sec['geom']['diam']])
#                         sec['geom']['pt3d'].append([offset+0, -sec['geom']['L'], 0, sec['geom']['diam']])	

#             if saveCellParams: netParams.saveCellParamsRule(label=label, fileName='cells/'+label+'_cellParams.pkl')

#------------------------------------------------------------------------------
# PT5B full cell model params (700+ comps)
if 'PT5B_full' not in loadCellParams:
	ihMod2str = {'harnett': 1, 'kole': 2, 'migliore': 3}
	cellRule = netParams.importCellParams(label='PT5B_full', conds={'cellType': 'PT', 'cellModel': 'HH_full'},
	  fileName='cells/PTcell.hoc', cellName='PTcell', cellArgs=[ihMod2str[cfg.ihModel], cfg.ihSlope], somaAtOrigin=True)
	nonSpiny = ['apic_0', 'apic_1']
	netParams.addCellParamsSecList(label='PT5B_full', secListName='perisom', somaDist=[0, 50])  # sections within 50 um of soma
	netParams.addCellParamsSecList(label='PT5B_full', secListName='apic_upper', somaDist=[300, 900])  # sections within 300-900 um of soma      # NOT PRESENT IN CFG.PY
	netParams.addCellParamsSecList(label='PT5B_full', secListName='apic_lower', somaDist=[0, 300])  # sections within 0-300 um of soma          # NOT PRESENT IN CFG.PY
	netParams.addCellParamsSecList(label='PT5B_full', secListName='below_soma', somaDistY=[-600, 0])  # sections within 0-300 um of soma
	for sec in nonSpiny: cellRule['secLists']['perisom'].remove(sec)
    # creates a list with different categories (alldend, apicdend, basaldend, spiny)
	cellRule['secLists']['alldend'] = [sec for sec in cellRule.secs if ('dend' in sec or 'apic' in sec)] # basal+apical
	cellRule['secLists']['apicdend'] = [sec for sec in cellRule.secs if ('apic' in sec)] # apical
	cellRule['secLists']['basaldend'] = [sec for sec in cellRule.secs if ('dend' in sec)] # apical
	cellRule['secLists']['spiny'] = [sec for sec in cellRule['secLists']['alldend'] if sec not in nonSpiny]
	# Adapt ih params based on cfg param
	for secName in cellRule['secs']:
		for mechName,mech in cellRule['secs'][secName]['mechs'].items():
			if mechName in ['ih','h','h15', 'hd']: 
				mech['gbar'] = [g*cfg.ihGbar for g in mech['gbar']] if isinstance(mech['gbar'],list) else mech['gbar']*cfg.ihGbar
				if cfg.ihModel == 'migliore':   
					mech['clk'] = cfg.ihlkc  # migliore's shunt current factor
					mech['elk'] = cfg.ihlke  # migliore's shunt current reversal potential
				if secName.startswith('dend'): 
					mech['gbar'] *= cfg.ihGbarBasal  # modify ih conductance in soma+basal dendrites
					mech['clk'] *= cfg.ihlkcBasal  # modify ih conductance in soma+basal dendrites
				if secName in cellRule['secLists']['below_soma']: #secName.startswith('dend'): 
					mech['clk'] *= cfg.ihlkcBelowSoma  # modify ih conductance in soma+basal dendrites
	# Reduce dend Na to avoid dend spikes (compensate properties by modifying axon)
	for secName in cellRule['secLists']['alldend']:
		cellRule['secs'][secName]['mechs']['nax']['gbar'] = 0.0153130368342 * cfg.dendNa #0.25 
		cellRule['secs'][secName]['mechs']['pas']['e'] *= cfg.epas                              # NOT PRESENT IN CFG.PY
		cellRule['secs'][secName]['mechs']['pas']['g'] *= cfg.gpas                              # NOT PRESENT IN CFG.PY
	cellRule['secs']['soma']['mechs']['nax']['gbar'] = 0.0153130368342  * cfg.somaNa
	cellRule['secs']['axon']['mechs']['nax']['gbar'] = 0.0153130368342  * cfg.axonNa #11  
	cellRule['secs']['axon']['geom']['Ra'] = 137.494564931 * cfg.axonRa #0.005 
	# Remove Na (TTX)
	if cfg.removeNa:
		for secName in cellRule['secs']:
			cellRule['secs'][secName]['mechs']['nax']['gbar'] = 0.0
	if cfg.weightNorm and not cfg.netClamp:
		netParams.addCellParamsWeightNorm('PT5B_full', 'conn/PT5B_full_weightNorm.pkl', threshold=cfg.weightNormThreshold)  # load weight norm
	# cellRule['secs']['apic_0']['weightNorm'] = [1e-6] # set temporarily to 0, so subConn rules determine if syns provide input or not
	netParams.saveCellParamsRule(label='PT5B_full', fileName='cells/PT5B_full_cellParams.pkl')

#------------------------------------------------------------------------------
# Population parameters
#------------------------------------------------------------------------------

#------------------------------------------------------------------------------
## load densities
with open('cells/cellDensity.pkl', 'rb') as fileObj: density = pickle.load(fileObj, encoding='latin1')['density']


# ORIGINAL CONFIGURATION FOR CFG_CELL.PY
# netParams.popParams['PT5B'] =	{'cellModel': cfg.cellmod['PT5B'], 'cellType': 'PT', 'ynormRange': layer['5B'], 'density': 0.5*density[('M1','E')][3]}#, 'xRange': [100,100], 'yRange': [735,735]}

# ORIGINAL CONFIGURATION FOR CFG.PY
netParams.popParams['PT5B'] = {'cellModel': 'HH_full', 'cellType': 'PT', 'ynormRange': layer['5B'], 'numCells':1}


if cfg.singleCellPops:
	for pop in netParams.popParams.values(): pop['numCells'] = 1

# #------------------------------------------------------------------------------
# ## Long-range input populations (VecStims)
# if cfg.addLongConn:
# 	## load experimentally based parameters for long range inputs
# 	# with open('conn/conn_long.pkl', 'r') as fileObj: connLongData = pickle.load(fileObj)
# 	with open('conn/conn_long.pkl', 'rb') as fileObj: connLongData = pickle.load(fileObj, encoding='latin1')
# 	#ratesLong = connLongData['rates']

# 	numCells = cfg.numCellsLong
# 	noise = cfg.noiseLong
# 	start = cfg.startLong

# 	longPops = ['TPO', 'TVL', 'S1', 'S2', 'cM1', 'M2', 'OC']
# 	## create populations with fixed 
# 	for longPop in longPops:
# 		netParams.popParams[longPop] = {'cellModel':    'VecStim', 
#                                         'numCells':     numCells, 
#                                         'rate':         cfg.ratesLong[longPop], 
# 										'noise':        noise, 
#                                         'start':        start, 
#                                         'pulses':       [], 
#                                         'ynormRange':   layer['long']}

#------------------------------------------------------------------------------
# Synaptic mechanism parameters
#------------------------------------------------------------------------------
multiplier1, multiplier2 = 1, 1
if cfg.simType == 'NetStim':
    multiplier1 = cfg.AMPATau2Factor
elif cfg.simType == 'GroupNetStim':
    multiplier2 = cfg.excTau2Factor # currently have no effect, because GroupNetStim is using only AMPA and NMDA synapses, and cfg.AMPATau2Factor = 1

# excitatory synapses
netParams.synMechParams['NMDA'] = {'mod':'MyExp2SynNMDABB', 'tau1NMDA': 15, 'tau2NMDA': 150,        'e': 0}
netParams.synMechParams['AMPA'] = {'mod':'MyExp2SynBB',     'tau1': 0.05,   'tau2': 5.3*multiplier1,'e': 0}
netParams.synMechParams['exc']  = {'mod':'Exp2Syn',         'tau1': 0.05,   'tau2': 5.3*multiplier2,'e': 0}
# inhibitory synapses
netParams.synMechParams['GABAB']            = {'mod':'MyExp2SynBB', 'tau1': 3.5,    'tau2': 260.9,  'e': -93} 
netParams.synMechParams['GABAA']            = {'mod':'MyExp2SynBB', 'tau1': 0.07,   'tau2': 18.2,   'e': -80}
netParams.synMechParams['GABAASlow']        = {'mod':'MyExp2SynBB', 'tau1': 2,      'tau2': 100,    'e': -80}
netParams.synMechParams['GABAASlowSlow']    = {'mod':'MyExp2SynBB', 'tau1': 200,    'tau2': 400,    'e': -80}

ESynMech =      ['AMPA', 'NMDA']
SOMESynMech =   ['GABAASlow','GABAB']
SOMISynMech =   ['GABAASlow']
PVSynMech =     ['GABAA']

# #------------------------------------------------------------------------------
# # Long range input pulses
# #------------------------------------------------------------------------------
# if cfg.addPulses:
# 	for key in [k for k in dir(cfg) if k.startswith('pulse')]:
# 		params = getattr(cfg, key, None)
# 		[pop, start, end, rate, noise] = [params[s] for s in ['pop', 'start', 'end', 'rate', 'noise']]
# 		if pop in netParams.popParams:
# 			if 'pulses' not in netParams.popParams[pop]: netParams.popParams[pop]['pulses'] = {} 	
# 			netParams.popParams[pop]['pulses'].append({'start': start, 'end': end, 'rate': rate, 'noise': noise})

#------------------------------------------------------------------------------
# Current inputs (IClamp)
#------------------------------------------------------------------------------
if cfg.addIClamp:
	for key in [k for k in dir(cfg) if k.startswith('IClamp')]:
		params = getattr(cfg, key, None)
		[pop,sec,loc,start,dur,amp] = [params[s] for s in ['pop','sec','loc','start','dur','amp']]

		cfg.analysis['plotTraces']['include'].append((pop,0))  # record that pop

		# add stim source
		netParams.stimSourceParams[key] = {'type': 'IClamp', 'delay': start, 'dur': dur, 'amp': amp}
		
		# connect stim source to target
		netParams.stimTargetParams[key+'_'+pop] =  {
			'source': key, 
			'conds': {'pop': pop},
			'sec': sec, 
			'loc': loc}

#------------------------------------------------------------------------------
# Voltage inputs (VClamp)
#------------------------------------------------------------------------------
if cfg.addVClamp:
	for key in [k for k in dir(cfg) if k.startswith('VClamp')]:
		params = getattr(cfg, key, None)
		[pop,sec,loc,start,dur,amp] = [params[s] for s in ['pop','sec','loc','start','dur','amp']]

		cfg.analysis['plotTraces']['include'].append((pop,0))  # record that pop

		# add stim source
		netParams.stimSourceParams[key] = {	'type': 'VClamp', 'dur': dur, 'amp':amp}#,
											# 'gain': 1, 'rstim': 0, 'tau1': 1, 'tau2': 1, 'i': 1}

		# Example of syntax:
		# netParams.stimSourceParams['Input_2'] = {	'type': 'VClamp', 
		# 											'dur': [0,50,200],    	# each value is a different starting time to vclamp
		# 											'amp': [-60,-30,40], 	# each value is a different clamping voltage
		# 											'gain': 1e5, 
		# 											'rstim': 1, 
		# 											'tau1': 0.1, 
		# 											'tau2': 0}

		
		# connect stim source to target
		netParams.stimTargetParams[key+'_'+pop] =  {
			'source': key, 
			'conds': {'pop': pop},
			'sec': sec, 
			'loc': loc}

#------------------------------------------------------------------------------
# NetStim inputs - FROM CFG.PY
#------------------------------------------------------------------------------
if cfg.addNetStim:
	for key in [k for k in dir(cfg) if k.startswith('NetStim')]:
		params = getattr(cfg, key, None)
		[pop, sec, loc, synMech, synMechWeightFactor, start, interval, noise, number, weight, delay] = \
		[params[s] for s in ['pop', 'sec', 'loc', 'synMech', 'synMechWeightFactor', 'start', 'interval', 'noise', 'number', 'weight', 'delay']] 

		cfg.analysis['plotTraces']['include'] = [(pop,0)]

		if synMech == ESynMech:
			wfrac = cfg.synWeightFractionEE
		elif synMech == SOMESynMech:
			wfrac = cfg.synWeightFractionSOME
		else:
			wfrac = [1.0]

		# add stim source
		netParams.stimSourceParams[key] = {'type': 'NetStim', 'start': start, 'interval': interval, 'noise': noise, 'number': number}

		# connect stim source to target
		# for i, syn in enumerate(synMech):
		netParams.stimTargetParams[key+'_'+pop] =  {
			'source': key, 
			'conds': {'pop': pop},
			'sec': sec, 
			'loc': loc,
			'synMech': synMech,
			# 'weight': weight,
			'weight': cfg.netWeight if cfg.netWeight is not None else weight,
			'synMechWeightFactor': synMechWeightFactor,
			'delay': delay}

#------------------------------------------------------------------------------
# GroupNetStim inputs - FROM CFG_CELL.PY
#------------------------------------------------------------------------------
# if cfg.addGroupNetStim:
#     # Group of NetStims
#     for key in [k for k in dir(cfg) if k.startswith('GroupNetStim')]:
#         params = getattr(cfg, key, None)
#         nstype, numStims, pop, ynorm, cellRule, secList, allSegs, synMech, start, interval, noise, number, weight, delay = [params[s] for s in ['nstype', 'numStims', 'pop', 'ynorm', 'cellRule', 'secList', 'allSegs', 'synMech', 'start', 'interval', 'noise', 'number', 'weight', 'delay']]

#         cfg.analysis['plotTraces']['include'].append((pop,0))

#         if not isinstance(secList, list):
#             secList = list(netParams.cellParams[cellRule]['secLists'][secList])

#         istim = 0
#         segs = []

#         if synMech == ESynMech:
#             wfrac = cfg.synWeightFractionEE
#         elif synMech == SOMESynMech:
#             wfrac = cfg.synWeightFractionSOME
#         else:
#             wfrac = [1.0]

#         if nstype == 'stim':  # implement as a stim - [jv] not being used
#             while istim < numStims:
#                 for secName,sec in netParams.cellParams[cellRule]['secs'].items():
#                     if secName in secList:
#                         if allSegs:
#                             nseg = sec['geom']['nseg']
#                             for iseg in range(nseg):
#                                 segs.append([secName, (iseg+1)*(1.0/(nseg+1))])
#                                 istim += 1
#                                 if istim >= numStims: break
#                         else:
#                             segs.append([secName, 0.5])
#                             istim += 1
                        
#                         if istim >= numStims: break

#             for istim, seg in enumerate(segs):

#                 # add stim source
#                 netParams.stimSourceParams[key+'_'+str(istim)] = {'type': 'NetStim', 'start': start, 'interval': interval, 'noise': noise, 'number': number}

#                 # connect stim source to target
#                 for i, syn in enumerate(synMech):
#                     netParams.stimTargetParams[key+'_'+pop+'_'+syn+'_'+str(istim)] =  {
#                         'source': key+'_'+str(istim), 
#                         'conds': {'pop': pop, 'ynorm': ynorm},
#                         'sec': seg[0], 
#                         'loc': seg[1],
#                         'synMech': syn,
#                         'weight': weight*wfrac[i],
#                         'delay': delay}

#         elif nstype == 'pop':  # implement as a pop
#             netParams.popParams[key] = {	'cellModel':'NetStim', 
# 											'numCells': numStims, 
# 											'rate': 	cfg.groupRate if cfg.groupRate else 1000/interval,
#                                          	'noise': 	noise, 
# 											'start': 	start, 
# 											'number': 	number}
            
#             netParams.connParams[key] = { 
#                         'preConds': 	{'pop': key}, 
#                         'postConds': 	{'pop': pop, 'ynorm': ynorm},
#                         'synMech': 		synMech,
#                         'weight': 		cfg.groupWeight if cfg.groupWeight is not None else weight, 
#                         'synMechWeightFactor': wfrac,
#                         'delay': 		delay,
#                         'synsPerConn': 	1,
#                         'sec': 			secList}
            
#             netParams.subConnParams[key] = {
#                         'preConds': 	{'pop': key}, 
#                         'postConds': 	{'pop': pop, 'ynorm': ynorm},  
#                         'sec': 			secList, 
#                         'groupSynMechs': ESynMech, # removed to use only AMPA and see if it affects spatial summation, and not a combination of [AMPA, NMDA] 2020_05_28
#                         'density': 		'uniform'} 

#------------------------------------------------------------------------------
# Network clamp (integrate into netpyne?)
#------------------------------------------------------------------------------
if cfg.netClamp:
	# load full files and save reduced file
	import os.path
	from netpyne.sim import ijsonLoad

	tagsFile = cfg.netClampConnsFile[:-5]+'_netClampTags_%d.json'%(cfg.netClampGid)
	connsFile = cfg.netClampConnsFile[:-5]+'_netClampConns_%d.json'%(cfg.netClampGid)

	if not os.path.isfile(tagsFile) and not os.path.isfile(connsFile): # load both tags+conns
		ijsonLoad(cfg.netClampConnsFile, tagsGidRange=None, connsGidRange=[cfg.netClampGid], loadTags=True, loadConns=True, tagFormat=['pop'], connFormat=None, 
						saveTags=tagsFile, saveConns=connsFile)
	elif not os.path.isfile(tagsFile): # load tags
		ijsonLoad(cfg.netClampConnsFile, tagsGidRange=None, loadTags=True, loadConns=False, tagFormat=['pop'], saveTags=tagsFile)
	elif not os.path.isfile(connsFile): # load conns
		ijsonLoad(cfg.netClampConnsFile, connsGidRange=[cfg.netClampGid], loadTags=False, loadConns=True, connFormat=None, saveConns=connsFile)

	# load reduced files
	with open(tagsFile, 'r') as fileObj: tags = json.load(fileObj)['tags']
	tags = {int(k) if k != 'format' else k:v  for k,v in tags.items()}
	with open(connsFile, 'r') as fileObj: conns = json.load(fileObj)['conns']#[cfg.netClampGid]
	conns = {int(k) if k != 'format' else k:v  for k,v in conns.items()}
	conns = conns[cfg.netClampGid]

	# load list of preGid cell
	preGids = list(set([conn['preGid'] for conn in conns]))

	# load spk times of preGid cells
	with open(cfg.netClampSpikesFile, 'r') as fileObj: data = json.load(fileObj)
	allSpkids,allSpkts = data['simData']['spkid'], data['simData']['spkt']
	# Note tags is imported using 'format', so is list of tags, in this case just 'pop'
	popIndex = tags['format'].index('pop')
	spkids,spkts,spkpops = zip(*[(spkid,spkt,tags[int(spkid)][popIndex]) for spkid,spkt in zip(allSpkids,allSpkts) if spkid in preGids])

	# group by prepops
	prePops = list(set(spkpops))

	# create one vectsim pop reproducing spk times per preGid; and multiple conns 
	for prePop in prePops:
		# get spkTimes for preGid
		spkGids = [spkid for spkid,spkpop in zip(spkids,spkpops) if spkpop == prePop]

		if len(spkGids) > 0:
			# get list of cell gids in this pop 
			popGids = list(set(spkGids))

			# set key/label of pop
			key = '' + str(prePop)

			# create 1 vectstim pop per conn (cellLabel=cell gid -- so can reference later)
			cellsList = []
			for popGid in popGids: 
				spkTimes = [spkt for spkid,spkt in zip(spkids,spkts) if spkid == popGid]
				if len(spkTimes) > 0:
					cellsList.append({'cellLabel': int(popGid), 'spkTimes': spkTimes})
					netParams.popParams[key] = {'cellModel': 'VecStim', 'cellsList': cellsList}

					# calculate conns for this preGid
					preConns = [conn for conn in conns if conn['preGid'] == popGid]

					for i,preConn in enumerate(preConns):
						netParams.connParams[key+'_'+str(popGid)+'_'+str(i)] = { 
								'preConds': {'cellLabel': preConn['preGid']},  # cellLabel corresponds to gid 
								'postConds': {'pop': cfg.netClampPop},
								'synMech': str(preConn['synMech']),
								'weight': float(preConn['weight']), 
								'delay': float(preConn['delay']),
								'sec': str(preConn['sec']), 
								'loc': str(preConn['loc'])}

	# longPops = ['TPO', 'TVL', 'S1', 'S2', 'cM1', 'M2', 'OC']

	# #Modify netClamp pops
	# rate = 50

	# for cell in netParams.popParams['PV5B']['cellsList']:
	#     cell['spkTimes'] = []# list(random.uniform(0,cfg.duration,(rate*cfg.duration/1000)))
	
# #------------------------------------------------------------------------------
# # Local connectivity parameters
# #------------------------------------------------------------------------------
# with open('conn/conn.pkl', 'rb') as fileObj: connData = pickle.load(fileObj, encoding='latin1')
# pmat = connData['pmat']
# wmat = connData['wmat']
# bins = connData['bins']

# #------------------------------------------------------------------------------
# ## E -> E
# if cfg.addConn and cfg.EEGain > 0.0:
# 	labelsConns = [('W+AS_norm', 'IT', 'L2/3'), ('W+AS_norm', 'IT', 'L4,5A,5B'), 
# 				   ('W+AS_norm', 'PT', 'L5B'), ('W+AS_norm', 'IT', 'L6'), ('W+AS_norm', 'CT', 'L6')]
# 	labelPostBins = [('W+AS', 'IT', 'L2/3'), ('W+AS', 'IT', 'L4,5A,5B'), ('W+AS', 'PT', 'L5B'), 
# 					('W+AS', 'IT', 'L6'), ('W+AS', 'CT', 'L6')]
# 	labelPreBins = ['W', 'AS', 'AS', 'W', 'W']
# 	preTypes = [['IT'], ['IT'], ['IT', 'PT'], ['IT','CT'], ['IT','CT']] 
# 	postTypes = ['IT', 'IT', 'PT', 'IT','CT']
# 	ESynMech = ['AMPA','NMDA']

# 	for i,(label, preBinLabel, postBinLabel) in enumerate(zip(labelsConns,labelPreBins, labelPostBins)):
# 		for ipre, preBin in enumerate(bins[preBinLabel]):
# 			for ipost, postBin in enumerate(bins[postBinLabel]):
# 				for cellModel in cellModels:
# 					ruleLabel = 'EE_'+cellModel+'_'+str(i)+'_'+str(ipre)+'_'+str(ipost)
# 					netParams.connParams[ruleLabel] = { 
# 						'preConds': {'cellType': preTypes[i], 'ynorm': list(preBin)}, 
# 						'postConds': {'cellModel': cellModel, 'cellType': postTypes[i], 'ynorm': list(postBin)},
# 						'synMech': ESynMech,
# 						'probability': pmat[label][ipost,ipre],
# 						'weight': wmat[label][ipost,ipre] * cfg.EEGain / cfg.synsperconn[cellModel], 
# 						'synMechWeightFactor': cfg.synWeightFractionEE,
# 						'delay': 'defaultDelay+dist_3D/propVelocity',
# 						'synsPerConn': cfg.synsperconn[cellModel],
# 						'sec': 'spiny'}
			

# #------------------------------------------------------------------------------
# ## E -> I
# if cfg.EIGain: # Use IEGain if value set
# 	cfg.EPVGain = cfg.EIGain
# 	cfg.ESOMGain = cfg.EIGain
# else: 
# 	cfg.EIGain = (cfg.EPVGain+cfg.ESOMGain)/2.0

# if cfg.addConn and (cfg.EPVGain > 0.0 or cfg.ESOMGain > 0.0):
# 	labelsConns = ['FS', 'LTS']
# 	labelPostBins = ['FS/LTS', 'FS/LTS']
# 	labelPreBins = ['FS/LTS', 'FS/LTS']
# 	preTypes = ['IT', 'PT', 'CT']
# 	postTypes = ['PV', 'SOM']
# 	ESynMech = ['AMPA','NMDA']
# 	lGain = [cfg.EPVGain, cfg.ESOMGain] # E -> PV or E -> SOM
# 	for i,(label, preBinLabel, postBinLabel) in enumerate(zip(labelsConns,labelPreBins, labelPostBins)):
# 		for ipre, preBin in enumerate(bins[preBinLabel]):
# 			for ipost, postBin in enumerate(bins[postBinLabel]):
# 				ruleLabel = 'EI_'+str(i)+'_'+str(ipre)+'_'+str(ipost)
# 				netParams.connParams[ruleLabel] = {
# 					'preConds': {'cellType': preTypes, 'ynorm': list(preBin)},
# 					'postConds': {'cellType': postTypes[i], 'ynorm': list(postBin)},
# 					'synMech': ESynMech,
# 					'probability': pmat[label][ipost,ipre],
# 					'weight': wmat[label][ipost,ipre] * lGain[i],
# 					'synMechWeightFactor': cfg.synWeightFractionEI,
# 					'delay': 'defaultDelay+dist_3D/propVelocity',
# 					'sec': 'soma'} # simple I cells used right now only have soma

# #------------------------------------------------------------------------------
# ## I -> all
# if cfg.IEGain: # Use IEGain if value set
# 	cfg.PVEGain = cfg.IEGain
# 	cfg.SOMEGain = cfg.IEGain
# else: 
# 	cfg.IEGain = (cfg.PVEGain+cfg.SOMEGain)/2.0

# if cfg.IIGain:  # Use IIGain if value set
# 	cfg.SOMPVGain = cfg.IIGain
# 	cfg.PVSOMGain = cfg.IIGain
# 	cfg.SOMSOMGain = cfg.IIGain
# 	cfg.PVPVGain = cfg.IIGain
# else:
# 	cfg.IIGain = (cfg.PVSOMGain+cfg.SOMPVGain+cfg.SOMSOMGain+cfg.PVPVGain)/4.0

# if cfg.addConn and (cfg.IEGain > 0.0 or cfg.IIGain > 0.0):
# 	# Local, intralaminar only; all-to-all but distance-based; high weights; L5A/B->L5A/B
# 	preCellTypes = ['SOM', 'SOM', 'SOM', 'PV', 'PV', 'PV']
# 	ynorms = [(0.12,0.31), (0.31,0.77), (0.77,1.0), (0.12,0.31), (0.31,0.77), (0.77,1.0)]
# 	IEweights = cfg.IEweights * 2  # [I->E2/3+4, I->E5, I->E6] weights (Note * 2 is repeat list operator)
# 	IIweights = cfg.IIweights * 2  # [I->I2/3+4, I->I5, I->I6] weights (Note * 2 is repeat list operator)
# 	postCellTypes = ['PT', ['IT','CT'], 'PV', 'SOM']
# 	IEdisynBiases = [None, cfg.IEdisynapticBias, cfg.IEdisynapticBias, None, cfg.IEdisynapticBias, cfg.IEdisynapticBias]
# 	disynapticBias = None  # default, used for I->I

# 	for i,(preCellType, ynorm, IEweight, IIweight, IEdisynBias) in enumerate(zip(preCellTypes, ynorms, IEweights, IIweights, IEdisynBiases)):
# 		for ipost, postCellType in enumerate(postCellTypes):
# 			for cellModel in cellModels:
# 				if postCellType == 'PV':	# postsynaptic I cell
# 					sec = 'soma'
# 					synWeightFraction = [1]
# 					if preCellType == 'PV':  			# PV->PV
# 						weight = IIweight * cfg.PVPVGain
# 						synMech = PVSynMech
# 					else:  							# SOM->PV
# 						weight = IIweight * cfg.SOMPVGain
# 						synMech = SOMISynMech
# 				elif postCellType == 'SOM':	# postsynaptic I cell
# 					sec = 'soma'
# 					synWeightFraction = [1]
# 					if preCellType == 'PV':  			# PV->SOM
# 						weight = IIweight * cfg.PVSOMGain
# 						synMech = PVSynMech
# 					else:  							# SOM->SOM
# 						weight = IIweight * cfg.SOMSOMGain
# 						synMech = SOMISynMech
# 				elif postCellType == ['IT','CT']: # postsynaptic IT,CT cell
# 					disynapticBias = IEdisynBias
# 					if preCellType == 'PV':  			# PV->E
# 						weight = IEweight * cfg.PVEGain
# 						synMech = PVSynMech
# 						sec = 'perisom'
# 					else:  							# SOM->E
# 						weight = IEweight * cfg.SOMEGain
# 						synMech = SOMESynMech
# 						sec = 'spiny'
# 						synWeightFraction = cfg.synWeightFractionSOME
# 				elif postCellType == 'PT': # postsynaptic PT cell
# 					disynapticBias = IEdisynBias
# 					if preCellType == 'PV':  			# PV->E
# 						weight = IEweight * cfg.IPTGain * cfg.PVEGain
# 						synMech = PVSynMech
# 						sec = 'perisom'
# 					else:  							# SOM->E
# 						weight = IEweight * cfg.IPTGain * cfg.SOMEGain
# 						synMech = SOMESynMech
# 						sec = 'spiny'
# 						synWeightFraction = cfg.synWeightFractionSOME
# 				if cellModel == 'HH_full':
# 					weight = weight * cfg.IFullGain


# 				ruleLabel = 'I_'+cellModel+'_'+str(i)+'_'+str(ipost)
# 				netParams.connParams[ruleLabel] = {
# 					'preConds': {'cellType': preCellType, 'ynorm': ynorm},
# 					'postConds': {'cellModel': cellModel, 'cellType': postCellType, 'ynorm': ynorm},
# 					'synMech': synMech,
# 					'probability': '1.0 * exp(-dist_3D/probLambda)',
# 					'weight': weight / cfg.synsperconn[cellModel],
# 					'delay': 'defaultDelay+dist_3D/propVelocity',
# 					'synsPerConn': cfg.synsperconn[cellModel],
# 					'synMechWeightFactor': synWeightFraction,
# 					'sec': sec,
# 					'disynapticBias': disynapticBias}

# #------------------------------------------------------------------------------
# # Long-range  connectivity parameters
# #------------------------------------------------------------------------------
# if cfg.addLongConn:

# 	# load load experimentally based parameters for long range inputs
# 	cmatLong = connLongData['cmat']
# 	binsLong = connLongData['bins']

# 	longPops = ['TPO', 'TVL', 'S1', 'S2', 'cM1', 'M2', 'OC']
# 	cellTypes = ['IT', 'PT', 'CT', 'PV', 'SOM']
# 	EorI = ['exc', 'inh']
# 	syns = {'exc': ESynMech, 'inh': 'GABAA'}
# 	synFracs = {'exc': cfg.synWeightFractionEE, 'inh': [1.0]}

# 	for longPop in longPops:
# 		for ct in cellTypes:
# 			for EorI in ['exc', 'inh']:
# 				for i, (binRange, convergence) in enumerate(zip(binsLong[(longPop, ct)], cmatLong[(longPop, ct, EorI)])):
# 					for cellModel in cellModels:
# 						ruleLabel = longPop+'_'+ct+'_'+EorI+'_'+cellModel+'_'+str(i)
# 						netParams.connParams[ruleLabel] = { 
# 							'preConds': {'pop': longPop}, 
# 							'postConds': {'cellModel': cellModel, 'cellType': ct, 'ynorm': list(binRange)},
# 							'synMech': syns[EorI],
# 							'convergence': convergence,
# 							'weight': cfg.weightLong / cfg.synsperconn[cellModel], 
# 							'synMechWeightFactor': cfg.synWeightFractionEE,
# 							'delay': 'defaultDelay+dist_3D/propVelocity',
# 							'synsPerConn': cfg.synsperconn[cellModel],
# 							'sec': 'spiny'}

#------------------------------------------------------------------------------
# Subcellular connectivity (synaptic distributions)
#------------------------------------------------------------------------------   		

#------------------------------------------------------------------------------
# NetStim (LSPS pixel) -> PT (Sheets fig4)
if cfg.addSubConn and cfg.ihSubConn:
	lenX = 8
	lenY = 24 
	spacing = 50
	fixedSomaY = -735
	gridX = range(0, spacing*lenX, spacing)
	gridY = range(0, -spacing*lenY, -spacing)

	map2d = [[0 for _ in range(lenY)] for _ in range(lenX)]
	map2d[cfg.ihX][cfg.ihY] = 1

	netParams.subConnParams['ih'] = {
		'preConds': {'pop': ['GroupNetStimEPT','GroupNetStimEPT2']}, 
		'postConds': {'cellType': ['PT','PT2']},  
		'sec': 'spiny',
		'groupSynMechs': ESynMech, 
		'density': {'type': '2Dmap', 'gridX': gridX, 'gridY': gridY, 'gridValues': map2d, 'fixedSomaY': fixedSomaY}} 

#------------------------------------------------------------------------------
# NetStim (L2/3 stand-in) -> PT (Sheets fig11)
if cfg.stimSubConn:
	with open('conn/conn_dend_PT.json', 'r') as fileObj: connDendPTData = json.load(fileObj)
	with open('conn/conn_dend_IT.json', 'r') as fileObj: connDendITData = json.load(fileObj)
	

	lenY = 30 
	spacing = 50
	gridY = range(0, -spacing*lenY, -spacing)
	synDens, _, fixedSomaY = connDendPTData['synDens'], connDendPTData['gridY'], connDendPTData['fixedSomaY']
	for k in synDens.keys():
		prePop,postType = k.split('_')  # eg. split 'M2_PT'
		if prePop == 'L2': prePop = ['GroupNetStimEPT', 'GroupNetStimEPT2']  # include conns from layer 2/3 and 4
		netParams.subConnParams[k] = {
		'preConds': {'pop': prePop}, 
		'postConds': {'cellType': ['PT', 'PT2']},  
		'sec': 'spiny',
		'groupSynMechs': ESynMech, 
		'density': {'type': '1Dmap', 'gridX': None, 'gridY': gridY, 'gridValues': synDens[k], 'fixedSomaY': fixedSomaY}}

#------------------------------------------------------------------------------
# Network model
if cfg.addSubConn:
	with open('conn/conn_dend_PT.json', 'r') as fileObj: connDendPTData = json.load(fileObj)
	with open('conn/conn_dend_IT.json', 'r') as fileObj: connDendITData = json.load(fileObj)
	
	#------------------------------------------------------------------------------
	# L2/3,TVL,S2,cM1,M2 -> PT (Suter, 2015)
	lenY = 30 
	spacing = 50
	gridY = [i for i in range(0, -spacing*lenY, -spacing)]
	# gridY = range(0, -spacing*lenY, -spacing)
	synDens, _, fixedSomaY = connDendPTData['synDens'], connDendPTData['gridY'], connDendPTData['fixedSomaY']
	for k in synDens.keys():
		prePop,postType = k.split('_')  # eg. split 'M2_PT'
		if prePop == 'L2': prePop = 'IT2'  # include conns from layer 2/3 and 4
		netParams.subConnParams[k] = {
		'preConds': {'pop': prePop}, 
		'postConds': {'cellType': postType},  
		'sec': 'spiny',
		'groupSynMechs': ESynMech, 
		'density': {'type': '1Dmap', 'gridX': None, 'gridY': gridY, 'gridValues': synDens[k], 'fixedSomaY': fixedSomaY}} 


	#------------------------------------------------------------------------------
	# TPO, TVL, M2, OC  -> E (L2/3, L5A, L5B, L6) (Hooks 2013)
	lenY = 26
	spacing = 50
	gridY = [i for i in range(0, -spacing*lenY, -spacing)]
	# gridY = range(0, -spacing*lenY, -spacing)
	synDens, _, fixedSomaY = connDendITData['synDens'], connDendITData['gridY'], connDendITData['fixedSomaY']
	for k in synDens.keys():
		prePop,post = k.split('_')  # eg. split 'M2_L2'
		postCellTypes = ['IT','PT','CT'] if prePop in ['OC','TPO'] else ['IT','CT']  # only OC,TPO include PT cells
		postyRange = list(layer[post.split('L')[1]]) # get layer yfrac range 
		if post == 'L2': postyRange[1] = layer['4'][1]  # apply L2 rule also to L4 
		netParams.subConnParams[k] = {
		'preConds': {'pop': prePop}, 
		'postConds': {'ynorm': postyRange , 'cellType': postCellTypes},  
		'sec': 'spiny',
		'groupSynMechs': ESynMech, 
		'density': {'type': '1Dmap', 'gridX': None, 'gridY': gridY, 'gridValues': synDens[k], 'fixedSomaY': fixedSomaY}} 

	# Removed - Bellow this point the SubConn is not being used in the Sheets figure 8 and 9

	# #------------------------------------------------------------------------------
	# # S1, S2, cM1 -> E IT/CT; no data, assume uniform over spiny
	# netParams.subConnParams['S1,S2,cM1->IT,CT'] = {
	# 	'preConds': {'pop': ['S1','S2','cM1']}, 
	# 	'postConds': {'cellType': ['IT','CT']},
	# 	'sec': 'spiny',
	# 	'groupSynMechs': ESynMech, 
	# 	'density': 'uniform'} 


	# #------------------------------------------------------------------------------
	# # rest of local E->E (exclude IT2->PT); uniform distribution over spiny
	# netParams.subConnParams['IT2->non-PT'] = {
	# 	'preConds': {'pop': ['IT2']}, 
	# 	'postConds': {'cellType': ['IT','CT']},
	# 	'sec': 'spiny',
	# 	'groupSynMechs': ESynMech, 
	# 	'density': 'uniform'} 
		
	# netParams.subConnParams['non-IT2->E'] = {
	# 	'preConds': {'pop': ['IT4','IT5A','IT5B','PT5B','IT6','CT6']}, 
	# 	'postConds': {'cellType': ['IT','PT','CT']},
	# 	'sec': 'spiny',
	# 	'groupSynMechs': ESynMech, 
	# 	'density': 'uniform'} 


	# #------------------------------------------------------------------------------
	# # PV->E; perisomatic (no sCRACM)
	# netParams.subConnParams['PV->E'] = {
	# 	'preConds': {'cellType': 'PV'}, 
	# 	'postConds': {'cellType': ['IT', 'CT', 'PT']},  
	# 	'sec': 'perisom', 
	# 	'density': 'uniform'} 


	# #------------------------------------------------------------------------------
	# # SOM->E; apical dendrites (no sCRACM)
	# netParams.subConnParams['SOM->E'] = {
	# 	'preConds': {'cellType': 'SOM'}, 
	# 	'postConds': {'cellType': ['IT', 'CT', 'PT']},  
	# 	'sec': 'apicdend',
	# 	'groupSynMechs': SOMESynMech,
	# 	'density': 'uniform'} 


	# #------------------------------------------------------------------------------
	# # All->I; apical dendrites (no sCRACM)
	# netParams.subConnParams['All->I'] = {
	# 	'preConds': {'cellType': ['IT', 'CT', 'PT', 'SOM', 'PV']+longPops}, 
	# 	'postConds': {'cellType': ['SOM', 'PV']},  
	# 	'sec': 'spiny',
	# 	'groupSynMechs': ESynMech,
	# 	'density': 'uniform'}