示例#1
0
    def setUp(self):

        #swc_file = os.path.join(os.path.dirname(__file__), "validation", "ballanddoublestick", "double.swc")

        swc_file = os.path.join(os.path.dirname(__file__), "validation", "striatum", "fs",
                                "str-fs-e161205_FS1-mMTC180800A-IDB-v20190312", "MTC180800A-IDB-cor-rep.swc")
        self.nm = NeuronMorphology(swc_filename=swc_file, load_morphology=True)
示例#2
0
文件: project.py 项目: wthun/Snudda
    def read_prototypes(self):

        for name, definition in self.config["Neurons"].items():

            morph = definition["morphology"]

            self.prototype_neurons[name] = NeuronMorphology(name=name,
                                                            swc_filename=morph)

        # TODO: The code below is duplicate from detect.py, update so both use same code base
        for name, definition in self.config["Connectivity"].items():

            pre_type, post_type = name.split(",")

            con_def = definition.copy()

            for key in con_def:
                if key == "GapJunction":
                    con_def[key]["channelModelID"] = 3
                else:
                    con_def[key]["channelModelID"] = self.next_channel_model_id
                    self.next_channel_model_id += 1

                # Also if conductance is just a number, add std 0
                if type(con_def[key]["conductance"]) not in [list, tuple]:
                    con_def[key]["conductance"] = [
                        con_def[key]["conductance"], 0
                    ]

            self.connectivity_distributions[pre_type, post_type] = con_def
示例#3
0
    def load_neuron(self, neuron_id):

        neuron_info = self.data["neurons"][neuron_id]
        self.load_config_file()

        prototype_info = self.config["Neurons"][neuron_info["name"]]

        from snudda.neurons.neuron_morphology import NeuronMorphology
        neuron = NeuronMorphology(name=neuron_info["name"],
                                  position=neuron_info["position"],
                                  rotation=neuron_info["rotation"],
                                  swc_filename=prototype_info["morphology"],
                                  mech_filename=prototype_info["mechanisms"],
                                  load_morphology=True)

        return neuron
示例#4
0
    def load_neuron(self, neuron_info=None, neuron_id=None):

        assert (neuron_info is None) + (
            neuron_id is None) == 1, "Specify neuron_info or neuron_id"

        if neuron_id is not None:
            print(f"Using id {neuron_id}")
            neuron_info = self.sl.data["neurons"][neuron_id]

        neuron_name = neuron_info["name"]

        if neuron_name not in self.prototype_neurons:
            self.prototype_neurons[neuron_name] = NeuronMorphology(
                name=neuron_name, swc_filename=neuron_info["morphology"])

        neuron = self.prototype_neurons[neuron_name].clone()
        neuron.place(rotation=neuron_info["rotation"],
                     position=neuron_info["position"])

        return neuron
示例#5
0
文件: rotation.py 项目: wthun/Snudda
    def get_rotations(self, volume_name, neuron_type, neuron_positions, rng):

        if (volume_name, neuron_type) in self.rotation_lookup:
            rotation_mode, field_position, field_rotation = self.rotation_lookup[volume_name, neuron_type]
        else:
            rotation_mode, field_position, field_rotation = "random", None, None

        if not rotation_mode or rotation_mode.lower() == "none":
            rotation_matrices = [np.eye]*neuron_positions.shape[0]

        elif rotation_mode in ["random", "default"]:
            rotation_matrices = [NeuronMorphology.rand_rotation_matrix(rand_nums=rng.random(size=(3,)))
                                 for x in range(0, neuron_positions.shape[0])]

        elif "vectorField" in rotation_mode:
            rotation_vectors = griddata(points=field_position,
                                        values=field_rotation,
                                        xi=neuron_positions, method="linear")

            assert not np.isnan(np.sum(rotation_vectors)), \
                (f"Invalid rotation vector for volume {volume_name}, neuron {neuron_type}, "
                 f"is neuron position outside the field?\nNeuron positions: {neuron_positions}"
                 f" (must be inside convex hull of the field's positions points)")

            if rotation_mode == "vectorFieldAndZ":
                rotation_matrices = [np.matmul(SnuddaRotate.rotation_matrix_from_vectors(np.array([0, 0, 1]), rv),
                                               self.random_z_rotate(rng))
                                     for rv in rotation_vectors]
            else:
                # We need to rotate z-axis to point to rotation_vector
                rotation_matrices = [SnuddaRotate.rotation_matrix_from_vectors(np.array([0, 0, 1]), rv)
                                     for rv in rotation_vectors]
        else:
            raise TypeError(f"Unknown rotation mode {rotation_mode}")

        return rotation_matrices
示例#6
0
    def add_neurons(self,
                    swc_filename,
                    num_neurons,
                    param_data=None,
                    mech_filename=None,
                    modulation=None,
                    name="Unnamed",
                    hoc=None,
                    volume_id=None,
                    rotation_mode="random",
                    virtual_neuron=False,
                    axon_density=None):

        assert volume_id is not None, "You must specify a volume for neuron " + name

        nm = NeuronMorphology(swc_filename=swc_filename,
                              param_data=param_data,
                              mech_filename=mech_filename,
                              name=name,
                              hoc=hoc,
                              virtual_neuron=virtual_neuron)

        neuron_type = name.split("_")[0]
        neuron_positions = self.volume[volume_id]["mesh"].place_neurons(
            num_neurons, neuron_type)

        first_added = True

        neuron_rotations = self.rotate_helper.get_rotations(
            volume_name=volume_id,
            neuron_type=neuron_type,
            neuron_positions=neuron_positions,
            rng=self.random_generator)

        for coords, rotation in zip(neuron_positions, neuron_rotations):
            # We set loadMorphology = False, to preserve memory
            # Only morphology loaded for nm then, to get axon and dend
            # radius needed for connectivity

            # Pick a random parameterset
            # parameter.json can be a list of lists, this allows you to select the
            # parameterset randomly
            # modulation.json is similarly formatted, pick a parameter set here
            parameter_id = self.random_generator.integers(1000000)
            modulation_id = self.random_generator.integers(1000000)

            n = nm.clone(position=coords,
                         rotation=rotation,
                         load_morphology=False,
                         parameter_id=parameter_id,
                         modulation_id=modulation_id)

            # self.writeLog("Place " + str(self.cellPos[i,:]))

            n.neuron_id = len(self.neurons)
            n.volume_id = volume_id

            assert axon_density is None or len(n.axon) == 0, \
                "!!! ERROR: Neuron: " + str(n.name) + " has both axon and axon density."

            n.axon_density = axon_density
            self.neurons.append(n)

            # This info is used by workers to speed things up
            if first_added:
                first_added = False
                self.neuronPrototypes[n.name] = n
示例#7
0
    def __init__(
            self,
            neuron_morphology,
            neuron_mechanisms,
            neuron_parameters,
            neuron_modulation,
            stim_times,
            synapse_density,
            num_synapses,
            synapse_section_id=None,  # if given, nSynapses is ignored
            synapse_section_x=None,  # same # of elements as synapseSectionID
            neuron_parameter_id=0,  # Which param set in parameter file to use
            neuron_modulation_id=0,
            holding_voltage=-70e-3,
            holding_current=None,
            synapse_type='glut',
            params={},
            time=2,
            random_seed=None,
            log_file=None,
            verbose=True):

        self.log_file = log_file  # File pointer
        self.verbose = verbose
        self.rng = np.random.default_rng(random_seed)

        self.write_log("Holding voltage: " + str(holding_voltage) + " V")
        self.write_log("Stim times: " + str(stim_times) + " s")
        self.write_log("Synapse type: " + str(synapse_type))

        self.time = time
        self.synapses = []
        self.i_clamp = None
        self.nc_syn = None

        self.i_save = None
        self.t_save = None
        self.v_save = None

        self.stim_vector = None
        self.vec_stim = None
        self.synapse_section_id = None
        self.synapse_section_x = None

        # Done in NrnSimulatorParallel
        # neuron.h.load_file('stdrun.hoc')

        self.sim = NrnSimulatorParallel(cvode_active=False)

        # Should we use weak reference for garbage collection? (weakref package)

        # We load the neuron morphology object also, used to place synapses
        self.write_log("Using morphology: " + str(neuron_morphology))
        self.morphology = NeuronMorphology(swc_filename=neuron_morphology)

        # We need to setup the Neuron model
        self.neuron = NeuronModel(param_file=neuron_parameters,
                                  morph_file=neuron_morphology,
                                  mech_file=neuron_mechanisms,
                                  cell_name="OptimisationNeuron",
                                  modulation_file=neuron_modulation,
                                  parameter_id=neuron_parameter_id,
                                  modulation_id=neuron_modulation_id)

        self.neuron.instantiate(sim=self.sim)
        self.set_resting_voltage(holding_voltage * 1e3)

        neuron.h.celsius = 35

        # gnabar_hh: The maximum specific sodium channel conductance [Default value = 0.120 S/cm2]
        # gkbar_hh: The maximum specific potassium channel conductance [Default value = 0.036 S/cm2]
        # gl_hh: The maximum specific leakage conductance [Default value = 0.0003 S/cm2]
        # ena: The reversal potential for the sodium channel [Default value = 50 mV]
        # ek: The reversal potential for the potassium channel [Default value = -77 mV]
        # el_hh: The reversal potential for the leakage channel [Default value = -54.3 mV]

        # We need to set the params also
        self.params = params
        self.default_cond = 5e-7

        # This returns (section,sectionX) so we can reuse it if needed
        self.synapse_positions = self.add_synapse_density(
            synapse_type=synapse_type,
            synapse_density=synapse_density,
            num_synapses=num_synapses,
            section_id=synapse_section_id,
            section_x=synapse_section_x)

        self.stim_times = np.array(stim_times)

        # Assumes input in seconds (SI units)
        self.connect_input_to_synapses(self.stim_times)

        self.soma_record()
        self.synapse_current_record()

        self.holding_current = self.update_holding_current(
            holding_voltage=holding_voltage, holding_current=holding_current)
示例#8
0
class RunSynapseRun(object):
    def __init__(
            self,
            neuron_morphology,
            neuron_mechanisms,
            neuron_parameters,
            neuron_modulation,
            stim_times,
            synapse_density,
            num_synapses,
            synapse_section_id=None,  # if given, nSynapses is ignored
            synapse_section_x=None,  # same # of elements as synapseSectionID
            neuron_parameter_id=0,  # Which param set in parameter file to use
            neuron_modulation_id=0,
            holding_voltage=-70e-3,
            holding_current=None,
            synapse_type='glut',
            params={},
            time=2,
            random_seed=None,
            log_file=None,
            verbose=True):

        self.log_file = log_file  # File pointer
        self.verbose = verbose
        self.rng = np.random.default_rng(random_seed)

        self.write_log("Holding voltage: " + str(holding_voltage) + " V")
        self.write_log("Stim times: " + str(stim_times) + " s")
        self.write_log("Synapse type: " + str(synapse_type))

        self.time = time
        self.synapses = []
        self.i_clamp = None
        self.nc_syn = None

        self.i_save = None
        self.t_save = None
        self.v_save = None

        self.stim_vector = None
        self.vec_stim = None
        self.synapse_section_id = None
        self.synapse_section_x = None

        # Done in NrnSimulatorParallel
        # neuron.h.load_file('stdrun.hoc')

        self.sim = NrnSimulatorParallel(cvode_active=False)

        # Should we use weak reference for garbage collection? (weakref package)

        # We load the neuron morphology object also, used to place synapses
        self.write_log("Using morphology: " + str(neuron_morphology))
        self.morphology = NeuronMorphology(swc_filename=neuron_morphology)

        # We need to setup the Neuron model
        self.neuron = NeuronModel(param_file=neuron_parameters,
                                  morph_file=neuron_morphology,
                                  mech_file=neuron_mechanisms,
                                  cell_name="OptimisationNeuron",
                                  modulation_file=neuron_modulation,
                                  parameter_id=neuron_parameter_id,
                                  modulation_id=neuron_modulation_id)

        self.neuron.instantiate(sim=self.sim)
        self.set_resting_voltage(holding_voltage * 1e3)

        neuron.h.celsius = 35

        # gnabar_hh: The maximum specific sodium channel conductance [Default value = 0.120 S/cm2]
        # gkbar_hh: The maximum specific potassium channel conductance [Default value = 0.036 S/cm2]
        # gl_hh: The maximum specific leakage conductance [Default value = 0.0003 S/cm2]
        # ena: The reversal potential for the sodium channel [Default value = 50 mV]
        # ek: The reversal potential for the potassium channel [Default value = -77 mV]
        # el_hh: The reversal potential for the leakage channel [Default value = -54.3 mV]

        # We need to set the params also
        self.params = params
        self.default_cond = 5e-7

        # This returns (section,sectionX) so we can reuse it if needed
        self.synapse_positions = self.add_synapse_density(
            synapse_type=synapse_type,
            synapse_density=synapse_density,
            num_synapses=num_synapses,
            section_id=synapse_section_id,
            section_x=synapse_section_x)

        self.stim_times = np.array(stim_times)

        # Assumes input in seconds (SI units)
        self.connect_input_to_synapses(self.stim_times)

        self.soma_record()
        self.synapse_current_record()

        self.holding_current = self.update_holding_current(
            holding_voltage=holding_voltage, holding_current=holding_current)

        # import pdb
        # pdb.set_trace()

    ############################################################################

    def __del__(self):

        # This should not be needed but...
        self.neuron = None
        self.morphology = None
        self.i_clamp = None
        self.v_clamp = None
        self.v_save = None
        self.t_save = None
        self.i_save = None
        self.nc_syn = None

        self.vec_stim = None
        self.stim_vector = None
        self.little_synapse = None

    ############################################################################

    def update_holding_current(self,
                               holding_voltage=None,
                               holding_current=None):

        if holding_voltage is None:
            holding_voltage = self.holding_voltage
        else:
            self.holding_voltage = holding_voltage

        if holding_current is not None:
            if self.i_clamp is None:
                self.i_clamp = neuron.h.IClamp(self.neuron.icell.soma[0](0.5))

            # Update current on iClamp
            self.i_clamp.amp = holding_current * 1e9  # Convert SI -> nA for NEURON
            self.i_clamp.dur = 2 * self.time * 1e3

            self.set_resting_voltage(self.holding_voltage * 1e3)
            self.write_log(
                f"Set holding current {holding_current}A and holding voltage {holding_voltage}V"
            )
            return holding_current

        self.write_log("Updating holding current, might take a bit of time")

        # Disable old iClamp temporarily
        if self.i_clamp is not None:
            self.i_clamp.amp = 0

        # Setup a temporary VClamp
        self.v_clamp = neuron.h.SEClamp(self.neuron.icell.soma[0](0.5))
        self.v_clamp.rs = 1e-9
        self.v_clamp.amp1 = holding_voltage * 1e3
        self.v_clamp.dur1 = self.time * 2 * 1e3
        # self.writeLog("VClamp duration: " + str(self.VClamp.dur1))

        neuron.h.finitialize(self.holding_voltage * 1e3)
        # !!! There is a WEIRD neuron bug, that if this tstop here is
        # different from duration of simulation, then the *SECOND* time
        # a model is initialised we get the length of tSave set by this
        # value, and not by the tStop of that simulation --- go figure!
        self.set_resting_voltage(self.holding_voltage * 1e3)

        neuron.h.tstop = self.time * 1e3  # Must set tstop
        neuron.h.run()

        if False:
            import matplotlib.pyplot as plt
            plt.figure()
            plt.plot(self.t_save, self.v_save)
            plt.title("Holding voltage should be " +
                      str(self.holding_voltage * 1e3) + "mV")
            plt.xlabel("time (ms)")
            plt.ylabel("volt (mV)")
            plt.ion()
            plt.show()

            import pdb
            pdb.set_trace()

        cur = float(self.v_clamp.i)

        # Remove VClamp
        self.v_clamp = None

        if self.i_clamp is None:
            self.i_clamp = neuron.h.IClamp(self.neuron.icell.soma[0](0.5))

        # Update current on iClamp
        self.i_clamp.amp = cur
        self.i_clamp.dur = 2 * self.time * 1e3

        self.set_resting_voltage(self.holding_voltage * 1e3)

        self.write_log(
            f"Holding voltage {self.holding_voltage * 1e3} mV, IClamp amp = {cur} nA"
        )

        return cur * 1e-9  # Convert to SI units

    ############################################################################

    def set_stim_times(self, stim_times):

        if len(stim_times) != len(self.stim_times) or (stim_times !=
                                                       self.stim_times).any():
            print(f"Setting stim times to {stim_times} s")
            self.write_log(f"Setting stim times to {stim_times} s")
            self.stim_vector = neuron.h.Vector(stim_times * 1e3)
            self.stim_times = stim_times * 1e3

    ############################################################################

    def add_synapse_density(self,
                            synapse_type,
                            synapse_density,
                            num_synapses=None,
                            plot_flag=False,
                            section_id=None,
                            section_x=None):

        if plot_flag:

            assert section_id is None and section_x is None, \
                "Can not plot if sectionID and sectionX are given"

            input_coords, section_id, section_x, density_function, dist_syn_soma = \
                self.morphology.dendrite_input_locations(synapse_density=synapse_density,
                                                         num_locations=num_synapses,
                                                         return_density=True)

            self.synapse_locations = input_coords
            dist_from_soma = self.morphology.dend[:, 4]

            # plot density function
            plt.figure()
            plt.plot(dist_from_soma * 1e6, density_function, 'o')
            plt.xlabel('distance from soma $(\mu m)$')
            plt.title('density function')
            plt.ion()
            plt.show()

            # plot histogram - distance synapses from soma
            plt.figure()
            plt.hist(dist_syn_soma * 1e6,
                     edgecolor='gray',
                     bins=dist_syn_soma.size)
            plt.xlabel('distance from soma $(\mu m)$')
            plt.ylabel('frequency')
            plt.title('synaptic distance from soma')
            plt.ion()
            plt.show()

        elif section_id is None or section_x is None:

            input_coords, section_id, section_x, dist_syn_soma = \
                self.morphology.dendrite_input_locations(synapse_density=synapse_density,
                                                         num_locations=num_synapses,
                                                         rng=self.rng)

            self.synapse_locations = input_coords

        else:
            self.synapse_locations = "Unknown, you specified sectionX and sectionID, " \
                                     + "but not synapse xyz coordinates."

        # This is so we can find out where the synapses were placed
        self.synapse_section_id = section_id
        self.synapse_section_x = section_x

        sections = self.neuron.map_id_to_compartment(section_id)

        for s, sx in zip(sections, section_x):
            self.add_synapse(synapse_type, s, sx, self.params)

        # Return synapse position if we want to reuse them elsewhere
        return sections, section_x

    ############################################################################

    def add_synapse(self, synapse_type, section, section_x, params):

        section_x = np.maximum(section_x, 1e-6)  # Cant be 0 or 1

        try:
            if synapse_type.lower() == 'glut':
                syn = neuron.h.tmGlut_double(section(section_x))
            elif synapse_type.lower() == "gaba":
                syn = neuron.h.tmGabaA(section(section_x))
            else:
                assert False, f"Unknown synapse type: {synapse_type}"

            self.synapses.append(syn)

        except:
            import traceback
            tstr = traceback.format_exc()
            self.write_log(tstr)

            self.write_log(
                "Did you remember to run nrnivmodl first, to generate channels mod files?"
            )
            exit(-1)

        for p in params:

            # Conductance is set separately, it is a property of netcon
            if p == "cond":
                self.default_cond = params["cond"]
                continue

            val = self.si_to_natural_units(p, params[p])

            setattr(syn, p, val)
            self.write_log(
                f"Setting parameters: {p} = {val} (neuron natural units)")

    ############################################################################

    def connect_input_to_synapses(self, stim_times):

        self.write_log(f"Stimulation times (s): {stim_times}")
        self.nc_syn = []

        self.stim_vector = neuron.h.Vector(stim_times * 1e3)
        self.vec_stim = neuron.h.VecStim()
        self.vec_stim.play(self.stim_vector)

        for syn in self.synapses:
            ncs = neuron.h.NetCon(self.vec_stim, syn)
            ncs.delay = 0
            ncs.threshold = 0
            self.nc_syn.append(ncs)

    ############################################################################

    def soma_record(self):

        self.t_save = neuron.h.Vector()
        self.t_save.record(neuron.h._ref_t)

        self.v_save = neuron.h.Vector()
        self.v_save.record(self.neuron.icell.soma[0](0.5)._ref_v)

    ############################################################################

    def synapse_current_record(self):

        self.i_save = []

        for syn in self.synapses:
            i_rec = neuron.h.Vector()
            i_rec.record(syn._ref_i)
            self.i_save.append(i_rec)

    ############################################################################

    def run(self, tau, tau_r, tau_f, u, cond=None, time=None):

        assert False, "This is the old run method"

        if time is None:
            time = self.time
        else:
            self.time = time

        if cond is None:
            cond = self.default_cond

        # print(vars())

        # print("Running: tau: %.3g, tauR: %.3g, tauF: %.3g, U: %.3g, cond: %.3g\n" \
        #      % (tau,tauR,tauF,U,cond))

        # Convert from SI units to natural units that Neuron uses
        for ncs in self.nc_syn:
            ncs.weight[0] = 1 * cond * 1e6

        for syn in self.synapses:
            syn.tau = tau * 1e3
            syn.tau_r = tau_r * 1e3
            syn.tau_f = tau_f * 1e3
            syn.u = u

        # print(self.littleSynapse.tau)

        # print("Initialise voltage to " + str(self.holdingVoltage*1e3) + " mV")
        neuron.h.finitialize(self.holding_voltage * 1e3)  # OLD : -70
        neuron.h.tstop = time * 1e3

        neuron.h.run()

        # self.tSave.resize()
        # self.vSave.resize()
        # self.iSave.resize()

        if np.array(self.t_save).shape != np.array(self.v_save).shape:
            self.write_log("THIS IS WRONG, should be same shape!!")
            self.write_log(f"size t = {np.array(self.t_save).shape}")
            self.write_log(f"size v = {np.array(self.v_save).shape}")
            import pdb
            pdb.set_trace()

        # print("Last V = " + str(self.vSave[-1]*1e-3))

        # Convert back to SI units
        return (np.array(self.t_save) * 1e-3, np.array(self.v_save) * 1e-3,
                np.array(self.i_save) * 1e-9)

    ############################################################################

    def set_resting_voltage(self, rest_volt):

        self.write_log("Setting resting voltage to %.3f mV" % rest_volt)

        soma = [x for x in self.neuron.icell.soma]
        axon = [x for x in self.neuron.icell.axon]
        dend = [x for x in self.neuron.icell.dend]

        cell = soma + axon + dend

        for sec in cell:
            for seg in sec.allseg():
                seg.v = rest_volt

    ############################################################################

    # I wish Neuron would use natural units...

    def si_to_natural_units(self, var_name, value):

        conv_factor = {
            "U": 1.0,
            "tauR": 1e3,
            "tauF": 1e3,
            "cond": 1e6,
            "tau": 1e3,
            "nmda_ratio": 1.0,
            "tau1_ampa": 1.0,  # Ilaria's file has ms already
            "tau2_ampa": 1.0,  # Ilaria's file has ms already
            "tau3_ampa": 1.0,  # Ilaria's file has ms already
            "tau1_nmda": 1.0,  # Ilaria's file has ms already
            "tau2_nmda": 1.0,  # Ilaria's file has ms already
            "tau3_nmda": 1.0,  # Ilaria's file has ms already
            "tpeak_ampa": 1.0,  # Ilaria's file has ms already
            "tpeak_nmda": 1.0,  # Ilaria's file has ms already :/
            "ratio_nmda": 1.0,
            "I2_ampa": 1.0,  # Ilaria's file has ms already
            "I3_ampa": 1.0,  # Ilaria's file has ms already
            "I2_nmda": 1.0,  # Ilaria's file has ms already
            "I3_nmda": 1.0,  # Ilaria's file has ms already
            "factor_ampa": 1.0,  # Ilaria's file has ms already
            "factor_nmda": 1.0  # Ilaria's file has ms already
        }

        if var_name not in conv_factor:
            self.write_log("Missing conversion fractor for " + str(var_name) \
                           + ". Please update SItoNaturalUnits function.")
            self.write_log("convFactor = " + str(conv_factor))
            import pdb
            pdb.set_trace()

        try:
            return value * conv_factor[var_name]
        except:
            import traceback
            tstr = traceback.format_exc()
            self.write_log(tstr)
            import pdb
            pdb.set_trace()

    ############################################################################
    def plot(self):

        ax = self.morphology.plot_neuron(axon_colour='red',
                                         dend_colour='blue',
                                         soma_colour='green')

        ax.scatter(self.synapse_locations[:, 0],
                   self.synapse_locations[:, 1],
                   self.synapse_locations[:, 2],
                   color='black',
                   marker='o',
                   s=20)
        plt.ion()

        ############################################################################

    # pars = { "tau1" : 0.25e-3 }
    # The code converts to natural units internally, if your parameter is missing
    # then update SItoNaturalUnits

    # OBS, soma parameters are ignored by run2 (they should be set during setup)

    def run2(self, pars, time=None, cond=1e-8):

        self.write_log(f"Running with pars: {pars}")

        if time is None:
            time = self.time
        else:
            self.time = time

        for p in pars:

            if p == "cond":
                cond = self.si_to_natural_units(p, pars[p])

            else:
                v = self.si_to_natural_units(p, pars[p])
                for s in self.synapses:
                    setattr(s, p, v)

        neuron.h.finitialize(self.holding_voltage * 1e3)
        for ncs in self.nc_syn:
            ncs.weight[0] = cond

        self.set_resting_voltage(self.holding_voltage * 1e3)

        neuron.h.v_init = self.holding_voltage * 1e3
        neuron.h.tstop = time * 1e3
        self.write_log("About to start NEURON... stay safe")
        neuron.h.run()
        self.write_log("NEURON actually completed?!")

        # Convert results back to SI units
        return (np.array(self.t_save) * 1e-3, np.array(self.v_save) * 1e-3,
                np.array(self.i_save) * 1e-9)

    ############################################################################

    def write_log(self,
                  text,
                  flush=True):  # Change flush to False in future, debug
        if self.log_file is not None:
            self.log_file.write(text + "\n")

            if self.verbose:
                print(text)

            if flush:
                self.log_file.flush()
        else:
            if self.verbose:
                print(text)
示例#9
0
    def has_axon(swc_file):
        nm = NeuronMorphology(swc_filename=snudda_parse_path(swc_file))

        return len(nm.axon) > 0
示例#10
0
class MyTestCase(unittest.TestCase):

    def setUp(self):

        #swc_file = os.path.join(os.path.dirname(__file__), "validation", "ballanddoublestick", "double.swc")

        swc_file = os.path.join(os.path.dirname(__file__), "validation", "striatum", "fs",
                                "str-fs-e161205_FS1-mMTC180800A-IDB-v20190312", "MTC180800A-IDB-cor-rep.swc")
        self.nm = NeuronMorphology(swc_filename=swc_file, load_morphology=True)

    def test_input_location(self, stage="dist_to_soma"):

        synapse_density = "(d > 100e-6)*1"
        rng = np.random.default_rng(123456)  #

        xyz, sec_id, sec_x, dist_to_soma = self.nm.dendrite_input_locations(synapse_density=synapse_density,
                                                                            rng=rng, num_locations=100)

        # Please note that num_locations currently does not guarantee 100 synpases when requesting it

        # 3e-6 due to compartment length sampled at 3 micrometers
        self.assertTrue((dist_to_soma > 100e-6 - 3e-6).all())

        self.assertEqual(xyz.shape[1], 3)
        self.assertEqual(len(dist_to_soma), xyz.shape[0])
        self.assertEqual(len(dist_to_soma), len(sec_id))
        self.assertEqual(len(sec_id), len(sec_x))

        # Repeat test but for smaller than 100
        synapse_density = "(d < 200e-6)*1"

        xyz, sec_id, sec_x, dist_to_soma = self.nm.dendrite_input_locations(synapse_density=synapse_density,
                                                                            rng=rng, num_locations=100)
        # 3e-6 due to compartment length sampled at 3 micrometers
        self.assertTrue((dist_to_soma < 200e-6 + 3e-6).all())

    def test_rand_rotation(self, stage="rand_rotation"):

        for idx in range(0, 100):
            rot_mat = self.nm.rand_rotation_matrix()
            self.assertAlmostEqual(np.linalg.det(rot_mat), 1, places=10)

    def test_clone(self, stage="clone"):
        new_nm = self.nm.clone()
        
        self.assertTrue((self.nm.dend == new_nm.dend).all())
        self.assertTrue((self.nm.axon == new_nm.axon).all())
        self.assertTrue((self.nm.soma == new_nm.soma).all())

        # Make sure that clone is a copy, and don't point back to same arrays
        ang = np.pi
        R_x = np.array([[1, 0, 0],
                        [0, np.cos(ang), -np.sin(ang)],
                        [0, np.sin(ang), np.cos(ang)]])

        new_nm.place(rotation=R_x, position=np.array([0, 0, 0]))

        self.assertTrue((np.abs(self.nm.dend[:, 0] - new_nm.dend[:, 0]) < 1e-6).all())
        self.assertTrue((np.abs(self.nm.dend[:, 1] + new_nm.dend[:, 1]) < 1e-6).all())
        self.assertTrue((np.abs(self.nm.dend[:, 2] + new_nm.dend[:, 2]) < 1e-6).all())

        self.assertTrue((np.abs(self.nm.axon[:, 0] - new_nm.axon[:, 0]) < 1e-6).all())
        self.assertTrue((np.abs(self.nm.axon[:, 1] + new_nm.axon[:, 1]) < 1e-6).all())
        self.assertTrue((np.abs(self.nm.axon[:, 2] + new_nm.axon[:, 2]) < 1e-6).all())

        new_nm.place(position=np.array([1, 2, 3]))
        self.assertTrue((np.abs(new_nm.soma[0,:3] - np.array([1, 2, 3])) < 1e-6).all())
示例#11
0
    def __init__(
            self,
            neuronMorphology,
            neuronMechanisms,
            neuronParameters,
            neuronModulation,
            stimTimes,
            synapseDensity,
            nSynapses,
            synapseSectionID=None,  # if given, nSynapses is ignored
            synapseSectionX=None,  # same # of elements as synapseSectionID
            neuronParameterID=0,  # Which param set in parameter file to use
            neuronModulationID=0,
            holdingVoltage=-70e-3,
            synapseType='glut',
            params={},
            time=2,
            logFile=None,
            verbose=True,
            rng=None):

        self.logFile = logFile  # File pointer
        self.verbose = verbose

        self.writeLog("Holding voltage: " + str(holdingVoltage) + " V")
        self.writeLog("Stim times: " + str(stimTimes) + " s")
        self.writeLog("Synapse type: " + str(synapseType))

        self.time = time
        self.synapses = []
        self.IClamp = None
        self.ncSyn = None

        # Done in NrnSimulatorParallel
        # neuron.h.load_file('stdrun.hoc')

        self.sim = NrnSimulatorParallel(cvode_active=False)

        # Should we use weak reference for garbage collection? (weakref package)

        # We load the neuron morphology object also, used to place synapses
        self.writeLog("Using morphology: " + str(neuronMorphology))
        self.morphology = NeuronMorphology(swc_filename=neuronMorphology)

        # We need to setup the Neuron model
        self.neuron = NeuronModel(param_file=neuronParameters,
                                  morph_file=neuronMorphology,
                                  mech_file=neuronMechanisms,
                                  cell_name="OptimisationNeuron",
                                  modulation_file=neuronModulation,
                                  parameter_id=neuronParameterID,
                                  modulation_id=neuronModulationID)

        self.neuron.instantiate(sim=self.sim)
        self.setRestingVoltage(holdingVoltage * 1e3)

        neuron.h.celsius = 35

        # gnabar_hh: The maximum specific sodium channel conductance [Default value = 0.120 S/cm2]
        # gkbar_hh: The maximum specific potassium channel conductance [Default value = 0.036 S/cm2]
        # gl_hh: The maximum specific leakage conductance [Default value = 0.0003 S/cm2]
        # ena: The reversal potential for the sodium channel [Default value = 50 mV]
        # ek: The reversal potential for the potassium channel [Default value = -77 mV]
        # el_hh: The reversal potential for the leakage channel [Default value = -54.3 mV]

        # We need to set the params also
        self.params = params
        self.defaultCond = 5e-7
        self.rng = rng

        assert rng, " Code has been updated, rng must be a random number generator, eg. rng = np.random.default_rng(random_seed)"

        self.addSynapseDensity(synapseType,
                               synapseDensity,
                               nSynapses,
                               synapseSectionID,
                               synapseSectionX,
                               rng=self.rng)

        self.stimTimes = stimTimes * 1e3

        # Assumes input in seconds (SI units)
        self.connectInputToSynapses(stimTimes)

        self.somaRecord()
        self.synapseCurrentRecord()

        self.updateHoldingCurrent(holdingVoltage)