From 108fa32f271b699058c0bf271347186eed9605f8 Mon Sep 17 00:00:00 2001 From: James Chen Date: Sun, 17 Mar 2024 12:30:54 -0400 Subject: [PATCH 01/42] batch tools subpackage --- netpyne/batchtools/__init__.py | 3 +++ netpyne/batchtools/comm.py | 37 ++++++++++++++++++++++++++++++++++ netpyne/batchtools/header.py | 0 3 files changed, 40 insertions(+) create mode 100644 netpyne/batchtools/__init__.py create mode 100644 netpyne/batchtools/comm.py create mode 100644 netpyne/batchtools/header.py diff --git a/netpyne/batchtools/__init__.py b/netpyne/batchtools/__init__.py new file mode 100644 index 000000000..96f5d6ecf --- /dev/null +++ b/netpyne/batchtools/__init__.py @@ -0,0 +1,3 @@ +from pubtk.netpyne import specs +# from pubtk.netpyne import specs ? + diff --git a/netpyne/batchtools/comm.py b/netpyne/batchtools/comm.py new file mode 100644 index 000000000..14ce1104f --- /dev/null +++ b/netpyne/batchtools/comm.py @@ -0,0 +1,37 @@ +from pubtk.netpyne import specs +from pubtk.runtk.runners import create_runner +from neuron import h + +HOST = 0 # for the purposes of send and receive with mpi. + +class Comm(object): + def __init__(self, runner_type='socket'): + self.runner = specs + h.nrnmpi_init() + self.pc = h.ParallelContext() + self.rank = self.pc.id() + + def initialize(self): + if self.is_host(): + self.runner.connect() + + def set_runner(self, runner_type='socket'): + self.runner = create_runner(runner_type) + def is_host(self): + return self.rank == HOST + def send(self, data): + if self.is_host(): + self.runner.send(data) + + def recv(self): # to be implemented. need to broadcast value to all workers + if self.is_host(): + data = self.runner.recv() + else: + data = None + #data = self.is_host() and self.runner.recv() + #probably don't put a blocking statement in a boolean evaluation... + self.pc.barrier() + return self.pc.py_broadcast(data, HOST) + + def close(self): + self.runner.close() diff --git a/netpyne/batchtools/header.py b/netpyne/batchtools/header.py new file mode 100644 index 000000000..e69de29bb From 5446c1714577a0e97c602ab44b5f43b64a94f352 Mon Sep 17 00:00:00 2001 From: James Chen Date: Mon, 18 Mar 2024 17:34:30 -0400 Subject: [PATCH 02/42] comm update --- netpyne/batchtools/comm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netpyne/batchtools/comm.py b/netpyne/batchtools/comm.py index 14ce1104f..08709d2df 100644 --- a/netpyne/batchtools/comm.py +++ b/netpyne/batchtools/comm.py @@ -5,8 +5,8 @@ HOST = 0 # for the purposes of send and receive with mpi. class Comm(object): - def __init__(self, runner_type='socket'): - self.runner = specs + def __init__(self, runner = specs): + self.runner = runner h.nrnmpi_init() self.pc = h.ParallelContext() self.rank = self.pc.id() From f56bac6b46fe1b2d3982aeb12e61d5ee01a6e81e Mon Sep 17 00:00:00 2001 From: James Chen Date: Tue, 19 Mar 2024 00:33:50 -0400 Subject: [PATCH 03/42] new search methods --- netpyne/batchtools/search.py | 157 ++++++++++++++++++++++++++++++++++ netpyne/batchtools/submits.py | 155 +++++++++++++++++++++++++++++++++ 2 files changed, 312 insertions(+) create mode 100644 netpyne/batchtools/search.py create mode 100644 netpyne/batchtools/submits.py diff --git a/netpyne/batchtools/search.py b/netpyne/batchtools/search.py new file mode 100644 index 000000000..23105e4f6 --- /dev/null +++ b/netpyne/batchtools/search.py @@ -0,0 +1,157 @@ +import ray +import pandas +import os +from ray import tune, train +from ray.air import session, RunConfig +from ray.tune.search.basic_variant import BasicVariantGenerator +from ray.tune.search import create_searcher, ConcurrencyLimiter, SEARCH_ALG_IMPORT + +""" +SEE: +'variant_generator' +'random' +'ax' +'dragonfly' +'skopt' +'hyperopt' +'bayesopt' +'bohb' +'nevergrad' +'optuna' +'zoopt' +'sigopt' +'hebo' +'blendsearch' +'cfo' +""" + + + + +def ray_search(dispatcher_constructor, submit_constructor, algorithm = "variant_generator", label = 'search', + params = None, concurrency = 1, output_path = '../batch', checkpoint_path = '../ray', + batch_config = None): + ray.init( + runtime_env={"working_dir": "."}) # needed for python import statements + + #TODO class this object for self calls? cleaner? vs nested functions + #TODO clean up working_dir and excludes + if checkpoint_path[0] == '/': + storage_path = os.path.normpath(checkpoint_path) + elif checkpoint_path[0] == '.': + storage_path = os.path.normpath(os.path.join(os.getcwd(), checkpoint_path)) + else: + raise ValueError("checkpoint_dir must be an absolute path (starts with /) or relative to the current working directory (starts with .)") + algo = create_searcher(algorithm) + algo = ConcurrencyLimiter(searcher=algo, max_concurrent=concurrency, batch=True) + + submit = submit_constructor() + submit.update_templates( + **batch_config + ) + project_path = os.getcwd() + def run(config): + tid = ray.train.get_context().get_trial_id() + tid = int(tid.split('_')[-1]) #integer value for the trial + run_label = '{}_{}'.format(label, tid) + dispatcher = dispatcher_constructor(project_path = project_path, output_path = output_path, submit = submit, + gid = run_label) + + dispatcher.update_env(dictionary = config) + try: + dispatcher.run() + dispatcher.accept() + data = dispatcher.recv() + dispatcher.clean() + except Exception as e: + dispatcher.clean() + raise(e) + data = pandas.read_json(data, typ='series', dtype=float) + session.report({'data': data}) + + tuner = tune.Tuner( + run, + tune_config=tune.TuneConfig( + search_alg=algo, + num_samples=1, # grid search samples 1 for each param + metric="data" + ), + run_config=RunConfig( + storage_path=checkpoint_path, + name=algorithm, + ), + param_space=params, + ) + + results = tuner.fit() + resultsdf = results.get_dataframe() + resultsdf.to_csv("{}.csv".format(label)) + + +def ray_grid_search(dispatcher_constructor, submit_constructor, label = 'grid', params = None, concurrency = 1, checkpoint_dir = '../grid', batch_config = None): + ray.init( + runtime_env={"working_dir": ".", # needed for python import statements + "excludes": ["*.csv", "*.out", "*.run", + "*.sh" , "*.sgl", ]} + ) + #TODO class this object for self calls? cleaner? vs nested functions + #TODO clean up working_dir and excludes + + for key, val in params.items(): + if 'grid_search' not in val: #check that parametrized to grid_search + params[key] = tune.grid_search(val) + + #brief check path + if checkpoint_dir[0] == '/': + storage_path = os.path.normpath(checkpoint_dir) + elif checkpoint_dir[0] == '.': + storage_path = os.path.normpath(os.path.join(os.getcwd(), checkpoint_dir)) + else: + raise ValueError("checkpoint_dir must be an absolute path (starts with /) or relative to the current working directory (starts with .)") + #TODO check that write permissions to path are possible + """ + if os.path.exists(checkpoint_dir): + storage_path = os.path.normpath(checkpoint_dir) + else: + storage_path = os.path.normpath(os.path.join(os.getcwd(), checkpoint_dir)) + """ + algo = create_searcher('variant_generator') + algo = ConcurrencyLimiter(searcher=algo, max_concurrent=concurrency, batch=True) + submit = submit_constructor() + submit.update_templates( + **batch_config + ) + cwd = os.getcwd() + def run(config): + tid = ray.train.get_context().get_trial_id() + tid = int(tid.split('_')[-1]) #integer value for the trial + dispatcher = dispatcher_constructor(cwd = cwd, submit = submit, gid = '{}_{}'.format(label, tid)) + dispatcher.update_env(dictionary = config) + try: + dispatcher.run() + dispatcher.accept() + data = dispatcher.recv(1024) + dispatcher.clean([]) + except Exception as e: + dispatcher.clean([]) + raise(e) + data = pandas.read_json(data, typ='series', dtype=float) + session.report({'data': data}) + + tuner = tune.Tuner( + run, + tune_config=tune.TuneConfig( + search_alg=algo, + num_samples=1, # grid search samples 1 for each param + metric="data" + ), + run_config=RunConfig( + storage_path=storage_path, + name="grid", + ), + param_space=params, + ) + + results = tuner.fit() + resultsdf = results.get_dataframe() + resultsdf.to_csv("{}.csv".format(label)) \ No newline at end of file diff --git a/netpyne/batchtools/submits.py b/netpyne/batchtools/submits.py new file mode 100644 index 000000000..e3cd9ba53 --- /dev/null +++ b/netpyne/batchtools/submits.py @@ -0,0 +1,155 @@ +from pubtk.runtk import Submit, Template +from pubtk import runtk + +class ZSHSubmit(Submit): + script_args = {'label', 'project_path', 'output_path', 'env', 'command'} + script_template = \ + """\ +#!/bin/zsh +cd {project_path} +export JOBID=$$ +{env} +nohup {command} > {output_path}/{label}.run 2>&1 & +pid=$! +echo $pid >&1 +""" + script_handles = { + runtk.STDOUT: '{output_path}/{label}.run', + runtk.SUBMIT: '{output_path}/{label}.sh'} + def __init__(self, **kwargs): + super().__init__( + submit_template = Template(template="zsh {output_path}/{label}.sh", + key_args={'project_path', 'output_path', 'label'}), + script_template = Template(template=self.script_template, + key_args=self.script_args), + handles = self.script_handles, + ) + def set_handles(self): + pass + + def submit_job(self): + proc = super().submit_job() + try: + self.job_id = int(proc.stdout) + except Exception as e: + raise(Exception("{}\nJob submission failed:\n{}\n{}\n{}\n{}".format(e, self.submit, self.script, proc.stdout, proc.stderr))) + if self.job_id < 0: + raise(Exception("Job submission failed:\n{}\n{}\n{}\n{}".format(self.submit, self.script, proc.stdout, proc.stderr))) + return self.job_id + +class ZSHSubmitSFS(ZSHSubmit): + script_args = {'label', 'project_path', 'output_path', 'env', 'command'} + script_template = \ + """\ +#!/bin/zsh +cd {project_path} +export OUTFILE="{output_path}/{label}.out" +export SGLFILE="{output_path}/{label}.sgl" +export JOBID=$$ +{env} +nohup {command} > {output_path}/{label}.run 2>&1 & +pid=$! +echo $pid >&1 +""" + script_handles = {runtk.SUBMIT: '{output_path}/{label}.sh', + runtk.STDOUT: '{output_path}/{label}.run', + runtk.MSGOUT: '{output_path}/{label}.out', + runtk.SGLOUT: '{output_path}/{label}.sgl'} + +class ZSHSubmitSOCK(ZSHSubmit): + script_args = {'label', 'project_path', 'output_path', 'env', 'command', 'sockname'} + script_template = \ + """\ +#!/bin/zsh +cd {project_path} +export SOCNAME="{sockname}" +export JOBID=$$ +{env} +nohup {command} > {output_path}/{label}.run 2>&1 & +pid=$! +echo $pid >&1 +""" + script_handles = {runtk.SUBMIT: '{output_path}/{label}.sh', + runtk.STDOUT: '{output_path}/{label}.run', + runtk.SOCKET: '{sockname}'} + +class SGESubmit(Submit): + script_args = {'label', 'project_path', 'output_path', 'env', 'command', 'cores', 'vmem', } + script_template = \ + """\ +#!/bin/bash +#$ -N j{label} +#$ -pe smp {cores} +#$ -l h_vmem={vmem} +#$ -o {output_path}/{label}.run +cd {project_path} +source ~/.bashrc +export JOBID=$JOB_ID +{env} +{command} +""" + script_handles = {runtk.SUBMIT: '{output_path}/{label}.sh', + runtk.STDOUT: '{output_path}/{label}.run'} + def __init__(self, **kwargs): + super().__init__( + submit_template = Template(template="qsub {output_path}/{label}.sh", + key_args={'output_path', 'label'}), + script_template = Template(template=self.script_template, + key_args=self.script_args), + handles = self.script_handles, + ) + + def submit_job(self, **kwargs): + proc = super().submit_job() + try: + self.job_id = proc.stdout.split(' ')[2] + except Exception as e: + raise(Exception("{}\nJob submission failed:\n{}\n{}\n{}\n{}".format(e, self.submit, self.script, proc.stdout, proc.stderr))) + return self.job_id + + def set_handles(self): + pass + +class SGESubmitSFS(SGESubmit): + script_args = {'label', 'project_path', 'output_path', 'env', 'command', 'cores', 'vmem', } + script_template = \ + """\ +#!/bin/bash +#$ -N j{label} +#$ -pe smp {cores} +#$ -l h_vmem={vmem} +#$ -o {output_path}/{label}.run +cd {project_path} +source ~/.bashrc +export OUTFILE="{output_path}/{label}.out" +export SGLFILE="{output_path}/{label}.sgl" +export JOBID=$JOB_ID +{env} +{command} +""" + script_handles = {runtk.SUBMIT: '{output_path}/{label}.sh', + runtk.STDOUT: '{output_path}/{label}.run', + runtk.MSGOUT: '{output_path}/{label}.out', + runtk.SGLOUT: '{output_path}/{label}.sgl', + } + +class SGESubmitSOCK(SGESubmit): + script_args = {'label', 'project_path', 'output_path', 'env', 'command', 'cores', 'vmem', 'sockname'} + script_template = \ + """\ +#!/bin/bash +#$ -N j{label} +#$ -pe smp {cores} +#$ -l h_vmem={vmem} +#$ -o {output_path}/{label}.run +cd {project_path} +source ~/.bashrc +export SOCNAME="{sockname}" +export JOBID=$JOB_ID +{env} +{command} +""" + script_handles = {runtk.SUBMIT: '{output_path}/{label}.sh', + runtk.STDOUT: '{output_path}/{label}.run', + runtk.SOCKET: '{sockname}' + } From b2935c14077847f913c5f5d586517bfa98dece8a Mon Sep 17 00:00:00 2001 From: James Chen Date: Tue, 19 Mar 2024 19:31:06 -0400 Subject: [PATCH 04/42] fixed import issues --- netpyne/batchtools/__init__.py | 8 +- netpyne/batchtools/runners.py | 133 +++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 netpyne/batchtools/runners.py diff --git a/netpyne/batchtools/__init__.py b/netpyne/batchtools/__init__.py index 96f5d6ecf..88099b90c 100644 --- a/netpyne/batchtools/__init__.py +++ b/netpyne/batchtools/__init__.py @@ -1,3 +1,7 @@ -from pubtk.netpyne import specs -# from pubtk.netpyne import specs ? +from netpyne.batchtools.runners import NetpyneRunner +from pubtk import runtk +from comm import Comm + +specs = NetpyneRunner() + diff --git a/netpyne/batchtools/runners.py b/netpyne/batchtools/runners.py new file mode 100644 index 000000000..46c0e8b66 --- /dev/null +++ b/netpyne/batchtools/runners.py @@ -0,0 +1,133 @@ +from pubtk.runtk.utils import convert, set_map, create_script +from pubtk import runtk +from pubtk.runtk.runners import Runner, create_runner + +class NetpyneRunner(Runner): + """ + runner for netpyne + see class runner + mappings <- + """ + def __new__(cls, inherit='socket', **kwargs): + + _super = create_runner(inherit) + + def __init__(self, netParams=None, cfg=None, **kwargs): + """ + NetpyneRunner constructor + + Parameters + ---------- + self - NetpyneRunner instance + netParams - optional netParams instance (defaults to None, created with method: get_NetParams) + cfg - optional SimConfig instance (defaults to None, created with method: get_SimConfig) + N.B. requires cfg with the update_cfg method. see in get_SimConfig: + self.cfg = type("Runner_SimConfig", (specs.SimConfig,), + {'__mappings__': self.mappings, + 'update_cfg': update_cfg})() + kwargs - Unused + """ + _super.__init__(self, **kwargs) + self.netParams = netParams + self.cfg = cfg + + def _set_inheritance(self, inherit): + """ + Method for changing inheritance of NetpyneRunner + see runtk.RUNNERS + Parameters + ---------- + self + inherit + """ + if inherit in runtk.RUNNERS: + cls = type(self) + cls.__bases__ = (runtk.RUNNERS[inherit],) + + def get_NetParams(self): + """ + Creates / Returns a NetParams instance + Parameters + ---------- + self + + Returns + ------- + NetParams instance + + """ + if self.netParams: + return self.netParams + else: + from netpyne import specs + self.netParams = specs.NetParams() + return self.netParams + + def update_cfg(self): #intended to take `cfg` instance as self + """ + Updates the SimConfig instance with mappings to the runner, called from a SimConfig instance + + Parameters + ---------- + self - specs (NetpyneRunner) SimConfig instance + + Returns + ------- + None (updates SimConfig instance in place) + """ + for assign_path, value in self.__mappings__.items(): + try: + set_map(self, assign_path, value) + except Exception as e: + raise Exception("failed on mapping: cfg.{} with value: {}\n{}".format(assign_path, value, e)) + + def get_SimConfig(self): + """ + Creates / Returns a SimConfig instance + Parameters + ---------- + self - NetpyneRunner instance + + Returns + ------- + SimConfig instance + """ + if self.cfg: + return self.cfg + else: + from netpyne import specs + self.cfg = type("Runner_SimConfig", (specs.SimConfig,), + {'__mappings__': self.mappings, + 'update_cfg': update_cfg})() + return self.cfg + + def set_SimConfig(self): + """ + updates the SimConfig instance with mappings to the runner, called from a Runner instance + + Parameters + ---------- + self + """ + # assumes values are only in 'cfg' + for assign_path, value in self.mappings.items(): + try: + set_map(self, "cfg.{}".format(assign_path), value) + except Exception as e: + raise Exception("failed on mapping: cfg.{} with value: {}\n{}".format(assign_path, value, e)) + + def set_mappings(self, filter=''): + # arbitrary filter, can work with 'cfg' or 'netParams' + for assign_path, value in self.mappings.items(): + if filter in assign_path: + set_map(self, assign_path, value) + + return type("NetpyneRunner{}".format(str(_super.__name__)), (_super,), + {'__init__': __init__, + '_set_inheritance': _set_inheritance, + 'get_NetParams': get_NetParams, + 'NetParams': get_NetParams, + 'SimConfig': get_SimConfig, + 'get_SimConfig': get_SimConfig, + 'set_SimConfig': set_SimConfig, + 'set_mappings': set_mappings})(**kwargs) # need to override __init__ or else will call parent From 1bc1eab1fc6006105836fa92aeb1cfabdb52e07f Mon Sep 17 00:00:00 2001 From: James Chen Date: Wed, 20 Mar 2024 16:41:13 -0400 Subject: [PATCH 05/42] updates comm, search --- netpyne/batchtools/__init__.py | 7 ++- netpyne/batchtools/comm.py | 2 +- netpyne/batchtools/search.py | 85 ++++------------------------------ 3 files changed, 17 insertions(+), 77 deletions(-) diff --git a/netpyne/batchtools/__init__.py b/netpyne/batchtools/__init__.py index 88099b90c..9021018a2 100644 --- a/netpyne/batchtools/__init__.py +++ b/netpyne/batchtools/__init__.py @@ -1,7 +1,12 @@ from netpyne.batchtools.runners import NetpyneRunner from pubtk import runtk -from comm import Comm specs = NetpyneRunner() +from netpyne.batchtools.comm import Comm + +comm = Comm() + +#from ray import tune as space.comm +#list and lb ub diff --git a/netpyne/batchtools/comm.py b/netpyne/batchtools/comm.py index 08709d2df..78ab290ec 100644 --- a/netpyne/batchtools/comm.py +++ b/netpyne/batchtools/comm.py @@ -1,4 +1,4 @@ -from pubtk.netpyne import specs +from netpyne.batchtools import specs from pubtk.runtk.runners import create_runner from neuron import h diff --git a/netpyne/batchtools/search.py b/netpyne/batchtools/search.py index 23105e4f6..9797cf206 100644 --- a/netpyne/batchtools/search.py +++ b/netpyne/batchtools/search.py @@ -30,7 +30,7 @@ def ray_search(dispatcher_constructor, submit_constructor, algorithm = "variant_generator", label = 'search', params = None, concurrency = 1, output_path = '../batch', checkpoint_path = '../ray', - batch_config = None): + batch_config = None, num_samples = 1): ray.init( runtime_env={"working_dir": "."}) # needed for python import statements @@ -42,8 +42,8 @@ def ray_search(dispatcher_constructor, submit_constructor, algorithm = "variant_ storage_path = os.path.normpath(os.path.join(os.getcwd(), checkpoint_path)) else: raise ValueError("checkpoint_dir must be an absolute path (starts with /) or relative to the current working directory (starts with .)") - algo = create_searcher(algorithm) - algo = ConcurrencyLimiter(searcher=algo, max_concurrent=concurrency, batch=True) + algo = create_searcher(algorithm, max_concurrent=concurrency, batch=True) + #algo = ConcurrencyLimiter(searcher=algo, max_concurrent=concurrency, batch=True) submit = submit_constructor() submit.update_templates( @@ -58,6 +58,10 @@ def run(config): gid = run_label) dispatcher.update_env(dictionary = config) + dispatcher.update_env(dictionary = { + 'saveFolder': output_path, + 'simLabel': run_label, + }) try: dispatcher.run() dispatcher.accept() @@ -67,17 +71,17 @@ def run(config): dispatcher.clean() raise(e) data = pandas.read_json(data, typ='series', dtype=float) - session.report({'data': data}) + session.report({'data': data, 'config': config}) tuner = tune.Tuner( run, tune_config=tune.TuneConfig( search_alg=algo, - num_samples=1, # grid search samples 1 for each param + num_samples=num_samples, # grid search samples 1 for each param metric="data" ), run_config=RunConfig( - storage_path=checkpoint_path, + storage_path=storage_path, name=algorithm, ), param_space=params, @@ -86,72 +90,3 @@ def run(config): results = tuner.fit() resultsdf = results.get_dataframe() resultsdf.to_csv("{}.csv".format(label)) - - -def ray_grid_search(dispatcher_constructor, submit_constructor, label = 'grid', params = None, concurrency = 1, checkpoint_dir = '../grid', batch_config = None): - ray.init( - runtime_env={"working_dir": ".", # needed for python import statements - "excludes": ["*.csv", "*.out", "*.run", - "*.sh" , "*.sgl", ]} - ) - #TODO class this object for self calls? cleaner? vs nested functions - #TODO clean up working_dir and excludes - - for key, val in params.items(): - if 'grid_search' not in val: #check that parametrized to grid_search - params[key] = tune.grid_search(val) - - #brief check path - if checkpoint_dir[0] == '/': - storage_path = os.path.normpath(checkpoint_dir) - elif checkpoint_dir[0] == '.': - storage_path = os.path.normpath(os.path.join(os.getcwd(), checkpoint_dir)) - else: - raise ValueError("checkpoint_dir must be an absolute path (starts with /) or relative to the current working directory (starts with .)") - #TODO check that write permissions to path are possible - """ - if os.path.exists(checkpoint_dir): - storage_path = os.path.normpath(checkpoint_dir) - else: - storage_path = os.path.normpath(os.path.join(os.getcwd(), checkpoint_dir)) - """ - algo = create_searcher('variant_generator') - algo = ConcurrencyLimiter(searcher=algo, max_concurrent=concurrency, batch=True) - submit = submit_constructor() - submit.update_templates( - **batch_config - ) - cwd = os.getcwd() - def run(config): - tid = ray.train.get_context().get_trial_id() - tid = int(tid.split('_')[-1]) #integer value for the trial - dispatcher = dispatcher_constructor(cwd = cwd, submit = submit, gid = '{}_{}'.format(label, tid)) - dispatcher.update_env(dictionary = config) - try: - dispatcher.run() - dispatcher.accept() - data = dispatcher.recv(1024) - dispatcher.clean([]) - except Exception as e: - dispatcher.clean([]) - raise(e) - data = pandas.read_json(data, typ='series', dtype=float) - session.report({'data': data}) - - tuner = tune.Tuner( - run, - tune_config=tune.TuneConfig( - search_alg=algo, - num_samples=1, # grid search samples 1 for each param - metric="data" - ), - run_config=RunConfig( - storage_path=storage_path, - name="grid", - ), - param_space=params, - ) - - results = tuner.fit() - resultsdf = results.get_dataframe() - resultsdf.to_csv("{}.csv".format(label)) \ No newline at end of file From 3d5d0a879654298936f3febbf07d05cedc02d442 Mon Sep 17 00:00:00 2001 From: James Chen Date: Thu, 21 Mar 2024 11:21:07 -0400 Subject: [PATCH 06/42] search.py --- netpyne/batchtools/search.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/netpyne/batchtools/search.py b/netpyne/batchtools/search.py index 9797cf206..895f40d5b 100644 --- a/netpyne/batchtools/search.py +++ b/netpyne/batchtools/search.py @@ -25,7 +25,8 @@ 'cfo' """ - +def search(): + pass def ray_search(dispatcher_constructor, submit_constructor, algorithm = "variant_generator", label = 'search', From cad0574e6b232dfd18d6ccfccb19d8be5e494f5c Mon Sep 17 00:00:00 2001 From: James Chen Date: Wed, 27 Mar 2024 11:52:51 -0400 Subject: [PATCH 07/42] wrapper tools search --- netpyne/batchtools/search.py | 78 +++++++++++++++++++++++++++-- netpyne/batchtools/submits.py | 94 +++++++++++++++++++++++++++++++++-- 2 files changed, 164 insertions(+), 8 deletions(-) diff --git a/netpyne/batchtools/search.py b/netpyne/batchtools/search.py index 895f40d5b..3432ae5ae 100644 --- a/netpyne/batchtools/search.py +++ b/netpyne/batchtools/search.py @@ -5,11 +5,37 @@ from ray.air import session, RunConfig from ray.tune.search.basic_variant import BasicVariantGenerator from ray.tune.search import create_searcher, ConcurrencyLimiter, SEARCH_ALG_IMPORT - +from netpyne.batchtools import runtk +from collections import namedtuple +import numpy """ +from netpyne.batchtools import search, paramtypes +import numpy + +https://docs.ray.io/en/latest/tune/api/doc/ray.tune.search.Searcher.html#ray.tune.search.Searcher + + + +params = {'synMechTau2': [3.0, 5.0, 7.0], # assumes list of values by default if grid search-like algo + #'synMechTau2': [3.0, 7.0], # assumes lower/upper bounds by default if evol-like algo + 'connWeight' : paramtypes.sample_from(lambda _: numpy.random.uniform(0.005, 0.15))} # can optionally pass any of the paramtypes (= ray.tune data types) + +batch_config = {'sge': 5, 'command': 'python init.py'} + +#TODO rename ray_search to search +search(dispatcher = 'inet', # defaults to 'inet' if no arg is passed? + submit = 'socket', # defaults to 'socket' if no arg is passed? + params = params, + batch_config = batch_config, # + algorithm = "variant_generator", + concurrency = 9, + output_path = '../batch_func', + checkpoint_path = '../grid_func', + label = 'func_search', + num_samples = 3) SEE: 'variant_generator' -'random' +'random' -> points to variant_generator 'ax' 'dragonfly' 'skopt' @@ -25,9 +51,53 @@ 'cfo' """ -def search(): - pass +#should be constant? +constructors = namedtuple('constructors', 'dispatcher, submit') +constructor_tuples = { + ('sge', 'socket'): constructors(runtk.dispatchers.INETDispatcher, runtk.submits.SGESubmitSOCK), + #('sge', 'unix'): constructors(runtk.dispatchers.UNIXDispatcher, runtk.submits.SGESubmitSOCK), #can't use AF_UNIX sockets on networked machines + ('sge', 'sfs' ): constructors(runtk.dispatchers.SFSDispatcher , runtk.submits.SGESubmitSFS ), + #('zsh', 'inet'): constructors(runtk.dispatchers.INETDispatcher, runtk.submits.ZSHSubmitSOCK), #TODO preferable to use AF_UNIX sockets on local machines + ('zsh', 'socket'): constructors(runtk.dispatchers.UNIXDispatcher, runtk.submits.ZSHSubmitSOCK), + ('zsh', 'sfs' ): constructors(runtk.dispatchers.SFSDispatcher , runtk.submits.ZSHSubmitSFS ), +}#TODO, just say "socket"? + +""" +some shim functions before ray_search +""" +def generate_constructors(job_type, comm_type = 'socket'): + """" + returns the dispatcher, submit constructor pair for ray_search based on the job_type and comm_type inputs + """ + if (job_type, comm_type) not in constructor_tuples: + raise ValueError("Invalid job_type or comm_type pairing") + return constructor_tuples[(job_type, comm_type)] + +def generate_parameters(param_dict, algo): + """ + returns a dictionary of parameters for ray_search based on the input dictionary + from NOTES Salvador: + params = {'synMechTau2': [3.0, 5.0, 7.0], # assumes list of values by default if grid search-like algo + #'synMechTau2': [3.0, 7.0], # assumes lower/upper bounds by default if evol-like algo + 'connWeight' : paramtypes.sample_from(lambda _: numpy.random.uniform(0.005, 0.15))} # can optionally pass any of the paramtypes (= ray.tune data types) + #TODO: bloated function, prone to error + """ + ray_params = {} + for param, space in param_dict.items(): + lsp = len(space) == 2 + if isinstance(space, (list, tuple)) and algo in {'variant_generator'}: + ray_params[param] = tune.grid_search(space) + elif isinstance(space, (list, tuple)) and algo in SEARCH_ALG_IMPORT.keys(): + if lsp: #if 2 sample from uniform lb, ub + ray_params[param] = tune.uniform(*space) + else: #otherwise treat as a list + ray_params[param] = tune.choice(space) + return ray_params +def search(job_type, params, batch_config, algorithm, concurrency, output_path, checkpoint_path, label, num_samples = 1, comm_type='socket'): #requires some shimming + dispatcher_constructor, submit_constructor = generate_constructors(job_type, comm_type) + params = generate_parameters(params, algorithm) + ray_search(dispatcher_constructor, submit_constructor, algorithm, label, params, concurrency, output_path, checkpoint_path, batch_config, num_samples) def ray_search(dispatcher_constructor, submit_constructor, algorithm = "variant_generator", label = 'search', params = None, concurrency = 1, output_path = '../batch', checkpoint_path = '../ray', diff --git a/netpyne/batchtools/submits.py b/netpyne/batchtools/submits.py index e3cd9ba53..4a9ec3d5f 100644 --- a/netpyne/batchtools/submits.py +++ b/netpyne/batchtools/submits.py @@ -1,6 +1,10 @@ from pubtk.runtk import Submit, Template from pubtk import runtk +SFS_HANDLES = {runtk.SUBMIT: '{output_path}/{label}.sh', + runtk.STDOUT: '{output_path}/{label}.run', + runtk.MSGOUT: '{output_path}/{label}.out', + runtk.SGLOUT: '{output_path}/{label}.sgl'} class ZSHSubmit(Submit): script_args = {'label', 'project_path', 'output_path', 'env', 'command'} script_template = \ @@ -78,7 +82,7 @@ class SGESubmit(Submit): script_template = \ """\ #!/bin/bash -#$ -N j{label} +#$ -N job{label} #$ -pe smp {cores} #$ -l h_vmem={vmem} #$ -o {output_path}/{label}.run @@ -103,7 +107,7 @@ def submit_job(self, **kwargs): proc = super().submit_job() try: self.job_id = proc.stdout.split(' ')[2] - except Exception as e: + except Exception as e: #not quite sure how this would occur raise(Exception("{}\nJob submission failed:\n{}\n{}\n{}\n{}".format(e, self.submit, self.script, proc.stdout, proc.stderr))) return self.job_id @@ -115,7 +119,7 @@ class SGESubmitSFS(SGESubmit): script_template = \ """\ #!/bin/bash -#$ -N j{label} +#$ -N job{label} #$ -pe smp {cores} #$ -l h_vmem={vmem} #$ -o {output_path}/{label}.run @@ -138,7 +142,7 @@ class SGESubmitSOCK(SGESubmit): script_template = \ """\ #!/bin/bash -#$ -N j{label} +#$ -N job{label} #$ -pe smp {cores} #$ -l h_vmem={vmem} #$ -o {output_path}/{label}.run @@ -153,3 +157,85 @@ class SGESubmitSOCK(SGESubmit): runtk.STDOUT: '{output_path}/{label}.run', runtk.SOCKET: '{sockname}' } + + +class SGESubmit(Submit): + script_args = {'label', 'project_path', 'output_path', 'env', 'command', 'cores', 'vmem', } + script_template = \ + """\ +#!/bin/bash +#$ -N job{label} +#$ -pe smp {cores} +#$ -l h_vmem={vmem} +#$ -o {output_path}/{label}.run +cd {project_path} +source ~/.bashrc +export JOBID=$JOB_ID +{env} +{command} +""" + script_handles = {runtk.SUBMIT: '{output_path}/{label}.sh', + runtk.STDOUT: '{output_path}/{label}.run'} + def __init__(self, **kwargs): + super().__init__( + submit_template = Template(template="qsub {output_path}/{label}.sh", + key_args={'output_path', 'label'}), + script_template = Template(template=self.script_template, + key_args=self.script_args), + handles = self.script_handles, + ) + + def submit_job(self, **kwargs): + proc = super().submit_job() + try: + self.job_id = proc.stdout.split(' ')[2] + except Exception as e: #not quite sure how this would occur + raise(Exception("{}\nJob submission failed:\n{}\n{}\n{}\n{}".format(e, self.submit, self.script, proc.stdout, proc.stderr))) + return self.job_id + + def set_handles(self): + pass + +class SGESubmitSFS(SGESubmit): + script_args = {'label', 'project_path', 'output_path', 'env', 'command', 'cores', 'vmem', } + script_template = \ + """\ +#!/bin/bash +#$ -N job{label} +#$ -pe smp {cores} +#$ -l h_vmem={vmem} +#$ -o {output_path}/{label}.run +cd {project_path} +source ~/.bashrc +export OUTFILE="{output_path}/{label}.out" +export SGLFILE="{output_path}/{label}.sgl" +export JOBID=$JOB_ID +{env} +{command} +""" + script_handles = {runtk.SUBMIT: '{output_path}/{label}.sh', + runtk.STDOUT: '{output_path}/{label}.run', + runtk.MSGOUT: '{output_path}/{label}.out', + runtk.SGLOUT: '{output_path}/{label}.sgl', + } + +class SGESubmitSOCK(SGESubmit): + script_args = {'label', 'project_path', 'output_path', 'env', 'command', 'cores', 'vmem', 'sockname'} + script_template = \ + """\ +#!/bin/bash +#$ -N job{label} +#$ -pe smp {cores} +#$ -l h_vmem={vmem} +#$ -o {output_path}/{label}.run +cd {project_path} +source ~/.bashrc +export SOCNAME="{sockname}" +export JOBID=$JOB_ID +{env} +{command} +""" + script_handles = {runtk.SUBMIT: '{output_path}/{label}.sh', + runtk.STDOUT: '{output_path}/{label}.run', + runtk.SOCKET: '{sockname}' + } \ No newline at end of file From 14502fa7096e464340613c9926a38fac95fa6d64 Mon Sep 17 00:00:00 2001 From: James Chen Date: Sat, 30 Mar 2024 15:12:07 -0400 Subject: [PATCH 08/42] update to batchtools --- netpyne/batchtools/search.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/netpyne/batchtools/search.py b/netpyne/batchtools/search.py index 3432ae5ae..7db02905d 100644 --- a/netpyne/batchtools/search.py +++ b/netpyne/batchtools/search.py @@ -7,6 +7,7 @@ from ray.tune.search import create_searcher, ConcurrencyLimiter, SEARCH_ALG_IMPORT from netpyne.batchtools import runtk from collections import namedtuple +from pubtk.raytk.search import ray_trial import numpy """ from netpyne.batchtools import search, paramtypes @@ -122,6 +123,7 @@ def ray_search(dispatcher_constructor, submit_constructor, algorithm = "variant_ ) project_path = os.getcwd() def run(config): + data = ray_trial(config, label, dispatcher_constructor, project_path, output_path, submit) tid = ray.train.get_context().get_trial_id() tid = int(tid.split('_')[-1]) #integer value for the trial run_label = '{}_{}'.format(label, tid) From d7d3ead2973b580d175520e149b14c56cc8e28d6 Mon Sep 17 00:00:00 2001 From: James Chen Date: Thu, 4 Apr 2024 16:13:09 -0400 Subject: [PATCH 09/42] codebase moved to netpyne batchtools https://github.com/jchen6727/netpyne/tree/batch --- netpyne/batchtools/search.py | 277 +++++++++++++++++++++++++++-------- 1 file changed, 219 insertions(+), 58 deletions(-) diff --git a/netpyne/batchtools/search.py b/netpyne/batchtools/search.py index 7db02905d..c108835f2 100644 --- a/netpyne/batchtools/search.py +++ b/netpyne/batchtools/search.py @@ -7,50 +7,172 @@ from ray.tune.search import create_searcher, ConcurrencyLimiter, SEARCH_ALG_IMPORT from netpyne.batchtools import runtk from collections import namedtuple -from pubtk.raytk.search import ray_trial -import numpy -""" -from netpyne.batchtools import search, paramtypes +from pubtk.raytk.search import ray_trial, LABEL_POINTER +from pubtk.utils import get_path import numpy -https://docs.ray.io/en/latest/tune/api/doc/ray.tune.search.Searcher.html#ray.tune.search.Searcher +def ray_optuna_search(dispatcher_constructor, submit_constructor, label = 'optuna_search', + params = None, output_path = '../batch', checkpoint_path = '../ray', + batch_config = None, max_concurrent = 1, batch = True, num_samples = 1, + metric = "loss", mode = "min", optuna_config = None): + """ + ray_optuna_search(dispatcher_constructor, submit_constructor, label, + params, output_path, checkpoint_path, + batch_config, max_concurrent, batch, num_samples, + metric, mode, optuna_config) + Parameters + ---------- + dispatcher_constructor + submit_constructor + label + params + output_path + checkpoint_path + batch_config + max_concurrent + batch + num_samples + metric + mode + optuna_config + Returns + ------- + """ + from ray.tune.search.optuna import OptunaSearch -params = {'synMechTau2': [3.0, 5.0, 7.0], # assumes list of values by default if grid search-like algo - #'synMechTau2': [3.0, 7.0], # assumes lower/upper bounds by default if evol-like algo - 'connWeight' : paramtypes.sample_from(lambda _: numpy.random.uniform(0.005, 0.15))} # can optionally pass any of the paramtypes (= ray.tune data types) + ray.init(runtime_env={"working_dir": "."})# TODO needed for python import statements ? + if optuna_config == None: + optuna_config = {} -batch_config = {'sge': 5, 'command': 'python init.py'} + storage_path = get_path(checkpoint_path) + algo = ConcurrencyLimiter(searcher=OptunaSearch(metric=metric, mode=mode, **optuna_config), + max_concurrent=max_concurrent, + batch=batch) #TODO does max_concurrent and batch work? + + submit = submit_constructor() + submit.update_templates( + **batch_config + ) + project_path = os.getcwd() + + def run(config): + config.update({'saveFolder': output_path, 'simLabel': LABEL_POINTER}) + data = ray_trial(config, label, dispatcher_constructor, project_path, output_path, submit) + if isinstance(metric, str):#TODO only Optuna supports multiobjective? + metrics = {'config': config, 'data': data, metric: data[metric]} + session.report(metrics) + elif isinstance(metric, (list, tuple)): + metrics = {k: data[k] for k in metric} + metrics['config'] = config + metrics['data'] = data + session.report(metrics) + else: + raise ValueError("metric must be a string or a list/tuple of strings") + tuner = tune.Tuner( + run, + tune_config=tune.TuneConfig( + search_alg=algo, + num_samples=num_samples, + ), + run_config=RunConfig( + storage_path=storage_path, + name=label, + ), + param_space=params, + ) + + results = tuner.fit() + resultsdf = results.get_dataframe() + resultsdf.to_csv("{}.csv".format(label)) + return namedtuple('Study', ['algo', 'results'])(algo, results) -#TODO rename ray_search to search -search(dispatcher = 'inet', # defaults to 'inet' if no arg is passed? - submit = 'socket', # defaults to 'socket' if no arg is passed? - params = params, - batch_config = batch_config, # - algorithm = "variant_generator", - concurrency = 9, - output_path = '../batch_func', - checkpoint_path = '../grid_func', - label = 'func_search', - num_samples = 3) -SEE: -'variant_generator' -'random' -> points to variant_generator -'ax' -'dragonfly' -'skopt' -'hyperopt' -'bayesopt' -'bohb' -'nevergrad' -'optuna' -'zoopt' -'sigopt' -'hebo' -'blendsearch' -'cfo' """ +Parameters +: +space – +Hyperparameter search space definition for Optuna’s sampler. This can be either a dict with parameter names as keys and optuna.distributions as values, or a Callable - in which case, it should be a define-by-run function using optuna.trial to obtain the hyperparameter values. The function should return either a dict of constant values with names as keys, or None. For more information, see https://optuna.readthedocs.io/en/stable/tutorial/10_key_features/002_configurations.html. +Warning +No actual computation should take place in the define-by-run function. Instead, put the training logic inside the function or class trainable passed to tune.Tuner(). +metric – The training result objective value attribute. If None but a mode was passed, the anonymous metric _metric will be used per default. Can be a list of metrics for multi-objective optimization. +mode – One of {min, max}. Determines whether objective is minimizing or maximizing the metric attribute. Can be a list of modes for multi-objective optimization (corresponding to metric). +points_to_evaluate – Initial parameter suggestions to be run first. This is for when you already have some good parameters you want to run first to help the algorithm make better suggestions for future parameters. Needs to be a list of dicts containing the configurations. +sampler – +Optuna sampler used to draw hyperparameter configurations. Defaults to MOTPESampler for multi-objective optimization with Optuna<2.9.0, and TPESampler in every other case. See https://optuna.readthedocs.io/en/stable/reference/samplers/index.html for available Optuna samplers. +Warning +Please note that with Optuna 2.10.0 and earlier default MOTPESampler/TPESampler suffer from performance issues when dealing with a large number of completed trials (approx. >100). This will manifest as a delay when suggesting new configurations. This is an Optuna issue and may be fixed in a future Optuna release. +seed – Seed to initialize sampler with. This parameter is only used when sampler=None. In all other cases, the sampler you pass should be initialized with the seed already. +evaluated_rewards – +If you have previously evaluated the parameters passed in as points_to_evaluate you can avoid re-running those trials by passing in the reward attributes as a list so the optimiser can be told the results without needing to re-compute the trial. Must be the same length as points_to_evaluate. +""" + +def ray_search(dispatcher_constructor, submit_constructor, algorithm = "variant_generator", label = 'search', + params = None, output_path = '../batch', checkpoint_path = '../ray', + batch_config = None, num_samples = 1, metric = "loss", mode = "min", algorithm_config = None): + ray.init(runtime_env={"working_dir": "."}) # TODO needed for python import statements ? + + if algorithm_config == None: + algorithm_config = {} + + if 'metric' in algorithm_config: + metric = algorithm_config['metric'] + else: + metric = None + + if 'mode' in algorithm_config: + mode = algorithm_config['mode'] + else: + mode = None + #TODO class this object for self calls? cleaner? vs nested functions + #TODO clean up working_dir and excludes + storage_path = get_path(checkpoint_path) + algo = create_searcher(algorithm, **algorithm_config) #concurrency may not be accepted by all algo + #search_alg – The search algorithm to use. + # metric – The training result objective value attribute. Stopping procedures will use this attribute. + # mode – One of {min, max}. Determines whether objective is minimizing or maximizing the metric attribute. + # **kwargs – Additional parameters. These keyword arguments will be passed to the initialization function of the chosen class. + try: + algo = ConcurrencyLimiter(searcher=algo, max_concurrent=algorithm_config['max_concurrent'], batch=algorithm_config['batch']) + except: + pass + + submit = submit_constructor() + submit.update_templates( + **batch_config + ) + project_path = os.getcwd() + def run(config): + data = ray_trial(config, label, dispatcher_constructor, project_path, output_path, submit) + if isinstance(metric, str): + metrics = {'config': config, 'data': data, metric: data[metric]} + session.report(metrics) + elif isinstance(metric, (list, tuple)): + metrics = {k: data[k] for k in metric} + metrics['data'] = data + metrics['config'] = config + session.report(metrics) + else: + session.report({'data': data, 'config': config}) + + tuner = tune.Tuner( + run, + tune_config=tune.TuneConfig( + search_alg=algo, + num_samples=num_samples, # grid search samples 1 for each param + metric="data" + ), + run_config=RunConfig( + storage_path=storage_path, + name=algorithm, + ), + param_space=params, + ) + + results = tuner.fit() + resultsdf = results.get_dataframe() + resultsdf.to_csv("{}.csv".format(label)) + #should be constant? constructors = namedtuple('constructors', 'dispatcher, submit') @@ -87,7 +209,7 @@ def generate_parameters(param_dict, algo): ray_params = {} for param, space in param_dict.items(): lsp = len(space) == 2 - if isinstance(space, (list, tuple)) and algo in {'variant_generator'}: + if isinstance(space, (list, tuple, numpy.ndarray)) and algo in {'variant_generator'}: ray_params[param] = tune.grid_search(space) elif isinstance(space, (list, tuple)) and algo in SEARCH_ALG_IMPORT.keys(): if lsp: #if 2 sample from uniform lb, ub @@ -95,11 +217,14 @@ def generate_parameters(param_dict, algo): else: #otherwise treat as a list ray_params[param] = tune.choice(space) return ray_params + def search(job_type, params, batch_config, algorithm, concurrency, output_path, checkpoint_path, label, num_samples = 1, comm_type='socket'): #requires some shimming dispatcher_constructor, submit_constructor = generate_constructors(job_type, comm_type) params = generate_parameters(params, algorithm) ray_search(dispatcher_constructor, submit_constructor, algorithm, label, params, concurrency, output_path, checkpoint_path, batch_config, num_samples) + +""" def ray_search(dispatcher_constructor, submit_constructor, algorithm = "variant_generator", label = 'search', params = None, concurrency = 1, output_path = '../batch', checkpoint_path = '../ray', batch_config = None, num_samples = 1): @@ -116,34 +241,14 @@ def ray_search(dispatcher_constructor, submit_constructor, algorithm = "variant_ raise ValueError("checkpoint_dir must be an absolute path (starts with /) or relative to the current working directory (starts with .)") algo = create_searcher(algorithm, max_concurrent=concurrency, batch=True) #algo = ConcurrencyLimiter(searcher=algo, max_concurrent=concurrency, batch=True) - submit = submit_constructor() submit.update_templates( **batch_config ) project_path = os.getcwd() def run(config): + config.update({'saveFolder': output_path, 'simLabel': LABEL_POINTER}) data = ray_trial(config, label, dispatcher_constructor, project_path, output_path, submit) - tid = ray.train.get_context().get_trial_id() - tid = int(tid.split('_')[-1]) #integer value for the trial - run_label = '{}_{}'.format(label, tid) - dispatcher = dispatcher_constructor(project_path = project_path, output_path = output_path, submit = submit, - gid = run_label) - - dispatcher.update_env(dictionary = config) - dispatcher.update_env(dictionary = { - 'saveFolder': output_path, - 'simLabel': run_label, - }) - try: - dispatcher.run() - dispatcher.accept() - data = dispatcher.recv() - dispatcher.clean() - except Exception as e: - dispatcher.clean() - raise(e) - data = pandas.read_json(data, typ='series', dtype=float) session.report({'data': data, 'config': config}) tuner = tune.Tuner( @@ -163,3 +268,59 @@ def run(config): results = tuner.fit() resultsdf = results.get_dataframe() resultsdf.to_csv("{}.csv".format(label)) +""" + + + + +""" +from netpyne.batchtools import search, paramtypes +import numpy + +https://docs.ray.io/en/latest/tune/api/doc/ray.tune.search.Searcher.html#ray.tune.search.Searcher + + + +params = {'synMechTau2': [3.0, 5.0, 7.0], # assumes list of values by default if grid search-like algo + #'synMechTau2': [3.0, 7.0], # assumes lower/upper bounds by default if evol-like algo + 'connWeight' : paramtypes.sample_from(lambda _: numpy.random.uniform(0.005, 0.15))} # can optionally pass any of the paramtypes (= ray.tune data types) + +batch_config = {'sge': 5, 'command': 'python init.py'} + +#TODO rename ray_search to search +search(dispatcher = 'inet', # defaults to 'inet' if no arg is passed? + submit = 'socket', # defaults to 'socket' if no arg is passed? + params = params, + batch_config = batch_config, # + algorithm = "variant_generator", + concurrency = 9, + output_path = '../batch_func', + checkpoint_path = '../grid_func', + label = 'func_search', + num_samples = 3) +SEE: +'variant_generator' +'random' -> points to variant_generator +'ax' +'dragonfly' +'skopt' +'hyperopt' +'bayesopt' +'bohb' +'nevergrad' +'optuna' +'zoopt' +'sigopt' +'hebo' +'blendsearch' +'cfo' +""" + + + + + + + + + From ccaa1d23c7dd0a34c89b5b933fd11f5b0b804f41 Mon Sep 17 00:00:00 2001 From: James Chen Date: Mon, 8 Apr 2024 17:08:00 -0400 Subject: [PATCH 10/42] update to comm.py, runners.py --- netpyne/batchtools/comm.py | 27 +++++++++++++++++++-------- netpyne/batchtools/runners.py | 11 +++++++---- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/netpyne/batchtools/comm.py b/netpyne/batchtools/comm.py index 78ab290ec..bf0d8c061 100644 --- a/netpyne/batchtools/comm.py +++ b/netpyne/batchtools/comm.py @@ -1,7 +1,8 @@ from netpyne.batchtools import specs -from pubtk.runtk.runners import create_runner +from pubtk.runtk.runners import get_class +from pubtk import runtk from neuron import h - +import warnings HOST = 0 # for the purposes of send and receive with mpi. class Comm(object): @@ -10,21 +11,31 @@ def __init__(self, runner = specs): h.nrnmpi_init() self.pc = h.ParallelContext() self.rank = self.pc.id() + self.connected = False def initialize(self): if self.is_host(): - self.runner.connect() + try: + self.runner.connect() + self.connected = True + except Exception as e: + print("Failed to connect to the Dispatch Server, failover to Local mode. See: {}".format(e)) + self.runner._set_inheritance('file') #TODO or could change the inheritance of the runner ... + self.runner.env[runtk.MSGOUT] = "{}/{}.out".format(self.runner.cfg.saveFolder, self.runner.cfg.simLabel) - def set_runner(self, runner_type='socket'): - self.runner = create_runner(runner_type) + def set_runner(self, runner_type): + self.runner = get_class(runner_type)() def is_host(self): return self.rank == HOST def send(self, data): if self.is_host(): - self.runner.send(data) + if self.connected: + self.runner.send(data) + else: + self.runner.write(data) - def recv(self): # to be implemented. need to broadcast value to all workers - if self.is_host(): + def recv(self): #TODO to be tested, broadcast to all workers? + if self.is_host() and self.connected: data = self.runner.recv() else: data = None diff --git a/netpyne/batchtools/runners.py b/netpyne/batchtools/runners.py index 46c0e8b66..6cfa0a03d 100644 --- a/netpyne/batchtools/runners.py +++ b/netpyne/batchtools/runners.py @@ -1,6 +1,7 @@ from pubtk.runtk.utils import convert, set_map, create_script from pubtk import runtk -from pubtk.runtk.runners import Runner, create_runner +from pubtk.runtk.runners import Runner, get_class +import os class NetpyneRunner(Runner): """ @@ -8,9 +9,8 @@ class NetpyneRunner(Runner): see class runner mappings <- """ - def __new__(cls, inherit='socket', **kwargs): - - _super = create_runner(inherit) + def __new__(cls, inherit=None, **kwargs): + _super = get_class(inherit) def __init__(self, netParams=None, cfg=None, **kwargs): """ @@ -43,6 +43,9 @@ def _set_inheritance(self, inherit): if inherit in runtk.RUNNERS: cls = type(self) cls.__bases__ = (runtk.RUNNERS[inherit],) + else: + raise KeyError("inheritance {} not found in runtk.RUNNERS (please check runtk.RUNNERS for valid strings...".format(inherit)) + def get_NetParams(self): """ From 0b34c0ff168fb5a0712f476a9d42a7b4d3e394c0 Mon Sep 17 00:00:00 2001 From: James Chen Date: Tue, 16 Apr 2024 19:34:40 -0400 Subject: [PATCH 11/42] update to search (kwargs) --- netpyne/batchtools/search.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/netpyne/batchtools/search.py b/netpyne/batchtools/search.py index c108835f2..d1ca764a1 100644 --- a/netpyne/batchtools/search.py +++ b/netpyne/batchtools/search.py @@ -107,7 +107,8 @@ def run(config): If you have previously evaluated the parameters passed in as points_to_evaluate you can avoid re-running those trials by passing in the reward attributes as a list so the optimiser can be told the results without needing to re-compute the trial. Must be the same length as points_to_evaluate. """ -def ray_search(dispatcher_constructor, submit_constructor, algorithm = "variant_generator", label = 'search', +def ray_search(dispatcher_constructor, submit_constructor, algorithm = "variant_generator", + max_concurrent = 1, label = 'search', batch = True, params = None, output_path = '../batch', checkpoint_path = '../ray', batch_config = None, num_samples = 1, metric = "loss", mode = "min", algorithm_config = None): ray.init(runtime_env={"working_dir": "."}) # TODO needed for python import statements ? @@ -115,15 +116,18 @@ def ray_search(dispatcher_constructor, submit_constructor, algorithm = "variant_ if algorithm_config == None: algorithm_config = {} - if 'metric' in algorithm_config: - metric = algorithm_config['metric'] - else: - metric = None + if 'metric' not in algorithm_config: + algorithm_config['metric'] = metric + + if 'mode' not in algorithm_config: + algorithm_config['mode'] = mode + + if 'max_concurrent' not in algorithm_config: + algorithm_config['max_concurrent'] = max_concurrent + + if 'batch' not in algorithm_config: + algorithm_config['batch'] = batch - if 'mode' in algorithm_config: - mode = algorithm_config['mode'] - else: - mode = None #TODO class this object for self calls? cleaner? vs nested functions #TODO clean up working_dir and excludes storage_path = get_path(checkpoint_path) From fbc323e9554c7894e798e3af8a46f50a327dd46b Mon Sep 17 00:00:00 2001 From: James Chen Date: Thu, 18 Apr 2024 17:30:19 -0400 Subject: [PATCH 12/42] config update (should delete two keys @ end?) --- netpyne/batchtools/search.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/netpyne/batchtools/search.py b/netpyne/batchtools/search.py index d1ca764a1..5372ac340 100644 --- a/netpyne/batchtools/search.py +++ b/netpyne/batchtools/search.py @@ -147,6 +147,7 @@ def ray_search(dispatcher_constructor, submit_constructor, algorithm = "variant_ ) project_path = os.getcwd() def run(config): + config.update({'saveFolder': output_path, 'simLabel': LABEL_POINTER}) data = ray_trial(config, label, dispatcher_constructor, project_path, output_path, submit) if isinstance(metric, str): metrics = {'config': config, 'data': data, metric: data[metric]} @@ -164,7 +165,8 @@ def run(config): tune_config=tune.TuneConfig( search_alg=algo, num_samples=num_samples, # grid search samples 1 for each param - metric="data" + metric=algorithm_config['metric'], + mode=algorithm_config['mode'], ), run_config=RunConfig( storage_path=storage_path, From 9622aa2bdc8a54d0ffa08e041e902cc5fb57cc2a Mon Sep 17 00:00:00 2001 From: James Chen Date: Wed, 24 Apr 2024 21:32:33 -0400 Subject: [PATCH 13/42] replace pubtk with batchtk for compatibility with pip --- netpyne/batchtools/__init__.py | 2 +- netpyne/batchtools/comm.py | 4 ++-- netpyne/batchtools/runners.py | 6 +++--- netpyne/batchtools/search.py | 4 ++-- netpyne/batchtools/submits.py | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/netpyne/batchtools/__init__.py b/netpyne/batchtools/__init__.py index 9021018a2..e5a491044 100644 --- a/netpyne/batchtools/__init__.py +++ b/netpyne/batchtools/__init__.py @@ -1,5 +1,5 @@ from netpyne.batchtools.runners import NetpyneRunner -from pubtk import runtk +from batchtk import runtk specs = NetpyneRunner() diff --git a/netpyne/batchtools/comm.py b/netpyne/batchtools/comm.py index bf0d8c061..1a8a12763 100644 --- a/netpyne/batchtools/comm.py +++ b/netpyne/batchtools/comm.py @@ -1,6 +1,6 @@ from netpyne.batchtools import specs -from pubtk.runtk.runners import get_class -from pubtk import runtk +from batchtk.runtk.runners import get_class +from batchtk import runtk from neuron import h import warnings HOST = 0 # for the purposes of send and receive with mpi. diff --git a/netpyne/batchtools/runners.py b/netpyne/batchtools/runners.py index 6cfa0a03d..e816af538 100644 --- a/netpyne/batchtools/runners.py +++ b/netpyne/batchtools/runners.py @@ -1,6 +1,6 @@ -from pubtk.runtk.utils import convert, set_map, create_script -from pubtk import runtk -from pubtk.runtk.runners import Runner, get_class +from batchtk.runtk.utils import convert, set_map, create_script +from batchtk import runtk +from batchtk.runtk.runners import Runner, get_class import os class NetpyneRunner(Runner): diff --git a/netpyne/batchtools/search.py b/netpyne/batchtools/search.py index 5372ac340..c303db4b9 100644 --- a/netpyne/batchtools/search.py +++ b/netpyne/batchtools/search.py @@ -7,8 +7,8 @@ from ray.tune.search import create_searcher, ConcurrencyLimiter, SEARCH_ALG_IMPORT from netpyne.batchtools import runtk from collections import namedtuple -from pubtk.raytk.search import ray_trial, LABEL_POINTER -from pubtk.utils import get_path +from batchtk.raytk.search import ray_trial, LABEL_POINTER +from batchtk.utils import get_path import numpy diff --git a/netpyne/batchtools/submits.py b/netpyne/batchtools/submits.py index 4a9ec3d5f..2f42ecb76 100644 --- a/netpyne/batchtools/submits.py +++ b/netpyne/batchtools/submits.py @@ -1,5 +1,5 @@ -from pubtk.runtk import Submit, Template -from pubtk import runtk +from batchtk.runtk import Submit, Template +from batchtk import runtk SFS_HANDLES = {runtk.SUBMIT: '{output_path}/{label}.sh', runtk.STDOUT: '{output_path}/{label}.run', From c5ffb3dffff66b3ef47df6dd4f09c5c6dca1ac80 Mon Sep 17 00:00:00 2001 From: James Chen Date: Wed, 24 Apr 2024 23:19:23 -0400 Subject: [PATCH 14/42] update the submit (zsh->sh) --- netpyne/batchtools/submits.py | 95 +++-------------------------------- 1 file changed, 7 insertions(+), 88 deletions(-) diff --git a/netpyne/batchtools/submits.py b/netpyne/batchtools/submits.py index 2f42ecb76..3f2d1cf3b 100644 --- a/netpyne/batchtools/submits.py +++ b/netpyne/batchtools/submits.py @@ -5,11 +5,11 @@ runtk.STDOUT: '{output_path}/{label}.run', runtk.MSGOUT: '{output_path}/{label}.out', runtk.SGLOUT: '{output_path}/{label}.sgl'} -class ZSHSubmit(Submit): +class SHSubmit(Submit): script_args = {'label', 'project_path', 'output_path', 'env', 'command'} script_template = \ """\ -#!/bin/zsh +#!/bin/sh cd {project_path} export JOBID=$$ {env} @@ -22,7 +22,7 @@ class ZSHSubmit(Submit): runtk.SUBMIT: '{output_path}/{label}.sh'} def __init__(self, **kwargs): super().__init__( - submit_template = Template(template="zsh {output_path}/{label}.sh", + submit_template = Template(template="sh {output_path}/{label}.sh", key_args={'project_path', 'output_path', 'label'}), script_template = Template(template=self.script_template, key_args=self.script_args), @@ -41,11 +41,11 @@ def submit_job(self): raise(Exception("Job submission failed:\n{}\n{}\n{}\n{}".format(self.submit, self.script, proc.stdout, proc.stderr))) return self.job_id -class ZSHSubmitSFS(ZSHSubmit): +class SHSubmitSFS(SHSubmit): script_args = {'label', 'project_path', 'output_path', 'env', 'command'} script_template = \ """\ -#!/bin/zsh +#!/bin/sh cd {project_path} export OUTFILE="{output_path}/{label}.out" export SGLFILE="{output_path}/{label}.sgl" @@ -60,11 +60,11 @@ class ZSHSubmitSFS(ZSHSubmit): runtk.MSGOUT: '{output_path}/{label}.out', runtk.SGLOUT: '{output_path}/{label}.sgl'} -class ZSHSubmitSOCK(ZSHSubmit): +class SHSubmitSOCK(SHSubmit): script_args = {'label', 'project_path', 'output_path', 'env', 'command', 'sockname'} script_template = \ """\ -#!/bin/zsh +#!/bin/sh cd {project_path} export SOCNAME="{sockname}" export JOBID=$$ @@ -158,84 +158,3 @@ class SGESubmitSOCK(SGESubmit): runtk.SOCKET: '{sockname}' } - -class SGESubmit(Submit): - script_args = {'label', 'project_path', 'output_path', 'env', 'command', 'cores', 'vmem', } - script_template = \ - """\ -#!/bin/bash -#$ -N job{label} -#$ -pe smp {cores} -#$ -l h_vmem={vmem} -#$ -o {output_path}/{label}.run -cd {project_path} -source ~/.bashrc -export JOBID=$JOB_ID -{env} -{command} -""" - script_handles = {runtk.SUBMIT: '{output_path}/{label}.sh', - runtk.STDOUT: '{output_path}/{label}.run'} - def __init__(self, **kwargs): - super().__init__( - submit_template = Template(template="qsub {output_path}/{label}.sh", - key_args={'output_path', 'label'}), - script_template = Template(template=self.script_template, - key_args=self.script_args), - handles = self.script_handles, - ) - - def submit_job(self, **kwargs): - proc = super().submit_job() - try: - self.job_id = proc.stdout.split(' ')[2] - except Exception as e: #not quite sure how this would occur - raise(Exception("{}\nJob submission failed:\n{}\n{}\n{}\n{}".format(e, self.submit, self.script, proc.stdout, proc.stderr))) - return self.job_id - - def set_handles(self): - pass - -class SGESubmitSFS(SGESubmit): - script_args = {'label', 'project_path', 'output_path', 'env', 'command', 'cores', 'vmem', } - script_template = \ - """\ -#!/bin/bash -#$ -N job{label} -#$ -pe smp {cores} -#$ -l h_vmem={vmem} -#$ -o {output_path}/{label}.run -cd {project_path} -source ~/.bashrc -export OUTFILE="{output_path}/{label}.out" -export SGLFILE="{output_path}/{label}.sgl" -export JOBID=$JOB_ID -{env} -{command} -""" - script_handles = {runtk.SUBMIT: '{output_path}/{label}.sh', - runtk.STDOUT: '{output_path}/{label}.run', - runtk.MSGOUT: '{output_path}/{label}.out', - runtk.SGLOUT: '{output_path}/{label}.sgl', - } - -class SGESubmitSOCK(SGESubmit): - script_args = {'label', 'project_path', 'output_path', 'env', 'command', 'cores', 'vmem', 'sockname'} - script_template = \ - """\ -#!/bin/bash -#$ -N job{label} -#$ -pe smp {cores} -#$ -l h_vmem={vmem} -#$ -o {output_path}/{label}.run -cd {project_path} -source ~/.bashrc -export SOCNAME="{sockname}" -export JOBID=$JOB_ID -{env} -{command} -""" - script_handles = {runtk.SUBMIT: '{output_path}/{label}.sh', - runtk.STDOUT: '{output_path}/{label}.run', - runtk.SOCKET: '{sockname}' - } \ No newline at end of file From 62fbc30a85bbc6c62f52ff692a0a368800b8a4eb Mon Sep 17 00:00:00 2001 From: jchen_lethe Date: Sun, 28 Apr 2024 18:54:22 -0400 Subject: [PATCH 15/42] update batchtools, submits --- netpyne/batchtools/__init__.py | 1 + netpyne/batchtools/submits.py | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/netpyne/batchtools/__init__.py b/netpyne/batchtools/__init__.py index e5a491044..dd7c370b8 100644 --- a/netpyne/batchtools/__init__.py +++ b/netpyne/batchtools/__init__.py @@ -1,4 +1,5 @@ from netpyne.batchtools.runners import NetpyneRunner +from batchtk.runtk import dispatchers from batchtk import runtk specs = NetpyneRunner() diff --git a/netpyne/batchtools/submits.py b/netpyne/batchtools/submits.py index 3f2d1cf3b..af515643a 100644 --- a/netpyne/batchtools/submits.py +++ b/netpyne/batchtools/submits.py @@ -114,12 +114,28 @@ def submit_job(self, **kwargs): def set_handles(self): pass + +""" +#!/bin/bash +#$ -cwd +#$ -N tauWeight_0_1 +#$ -q cpu.q +#$ -pe smp 4 +#$ -l h_vmem=32G +#$ -l h_rt=00:30:00 +#$ -o /ddn/jchen/dev/mpitest/tut8_data/tauWeight_0_1.run +#$ -e /ddn/jchen/dev/mpitest/tut8_data/tauWeight_0_1.err +tree +source ~/.bashrc +mpiexec -n 4 nrniv -python -mpi init.py simConfig=tut8_data/tauWeight_0_1_cfg.json netParams=tut8_data/tauWeight_netParams.py +""" class SGESubmitSFS(SGESubmit): script_args = {'label', 'project_path', 'output_path', 'env', 'command', 'cores', 'vmem', } script_template = \ """\ #!/bin/bash #$ -N job{label} +#$ -q cpu.q #$ -pe smp {cores} #$ -l h_vmem={vmem} #$ -o {output_path}/{label}.run From 62735019b80af0a10edd162900f791a7d9220aa8 Mon Sep 17 00:00:00 2001 From: jchen_lethe Date: Tue, 30 Apr 2024 15:37:22 -0400 Subject: [PATCH 16/42] fixed socket functionality for submits.py --- netpyne/batchtools/submits.py | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/netpyne/batchtools/submits.py b/netpyne/batchtools/submits.py index af515643a..1d27a41cc 100644 --- a/netpyne/batchtools/submits.py +++ b/netpyne/batchtools/submits.py @@ -83,8 +83,10 @@ class SGESubmit(Submit): """\ #!/bin/bash #$ -N job{label} +#$ -q {queue} #$ -pe smp {cores} #$ -l h_vmem={vmem} +#$ -l h_rt={realtime} #$ -o {output_path}/{label}.run cd {project_path} source ~/.bashrc @@ -115,35 +117,22 @@ def set_handles(self): pass -""" -#!/bin/bash -#$ -cwd -#$ -N tauWeight_0_1 -#$ -q cpu.q -#$ -pe smp 4 -#$ -l h_vmem=32G -#$ -l h_rt=00:30:00 -#$ -o /ddn/jchen/dev/mpitest/tut8_data/tauWeight_0_1.run -#$ -e /ddn/jchen/dev/mpitest/tut8_data/tauWeight_0_1.err -tree -source ~/.bashrc -mpiexec -n 4 nrniv -python -mpi init.py simConfig=tut8_data/tauWeight_0_1_cfg.json netParams=tut8_data/tauWeight_netParams.py -""" class SGESubmitSFS(SGESubmit): script_args = {'label', 'project_path', 'output_path', 'env', 'command', 'cores', 'vmem', } script_template = \ """\ #!/bin/bash #$ -N job{label} -#$ -q cpu.q +#$ -q {queue} #$ -pe smp {cores} #$ -l h_vmem={vmem} +#$ -l h_rt={realtime} #$ -o {output_path}/{label}.run cd {project_path} source ~/.bashrc +export JOBID=$JOB_ID export OUTFILE="{output_path}/{label}.out" export SGLFILE="{output_path}/{label}.sgl" -export JOBID=$JOB_ID {env} {command} """ @@ -159,13 +148,15 @@ class SGESubmitSOCK(SGESubmit): """\ #!/bin/bash #$ -N job{label} +#$ -q {queue} #$ -pe smp {cores} #$ -l h_vmem={vmem} +#$ -l h_rt={realtime} #$ -o {output_path}/{label}.run cd {project_path} source ~/.bashrc -export SOCNAME="{sockname}" export JOBID=$JOB_ID +export SOCNAME="{sockname}" {env} {command} """ From 0626add16df064aeb065040fbf5dfc37d9175a7c Mon Sep 17 00:00:00 2001 From: James Chen Date: Tue, 7 May 2024 14:11:03 -0400 Subject: [PATCH 17/42] batchtools documentation --- netpyne/batchtools/__init__.py | 1 + netpyne/batchtools/docs/batchtools.ipynb | 314 +++++++++++++++++ netpyne/batchtools/docs/batchtools.rst | 206 +++++++++++ netpyne/batchtools/examples/CA3/cfg.py | 45 +++ .../batchtools/examples/CA3/grid_search.py | 39 +++ netpyne/batchtools/examples/CA3/init.py | 32 ++ netpyne/batchtools/examples/CA3/mod/CA1ih.mod | 64 ++++ .../batchtools/examples/CA3/mod/CA1ika.mod | 85 +++++ .../batchtools/examples/CA3/mod/CA1ikdr.mod | 60 ++++ .../batchtools/examples/CA3/mod/CA1ina.mod | 89 +++++ .../examples/CA3/mod/MyExp2SynBB.mod | 67 ++++ .../examples/CA3/mod/MyExp2SynNMDABB.mod | 108 ++++++ .../batchtools/examples/CA3/mod/aux_fun.inc | 43 +++ .../batchtools/examples/CA3/mod/caolmw.mod | 47 +++ .../batchtools/examples/CA3/mod/icaolmw.mod | 51 +++ .../batchtools/examples/CA3/mod/iholmw.mod | 60 ++++ .../batchtools/examples/CA3/mod/kcaolmw.mod | 52 +++ .../batchtools/examples/CA3/mod/kdrbwb.mod | 76 +++++ .../batchtools/examples/CA3/mod/nafbwb.mod | 81 +++++ netpyne/batchtools/examples/CA3/netParams.py | 321 ++++++++++++++++++ .../batchtools/examples/CA3/optuna_search.py | 38 +++ netpyne/batchtools/runners.py | 3 +- netpyne/batchtools/search.py | 194 ++++++++--- 23 files changed, 2027 insertions(+), 49 deletions(-) create mode 100644 netpyne/batchtools/docs/batchtools.ipynb create mode 100644 netpyne/batchtools/docs/batchtools.rst create mode 100644 netpyne/batchtools/examples/CA3/cfg.py create mode 100644 netpyne/batchtools/examples/CA3/grid_search.py create mode 100644 netpyne/batchtools/examples/CA3/init.py create mode 100644 netpyne/batchtools/examples/CA3/mod/CA1ih.mod create mode 100644 netpyne/batchtools/examples/CA3/mod/CA1ika.mod create mode 100644 netpyne/batchtools/examples/CA3/mod/CA1ikdr.mod create mode 100644 netpyne/batchtools/examples/CA3/mod/CA1ina.mod create mode 100644 netpyne/batchtools/examples/CA3/mod/MyExp2SynBB.mod create mode 100644 netpyne/batchtools/examples/CA3/mod/MyExp2SynNMDABB.mod create mode 100644 netpyne/batchtools/examples/CA3/mod/aux_fun.inc create mode 100644 netpyne/batchtools/examples/CA3/mod/caolmw.mod create mode 100644 netpyne/batchtools/examples/CA3/mod/icaolmw.mod create mode 100644 netpyne/batchtools/examples/CA3/mod/iholmw.mod create mode 100644 netpyne/batchtools/examples/CA3/mod/kcaolmw.mod create mode 100644 netpyne/batchtools/examples/CA3/mod/kdrbwb.mod create mode 100644 netpyne/batchtools/examples/CA3/mod/nafbwb.mod create mode 100644 netpyne/batchtools/examples/CA3/netParams.py create mode 100644 netpyne/batchtools/examples/CA3/optuna_search.py diff --git a/netpyne/batchtools/__init__.py b/netpyne/batchtools/__init__.py index dd7c370b8..c380458d2 100644 --- a/netpyne/batchtools/__init__.py +++ b/netpyne/batchtools/__init__.py @@ -8,6 +8,7 @@ comm = Comm() + #from ray import tune as space.comm #list and lb ub diff --git a/netpyne/batchtools/docs/batchtools.ipynb b/netpyne/batchtools/docs/batchtools.ipynb new file mode 100644 index 000000000..22fe3489f --- /dev/null +++ b/netpyne/batchtools/docs/batchtools.ipynb @@ -0,0 +1,314 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "Jupyter Tutorial: The NetPyNE batchtools subpackage\n", + "How to use the `specs` and `comm` to communicate with the `batchtools` `dispatcher`\n" + ], + "metadata": { + "collapsed": false + }, + "id": "89ec6ca2392a9a0d" + }, + { + "cell_type": "markdown", + "source": [ + "For each individual `sim`, communication with the `batchtools` `dispatcher` occurs through the `specs` and `comm` objects" + ], + "metadata": { + "collapsed": false + }, + "id": "be50f40d8e61a944" + }, + { + "cell_type": "code", + "outputs": [], + "source": [ + "from netpyne.batchtools import specs, comm" + ], + "metadata": { + "collapsed": false + }, + "id": "6f321aedb7faf945", + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "the `specs` object is an instantiation of a custom class extending the `batchtk` `Runner` ..." + ], + "metadata": { + "collapsed": false + }, + "id": "5f2f08f0b5e582c3" + }, + { + "cell_type": "code", + "outputs": [], + "source": [ + "help(type(specs))" + ], + "metadata": { + "collapsed": false + }, + "id": "29fa261236494bc3", + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "From this `specs` object, we can similarly call `specs.NetParams` and `specs.SimConfig` to create the NetPyNE objects..." + ], + "metadata": { + "collapsed": false + }, + "id": "64ead24451bbad4a" + }, + { + "cell_type": "code", + "outputs": [], + "source": [ + "help(specs.NetParams)\n", + "help(specs.SimConfig)" + ], + "metadata": { + "collapsed": false + }, + "id": "43d263d080800019", + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "The `batchtools` job submission tool uses `environmental variables` to pass values to our `config` object created by `specs.SimConfig`, these `environmental variables` are captured during the `specs` `object creation` which occurs during the batchtools `import` (from the `batchtools` `__init__.py`:\n", + "```\n", + "from netpyne.batchtools.runners import NetpyneRunner\n", + "specs = NetpyneRunner()\n", + "```" + ], + "metadata": { + "collapsed": false + }, + "id": "710cc6084bd7af02" + }, + { + "cell_type": "markdown", + "source": [ + "Let's `export` some `environmental variables` to pass values to our `config` object. When this is handled by the `batchtools` `subpackage`, this occurs automatically..." + ], + "metadata": { + "collapsed": false + }, + "id": "52704684f5e80f3c" + }, + { + "cell_type": "code", + "outputs": [], + "source": [ + "%env STRRUNTK0 =foo.bar=baz\n", + "%env FLOATRUNTK1 =float_val=7.7\n", + "from netpyne.batchtools import NetpyneRunner\n", + "specs = NetpyneRunner()" + ], + "metadata": { + "collapsed": false + }, + "id": "50de117ff7f43aa6", + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "One way of retrieving these values is by calling `specs.get_mappings()`" + ], + "metadata": { + "collapsed": false + }, + "id": "fac14e517044b980" + }, + { + "cell_type": "code", + "outputs": [], + "source": [ + "print(specs.get_mappings())" + ], + "metadata": { + "collapsed": false + }, + "id": "257fad390f4abce", + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Now, let's create our `config` object using the `specs.SimConfig()` constructor\n", + "This `config` object will hold a `dictionary` such that the initial values `foo['bar']` = `not_baz` and a `float_val` = `3.3`" + ], + "metadata": { + "collapsed": false + }, + "id": "92d41061bb828744" + }, + { + "cell_type": "code", + "outputs": [], + "source": [ + "cfg = specs.SimConfig()\n", + "cfg.foo = {'bar': 'not_baz', 'qux': 'quux'}\n", + "cfg.float_val = 3.3\n", + "print(\"cfg.foo['bar'] = {}\".format(cfg.foo['bar']))\n", + "print(\"cfg.float_val = {}\".format(cfg.float_val))" + ], + "metadata": { + "collapsed": false + }, + "id": "ca121d6ab30c3e7b", + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Finally, calling the `cfg.update_cfg()` method will overwrite the original values with our environment values, (`baz` and `7.7`)...\n", + "\n", + "in NetPyNE, this was originally handled with the:\n", + "```\n", + "try:\n", + " from __main__ import cfg\n", + "except:\n", + " from cfg import cfg\n", + "```\n", + "API idiom in the `netParams.py` file...\n", + " \n", + "as well as the \n", + "```\n", + "cfg, netParams = sim.readCmdLineArgs(simConfigDefault='src/cfg.py', netParamsDefault='src/netParams.py')\n", + "```\n", + "API idiom in the `init.py` file...\n", + "\n", + "using the `batchtools` subpackage, we can treat the `cfg` as an object and pass it between scripts via `import` statements...\n", + "in `netParams.py`...\n", + "```\n", + "from cfg import cfg\n", + "cfg.update()\n", + "```\n", + "in `init.py`...\n", + "```\n", + "from netParams import cfg, netParams\n", + "sim.createSimulateAnalyze(simConfig=cfg, netParams=netParams)\n", + "```" + ], + "metadata": { + "collapsed": false + }, + "id": "6ea43f729d0685d4" + }, + { + "cell_type": "code", + "outputs": [], + "source": [ + "print(\"prior to cfg.update()\")\n", + "print(\"cfg.foo['bar'] = {}\".format(cfg.foo['bar']))\n", + "print(\"cfg.float_val = {}\".format(cfg.float_val))\n", + "print()\n", + "cfg.update() # call update_cfg to update values in the cfg object with values assigned by batch\n", + "print(\"after the cfg.update()\")\n", + "print(\"cfg.foo['bar'] = {}\".format(cfg.foo['bar']))\n", + "print(\"cfg.float_val = {}\".format(cfg.float_val))" + ], + "metadata": { + "collapsed": false + }, + "id": "a9426b6e6594961", + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Finally, the `comm object` is used to report to the monitoring `dispatcher object`\n", + "the means of communication is dependent on which `dispatcher object` is instantiated, and communicated through environmental variables\n", + "in this case, since there is no `dispatcher object` the `comm` methods will simply perform `pass operations`" + ], + "metadata": { + "collapsed": false + }, + "id": "65bbb0ef2c76295a" + }, + { + "cell_type": "code", + "outputs": [], + "source": [ + "comm.initialize() # initializes comm object, establishing channel to communicate with the host dispatcher object" + ], + "metadata": { + "collapsed": false + }, + "id": "e9141d91d6e02aa3", + "execution_count": null + }, + { + "cell_type": "code", + "outputs": [], + "source": [ + "print(comm.is_host()) # returns a boolean IF the calling process is the 0th ranked parallelcontext, similar to sim.pc.rank == 0" + ], + "metadata": { + "collapsed": false + }, + "id": "5ed6a524bd8a3e0b", + "execution_count": null + }, + { + "cell_type": "code", + "outputs": [], + "source": [ + "comm.send('message') # sends 'message' to the `dispatcher object`" + ], + "metadata": { + "collapsed": false + }, + "id": "1966edbf32649352", + "execution_count": null + }, + { + "cell_type": "code", + "outputs": [], + "source": [ + "comm.close() #finalizes communication, closes any resources used to communicate with the `dispatcher object`" + ], + "metadata": { + "collapsed": false + }, + "id": "34f021af4127363c" + }, + { + "cell_type": "markdown", + "source": [], + "metadata": { + "collapsed": false + }, + "id": "648746fff96b8a72" + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/netpyne/batchtools/docs/batchtools.rst b/netpyne/batchtools/docs/batchtools.rst new file mode 100644 index 000000000..38bf6e7c9 --- /dev/null +++ b/netpyne/batchtools/docs/batchtools.rst @@ -0,0 +1,206 @@ +Running a Batch Job +=================== + +The NetPyNE batchtools subpackage provides a method of automating job submission and reporting:: + + + batch<-->\ /---> configuration_0 >---\ + \ / specs---\ + \<--->dispatcher_0 sim_0 + \ \ comm ---/ + \ \---< results_0 <---/ + \ + \ /---> configuration_1 >---\ + \ / specs---\ + \<--->dispatcher_1 sim_1 + \ \ comm ---/ + \ \---< results_1 <---/ + \ + \ + ... + + +1. Retrieving batch configuration values through the ``specs`` object +----- +Each simulation is able to retrieve relevant configurations through the ``specs`` object, and communicate with +the dispatcher through the ``comm`` object. + +importing the relevant objects:: + + from netpyne.batchtools import specs, comm + cfg = specs.SimConfig() # create a SimConfig object + netParams = specs.NetParams() # create a netParams object + +``netpyne.batchtools.specs`` behaves similarly to ``netpyne.sim.specs`` except in the following cases: + +* ``netpyne.batchtools.specs`` automatically captures relevant configuration mappings created by the ``dispatcher`` upon initialization + + * these mappings can be retrieved via ``specs.get_mappings()`` + +* the SimConfig object created by ``netpyne.batch.specs.SimConfig()`` will update itself with relevant configuration mappings through the ``update()`` method:: + + from netpyne.batchtools import specs # import the custom batch specs + cfg = specs.SimConfig() # create a SimConfig object + cfg.update() # update the cfg object with any relevant mappings for this particular batch job + +The ``update`` method will update the ``SimConfig`` object with the configuration mappings captured in ``specs`` (see: ``specs.get_mappings()``) + +This replaces the previous idiom for updating the SimConfig object with mappings from the batched job submission:: + + try: + from __main__ import cfg # import SimConfig object with params from parent module + except: + from cfg import cfg # if no simConfig in parent module, import directly from tut8_cfg module + + + +2. Communicating results to the ``dispatcher`` with the ``comm`` object +----- + +Prior batched simulations relied on ``.pkl`` files to communicate data. The ``netpyne.batch`` subpackage uses a specific ``comm`` object to send custom data back +The ``comm`` object determines the method of communication based on the batch job submission type. + +In terms of the simulation, the following functions are available to the user: + +* **comm.initialize()**: establishes a connection with the batch ``dispatcher`` for sending data + +* **comm.send()**: sends ```` to the batch ``dispatcher`` + +* **comm.close()**: closes and cleans up the connection with the batch ``dispatcher`` + +3. Specifying a batch job +----- +Batch job handling is implemented with methods from ``netpyne.batchtools.search`` + +**search**:: + + def search(job_type: str, # the submission engine to run a single simulation (e.g. 'sge', 'sh') + comm_type: str, # the method of communication between host dispatcher and the simulation (e.g. 'socket', 'filesystem') + run_config: Dict, # batch configuration, (keyword: string pairs to customize the submit template) + params: Dict, # search space (dictionary of parameter keys: tune search spaces) + algorithm: Optional[str] = "variant_generator", # search algorithm to use, see SEARCH_ALG_IMPORT for available options + label: Optional[str] = 'search', # label for the search + output_path: Optional[str] = '../batch', # directory for storing generated files + checkpoint_path: Optional[str] = '../ray', # directory for storing checkpoint files + max_concurrent: Optional[int] = 1, # number of concurrent trials to run at one time + batch: Optional[bool] = True, # whether concurrent trials should run synchronously or asynchronously + num_samples: Optional[int] = 1, # number of trials to run + metric: Optional[str] = "loss", # metric to optimize (this should match some key: value pair in the returned data + mode: Optional[str] = "min", # either 'min' or 'max' (whether to minimize or maximize the metric + algorithm_config: Optional[dict] = None, # additional configuration for the search algorithm + ) -> tune.ResultGrid: # results of the search + +The basic search implemented with the ``search`` function uses ``ray.tune`` as the search algorithm backend, returning a ``tune.ResultGrid`` which can be used to evaluate the search space and results. It takes the following parameters; + +* **job_type**: either "``sge``" or "``sh``", specifying how the job should be submitted, "``sge``" will submit batch jobs through the Sun Grid Engine. "``sh``" will submit bach jobs through the shell on a local machine +* **comm_type**: either "``socket``" or "``filesystem``", specifying how the job should communicate with the dispatcher +* **run_config**: a dictionary of keyword: string pairs to customize the submit template, the expected keyword: string pairs are dependent on the job_type:: + + ======= + sge + ======= + queue: the queue to submit the job to (#$ -q {queue}) + cores: the number of cores to request for the job (#$ -pe smp {cores}) + vmem: the amount of memory to request for the job (#$ -l h_vmem={vmem}) + realtime: the amount of time to request for the job (#$ -l h_rt={realtime}) + command: the command to run for the job + + example: + run_config = { + 'queue': 'cpu.q', # request job to be run on the 'cpu.q' queue + 'cores': 8, # request 8 cores for the job + 'vmem': '8G', # request 8GB of memory for the job + 'realtime': '24:00:00', # set timeout of the job to 24 hours + 'command': 'mpiexec -n $NSLOTS -hosts $(hostname) nrniv -python -mpi init.py' + } # set the command to be run to 'mpiexec -n $NSLOTS -hosts $(hostname) nrniv -python -mpi init.py' + + ======= + sh + ======= + command: the command to run for the job + + example: + run_config = { + 'command': 'mpiexec -n 8 nrniv -python -mpi init.py' + } # set the command to be run + +* **params**: a dictionary of config values to perform the search over. The keys of the dictionary should match the keys of the config object to be updated. Lists or numpy generators >2 values will force a grid search over the values; otherwise, a list of two values will create a uniform distribution sample space. + + **usage 1**: updating a constant value specified in the ``SimConfig`` object :: + + # take a config object with the following parameter ``foo`` + cfg = specs.SimConfig() + cfg.foo = 0 + cfg.update() + + # specify a search space for ``foo`` such that a simulation will run with: + # cfg.foo = 0 + # cfg.foo = 1 + # cfg.foo = 2 + # ... + # cfg.foo = 9 + + # using: + params = { + 'foo': range(10) + } + + **usage 2**: updating a nested object in the ``SimConfig`` object:: + + # to update a nested object, the package uses the `.` operator to specify reflection into the object. + # take a config object with the following parameter object ``foo`` + cfg = specs.SimConfig() + cfg.foo = {'bar': 0, 'baz': 0} + cfg.update() + + # specify a search space for ``foo['bar']`` with `foo.bar` such that a simulation will run: + # cfg.foo['bar'] = 0 + # cfg.foo['bar'] = 1 + # cfg.foo['bar'] = 2 + # ... + # cfg.foo['bar'] = 9 + + # using: + params = { + 'foo.bar': range(10) + } + + # this reflection works with nested objects as well... + # i.e. + # cfg.foo = {'bar': {'baz': 0}} + # params = {'foo.bar.baz': range(10)} + +* **algorithm** : the search algorithm (supported within ``ray.tune``) + + **Supported algorithms**:: + + * "variant_generator": grid and random based search of the parameter space (see: https://docs.ray.io/en/latest/tune/api/suggestion.html) + * "random": grid and random based search of the parameter space (see: https://docs.ray.io/en/latest/tune/api/suggestion.html) + * "axe": optimization algorithm (see: https://docs.ray.io/en/latest/tune/api/suggestion.html) + * "bayesopt": optimization algorithm (see: https://docs.ray.io/en/latest/tune/api/suggestion.html) + * "hyperopt": optimization algorithm (see: https://docs.ray.io/en/latest/tune/api/suggestion.html) + * "bohb": optimization algorithm (see: https://docs.ray.io/en/latest/tune/api/suggestion.html) + * "nevergrad": optimization algorithm (see: https://docs.ray.io/en/latest/tune/api/suggestion.html) + * "optuna": optimization algorithm (see: https://docs.ray.io/en/latest/tune/api/suggestion.html) + * "hebo": optimization algorithm (see: https://docs.ray.io/en/latest/tune/api/suggestion.html) + * "sigopt": optimization algorithm (see: https://docs.ray.io/en/latest/tune/api/suggestion.html) + * "zoopt": optimization algorithm (see: https://docs.ray.io/en/latest/tune/api/suggestion.html) + +* **label**: a label for the search, used for output file naming + +* **output_path**: the directory for storing generated files, can be a relative or absolute path + +* **checkpoint_path**: the directory for storing checkpoint files in case the search needs to be restored, can be a relative or absolute path + +* **max_concurrent**: the number of concurrent trials to run at one time, it is recommended to keep in mind the resource usage of each trial to avoid overscheduling + +* **batch**: whether concurrent trials should run synchronously or asynchronously + +* **num_samples**: the number of trials to run, for any grid search, each value in the grid will be sampled ``num_samples`` times. + +* **metric**: the metric to optimize (this should match some key: value pair in the returned data) + +* **mode**: either 'min' or 'max' (whether to minimize or maximize the metric) + +* **algorithm_config**: additional configuration for the search algorithm (see: https://docs.ray.io/en/latest/tune/api/suggestion.html) + diff --git a/netpyne/batchtools/examples/CA3/cfg.py b/netpyne/batchtools/examples/CA3/cfg.py new file mode 100644 index 000000000..6041126a3 --- /dev/null +++ b/netpyne/batchtools/examples/CA3/cfg.py @@ -0,0 +1,45 @@ +from netpyne.batchtools import specs + +### config ### + +cfg = specs.SimConfig() + +cfg.duration = 1000 +cfg.dt = 0.1 +cfg.hparams = {'v_init': -65.0} +cfg.verbose = False +cfg.recordTraces = {} # don't save this +cfg.recordStim = False +cfg.recordStep = 0.1 # Step size in ms to save data (eg. V traces, LFP, etc) +cfg.filename = '00' # Set file output name +cfg.savePickle = False # Save params, network and sim output to pickle file +cfg.saveDat = False +cfg.saveJson = True +cfg.printRunTime = 0.1 +cfg.recordLFP = None # don't save this + +cfg.analysis['plotRaster'] = {'saveFig': True} # raster ok +cfg.analysis['plotTraces'] = { } # don't save this +cfg.analysis['plotLFPTimeSeries'] = { } # don't save this + +cfg.cache_efficient = True # better with MPI? +""" remove all of the unecessary data """ +cfg.saveCellSecs = False +cfg.saveCellConns = False + +cfg.nmda={#NMDA search space + "PYR->BC" : 1.38e-3, + "PYR->OLM": 0.7e-3, + "PYR->PYR": 0.004e-3, +} +cfg.ampa={#AMPA search space + "PYR->BC" : 0.36e-3, + "PYR->OLM": 0.36e-3, + "PYR->PYR": 0.02e-3, +} + +cfg.gaba = {#GABA search space + "BC->BC" : 4.5e-3, + "BC->PYR" : 0.72e-3, + "OLM->PYR": 72e-3, +} diff --git a/netpyne/batchtools/examples/CA3/grid_search.py b/netpyne/batchtools/examples/CA3/grid_search.py new file mode 100644 index 000000000..955652fa3 --- /dev/null +++ b/netpyne/batchtools/examples/CA3/grid_search.py @@ -0,0 +1,39 @@ +from netpyne.batchtools.search import search +import numpy + +params = {'nmda.PYR->BC' : numpy.linspace(1e-3, 1.8e-3, 3), + #'nmda.PYR->OLM': numpy.linspace(0.4e-3, 1.0e-3, 3), + #'nmda.PYR->PYR': numpy.linspace(0.001e-3, 0.007e-3, 3), + 'ampa.PYR->BC' : numpy.linspace(0.2e-3, 0.5e-3, 3), + #'ampa.PYR->OLM': numpy.linspace(0.2e-3, 0.5e-3, 3), + #'ampa.PYR->PYR': numpy.linspace(0.01e-3, 0.03e-3, 3), + #'gaba.BC->BC' : numpy.linspace(1e-3, 7e-3, 3), + 'gaba.BC->PYR' : numpy.linspace(0.4e-3, 1.0e-3, 3), + #'gaba.OLM->PYR': numpy.linspace(40e-3, 100e-3, 3), + } + +# use batch_shell_config if running directly on the machine +shell_config = {'command': 'mpiexec -np 4 nrniv -python -mpi init.py',} + +# use batch_sge_config if running on a +sge_config = { + 'queue': 'cpu.q', + 'cores': 5, + 'vmem': '4G', + 'realtime': '00:30:00', + 'command': 'mpiexec -n $NSLOTS -hosts $(hostname) nrniv -python -mpi init.py'} + +run_config = shell_config + +search(job_type = 'sh', + comm_type = 'socket', + label = 'search', + params = params, + output_path = '../batch', + checkpoint_path = '../ray', + run_config = run_config, + num_samples = 1, + metric = 'loss', + mode = 'min', + algorithm = "variant_generator", + max_concurrent = 4) diff --git a/netpyne/batchtools/examples/CA3/init.py b/netpyne/batchtools/examples/CA3/init.py new file mode 100644 index 000000000..f1921bab3 --- /dev/null +++ b/netpyne/batchtools/examples/CA3/init.py @@ -0,0 +1,32 @@ +from netpyne.batchtools import specs +from netpyne.batchtools import comm +from netpyne import sim +from netParams import netParams, cfg +import json + +comm.initialize() + +sim.createSimulate(netParams=netParams, simConfig=cfg) +print('completed simulation...') +#comm.pc.barrier() +#sim.gatherData() +if comm.is_host(): + netParams.save("{}/{}_params.json".format(cfg.saveFolder, cfg.simLabel)) + print('transmitting data...') + inputs = specs.get_mappings() + #print(json.dumps({**inputs})) + results = sim.analysis.popAvgRates(show=False) + + +#out_json = json.dumps({**inputs, **rates}) + + results['PYR_loss'] = (results['PYR'] - 3.33875)**2 + results['BC_loss'] = (results['BC'] - 19.725 )**2 + results['OLM_loss'] = (results['OLM'] - 3.470 )**2 + results['loss'] = (results['PYR_loss'] + results['BC_loss'] + results['OLM_loss']) / 3 + out_json = json.dumps({**inputs, **results}) + + print(out_json) +#TODO put all of this in a single function. + comm.send(out_json) + comm.close() diff --git a/netpyne/batchtools/examples/CA3/mod/CA1ih.mod b/netpyne/batchtools/examples/CA3/mod/CA1ih.mod new file mode 100644 index 000000000..93d435e30 --- /dev/null +++ b/netpyne/batchtools/examples/CA3/mod/CA1ih.mod @@ -0,0 +1,64 @@ +: $Id: CA1ih.mod,v 1.4 2010/12/13 21:35:47 samn Exp $ +TITLE Ih CA3 + +UNITS { + (mA) = (milliamp) + (mV) = (millivolt) +} + +NEURON { + SUFFIX hcurrent + NONSPECIFIC_CURRENT ih + RANGE g, e, v50, htau, hinf + RANGE gfactor +} + +PARAMETER { + celsius (degC) + g= 0.0001 (mho/cm2) + e= -30 (mV) + v50=-82 (mV) + gfactor = 1 +} + +STATE { + h +} + +ASSIGNED { + ih (mA/cm2) + hinf + htau (ms) + v (mV) +} + +PROCEDURE iassign () { ih=g*h*(v-e)*gfactor } + +BREAKPOINT { + SOLVE states METHOD cnexp + iassign() +} + +DERIVATIVE states { + rates(v) + h'= (hinf- h)/ htau +} + +INITIAL { + rates(v) + h = hinf + iassign() +} + +PROCEDURE rates(v (mV)) { + UNITSOFF + : HCN1 + :hinf = 1/(1+exp(0.151*(v-v50))) + :htau = exp((0.033*(v+75)))/(0.011*(1+exp(0.083*(v+75)))) + + : HCN2 + hinf = 1/(1+exp((v-v50)/10.5)) + htau = (1/(exp(-14.59-0.086*v)+exp(-1.87+0.0701*v))) + UNITSON +} + diff --git a/netpyne/batchtools/examples/CA3/mod/CA1ika.mod b/netpyne/batchtools/examples/CA3/mod/CA1ika.mod new file mode 100644 index 000000000..9e4fe6922 --- /dev/null +++ b/netpyne/batchtools/examples/CA3/mod/CA1ika.mod @@ -0,0 +1,85 @@ +: $Id: CA1ika.mod,v 1.2 2010/12/01 05:06:07 samn Exp $ +TITLE Ika CA1 + +UNITS { + (mA) = (milliamp) + (mV) = (millivolt) +} + +NEURON { + SUFFIX kacurrent + NONSPECIFIC_CURRENT ika, ikad + RANGE g, gd, e, ninf, ntau, ndinf, ndtau, linf, ltau +} + +PARAMETER { + celsius (degC) + g= 0.048 (mho/cm2) + gd= 0 (mho/cm2) + e= -90 (mV) +} + +STATE { + n + nd : distal + l +} + +ASSIGNED { + v (mV) + ika (mA/cm2) + ikad (mA/cm2) + ninf + ntau (ms) + ndinf + ndtau (ms) + linf + ltau (ms) +} + +PROCEDURE iassign () { + ika=g*n*l*(v-e) + ikad=gd*nd*l*(v-e) +} + +BREAKPOINT { + SOLVE states METHOD cnexp + iassign() +} + +DERIVATIVE states { + rates(v) + n'= (ninf- n)/ ntau + l'= (linf- l)/ ltau + nd'= (ndinf-nd)/ndtau +} + +INITIAL { + rates(v) + n = ninf + l = linf + iassign() +} + +PROCEDURE rates(v (mV)) { + LOCAL a, b + UNITSOFF + a = exp(-0.038*(1.5+1/(1+exp(v+40)/5))*(v-11)) + b = exp(-0.038*(0.825+1/(1+exp(v+40)/5))*(v-11)) + ntau=4*b/(1+a) + if (ntau<0.1) {ntau=0.1} + ninf=1/(1+a) + + a=exp(-0.038*(1.8+1/(1+exp(v+40)/5))*(v+1)) + b=exp(-0.038*(0.7+1/(1+exp(v+40)/5))*(v+1)) + ndtau=2*b/(1+a) + if (ndtau<0.1) {ndtau=0.1} + ndinf=1/(1+a) + + a = exp(0.11*(v+56)) + ltau=0.26*(v+50) + if (ltau<2) {ltau=2} + linf=1/(1+a) + UNITSON +} + diff --git a/netpyne/batchtools/examples/CA3/mod/CA1ikdr.mod b/netpyne/batchtools/examples/CA3/mod/CA1ikdr.mod new file mode 100644 index 000000000..4c5236362 --- /dev/null +++ b/netpyne/batchtools/examples/CA3/mod/CA1ikdr.mod @@ -0,0 +1,60 @@ +: $Id: CA1ikdr.mod,v 1.2 2010/12/01 05:10:52 samn Exp $ +TITLE IKDR CA1 + +UNITS { + (mA) = (milliamp) + (mV) = (millivolt) +} + +NEURON { + SUFFIX kdrcurrent + NONSPECIFIC_CURRENT ik + RANGE g, e, ninf, ntau +} + +PARAMETER { + celsius (degC) + g = 0.010 (mho/cm2) + e = -90 (mV) +} + +STATE { + n +} + +ASSIGNED { + v (mV) + ik (mA/cm2) + ninf + ntau (ms) +} + +PROCEDURE iassign () { ik=g*n*(v-e) } + +BREAKPOINT { + SOLVE states METHOD cnexp + iassign() +} + +DERIVATIVE states { + rates(v) + n'= (ninf- n)/ ntau +} + +INITIAL { + rates(v) + n = ninf + iassign() +} + +PROCEDURE rates(v (mV)) { + LOCAL a, b + UNITSOFF + a = exp(-0.11*(v-13)) + b = exp(-0.08*(v-13)) + ntau=50*b/(1+a) + if (ntau<2) {ntau=2} + ninf=1/(1+a) + UNITSON +} + diff --git a/netpyne/batchtools/examples/CA3/mod/CA1ina.mod b/netpyne/batchtools/examples/CA3/mod/CA1ina.mod new file mode 100644 index 000000000..d33ab9739 --- /dev/null +++ b/netpyne/batchtools/examples/CA3/mod/CA1ina.mod @@ -0,0 +1,89 @@ +: $Id: CA1ina.mod,v 1.4 2010/11/30 19:50:00 samn Exp $ +TITLE INa CA1 + +UNITS { + (mA) = (milliamp) + (mV) = (millivolt) +} + +NEURON { + SUFFIX nacurrent + NONSPECIFIC_CURRENT ina + RANGE g, e, vi, ki + RANGE minf,hinf,iinf,mtau,htau,itau : testing +} + +PARAMETER { + : v (mV) + celsius (degC) + g = 0.032 (mho/cm2) + e = 55 (mV) + vi = -60 (mV) + ki = 0.8 +} + +STATE { + m + h + I : i +} + +ASSIGNED { + i (mA/cm2) + ina (mA/cm2) + minf + mtau (ms) + hinf + htau (ms) + iinf + itau (ms) + v (mV) : testing +} + +: PROCEDURE iassign () { ina=g*m*m*m*h*i*(v-e) } +PROCEDURE iassign () { i=g*m*m*m*h*I*(v-e) ina=i} + +BREAKPOINT { + SOLVE states METHOD cnexp + iassign() +} + +DERIVATIVE states { + rates(v) + m' = (minf - m) / mtau + h' = (hinf - h) / htau + : i' = (iinf - i) / itau + I' = (iinf - I) / itau +} + +INITIAL { + rates(v) + h = hinf + m = minf + : i = iinf + I = iinf + iassign() : testing +} + + +PROCEDURE rates(v (mV)) { + LOCAL a, b + UNITSOFF + a = 0.4*(v+30)/(1-exp(-(v+30)/7.2)) + b = 0.124*(v+30)/(exp((v+30)/7.2)-1) + mtau=0.5/(a+b) + if (mtau<0.02) {mtau=0.02} + minf=a/(a+b) + a = 0.03*(v+45)/(1-exp(-(v+45)/1.5)) + b = 0.01*(v+45)/(exp((v+45)/1.5)-1) + htau=0.5/(a+b) + if (htau<0.5) {htau=0.5} + hinf=1/(1+exp((v+50)/4)) + a = exp(0.45*(v+66)) + b = exp(0.09*(v+66)) + itau=3000*b/(1+a) + if (itau<10) {itau=10} + iinf=(1+ki*exp((v-vi)/2))/(1+exp((v-vi)/2)) + UNITSON +} + diff --git a/netpyne/batchtools/examples/CA3/mod/MyExp2SynBB.mod b/netpyne/batchtools/examples/CA3/mod/MyExp2SynBB.mod new file mode 100644 index 000000000..9a68baef1 --- /dev/null +++ b/netpyne/batchtools/examples/CA3/mod/MyExp2SynBB.mod @@ -0,0 +1,67 @@ +: $Id: MyExp2SynBB.mod,v 1.4 2010/12/13 21:27:51 samn Exp $ +NEURON { +: THREADSAFE + POINT_PROCESS MyExp2SynBB + RANGE tau1, tau2, e, i, g, Vwt, gmax + NONSPECIFIC_CURRENT i +} + +UNITS { + (nA) = (nanoamp) + (mV) = (millivolt) + (uS) = (microsiemens) +} + +PARAMETER { + tau1=.1 (ms) <1e-9,1e9> + tau2 = 10 (ms) <1e-9,1e9> + e=0 (mV) + gmax = 1e9 (uS) + Vwt = 0 : weight for inputs coming in from vector +} + +ASSIGNED { + v (mV) + i (nA) + g (uS) + factor + etime (ms) +} + +STATE { + A (uS) + B (uS) +} + +INITIAL { + LOCAL tp + + Vwt = 0 : testing + + if (tau1/tau2 > .9999) { + tau1 = .9999*tau2 + } + A = 0 + B = 0 + tp = (tau1*tau2)/(tau2 - tau1) * log(tau2/tau1) + factor = -exp(-tp/tau1) + exp(-tp/tau2) + factor = 1/factor +} + +BREAKPOINT { + SOLVE state METHOD cnexp + g = B - A + if (g>gmax) {g=gmax}: saturation + i = g*(v - e) +} + +DERIVATIVE state { + A' = -A/tau1 + B' = -B/tau2 +} + +NET_RECEIVE(w (uS)) {LOCAL ww + ww=w + A = A + ww*factor + B = B + ww*factor +} diff --git a/netpyne/batchtools/examples/CA3/mod/MyExp2SynNMDABB.mod b/netpyne/batchtools/examples/CA3/mod/MyExp2SynNMDABB.mod new file mode 100644 index 000000000..01291643a --- /dev/null +++ b/netpyne/batchtools/examples/CA3/mod/MyExp2SynNMDABB.mod @@ -0,0 +1,108 @@ +: $Id: MyExp2SynNMDABB.mod,v 1.4 2010/12/13 21:28:02 samn Exp $ +NEURON { +: THREADSAFE + POINT_PROCESS MyExp2SynNMDABB + RANGE tau1, tau2, e, i, iNMDA, s, sNMDA, r, tau1NMDA, tau2NMDA, Vwt, smax, sNMDAmax + NONSPECIFIC_CURRENT i, iNMDA +} + +UNITS { + (nA) = (nanoamp) + (mV) = (millivolt) + (uS) = (microsiemens) +} + +PARAMETER { + tau1 = 0.1 (ms) <1e-9,1e9> + tau2 = 10 (ms) <1e-9,1e9> + tau1NMDA = 15 (ms) + tau2NMDA = 150 (ms) + e = 0 (mV) + mg = 1 + r = 1 + smax = 1e9 (1) + sNMDAmax = 1e9 (1) + + Vwt = 0 : weight for inputs coming in from vector +} + +ASSIGNED { + v (mV) + i (nA) + iNMDA (nA) + s (1) + sNMDA (1) + mgblock (1) + factor (1) + factor2 (1) + + etime (ms) +} + +STATE { + A (1) + B (1) + A2 (1) + B2 (1) +} + +INITIAL { + + LOCAL tp + + Vwt = 0 : testing + + if (tau1/tau2 > .9999) { + tau1 = .9999*tau2 + } + A = 0 + B = 0 + tp = (tau1*tau2)/(tau2 - tau1) * log(tau2/tau1) + factor = -exp(-tp/tau1) + exp(-tp/tau2) + factor = 1/factor + + if (tau1NMDA/tau2NMDA > .9999) { + tau1NMDA = .9999*tau2NMDA + } + A2 = 0 + B2 = 0 + tp = (tau1NMDA*tau2NMDA)/(tau2NMDA - tau1NMDA) * log(tau2NMDA/tau1NMDA) + factor2 = -exp(-tp/tau1NMDA) + exp(-tp/tau2NMDA) + factor2 = 1/factor2 +} + +BREAKPOINT { + SOLVE state METHOD cnexp + : Jahr Stevens 1990 J. Neurosci + mgblock = 1.0 / (1.0 + 0.28 * exp(-0.062(/mV) * v) ) + s = B - A + sNMDA = B2 - A2 + if (s >smax) {s =smax }: saturation + if (sNMDA>sNMDAmax) {sNMDA=sNMDAmax}: saturation + i = s * (v - e) + iNMDA = sNMDA * (v - e) * mgblock +} + +DERIVATIVE state { + A' = -A/tau1 + B' = -B/tau2 + A2' = -A2/tau1NMDA + B2' = -B2/tau2NMDA +} + +NET_RECEIVE(w (uS)) {LOCAL ww + ww=w + :printf("NMDA Spike: %g\n", t) + if(r>=0){ : if r>=0, g = AMPA + NMDA*r + A = A + factor *ww + B = B + factor *ww + A2 = A2 + factor2*ww*r + B2 = B2 + factor2*ww*r + }else{ + if(r>-1000){ : if r>-1, g = NMDA*r + A2 = A2 - factor2*ww*r + B2 = B2 - factor2*ww*r + } + : if r<0 and r<>-1, g = 0 + } +} diff --git a/netpyne/batchtools/examples/CA3/mod/aux_fun.inc b/netpyne/batchtools/examples/CA3/mod/aux_fun.inc new file mode 100644 index 000000000..ccb579afb --- /dev/null +++ b/netpyne/batchtools/examples/CA3/mod/aux_fun.inc @@ -0,0 +1,43 @@ +: $Id: aux_fun.inc,v 1.1 2009/11/04 01:24:52 samn Exp $ +COMMENT + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +// +// NOTICE OF COPYRIGHT AND OWNERSHIP OF SOFTWARE +// +// Copyright 2007, The University Of Pennsylvania +// School of Engineering & Applied Science. +// All rights reserved. +// For research use only; commercial use prohibited. +// Distribution without permission of Maciej T. Lazarewicz not permitted. +// mlazarew@seas.upenn.edu +// +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +ENDCOMMENT + + + +:------------------------------------------------------------------- +FUNCTION fun1(v(mV),V0(mV),A(/ms),B(mV))(/ms) { + + fun1 = A*exp((v-V0)/B) +} + +FUNCTION fun2(v(mV),V0(mV),A(/ms),B(mV))(/ms) { + + fun2 = A/(exp((v-V0)/B)+1) +} + +FUNCTION fun3(v(mV),V0(mV),A(/ms),B(mV))(/ms) { + + if(fabs((v-V0)/B)<1e-6) { + :if(v==V0) { + fun3 = A*B/1(mV) * (1- 0.5 * (v-V0)/B) + } else { + fun3 = A/1(mV)*(v-V0)/(exp((v-V0)/B)-1) + } +} + +FUNCTION min(x,y) { if (x<=y){ min = x }else{ min = y } } +FUNCTION max(x,y) { if (x>=y){ max = x }else{ max = y } } diff --git a/netpyne/batchtools/examples/CA3/mod/caolmw.mod b/netpyne/batchtools/examples/CA3/mod/caolmw.mod new file mode 100644 index 000000000..3ea21a7ef --- /dev/null +++ b/netpyne/batchtools/examples/CA3/mod/caolmw.mod @@ -0,0 +1,47 @@ +: $Id: caolmw.mod,v 1.2 2010/11/30 16:40:09 samn Exp $ +COMMENT + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +// +// NOTICE OF COPYRIGHT AND OWNERSHIP OF SOFTWARE +// +// Copyright 2007, The University Of Pennsylvania +// School of Engineering & Applied Science. +// All rights reserved. +// For research use only; commercial use prohibited. +// Distribution without permission of Maciej T. Lazarewicz not permitted. +// mlazarew@seas.upenn.edu +// +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +ENDCOMMENT + +UNITS { + (mollar) = (1/liter) + (M) = (mollar) + (mM) = (millimollar) + (mA) = (milliamp) + (mV) = (millivolt) + (mS) = (millisiemens) +} + +NEURON { + SUFFIX Caolmw + USEION ca READ ica, cai WRITE cai + RANGE alpha, tau +} + +PARAMETER { + alpha = 0.002 (cm2-M/mA-ms) + tau = 80 (ms) +} + +ASSIGNED { ica (mA/cm2) } + +INITIAL { cai = 0 } + +STATE { cai (mM) } + +BREAKPOINT { SOLVE states METHOD cnexp } + +DERIVATIVE states { cai' = -(1000) * alpha * ica - cai/tau } diff --git a/netpyne/batchtools/examples/CA3/mod/icaolmw.mod b/netpyne/batchtools/examples/CA3/mod/icaolmw.mod new file mode 100644 index 000000000..51112d099 --- /dev/null +++ b/netpyne/batchtools/examples/CA3/mod/icaolmw.mod @@ -0,0 +1,51 @@ +: $Id: icaolmw.mod,v 1.2 2010/11/30 16:44:13 samn Exp $ +COMMENT + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +// +// NOTICE OF COPYRIGHT AND OWNERSHIP OF SOFTWARE +// +// Copyright 2007, The University Of Pennsylvania +// School of Engineering & Applied Science. +// All rights reserved. +// For research use only; commercial use prohibited. +// Distribution without permission of Maciej T. Lazarewicz not permitted. +// mlazarew@seas.upenn.edu +// +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +ENDCOMMENT + +UNITS { + (mA) = (milliamp) + (mV) = (millivolt) + (mS) = (millisiemens) +} + +NEURON { + SUFFIX ICaolmw + USEION ca WRITE ica + RANGE gca,eca +} + +PARAMETER { + gca = 1 (mS/cm2) + eca = 120 (mV) +} + +ASSIGNED { + ica (mA/cm2) + v (mV) +} + +PROCEDURE iassign () { ica = (1e-3) * gca * mcainf(v)^2 * (v-eca) } + +INITIAL { + iassign() +} + +BREAKPOINT { iassign() } + +FUNCTION mcainf(v(mV)) { mcainf = fun2(v, -20, 1, -9)*1(ms) } + +INCLUDE "aux_fun.inc" diff --git a/netpyne/batchtools/examples/CA3/mod/iholmw.mod b/netpyne/batchtools/examples/CA3/mod/iholmw.mod new file mode 100644 index 000000000..ccd919202 --- /dev/null +++ b/netpyne/batchtools/examples/CA3/mod/iholmw.mod @@ -0,0 +1,60 @@ +: $Id: iholmw.mod,v 1.2 2010/11/30 16:34:22 samn Exp $ +COMMENT + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +// +// NOTICE OF COPYRIGHT AND OWNERSHIP OF SOFTWARE +// +// Copyright 2007, The University Of Pennsylvania +// School of Engineering & Applied Science. +// All rights reserved. +// For research use only; commercial use prohibited. +// Distribution without permission of Maciej T. Lazarewicz not permitted. +// mlazarew@seas.upenn.edu +// +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +ENDCOMMENT + +UNITS { + (mA) = (milliamp) + (mV) = (millivolt) + (mS) = (millisiemens) +} + +NEURON { + SUFFIX Iholmw + NONSPECIFIC_CURRENT i + RANGE gh,eh +} + +PARAMETER { + gh = 0.15 (mS/cm2) + eh = -40 (mV) +} + +ASSIGNED { + v (mV) + i (mA/cm2) +} + +STATE { q } + +PROCEDURE iassign () { i = (1e-3) * gh * q * (v-eh) } + +INITIAL { + q = qinf(v) + iassign() +} + +BREAKPOINT { + SOLVE states METHOD cnexp + iassign() +} + +DERIVATIVE states { q' = (qinf(v)-q)/qtau(v) } + +FUNCTION qinf(v(mV)) { qinf = fun2(v, -80, 1, 10)*1(ms) } +FUNCTION qtau(v(mV))(ms) { qtau = 200(ms)/(exp((v+70(mV))/20(mV))+exp(-(v+70(mV))/20(mV))) + 5(ms) } + +INCLUDE "aux_fun.inc" diff --git a/netpyne/batchtools/examples/CA3/mod/kcaolmw.mod b/netpyne/batchtools/examples/CA3/mod/kcaolmw.mod new file mode 100644 index 000000000..b2368787e --- /dev/null +++ b/netpyne/batchtools/examples/CA3/mod/kcaolmw.mod @@ -0,0 +1,52 @@ +: $Id: kcaolmw.mod,v 1.2 2010/11/30 16:47:18 samn Exp $ +COMMENT + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +// +// NOTICE OF COPYRIGHT AND OWNERSHIP OF SOFTWARE +// +// Copyright 2007, The University Of Pennsylvania +// School of Engineering & Applied Science. +// All rights reserved. +// For research use only; commercial use prohibited. +// Distribution without permission of Maciej T. Lazarewicz not permitted. +// mlazarew@seas.upenn.edu +// +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +ENDCOMMENT + +UNITS { + (mA) = (milliamp) + (mV) = (millivolt) + (mS) = (millisiemens) + (mollar) = (1/liter) + (mM) = (millimollar) +} + +NEURON { + SUFFIX KCaolmw + USEION k WRITE ik + USEION ca READ cai + RANGE gkca,ek,kd +} + +PARAMETER { + gkca = 10 (mS/cm2) + ek = -90 (mV) + kd = 30 (mM) +} + +ASSIGNED { + cai (mM) + v (mV) + ik (mA/cm2) +} + +PROCEDURE iassign () { ik = (1e-3) * gkca * cai/(cai+kd) * (v-ek) } + +INITIAL { + iassign() +} + +BREAKPOINT { iassign() } diff --git a/netpyne/batchtools/examples/CA3/mod/kdrbwb.mod b/netpyne/batchtools/examples/CA3/mod/kdrbwb.mod new file mode 100644 index 000000000..fc52ae534 --- /dev/null +++ b/netpyne/batchtools/examples/CA3/mod/kdrbwb.mod @@ -0,0 +1,76 @@ +: $Id: kdrbwb.mod,v 1.4 2010/12/13 21:35:26 samn Exp $ +COMMENT + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +// +// NOTICE OF COPYRIGHT AND OWNERSHIP OF SOFTWARE +// +// Copyright 2007, The University Of Pennsylvania +// School of Engineering & Applied Science. +// All rights reserved. +// For research use only; commercial use prohibited. +// Distribution without permission of Maciej T. Lazarewicz not permitted. +// mlazarew@seas.upenn.edu +// +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +ENDCOMMENT + +UNITS { + (mA) = (milliamp) + (mV) = (millivolt) + (mS) = (millisiemens) +} + +NEURON { + SUFFIX Kdrbwb + USEION k WRITE ik + RANGE phin,gkdr,ek + RANGE taon,ninf +} + +PARAMETER { + gkdr = 9 (mS/cm2) + ek = -90 (mV) + phin = 5 +} + +ASSIGNED { + v (mV) + ik (mA/cm2) + celsius (degC) + ninf (1) + taon (ms) +} + +STATE { n } + +PROCEDURE iassign () { ik = (1e-3) * gkdr * n^4 * (v-ek) } + +INITIAL { + rates(v) + n = ninf + iassign() +} + +BREAKPOINT { + SOLVE states METHOD cnexp + iassign() +} + +DERIVATIVE states { + rates(v) + n' = (ninf-n)/taon +} + +PROCEDURE rates(v(mV)) { LOCAL an, bn, q10 + q10 = phin:^((celsius-27.0(degC))/10.0(degC)) + + an = fun3(v, -34, -0.01, -10) + bn = fun1(v, -44, 0.125, -80) + + ninf = an/(an+bn) + taon = 1./((an+bn)*q10) +} + +INCLUDE "aux_fun.inc" diff --git a/netpyne/batchtools/examples/CA3/mod/nafbwb.mod b/netpyne/batchtools/examples/CA3/mod/nafbwb.mod new file mode 100644 index 000000000..37281dc94 --- /dev/null +++ b/netpyne/batchtools/examples/CA3/mod/nafbwb.mod @@ -0,0 +1,81 @@ +: $Id: nafbwb.mod,v 1.4 2010/12/13 21:35:08 samn Exp $ +COMMENT + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +// +// NOTICE OF COPYRIGHT AND OWNERSHIP OF SOFTWARE +// +// Copyright 2007, The University Of Pennsylvania +// School of Engineering & Applied Science. +// All rights reserved. +// For research use only; commercial use prohibited. +// Distribution without permission of Maciej T. Lazarewicz not permitted. +// mlazarew@seas.upenn.edu +// +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +ENDCOMMENT + +UNITS { + (mA) = (milliamp) + (mV) = (millivolt) + (mS) = (millisiemens) +} + +NEURON { + SUFFIX Nafbwb + USEION na WRITE ina + RANGE phih + RANGE gna, ena, taoh : testing +} + +PARAMETER { + gna = 35 (mS/cm2) + ena = 55 (mV) + phih = 5 +} + +ASSIGNED { + v (mV) + ina (mA/cm2) + minf (1) + hinf (1) + taoh (ms) + celsius (degC) +} + +STATE { h } + +PROCEDURE iassign () { ina = (1e-3) * gna * minf^3 * h * (v-ena) } + +INITIAL { + rates(v) + h = hinf + iassign() +} + +BREAKPOINT { + SOLVE states METHOD cnexp + iassign() +} + +DERIVATIVE states { + rates(v) + h' = (hinf-h)/taoh +} + +PROCEDURE rates(v(mV)) { LOCAL am, bm, ah, bh, q10 + + q10 = phih:^((celsius-27.0(degC))/10.0(degC)) + + am = fun3(v, -35, -0.1, -10) + bm = fun1(v, -60, 4, -18) + minf = am/(am+bm) + + ah = fun1(v, -58, 0.07, -20) + bh = fun2(v, -28, 1, -10) + hinf = ah/(ah+bh) + taoh = 1./((ah+bh)*q10) +} + +INCLUDE "aux_fun.inc" diff --git a/netpyne/batchtools/examples/CA3/netParams.py b/netpyne/batchtools/examples/CA3/netParams.py new file mode 100644 index 000000000..156e9ff20 --- /dev/null +++ b/netpyne/batchtools/examples/CA3/netParams.py @@ -0,0 +1,321 @@ +from netpyne.batchtools import specs +from cfg import cfg + +cfg.update_cfg() +### params ### +# Network parameters +netParams = specs.NetParams() # object of class NetParams to store the network parameters +netParams.defaultThreshold = 0.0 +netParams.defineCellShapes = True # sets 3d geometry aligned along the y-axis + + +############################################################################### +## Cell types +############################################################################### +# Basket cell +BasketCell = {'secs':{}} +BasketCell['secs']['soma'] = {'geom': {}, 'mechs': {}} +BasketCell['secs']['soma']['geom'] = {'diam': 100, 'L': 31.831, 'nseg': 1, 'cm': 1} +BasketCell['secs']['soma']['mechs'] = {'pas': {'g': 0.1e-3, 'e': -65}, 'Nafbwb': {}, 'Kdrbwb': {}} +netParams.cellParams['BasketCell'] = BasketCell + + +# OLM cell +OlmCell = {'secs':{}} +OlmCell['secs']['soma'] = {'geom': {}, 'mechs': {}} +OlmCell['secs']['soma']['geom'] = {'diam': 100, 'L': 31.831, 'nseg': 1, 'cm': 1} +OlmCell['secs']['soma']['mechs'] = { + 'pas': {'g': 0.1e-3, 'e': -65}, + 'Nafbwb': {}, + 'Kdrbwb': {}, + 'Iholmw': {}, + 'Caolmw': {}, + 'ICaolmw': {}, + 'KCaolmw': {}} +netParams.cellParams['OlmCell'] = OlmCell + + +# Pyramidal cell +PyrCell = {'secs':{}} +PyrCell['secs']['soma'] = {'geom': {}, 'mechs': {}} +PyrCell['secs']['soma']['geom'] = {'diam': 20, 'L': 20, 'cm': 1, 'Ra': 150} +PyrCell['secs']['soma']['mechs'] = { + 'pas': {'g': 0.0000357, 'e': -70}, + 'nacurrent': {}, + 'kacurrent': {}, + 'kdrcurrent': {}, + 'hcurrent': {}} +PyrCell['secs']['Bdend'] = {'geom': {}, 'mechs': {}} +PyrCell['secs']['Bdend']['geom'] = {'diam': 2, 'L': 200, 'cm': 1, 'Ra': 150} +PyrCell['secs']['Bdend']['topol'] = {'parentSec': 'soma', 'parentX': 0, 'childX': 0} +PyrCell['secs']['Bdend']['mechs'] = { + 'pas': {'g': 0.0000357, 'e': -70}, + 'nacurrent': {'ki': 1}, + 'kacurrent': {}, + 'kdrcurrent': {}, + 'hcurrent': {}} +PyrCell['secs']['Adend1'] = {'geom': {}, 'mechs': {}} +PyrCell['secs']['Adend1']['geom'] = {'diam': 2, 'L': 150, 'cm': 1, 'Ra': 150} +PyrCell['secs']['Adend1']['topol'] = {'parentSec': 'soma', 'parentX': 1.0, 'childX': 0} # here there is a change: connected to end soma(1) instead of soma(0.5) +PyrCell['secs']['Adend1']['mechs'] = { + 'pas': {'g': 0.0000357, 'e': -70}, + 'nacurrent': {'ki': 0.5}, + 'kacurrent': {'g': 0.072}, + 'kdrcurrent': {}, + 'hcurrent': {'v50': -82, 'g': 0.0002}} +PyrCell['secs']['Adend2'] = {'geom': {}, 'mechs': {}} +PyrCell['secs']['Adend2']['geom'] = {'diam': 2, 'L': 150, 'cm': 1, 'Ra': 150} +PyrCell['secs']['Adend2']['topol'] = {'parentSec': 'Adend1', 'parentX': 1, 'childX': 0} +PyrCell['secs']['Adend2']['mechs'] = { + 'pas': {'g': 0.0000357, 'e': -70}, + 'nacurrent': {'ki': 0.5}, + 'kacurrent': {'g': 0, 'gd': 0.120}, + 'kdrcurrent': {}, + 'hcurrent': {'v50': -90, 'g': 0.0004}} +PyrCell['secs']['Adend3'] = {'geom': {}, 'mechs': {}} +PyrCell['secs']['Adend3']['geom'] = {'diam': 2, 'L': 150, 'cm': 2, 'Ra': 150} +PyrCell['secs']['Adend3']['topol'] = {'parentSec': 'Adend2', 'parentX': 1, 'childX': 0} +PyrCell['secs']['Adend3']['mechs'] = { + 'pas': {'g': 0.0000714, 'e': -70}, + 'nacurrent': {'ki': 0.5}, + 'kacurrent': {'g': 0, 'gd': 0.200}, + 'kdrcurrent': {}, + 'hcurrent': {'v50': -90, 'g': 0.0007}} +netParams.cellParams['PyrCell'] = PyrCell + + +############################################################################### +## Synaptic mechs +############################################################################### + +netParams.synMechParams['AMPAf'] = {'mod': 'MyExp2SynBB', 'tau1': 0.05, 'tau2': 5.3, 'e': 0} +netParams.synMechParams['NMDA'] = {'mod': 'MyExp2SynNMDABB', 'tau1': 0.05, 'tau2': 5.3, 'tau1NMDA': 15, 'tau2NMDA': 150, 'r': 1, 'e': 0} +netParams.synMechParams['GABAf'] = {'mod': 'MyExp2SynBB', 'tau1': 0.07, 'tau2': 9.1, 'e': -80} +netParams.synMechParams['GABAs'] = {'mod': 'MyExp2SynBB', 'tau1': 0.2, 'tau2': 20, 'e': -80} +netParams.synMechParams['GABAss'] = {'mod': 'MyExp2SynBB', 'tau1': 20, 'tau2': 40, 'e': -80} + + +############################################################################### +## Populations +############################################################################### +netParams.popParams['PYR'] = {'cellType': 'PyrCell', 'numCells': 800} +netParams.popParams['BC'] = {'cellType': 'BasketCell', 'numCells': 200} +netParams.popParams['OLM'] = {'cellType': 'OlmCell', 'numCells': 200} + + +############################################################################### +# Current-clamp to cells +############################################################################### +netParams.stimSourceParams['IClamp_PYR'] = {'type': 'IClamp', 'del': 2*0.1, 'dur': 1e9, 'amp': 50e-3} +netParams.stimSourceParams['IClamp_OLM'] = {'type': 'IClamp', 'del': 2*0.1, 'dur': 1e9, 'amp': -25e-3} + +netParams.stimTargetParams['IClamp_PYR->PYR'] = { + 'source': 'IClamp_PYR', + 'sec': 'soma', + 'loc': 0.5, + 'conds': {'pop': 'PYR'}} + +netParams.stimTargetParams['IClamp_OLM->OLM'] = { + 'source': 'IClamp_OLM', + 'sec': 'soma', + 'loc': 0.5, + 'conds': {'pop': 'OLM'}} + + +############################################################################### +# Setting connections +############################################################################### + +# PYR -> X, NMDA +netParams.connParams['PYR->BC_NMDA'] = {'preConds': {'pop': 'PYR'}, 'postConds': {'pop': 'BC'}, + 'convergence': 100, + 'weight': cfg.nmda['PYR->BC'], + 'delay': 2, + 'sec': 'soma', + 'loc': 0.5, + 'synMech': 'NMDA'} + +netParams.connParams['PYR->OLM_NMDA'] = {'preConds': {'pop': 'PYR'}, 'postConds': {'pop': 'OLM'}, + 'convergence': 10, + 'weight': cfg.nmda['PYR->OLM'], + 'delay': 2, + 'sec': 'soma', + 'loc': 0.5, + 'synMech': 'NMDA'} + +netParams.connParams['PYR->PYR_NMDA'] = {'preConds': {'pop': 'PYR'}, 'postConds': {'pop': 'PYR'}, + 'convergence': 25, + 'weight': cfg.nmda['PYR->PYR'], + 'delay': 2, + 'sec': 'Bdend', + 'loc': 1.0, + 'synMech': 'NMDA'} + +# PYR -> X, AMPA +netParams.connParams['PYR->BC_AMPA'] = {'preConds': {'pop': 'PYR'}, 'postConds': {'pop': 'BC'}, + 'convergence': 100, + 'weight': cfg.ampa['PYR->BC'], + 'delay': 2, + 'sec': 'soma', + 'loc': 0.5, + 'synMech': 'AMPAf'} + +netParams.connParams['PYR->OLM_AMPA'] = {'preConds': {'pop': 'PYR'}, 'postConds': {'pop': 'OLM'}, + 'convergence': 10, + 'weight': cfg.ampa['PYR->OLM'], + 'delay': 2, + 'sec': 'soma', + 'loc': 0.5, + 'synMech': 'AMPAf'} + +netParams.connParams['PYR->PYR_AMPA'] = {'preConds': {'pop': 'PYR'}, 'postConds': {'pop': 'PYR'}, + 'convergence': 25, + 'weight': cfg.ampa['PYR->PYR'], + 'delay': 2, + 'sec': 'Bdend', + 'loc': 1.0, + 'synMech': 'AMPAf'} + +# BC -> X, GABA +netParams.connParams['BC->BC_GABA'] = {'preConds': {'pop': 'BC'}, 'postConds': {'pop': 'BC'}, + 'convergence': 60, + 'weight': cfg.gaba['BC->BC'], + 'delay': 2, + 'sec': 'soma', + 'loc': 0.5, + 'synMech': 'GABAf'} + +netParams.connParams['BC->PYR_GABA'] = {'preConds': {'pop': 'BC'}, 'postConds': {'pop': 'PYR'}, + 'convergence': 50, + 'weight': cfg.gaba['BC->PYR'], + 'delay': 2, + 'sec': 'soma', + 'loc': 0.5, + 'synMech': 'GABAf'} + + +# OLM -> PYR, GABA +netParams.connParams['OLM->PYR_GABA'] = {'preConds': {'pop': 'OLM'}, 'postConds': {'pop': 'PYR'}, + 'convergence': 20, + 'weight': cfg.gaba['OLM->PYR'], + 'delay': 2, + 'sec': 'Adend2', + 'loc': 0.5, + 'synMech': 'GABAs'} + + +############################################################################### +# Setting NetStims +############################################################################### +# to PYR +netParams.stimSourceParams['NetStim_PYR_SOMA_AMPA'] = {'type': 'NetStim', 'interval': 1, 'number': 1000*cfg.duration, 'start': 0, 'noise': 1} +netParams.stimTargetParams['NetStim_PYR_SOMA_AMPA->PYR'] = { + 'source': 'NetStim_PYR_SOMA_AMPA', + 'conds': {'pop': 'PYR'}, + 'sec': 'soma', + 'loc': 0.5, + 'weight': 4*0.05e-3, # different from published value + 'delay': 2*0.1, + 'synMech': 'AMPAf'} + +netParams.stimSourceParams['NetStim_PYR_ADEND3_AMPA'] = {'type': 'NetStim', 'interval': 1, 'number': 1000*cfg.duration, 'start': 0, 'noise': 1} +netParams.stimTargetParams['NetStim_PYR_ADEND3_AMPA->PYR'] = { + 'source': 'NetStim_PYR_ADEND3_AMPA', + 'conds': {'pop': 'PYR'}, + 'sec': 'Adend3', + 'loc': 0.5, + 'weight': 4*0.05e-3, # different from published value + 'delay': 2*0.1, + 'synMech': 'AMPAf'} + +netParams.stimSourceParams['NetStim_PYR_SOMA_GABA'] = {'type': 'NetStim', 'interval': 1, 'number': 1000*cfg.duration, 'start': 0, 'noise': 1} +netParams.stimTargetParams['NetStim_PYR_SOMA_GABA->PYR'] = { + 'source': 'NetStim_PYR_SOMA_GABA', + 'conds': {'pop': 'PYR'}, + 'sec': 'soma', + 'loc': 0.5, + 'weight': 0.012e-3, + 'delay': 2*0.1, + 'synMech': 'GABAf'} + +netParams.stimSourceParams['NetStim_PYR_ADEND3_GABA'] = {'type': 'NetStim', 'interval': 1, 'number': 1000*cfg.duration, 'start': 0, 'noise': 1} +netParams.stimTargetParams['NetStim_PYR_ADEND3_GABA->PYR'] = { + 'source': 'NetStim_PYR_ADEND3_GABA', + 'conds': {'pop': 'PYR'}, + 'sec': 'Adend3', + 'loc': 0.5, + 'weight': 0.012e-3, + 'delay': 2*0.1, + 'synMech': 'GABAf'} + +netParams.stimSourceParams['NetStim_PYR_ADEND3_NMDA'] = {'type': 'NetStim', 'interval': 100, 'number': int((1000/100.0)*cfg.duration), 'start': 0, 'noise': 1} +netParams.stimTargetParams['NetStim_PYR_ADEND3_NMDA->PYR'] = { + 'source': 'NetStim_PYR_ADEND3_NMDA', + 'conds': {'pop': 'PYR'}, + 'sec': 'Adend3', + 'loc': 0.5, + 'weight': 6.5e-3, + 'delay': 2*0.1, + 'synMech': 'NMDA'} + +# to BC +netParams.stimSourceParams['NetStim_BC_SOMA_AMPA'] = {'type': 'NetStim', 'interval': 1, 'number': 1000*cfg.duration, 'start': 0, 'noise': 1} +netParams.stimTargetParams['NetStim_BC_SOMA_AMPA->BC'] = { + 'source': 'NetStim_BC_SOMA_AMPA', + 'conds': {'pop': 'BC'}, + 'sec': 'soma', + 'loc': 0.5, + 'weight': 0.02e-3, + 'delay': 2*0.1, + 'synMech': 'AMPAf'} + +netParams.stimSourceParams['NetStim_BC_SOMA_GABA'] = {'type': 'NetStim', 'interval': 1, 'number': 1000*cfg.duration, 'start': 0, 'noise': 1} +netParams.stimTargetParams['NetStim_BC_SOMA_GABA->BC'] = { + 'source': 'NetStim_BC_SOMA_GABA', + 'conds': {'pop': 'BC'}, + 'sec': 'soma', + 'loc': 0.5, + 'weight': 0.2e-3, + 'delay': 2*0.1, + 'synMech': 'GABAf'} + +# to OLM +netParams.stimSourceParams['NetStim_OLM_SOMA_AMPA'] = {'type': 'NetStim', 'interval': 1, 'number': 1000*cfg.duration, 'start': 0, 'noise': 1} +netParams.stimTargetParams['NetStim_OLM_SOMA_AMPA->OLM'] = { + 'source': 'NetStim_OLM_SOMA_AMPA', + 'conds': {'pop': 'OLM'}, + 'sec': 'soma', + 'loc': 0.5, + 'weight': 0.0625e-3, + 'delay': 2*0.1, + 'synMech': 'AMPAf'} + +netParams.stimSourceParams['NetStim_OLM_SOMA_GABA'] = {'type': 'NetStim', 'interval': 1, 'number': 1000*cfg.duration, 'start': 0, 'noise': 1} +netParams.stimTargetParams['NetStim_OLM_SOMA_GABA->OLM'] = { + 'source': 'NetStim_OLM_SOMA_GABA', + 'conds': {'pop': 'OLM'}, + 'sec': 'soma', + 'loc': 0.5, + 'weight': 0.2e-3, + 'delay': 2*0.1, + 'synMech': 'GABAf'} + +# Medial Septal inputs to BC and OLM cells +netParams.stimSourceParams['Septal'] = {'type': 'NetStim', 'interval': 150, 'number': int((1000/150)*cfg.duration), 'start': 0, 'noise': 0} +netParams.stimTargetParams['Septal->BC'] = { + 'source': 'Septal', + 'conds': {'pop': 'BC'}, + 'sec': 'soma', + 'loc': 0.5, + 'weight': 1.6e-3, + 'delay': 2*0.1, + 'synMech': 'GABAss'} + +netParams.stimTargetParams['Septal->OLM'] = { + 'source': 'Septal', + 'conds': {'pop': 'OLM'}, + 'sec': 'soma', + 'loc': 0.5, + 'weight': 1.6e-3, + 'delay': 2*0.1, + 'synMech': 'GABAss'} diff --git a/netpyne/batchtools/examples/CA3/optuna_search.py b/netpyne/batchtools/examples/CA3/optuna_search.py new file mode 100644 index 000000000..662e0922a --- /dev/null +++ b/netpyne/batchtools/examples/CA3/optuna_search.py @@ -0,0 +1,38 @@ +from netpyne.batchtools.search import search + +params = {'nmda.PYR->BC' : [1e-3, 1.8e-3], + #'nmda.PYR->OLM': [0.4e-3, 1.0e-3], + #'nmda.PYR->PYR': [0.001e-3, 0.007e-3], + 'ampa.PYR->BC' : [0.2e-3, 0.5e-3], + #'ampa.PYR->OLM': [0.2e-3, 0.5e-3], + #'ampa.PYR->PYR': [0.01e-3, 0.03e-3], + #'gaba.BC->BC' : [1e-3, 7e-3], + 'gaba.BC->PYR' : [0.4e-3, 1.0e-3], + #'gaba.OLM->PYR': [40e-3, 100e-3], + } + +# use batch_shell_config if running directly on the machine +shell_config = {'command': 'mpiexec -np 4 nrniv -python -mpi init.py',} + +# use batch_sge_config if running on a +sge_config = { + 'queue': 'cpu.q', + 'cores': 5, + 'vmem': '4G', + 'realtime': '00:30:00', + 'command': 'mpiexec -n $NSLOTS -hosts $(hostname) nrniv -python -mpi init.py'} + +run_config = shell_config + +search(job_type = 'sh', + comm_type = 'socket', + label = 'search', + params = params, + output_path = '../optuna_batch', + checkpoint_path = '../ray', + run_config = run_config, + num_samples = 1, + metric = 'loss', + mode = 'min', + algorithm = 'optuna', + max_concurrent = 4) diff --git a/netpyne/batchtools/runners.py b/netpyne/batchtools/runners.py index e816af538..687ef3645 100644 --- a/netpyne/batchtools/runners.py +++ b/netpyne/batchtools/runners.py @@ -101,7 +101,8 @@ def get_SimConfig(self): from netpyne import specs self.cfg = type("Runner_SimConfig", (specs.SimConfig,), {'__mappings__': self.mappings, - 'update_cfg': update_cfg})() + 'update_cfg': update_cfg, + 'update': update_cfg})() return self.cfg def set_SimConfig(self): diff --git a/netpyne/batchtools/search.py b/netpyne/batchtools/search.py index c303db4b9..724e4ee6e 100644 --- a/netpyne/batchtools/search.py +++ b/netpyne/batchtools/search.py @@ -10,35 +10,54 @@ from batchtk.raytk.search import ray_trial, LABEL_POINTER from batchtk.utils import get_path import numpy - - -def ray_optuna_search(dispatcher_constructor, submit_constructor, label = 'optuna_search', - params = None, output_path = '../batch', checkpoint_path = '../ray', - batch_config = None, max_concurrent = 1, batch = True, num_samples = 1, - metric = "loss", mode = "min", optuna_config = None): +from typing import Any, Callable, Dict, List, Optional, Tuple, Union + + + +choice = tune.choice +grid = tune.grid_search +uniform = tune.uniform + +def ray_optuna_search(dispatcher_constructor: Callable, # constructor for the dispatcher (e.g. INETDispatcher) + submit_constructor: Callable, # constructor for the submit (e.g. SHubmitSOCK) + run_config: Dict, # batch configuration, (keyword: string pairs to customize the submit template) + params: Dict, # search space (dictionary of parameter keys: tune search spaces) + label: Optional[str] = 'optuna_search', # label for the search + output_path: Optional[str] = '../batch', # directory for storing generated files + checkpoint_path: Optional[str] = '../ray', # directory for storing checkpoint files + max_concurrent: Optional[int] = 1, # number of concurrent trials to run at one time + batch: Optional[bool] = True, # whether concurrent trials should run synchronously or asynchronously + num_samples: Optional[int] = 1, # number of trials to run + metric: Optional[str] = "loss", # metric to optimize (this should match some key: value pair in the returned data + mode: Optional[str] = "min", # either 'min' or 'max' (whether to minimize or maximize the metric + optuna_config: Optional[dict] = None, # additional configuration for the optuna search algorithm + ) -> namedtuple('Study', ['algo', 'results']): """ - ray_optuna_search(dispatcher_constructor, submit_constructor, label, - params, output_path, checkpoint_path, - batch_config, max_concurrent, batch, num_samples, - metric, mode, optuna_config) + ray_optuna_search(...) + Parameters ---------- - dispatcher_constructor - submit_constructor - label - params - output_path - checkpoint_path - batch_config - max_concurrent - batch - num_samples - metric - mode - optuna_config + dispatcher_constructor:Callable, # constructor for the dispatcher (e.g. INETDispatcher) + submit_constructor:Callable, # constructor for the submit (e.g. SHubmitSOCK) + run_config:Dict, # batch configuration, (keyword: string pairs to customize the submit template) + params:Dict, # search space (dictionary of parameter keys: tune search spaces) + label:Optional[str] = 'optuna_search', # label for the search + output_path:Optional[str] = '../batch', # directory for storing generated files + checkpoint_path:Optional[str] = '../ray', # directory for storing checkpoint files + max_concurrent:Optional[int] = 1, # number of concurrent trials to run at one time + batch:Optional[bool] = True, # whether concurrent trials should run synchronously or asynchronously + num_samples:Optional[int] = 1, # number of trials to run + metric:Optional[str] = "loss", # metric to optimize (this should match some key: value pair in the returned data + mode:Optional[str] = "min", # either 'min' or 'max' (whether to minimize or maximize the metric + optuna_config:Optional[dict] = None, # additional configuration for the optuna search algorithm (incl. sampler, seed, etc.) + + Creates + ------- +