Skip to content

Commit

Permalink
Merge pull request #198 from Neurosim-lab/development
Browse files Browse the repository at this point in the history
PR from development to master - VERSION 0.6.8
  • Loading branch information
salvadord authored Mar 10, 2017
2 parents 8354304 + 08245e3 commit 7728c30
Show file tree
Hide file tree
Showing 12 changed files with 1,175 additions and 293 deletions.
39 changes: 39 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,42 @@
# Version 0.6.8

- Keep track of last host after distributing cells of each pop (improves load balance) (issues #41 #196)

- Added option to run batch on HPC SLURM system (eg. SDSC Comet)

- Added cvode_atol option to cfg

- Improved plotShape() to use matplotlib and use colormap to show num syns

- Batch params can now have an arbitrary number of levels in structure (eg. dict of list of dicts etc)

- Batch params can now be grouped ('group':True) so values vary together not combinatorally

- Removed pc.done() at the end of Batch.run() method so can run multiple batches from same script

- Added skipCfg option to batch

- Added cfg.saveCellSecs option to reduce save time and file size (secs available via netParams)

- Added cfg.saveCellConns option to reduce save time and file size

- Modified code so 'cellModel' tag is optional

- Added renameCellParamsSec() method to netParams class

- When importing cell global 'v_init' is stored as param for each section

- Fixed small bugs when loading saved model

- Fixed bug when calling internal method _findPrePostCellsCondition()

- Fixed bug in subcellConn groupedSynMechs

- Fixed bug in subcellConn trying to add stims+conns to NetStims/VecStims

- Fixed bug in subcellConn so syns are not placed at loc 0.0 or 1.0 (error if syn uses ion)


# Version 0.6.7

- Added gridSpacing option to create populations with cells placed in grid with fixed spacing
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ Requires NEURON with Python and MPI support.
* **netpyne/utils.py**: utility python methods (eg. to import cell parameters)


Please cite as: "Salvador Dura-Bernal, Padraig Gleeson, Cliff C Kerr, Samuel Neymotin, William W Lytton. (2017). Neurosim-lab/NetPyNE: v0.6.7 [Data set]. Zenodo. http://doi.org/10.5281/zenodo.290623"

For further information please contact: [email protected]

2 changes: 1 addition & 1 deletion netpyne/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@

__version__ = '0.6.7'
__version__ = '0.6.8'
__gui__ = True # global option to enable/disable graphics
482 changes: 283 additions & 199 deletions netpyne/analysis.py

Large diffs are not rendered by default.

232 changes: 161 additions & 71 deletions netpyne/batch.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@


import datetime
from itertools import product
from itertools import izip, product
from popen2 import popen2
from time import sleep
import imp
from netpyne import specs
from neuron import h
pc = h.ParallelContext() # use bulletin board master/slave
if pc.id()==0: pc.master_works_on_jobs(0)
Expand All @@ -30,15 +31,18 @@ def runJob(script, cfgSavePath):

class Batch(object):

def __init__(self, cfgFile='cfg.py', netParamsFile='netParams.py'):
def __init__(self, cfgFile='cfg.py', netParamsFile='netParams.py', params=None):
self.batchLabel = 'batch_'+str(datetime.date.today())
self.cfgFile = cfgFile
self.netParamsFile = netParamsFile
self.params = []
self.saveFolder = '/'+self.batchLabel
self.method = 'grid'
self.runCfg = {}

self.params = []
if params:
for k,v in params.iteritems():
self.params.append({'label': k, 'values': v})

def save(self, filename):
import os
basename = os.path.basename(filename)
Expand All @@ -55,10 +59,13 @@ def save(self, filename):
dataSave = {'batch': self.__dict__}
if ext == 'json':
import json
#from json import encoder
#encoder.FLOAT_REPR = lambda o: format(o, '.12g')
print('Saving batch to %s ... ' % (filename))
with open(filename, 'w') as fileObj:
json.dump(dataSave, fileObj, indent=4, sort_keys=True)


def run(self):
if self.method in ['grid','list']:
# create saveFolder
Expand Down Expand Up @@ -86,88 +93,171 @@ def run(self):
cfgModule = imp.load_source(cfgModuleName, self.cfgFile)
self.cfg = cfgModule.cfg

# iterate over all param combinations
if self.method == 'grid':
# iterate over all param combinations
labelList, valuesList = zip(*[(p['label'], p['values']) for p in self.params])
valueCombinations = product(*(valuesList))
indexCombinations = product(*[range(len(x)) for x in valuesList])
elif self.method == 'list':
pass
groupedParams = False
for p in self.params:
if 'group' not in p:
p['group'] = False # by default set linear to False
elif 'group' == True:
groupedParams = True

labelList, valuesList = zip(*[(p['label'], p['values']) for p in self.params if p['group'] == False])
valueCombinations = list(product(*(valuesList)))
indexCombinations = list(product(*[range(len(x)) for x in valuesList]))

if groupedParams:
labelListGroup, valuesListGroup = zip(*[(p['label'], p['values']) for p in self.params if p['group'] == True])
valueCombGroups = izip(*(valuesListGroup))
indexCombGroups = izip(*[range(len(x)) for x in valuesListGroup])
else:
valueCombGroups = [(0,)] # this is a hack -- improve!
indexCombGroups = [(0,)]

# if using pc bulletin board, initialize all workers
if self.runCfg.get('type', None) == 'mpi':
for iworker in range(int(pc.nhost())):
pc.runworker()

for iComb, pComb in zip(indexCombinations, valueCombinations):
for i, paramVal in enumerate(pComb):
paramLabel = labelList[i]
if isinstance(paramLabel, tuple):
container = getattr(self.cfg, paramLabel[0])
container[paramLabel[1]] = paramVal

#if 1:
#for iComb, pComb in zip(indexCombinations, valueCombinations):

for iCombG, pCombG in zip(indexCombGroups, valueCombGroups):
for iCombNG, pCombNG in zip(indexCombinations, valueCombinations):
if groupedParams: # temporary hack - improve
iComb = iCombG+iCombNG
pComb = pCombG+pCombNG
else:
setattr(self.cfg, paramLabel, paramVal) # set simConfig params
print str(paramLabel)+' = '+str(paramVal)
iComb = iCombNG
pComb = pCombNG

# save simConfig json to saveFolder
simLabel = self.batchLabel+''.join([''.join('_'+str(i)) for i in iComb])
self.cfg.simLabel = simLabel
self.cfg.saveFolder = self.saveFolder
cfgSavePath = self.saveFolder+'/'+simLabel+'_cfg.json'
self.cfg.save(cfgSavePath)


# skip if output file already exists
jobName = self.saveFolder+'/'+simLabel
if self.runCfg.get('skip', False) and glob.glob(jobName+'.json'):
print 'Skipping job %s since output file already exists...' % (jobName)
else:
# hpc torque job submission
if self.runCfg.get('type',None) == 'hpc_torque':
print iComb, pComb

# read params or set defaults
sleepInterval = self.runCfg.get('sleepInterval', 1)
sleep(sleepInterval)

numproc = self.runCfg.get('numproc', 1)
script = self.runCfg.get('script', 'init.py')
walltime = self.runCfg.get('walltime', '00:30:00')
queueName = self.runCfg.get('queueName', 'default')
nodesppn = 'nodes=1:ppn=%d'%(numproc)
for i, paramVal in enumerate(pComb):
paramLabel = labelList[i]
if isinstance(paramLabel, tuple):
container = self.cfg
for ip in range(len(paramLabel)-1):
if isinstance(container, specs.SimConfig):
container = getattr(container, paramLabel[ip])
else:
container = container[paramLabel[ip]]
container[paramLabel[-1]] = paramVal
else:
setattr(self.cfg, paramLabel, paramVal) # set simConfig params
print str(paramLabel)+' = '+str(paramVal)

command = 'mpiexec -np %d nrniv -python -mpi %s simConfig=%s' % (numproc, script, cfgSavePath)

output, input = popen2('qsub') # Open a pipe to the qsub command.

jobString = """#!/bin/bash
#PBS -N %s
#PBS -l walltime=%s
#PBS -q %s
#PBS -l %s
#PBS -o %s.run
#PBS -e %s.err
cd $PBS_O_WORKDIR
echo $PBS_O_WORKDIR
%s""" % (jobName, walltime, queueName, nodesppn, jobName, jobName, command)

# Send job_string to qsub
input.write(jobString)
print jobString+'\n'
input.close()

# pc bulletin board job submission (master/slave) via mpi
# eg. usage: mpiexec -n 4 nrniv -mpi batch.py
elif self.runCfg.get('type',None) == 'mpi':
jobName = self.saveFolder+'/'+simLabel
print 'Submitting job ',jobName
# master/slave bulletin board schedulling of jobs
pc.submit(runJob, self.runCfg.get('script', 'init.py'), cfgSavePath)
# set simLabel and jobName
simLabel = self.batchLabel+''.join([''.join('_'+str(i)) for i in iComb])
jobName = self.saveFolder+'/'+simLabel

# skip if output file already exists
if self.runCfg.get('skip', False) and glob.glob(jobName+'.json'):
print 'Skipping job %s since output file already exists...' % (jobName)
elif self.runCfg.get('skipCfg', False) and glob.glob(jobName+'_cfg.json'):
print 'Skipping job %s since cfg file already exists...' % (jobName)
else:
# save simConfig json to saveFolder
self.cfg.simLabel = simLabel
self.cfg.saveFolder = self.saveFolder
cfgSavePath = self.saveFolder+'/'+simLabel+'_cfg.json'
self.cfg.save(cfgSavePath)

# hpc torque job submission
if self.runCfg.get('type',None) == 'hpc_torque':

# read params or set defaults
sleepInterval = self.runCfg.get('sleepInterval', 1)
sleep(sleepInterval)

numproc = self.runCfg.get('numproc', 1)
script = self.runCfg.get('script', 'init.py')
walltime = self.runCfg.get('walltime', '00:30:00')
queueName = self.runCfg.get('queueName', 'default')
nodesppn = 'nodes=1:ppn=%d'%(numproc)

command = 'mpiexec -np %d nrniv -python -mpi %s simConfig=%s' % (numproc, script, cfgSavePath)

output, input = popen2('qsub') # Open a pipe to the qsub command.

jobString = """#!/bin/bash
#PBS -N %s
#PBS -l walltime=%s
#PBS -q %s
#PBS -l %s
#PBS -o %s.run
#PBS -e %s.err
cd $PBS_O_WORKDIR
echo $PBS_O_WORKDIR
%s""" % (jobName, walltime, queueName, nodesppn, jobName, jobName, command)

# Send job_string to qsub
input.write(jobString)
print jobString+'\n'
input.close()

# hpc torque job submission
elif self.runCfg.get('type',None) == 'hpc_slurm':

# read params or set defaults
sleepInterval = self.runCfg.get('sleepInterval', 1)
sleep(sleepInterval)

allocation = self.runCfg.get('allocation', 'csd403') # NSG account
nodes = self.runCfg.get('nodes', 1)
coresPerNode = self.runCfg.get('coresPerNode', 1)
email = self.runCfg.get('email', '[email protected]')
folder = self.runCfg.get('folder', '.')
script = self.runCfg.get('script', 'init.py')
walltime = self.runCfg.get('walltime', '00:30:00')
numproc = nodes*coresPerNode
command = 'ibrun -np %d nrniv -python -mpi %s simConfig=%s' % (numproc, script, cfgSavePath)

jobString = """#!/bin/bash
#SBATCH --job-name=%s
#SBATCH -A %s
#SBATCH -t %s
#SBATCH --nodes=%d
#SBATCH --ntasks-per-node=%d
#SBATCH -o %s.run
#SBATCH -e %s.err
#SBATCH --mail-user=%s
#SBATCH --mail-type=end
source ~/.bashrc
cd %s
%s
wait
""" % (jobName, allocation, walltime, nodes, coresPerNode, jobName, jobName, email, folder, command)

# Send job_string to qsub
# output, input = popen2('sbatch') # Open a pipe to the qsub command.
# input.write(jobString)
print 'Submitting job ',jobName
print jobString+'\n'
# input.close()

batchfile = '%s.sbatch'%(jobName)
with open(batchfile, 'w') as text_file:
text_file.write("%s" % jobString)

#subprocess.call
output, pinput = popen2('sbatch '+batchfile) # Open a pipe to the qsub command.
pinput.close()

# pc bulletin board job submission (master/slave) via mpi
# eg. usage: mpiexec -n 4 nrniv -mpi batch.py
elif self.runCfg.get('type',None) == 'mpi':
jobName = self.saveFolder+'/'+simLabel
print 'Submitting job ',jobName
# master/slave bulletin board schedulling of jobs
pc.submit(runJob, self.runCfg.get('script', 'init.py'), cfgSavePath)

# wait for pc bulletin board jobs to finish
try:
while pc.working():
sleep(1)
pc.done()
#pc.done()
except:
pass

Expand Down
14 changes: 7 additions & 7 deletions netpyne/cell.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,10 @@ def create (self):
conditionsMet = 0
break
elif isinstance(condVal[0], basestring):
if self.tags[condKey] not in condVal:
if self.tags.get(condKey) not in condVal:
conditionsMet = 0
break
elif self.tags[condKey] != condVal:
elif self.tags.get(condKey) != condVal:
conditionsMet = 0
break
if conditionsMet: # if all conditions are met, set values for this cell
Expand Down Expand Up @@ -236,10 +236,10 @@ def modify (self, prop):
conditionsMet = 0
break
elif isinstance(condVal[0], basestring):
if self.tags[condKey] not in condVal:
if self.tags.get(condKey) not in condVal:
conditionsMet = 0
break
elif self.tags[condKey] != condVal:
elif self.tags.get(condKey) != condVal:
conditionsMet = 0
break

Expand Down Expand Up @@ -346,7 +346,7 @@ def createNEURONObj (self, prop):
# create section
if sectName not in self.secs:
self.secs[sectName] = Dict() # create sect dict if doesn't exist
if 'hSec' not in self.secs[sectName]:
if 'hSec' not in self.secs[sectName] or self.secs[sectName]['hSec'] == None:
self.secs[sectName]['hSec'] = h.Section(name=sectName, cell=self) # create h Section object
sec = self.secs[sectName] # pointer to section

Expand Down Expand Up @@ -495,7 +495,7 @@ def addConnsNEURONObj(self):

netcon.weight[0] = conn['weight']
netcon.delay = conn['delay']
netcon.threshold = conn['threshold']
netcon.threshold = conn.get('threshold', sim.net.params.defaultThreshold)
conn['hNetcon'] = netcon

# Add plasticity
Expand Down Expand Up @@ -819,7 +819,7 @@ def modifyConns (self, params):
conditionsMet = 0
break
elif isinstance(condVal, list) and isinstance(condVal[0], basestring):
if self.tags[condKey] not in condVal:
if self.tags.get(condKey) not in condVal:
conditionsMet = 0
break
elif self.tags.get(condKey) != condVal:
Expand Down
Loading

0 comments on commit 7728c30

Please sign in to comment.