Skip to content

Commit

Permalink
Merge branch 'new_conductance_source' of github.com:BlueBrain/neuroda…
Browse files Browse the repository at this point in the history
…mus into new_conductance_source

Conflicts:
	neurodamus/core/stimuli.py
  • Loading branch information
joseph-tharayil committed Apr 10, 2024
2 parents 1aaca21 + 4c1cc6d commit 81b27fd
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 30 deletions.
39 changes: 24 additions & 15 deletions neurodamus/core/stimuli.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ def __init__(self, base_amp=0.0, *, delay=0, rng=None, represents_physical_elect
Args:
base_amp: The base (resting) amplitude of the signal (Default: 0)
rng: The Random Number Generator. Used in the Noise functions
represents_physical_electrode: Whether the source represents a phsyical electrode or missing synaptic input
represents_physical_electrode: Whether the source represents a phsyical
electrode or missing synaptic input
"""
h = Neuron.h
self.stim_vec = h.Vector()
Expand Down Expand Up @@ -369,25 +370,27 @@ def __add__(self, other):
class CurrentSource(SignalSource):
_all_sources = []

def __init__(self, base_amp=0.0, *, delay=0, rng=None):
def __init__(self, base_amp=0.0, *, delay=0, rng=None, physical_electrode=False):
"""
Creates a new current source that injects a signal under IClamp
"""
super().__init__(base_amp, delay=delay, rng=rng)
super().__init__(base_amp, delay=delay, rng=rng,
represents_physical_electrode=physical_electrode)
self._clamps = set()
self._all_sources.append(self)

class _Clamp:
def __init__(self, cell_section, position=0.5, clamp_container=None,
stim_vec_mode=True, time_vec=None, stim_vec=None,
**clamp_params):

# Checks if new MembraneCurrentSource mechanism is available and if source does not represent physical electrode
if self._represents_physical_electrode == False and hasattr(Neuron.h, "MembraneCurrentSource"):
represents_physical_electrode = clamp_params.get('represents_physical_electrode', False)
# Checks if new MembraneCurrentSource mechanism is available and if source does not
# represent physical electrode, otherwise fall back to IClamp.
if not represents_physical_electrode and hasattr(Neuron.h, "MembraneCurrentSource"):
self.clamp = Neuron.h.MembraneCurrentSource(position, sec=cell_section)
else:
self.clamp = Neuron.h.IClamp(position, sec=cell_section)

if stim_vec_mode:
assert time_vec is not None and stim_vec is not None
self.clamp.dur = time_vec[-1]
Expand All @@ -405,8 +408,9 @@ def detach(self):
del self.clamp # Force del on the clamp (there might be references to self)

def attach_to(self, section, position=0.5):
return CurrentSource._Clamp(section, position, self._clamps, True,
self.time_vec, self.stim_vec)
return CurrentSource._Clamp(
section, position, self._clamps, True, self.time_vec, self.stim_vec,
represents_physical_electrode=self._represents_physical_electrode)

# Constant has a special attach_to and doesnt share any composing method
class Constant:
Expand All @@ -426,14 +430,16 @@ def attach_to(self, section, position=0.5):
class ConductanceSource(SignalSource):
_all_sources = []

def __init__(self, reversal=0.0, *, delay=.0, rng=None):
def __init__(self, reversal=0.0, *, delay=.0, rng=None, physical_electrode=False):
"""
Creates a new conductance source that injects a conductance by driving
the rs of an SEClamp at a given reversal potential.
reversal: reversal potential of conductance (mV)
"""
super().__init__(0.0, delay=delay, rng=rng) # set SignalSource's base_amp to zero
# set SignalSource's base_amp to zero
super().__init__(reversal, delay=delay, rng=rng,
represents_physical_electrode=physical_electrode)
self._reversal = reversal # set reversal from base_amp parameter in classmethods
self._clamps = set()
self._all_sources.append(self)
Expand All @@ -442,8 +448,10 @@ class _DynamicClamp:
def __init__(self, cell_section, position=0.5, clamp_container=None,
stim_vec_mode=True, time_vec=None, stim_vec=None,
reversal=0.0, **clamp_params):
# Checks if new conductanceSource mechanism is available and if source does not represent physical electrode
if self._represents_physical_electrode == False and hasattr(Neuron.h, "ConductanceSource"):
represents_physical_electrode = clamp_params.get('represents_physical_electrode', False)
# Checks if new conductanceSource mechanism is available and if source does not
# represent physical electrode, otherwise fall back to SEClamp.
if not represents_physical_electrode and hasattr(Neuron.h, "ConductanceSource"):
self.clamp = Neuron.h.ConductanceSource(position, sec=cell_section)
else:
self.clamp = Neuron.h.SEClamp(position, sec=cell_section)
Expand Down Expand Up @@ -473,8 +481,9 @@ def detach(self):
del self.clamp # Force del on the clamp (there might be references to self)

def attach_to(self, section, position=0.5):
return ConductanceSource._DynamicClamp(section, position, self._clamps, True,
self.time_vec, self.stim_vec, self._reversal)
return ConductanceSource._DynamicClamp(
section, position, self._clamps, True, self.time_vec, self.stim_vec,
self._reversal, represents_physical_electrode=self._represents_physical_electrode)


# EStim class is a derivative of TStim for stimuli with an extracelular electrode. The main
Expand Down
42 changes: 27 additions & 15 deletions neurodamus/stimulus_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,8 @@ class BaseStim:
def __init__(self, _target, stim_info: dict, _cell_manager):
self.duration = float(stim_info["Duration"]) # duration [ms]
self.delay = float(stim_info["Delay"]) # start time [ms]
self.represents_physical_electrode = stim_info.get('represents_physical_electrode', False)

if 'self.represents_physical_electrode' in stim_info.keys():
self.represents_physical_electrode = stim_info['represents_physical_electrode']
else:
self.represents_physical_electrode = False

@StimulusManager.register_type
class OrnsteinUhlenbeck(BaseStim):
Expand Down Expand Up @@ -127,7 +124,10 @@ def __init__(self, target, stim_info: dict, cell_manager):

rng = random.Random123(seed1, seed2, seed3(gid)) # setup RNG
ou_args = (self.tau, self.sigma, self.mean, self.duration)
ou_kwargs = {'dt': self.dt, 'delay': self.delay, 'rng': rng, 'represents_physical_electrode':self.represents_physical_electrode}
ou_kwargs = {
'dt': self.dt, 'delay': self.delay, 'rng': rng,
'represents_physical_electrode': self.represents_physical_electrode
}
# inject Ornstein-Uhlenbeck signal
if stim_info["Mode"] == "Conductance":
cs = ConductanceSource.ornstein_uhlenbeck(*ou_args, **ou_kwargs,
Expand Down Expand Up @@ -256,7 +256,10 @@ def __init__(self, target, stim_info: dict, cell_manager):
rng = random.Random123(seed1, seed2, seed3(gid)) # setup RNG
shotnoise_args = (self.tau_D, self.tau_R, self.rate,
self.amp_mean, self.amp_var, self.duration)
shotnoise_kwargs = {'dt': self.dt, 'delay': self.delay, 'rng': rng, 'represents_physical_electrode':self.represents_physical_electrode}
shotnoise_kwargs = {
'dt': self.dt, 'delay': self.delay, 'rng': rng,
'represents_physical_electrode': self.represents_physical_electrode
}
# generate shot noise current source
if stim_info["Mode"] == "Conductance":
cs = ConductanceSource.shot_noise(*shotnoise_args, **shotnoise_kwargs,
Expand Down Expand Up @@ -458,8 +461,11 @@ def __init__(self, target, stim_info: dict, cell_manager):
continue

# generate ramp current source
cs = CurrentSource.ramp(self.amp_start, self.amp_end, self.duration,
delay=self.delay, represents_physical_electrode=self.represents_physical_electrode)
cs = CurrentSource.ramp(
self.amp_start, self.amp_end, self.duration,
delay=self.delay,
represents_physical_electrode=self.represents_physical_electrode
)
# attach current source to section
cs.attach_to(sc.sec, tpoint_list.x[sec_id])
self.stimList.append(cs) # save CurrentSource
Expand Down Expand Up @@ -584,8 +590,10 @@ def __init__(self, target, stim_info: dict, cell_manager):
continue

# generate noise current source
cs = CurrentSource.noise(self.mean, self.var, self.duration,
dt=self.dt, delay=self.delay, rng=rng, represents_physical_electrode=self.represents_physical_electrode)
cs = CurrentSource.noise(
self.mean, self.var, self.duration, dt=self.dt, delay=self.delay, rng=rng,
represents_physical_electrode=self.represents_physical_electrode
)
# attach current source to section
cs.attach_to(sc.sec, tpoint_list.x[sec_id])
self.stimList.append(cs) # save CurrentSource
Expand Down Expand Up @@ -664,8 +672,11 @@ def __init__(self, target, stim_info: dict, cell_manager):
continue

# generate pulse train current source
cs = CurrentSource.train(self.amp, self.freq, self.width,
self.duration, delay=self.delay,represents_physical_electrode=self.represents_physical_electrode)
cs = CurrentSource.train(
self.amp, self.freq, self.width, self.duration,
delay=self.delay,
represents_physical_electrode=self.represents_physical_electrode
)
# attach current source to section
cs.attach_to(sc.sec, tpoint_list.x[sec_id])
self.stimList.append(cs) # save CurrentSource
Expand Down Expand Up @@ -700,8 +711,10 @@ def __init__(self, target, stim_info: dict, cell_manager):
continue

# generate sinusoidal current source
cs = CurrentSource.sin(self.amp, self.duration, self.freq,
step=self.dt, delay=self.delay,represents_physical_electrode=self.represents_physical_electrode)
cs = CurrentSource.sin(
self.amp, self.duration, self.freq, step=self.dt, delay=self.delay,
represents_physical_electrode=self.represents_physical_electrode
)
# attach current source to section
cs.attach_to(sc.sec, tpoint_list.x[sec_id])
self.stimList.append(cs) # save CurrentSource
Expand Down Expand Up @@ -737,7 +750,6 @@ def __init__(self, target, stim_info: dict, cell_manager):
if not sc.exists():
continue


# create single electrode voltage clamp at location
seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec)

Expand Down

0 comments on commit 81b27fd

Please sign in to comment.