def check_synapse_strengths(f, syn_list=(5, 100), target=5., num_runs=5, max_num_runs=10): """ Find the number of synapses that yields the target (Hz) Assumptions: - Same number of synapses :param f: file handle to write results :type f: TextIO """ h.tstop = 1000 inh_freq, inh_noise = 5, 1 exc_freq, exc_noise = 5, 1 exc_weights = [1, 2, 5, 7, 10, 15, 20] inh_weights = [1, 2, 5, 7, 10, 15, 20] means = [] stds = [] weights = [] h.inPy(1, inh_noise, 0) # Frequency, Noise, Weight (# synapses) h.ex(1, exc_noise, 0) # Frequency, Noise, Weight (uS) h.run() h.useCV() for syn in syn_list: # newSynapses from methods.hoc h.newSynapses(syn, syn) for inh_weight in inh_weights: above_max_f = False for exc_weight in exc_weights: f.write( "exc_weight: {} ({})\t inh_weight: {} ({})\n".format(exc_weight, syn, inh_weight, syn)) logger.info("exc_weight:{} ({})\t inh_weight: {} ({})\n".format(exc_weight, syn, inh_weight, syn)) if above_max_f: # skip values of excitation when firing rate is already above # 11 Hz for lower values of excitation f.write("\n{} +- {} (n={})\n".format(12, 0, 0)) logger.info("{} +- {} (n={})\n".format(12, 0, 0)) else: h.inPy(inh_freq, inh_noise, inh_weight) h.ex(exc_freq, exc_noise, exc_weight) x = [] f.write("spikes:\n") num_zero = 0 run_list = list(range(num_runs)) for run in run_list: h.run() x.append(h.apc.n) f.write("\t {}".format(h.apc.n)) logger.info("\t spikes {}".format(h.apc.n)) if not (0 < h.apc.n <= 11): if h.apc.n == 0: num_zero += 1 if num_zero >= num_runs/5: logger.info("break from too many 0's") f.write("break from too many 0's") break else: logger.info("break from above 11") f.write("break from above 11") above_max_f = True break elif (4 <= h.apc.n <= 6) and len(run_list) < max_num_runs: # get more accurate results for values close to 5 run_list.append(len(run_list)) mean = np.mean(x) std = np.std(x) f.write("\n{} +- {} (n={})\n".format(mean, std, run + 1)) logger.info("{} +- {} (n={})\n".format(mean, std, run + 1)) means.append(mean) stds.append(std) weights.append((exc_weight, inh_weight)) arr = np.abs(target - np.array(means)) idx = np.argmin(arr) return weights[idx]
def check_num_synapses(f, synapse_type, exc_weight, inh_weight, exc_syn_list=None, inh_syn_list=None, exc_freq=5, inh_freq=5, exc_noise=1, inh_noise=1, num_runs=5, max_num_runs=15, upper_bound=15): """ A target of 5 Hz is used, with simulations with 4, 5, and 6 spikes taking extra trials. This target and the range to expand the number of trials can be implemented relatively easily in the future. Assumptions - GABAa gmax per synapse = 350 pS - AMPA+NMDA gmax per synapse = 1000 pS [AMPA:NMDA ratio = 1] :param f: file handle to write results :type f: TextIO """ step = 10 if inh_syn_list is None: inh_syn_list = range(0, 800 + step, step) if exc_syn_list is None: exc_syn_list = range(0, 800 + step, step) if upper_bound is not None: assert upper_bound > 0 else: upper_bound = 10000 prev_run = f.read() load_file(synapse_type) h.tstop = 1000 h.useCV() # without a 2nd load NEURON seems to complain about synapseFile being a non-variable... load_file(synapse_type) for inh_syn in inh_syn_list: above_bound = False for exc_syn in exc_syn_list: line = "exc_syn: {} ({})\t inh_syn: {} ({})\n".format(exc_syn, exc_weight, inh_syn, inh_weight) if line in prev_run: continue f.write(line) logger.info(line) if above_bound: # skip values of excitation when firing rate is already above # 15 Hz for lower values of excitation f.write("\n{} +- {} (n={})\n".format(16, 0, 0)) logger.info("{} +- {} (n={})\n".format(16, 0, 0)) else: # newSynapses from methods.hoc h.newSynapses(exc_syn, inh_syn) # Frequency, Noise, Weight (# synapses) h.inPy(inh_freq, inh_noise, inh_weight) h.ex(exc_freq, exc_noise, exc_weight) x = [] f.write("spikes:\n") num_zero = 0 run_list = list(range(num_runs)) for run in run_list: h.run() x.append(h.apc.n) f.write("\t {}".format(h.apc.n)) logger.info("\t spikes {}".format(h.apc.n)) if h.apc.n == 0: num_zero += 1 if num_zero >= num_runs/2: logger.info("break from too many 0's") f.write("break from too many 0's") break elif (4 <= h.apc.n <= 6) and len(run_list) < max_num_runs: # get more accurate results for values close to 5 run_list.append(len(run_list)) elif h.apc.n > upper_bound: logger.info("break from above {}".format(upper_bound)) f.write("break from above {}".format(upper_bound)) above_bound = True break mean = np.mean(x) std = np.std(x) f.write("\n{} +- {} (n={})\n".format(mean, std, run + 1)) logger.info("{} +- {} (n={})\n".format(mean, std, run + 1))
def get_trace(file_name, synapse_type=0, synapse_numbers=(10, 10), hz=None, space_plot=False, vm=-65.0, cli=5.0, ldend_diam=0.5): """ Get the voltage trace and cli trace from running a hoc file. Optionally, specify space_plot to get the cli along the entire neuron (nseg dependent). `vm` and `cli` should be specified by running `get_base_vm_cli` beforehand and passing in those values. :param file_name: hoc-specified neuron to load (from hoc_files/cells) :type file_name: str :param synapse_type: 0 if 'f-in' NETSTIM synapses. 1 if 'persistetnt' fluctuating conductance synapses. :type synapse_type: int :param synapse_numbers: Number of (E,I) synapses. :type synapse_numbers: tuple of int :param hz: Input to the synapses. Keys used are 'in' and 'ex'. Either frequency-based (`synapse_type` is `0`) or relative conductance (`synapse_type` is `1`). :type hz: dict of str :param space_plot: Compute cli at every location. :type space_plot: bool :param vm: Initial membrane potential :type vm: float :param cli: Initial chloride ion concentration :type cli: float :param ldend_diam: Diameter of distal dendrite. :type ldend_diam: float :return: Time array, voltage array, chloride array, space plot dict data of form `{distance from soma: chloride array}` :rtype: tuple[h.Vector, h.Vector, h.Vector, dict of float:h.Vector] """ if hz is None: hz = {'in': 5, 'ex': 5} load_file(file_name) h.changeSynapseType(synapse_type) h.newSynapses(synapse_numbers[0], synapse_numbers[1]) if synapse_type == 0: h.inPy(hz['in'], 1, 1) h.ex(hz['ex'], 1, 1) else: h.inPy(hz['in']) h.ex(hz['ex']) if "distal" in file_name: compartment = h.ldend elif "proximal" in file_name: compartment = h.bdend else: compartment = h.soma h("forall {" + "cli={} ".format(cli) + "cli0_KCC2={}".format(cli) + "}") for sec in h.allsec: for seg in sec: seg.cli = cli h.cli0_cl_ion = cli h.ldend.diam = ldend_diam # sort on key data = {} if space_plot: h.distance(0, 1, sec=h.soma) for sec in h.allsec: for seg in sec: # label = f"{sec.name()}({seg.x:.5f})" label = h.distance(seg.x, sec=sec) if 'dend' in sec.name(): label *= -1 data[label] = h.Vector() data[label].record(sec(seg.x)._ref_cli) h.tstop = 1000.0 time_past = current_time('ms') logger.info("running {}...".format(file_name)) h.v_init = vm h.finitialize(vm) t_vec = h.Vector() t_vec.record(h._ref_t) v_vec = h.Vector() v_vec.record(h.axon(0.5)._ref_v) cli_vec = h.Vector() cli_vec.record(compartment(0.5)._ref_cli) h.run() logger.info("time taken: {}ms".format(current_time('ms') - time_past)) logger.info("no. spikes = {}".format(h.apc.n)) return t_vec, v_vec, cli_vec, data
def pyrun(file_name, synapse_type=1, synapse_numbers=(100, 100), syn_input=None, diam=None, pa_kcc2=None, location='axon', trials=1, save=True, tstop=TSTOP, **kwargs): """ Run a NEURON simulation for a neuron specified in ``file_name`` with input specified by other parameters provided. :param file_name: Neuron definition (excluding '.hoc'). :type file_name: str :param synapse_type: Type of synapses to use (0 for frequency-based 'f-in', 1 for persistent conductance, 'gclamp'). :type synapse_type: int :param synapse_numbers: Number of (E, I) on the neuron. :type synapse_numbers: (int, int) :param syn_input: Mapping of excitatory/inhibitory type to input strength. {'ex', E, 'in: I} :type syn_input: dict[str, int] :param diam: Re-specify diam for specific regions of the neuron. Valid: 'ldend', 'bdend', 'soma', 'axon'. :type diam: dict[str: float] :param pa_kcc2: Strength of KCC2. :type pa_kcc2: float :param location: Location to recording firing rate. :type location: str :param trials: Number of repeated simulations to run. :type trials: int :param save: Whether to load/save the results from/to file. :type save: bool :param tstop: Length of simulation (ms). :type tstop: float :param kwargs: Other keywords are ignored. :return: Pair of DataFrame with results and name of save file (even if not saved, the name is generated). :rtype: (pd.DataFrame, str) """ if syn_input is None: syn_input = {'in': 5, 'ex': 5} save_name = "{}_{}_{}_{}".format(file_name, synapse_type, synapse_numbers, syn_input) save_name += "_{}".format(diam) if diam is not None else '' save_name += "_{}".format(pa_kcc2) if pa_kcc2 is not None else '' save_name += "_{}_{}".format(location, trials) save_name = save_name.replace(" ", "").replace("'", "").replace( ":", "=").replace("{", "(").replace("}", ")") logger.info(save_name) if save: loaded = load_from_file(save_name) if loaded is not None: return loaded, save_name load_file(file_name) load_file(file_name) if diam is not None: for seg in diam.keys(): nrn_seg = get_compartment(seg) nrn_seg.diam = diam[seg] if pa_kcc2 is not None: hoc_cmd = "forall {" + """ Pa_KCC2 = {pa_kcc2}e-5""".format(pa_kcc2=pa_kcc2) +\ " }" h(hoc_cmd) compartment = get_compartment(location) if file_name.find('distal') > -1: cli_rec_loc = get_compartment('ldend') elif file_name.find('proximal') > -1 or file_name.find('proximal') > -1: cli_rec_loc = get_compartment('bdend') else: cli_rec_loc = get_compartment('soma') logger.info("recording cli from {}".format(cli_rec_loc.hname())) h("access {}".format(location)) h.changeSynapseType(synapse_type) h.newSynapses(synapse_numbers[0], synapse_numbers[1]) h.inPy(0) h.ex(0) vm_init, cli = get_base_vm_cli(file_name, compartment=compartment) h.v_init = vm_init h_str = """ forall{""" + """ cli = {0} cli0_cl_ion = {0} """.format(cli) if file_name.find("KCC2") > 0: h_str += """cli0_KCC2 = {0} """.format(cli) h_str += "}" h(h_str) h.tstop = tstop if synapse_type == 0: # Hz, duration (s), start (ms), noise, weight/channels h.inPy(syn_input['in'], h.tstop / 1000, 0, 1, 1) h.ex(syn_input['ex'], h.tstop / 1000, 0, 1, 1) else: h.inPy(syn_input['in']) h.ex(syn_input['ex']) # create recording vector objects t_rec = h.Vector() v_rec = h.Vector() cli_rec = h.Vector() spike_rec = h.Vector() t_rec.record(h._ref_t) v_rec.record(compartment(0.5)._ref_v) cli_rec.record(cli_rec_loc(0.5)._ref_cli) spike_rec.record(h.apc._ref_n) time_past = current_time('ms') logger.info("using {}...".format(file_name)) assert trials > 0 logger.info(save_name) logger.info("trial # | # spikes") df = pd.DataFrame() for i in range(trials): trial_num = i + 1 h.run() logger.info("{:7} | {:8}".format(trial_num, h.apc.n)) temp_dict = { (trial_num, 'v'): v_rec.as_numpy(), (trial_num, 'cli'): cli_rec.as_numpy(), (trial_num, 'spikes'): spike_rec.as_numpy() } recording = pd.DataFrame(temp_dict, index=t_rec.to_python()) df = pd.concat([df, recording], axis=1) logger.info("time taken: {}ms".format(current_time('ms') - time_past)) if save: save_to_file(save_name, df) return df, save_name
def get_base_vm_cli(file_name, load=False, compartment=None): """ Determine steady-state internal chloride concentration by 1) instantiating a class that extends BaseNeuron (NOTE: class should not have spiking at default values) 2) adding KCC2 using the add_kcc2() method 3) setting [Cl]_i to an arbitrary value (can be set in method invocation) running a fast simulation for a long time checking if chloride is at steady state (repeat 4 until it is) return steady state Vm and [Cl]_i :return: steady state Vm and [Cl]_i """ logger.debug(f"finding steady-state vm and cli for {file_name}") if load: load_file(file_name, set_file_name=False) if compartment is None: compartment = h.soma h.inPy(0) h.ex(0) if file_name.find("KCC2") > 0: kcc2_already = True else: kcc2_already = False h.load_file(1, "insert_KCC2.hoc") logger.info("KCC2 temporarily inserted") h.tstop = 50000 h.useCV() h.finitialize(-65) h.run() def at_steady_state(compartment, continue_dt): """ check if [Cl]_i is at steady state :param continue_dt: amount of time to run :return: [Cl]_i if at steady state, False otherwise """ v_start = compartment(.5).v cli_start = compartment(.5).cli h.continuerun(h.tstop + continue_dt) h.tstop += continue_dt v_after = compartment(.5).v cli_after = compartment(.5).cli if v_after - v_start < 1e-8 and cli_after - cli_start < 1e-8: return cli_after else: return False num_steady_state_checks = 0 while not at_steady_state(compartment, 1): h.continuerun(h.tstop + 10000) h.tstop += 10000 num_steady_state_checks += 1 if num_steady_state_checks > 10: logger.info("not at steady state even after {} ms".format( 50000 + num_steady_state_checks * 10000)) exit(-1) h.disableCV() vm, cli = compartment(.5).v, compartment(.5).cli logger.info("steady state [Cl]_i {}".format(cli)) logger.info("steady state Vm {}".format(vm)) logger.info( "took {} ms (simulation time)".format(50000 + num_steady_state_checks * 10000)) if not kcc2_already: h(""" forall{ uninsert KCC2 } """) logger.info("temporary KCC2 removed") return vm, cli