From 73d945d1a17601c70d55eb59728dddf86abc816e Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Tue, 27 Feb 2024 11:32:30 +0100 Subject: [PATCH 01/55] Replaces SEClamp with new conductanceSource point process --- neurodamus/core/stimuli.py | 2 +- neurodamus/stimulus_manager.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 92debf55..6454cd92 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -434,7 +434,7 @@ 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): - self.clamp = Neuron.h.SEClamp(position, sec=cell_section) + self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) if stim_vec_mode: assert time_vec is not None and stim_vec is not None self.clamp.dur1 = time_vec[-1] diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index b89c3cc1..6a765cbe 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -753,7 +753,7 @@ def __init__(self, target, stim_info: dict, cell_manager): continue # create single electrode voltage clamp at location - seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) + seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) seclamp.rs = self.rs seclamp.dur1 = self.duration seclamp.amp1 = self.vhold From b794902c08819bb850ee2645ea52eef6cee826c5 Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Tue, 27 Feb 2024 11:48:02 +0100 Subject: [PATCH 02/55] Checks if conductanceSource point process is available before trying to insert it --- neurodamus/core/stimuli.py | 19 ++++++++++++++++++- neurodamus/stimulus_manager.py | 17 ++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 6454cd92..77348aca 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -434,7 +434,24 @@ 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): - self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) + + + # Check sif new conductanceSource mechanism is available + mt = h.MechanismType(1) + mname = h.ref('') + mList = [] + for i in range(mt.count()): + mt.select(i) + mt.selected(mname) + mList.append(mname[0]) + + if 'conductanceSource' in mList + + self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) + + else: + self.clamp = Neuron.h.SEClamp(position, sec=cell_section) + if stim_vec_mode: assert time_vec is not None and stim_vec is not None self.clamp.dur1 = time_vec[-1] diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 6a765cbe..f0e711c0 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -753,7 +753,22 @@ def __init__(self, target, stim_info: dict, cell_manager): continue # create single electrode voltage clamp at location - seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) + + # Checks if new conductanceSource mechanism is available + mt = h.MechanismType(1) + mname = h.ref('') + mList = [] + for i in range(mt.count()): + mt.select(i) + mt.selected(mname) + mList.append(mname[0]) + + # If conductanceSource not available, insert standard SEClamp + if 'conductanceSource' in mList: + seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) + else: + seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) + seclamp.rs = self.rs seclamp.dur1 = self.duration seclamp.amp1 = self.vhold From a310e18bfe0fc7b46b3795f80d9d63f5aaf3945d Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Tue, 27 Feb 2024 16:04:47 +0100 Subject: [PATCH 03/55] Bug fixes --- neurodamus/core/stimuli.py | 8 ++++---- neurodamus/stimulus_manager.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 77348aca..f9293d95 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -437,16 +437,16 @@ def __init__(self, cell_section, position=0.5, clamp_container=None, # Check sif new conductanceSource mechanism is available - mt = h.MechanismType(1) - mname = h.ref('') + mt = Neuron.h.MechanismType(1) + mname = Neuron.h.ref('') mList = [] for i in range(mt.count()): mt.select(i) mt.selected(mname) mList.append(mname[0]) - if 'conductanceSource' in mList - + if 'conductanceSource' in mList: + self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) else: diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index f0e711c0..424f9051 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -755,8 +755,8 @@ def __init__(self, target, stim_info: dict, cell_manager): # create single electrode voltage clamp at location # Checks if new conductanceSource mechanism is available - mt = h.MechanismType(1) - mname = h.ref('') + mt = Nd.h.MechanismType(1) + mname = Nd.h.ref('') mList = [] for i in range(mt.count()): mt.select(i) From 0c8467d84d12b7663bc7cb12e796c6d676142c61 Mon Sep 17 00:00:00 2001 From: Jorge Blanco Alonso Date: Wed, 28 Feb 2024 11:18:53 +0100 Subject: [PATCH 04/55] Fix flake8 complains --- neurodamus/core/stimuli.py | 11 ++++------- neurodamus/stimulus_manager.py | 9 ++++----- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index f9293d95..0dbf2e66 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -356,7 +356,7 @@ def shot_noise(cls, tau_D, tau_R, rate, amp_mean, var, duration, dt=0.25, base_a @classmethod def ornstein_uhlenbeck(cls, tau, sigma, mean, duration, dt=0.25, base_amp=.0, **kw): - return cls(base_amp, **kw).add_ornstein_uhlenbeck(tau, sigma, mean,duration, dt) + return cls(base_amp, **kw).add_ornstein_uhlenbeck(tau, sigma, mean, duration, dt) # Operations def __add__(self, other): @@ -434,9 +434,8 @@ 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): - - - # Check sif new conductanceSource mechanism is available + + # Checks if new conductanceSource mechanism is available mt = Neuron.h.MechanismType(1) mname = Neuron.h.ref('') mList = [] @@ -444,11 +443,9 @@ def __init__(self, cell_section, position=0.5, clamp_container=None, mt.select(i) mt.selected(mname) mList.append(mname[0]) - - if 'conductanceSource' in mList: + if 'conductanceSource' in mList: self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) - else: self.clamp = Neuron.h.SEClamp(position, sec=cell_section) diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 424f9051..210d793b 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -752,8 +752,6 @@ def __init__(self, target, stim_info: dict, cell_manager): if not sc.exists(): continue - # create single electrode voltage clamp at location - # Checks if new conductanceSource mechanism is available mt = Nd.h.MechanismType(1) mname = Nd.h.ref('') @@ -762,13 +760,14 @@ def __init__(self, target, stim_info: dict, cell_manager): mt.select(i) mt.selected(mname) mList.append(mname[0]) - + # If conductanceSource not available, insert standard SEClamp - if 'conductanceSource' in mList: + if 'conductanceSource' in mList: seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) else: + # create single electrode voltage clamp at location seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) - + seclamp.rs = self.rs seclamp.dur1 = self.duration seclamp.amp1 = self.vhold From b5b2c1ea89cdea6d70c1dd2c2ad33121b6199441 Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Wed, 28 Feb 2024 22:37:40 +0100 Subject: [PATCH 05/55] Uses hasattr() to check if conductanceSource mechanism is available --- neurodamus/core/stimuli.py | 13 ++----------- neurodamus/stimulus_manager.py | 11 +---------- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index f9293d95..bced1294 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -435,17 +435,8 @@ 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): - - # Check sif new conductanceSource mechanism is available - mt = Neuron.h.MechanismType(1) - mname = Neuron.h.ref('') - mList = [] - for i in range(mt.count()): - mt.select(i) - mt.selected(mname) - mList.append(mname[0]) - - if 'conductanceSource' in mList: + # Checks if new conductanceSource mechanism is available + if hasattr(Nd.h,"conductanceSource"): self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 424f9051..dfff350d 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -754,17 +754,8 @@ def __init__(self, target, stim_info: dict, cell_manager): # create single electrode voltage clamp at location - # Checks if new conductanceSource mechanism is available - mt = Nd.h.MechanismType(1) - mname = Nd.h.ref('') - mList = [] - for i in range(mt.count()): - mt.select(i) - mt.selected(mname) - mList.append(mname[0]) - # If conductanceSource not available, insert standard SEClamp - if 'conductanceSource' in mList: + if hasattr(Nd.h,"conductanceSource"): seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) else: seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) From 4177aa22d106cc6d3d7e587d6a604ac356de0548 Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Tue, 27 Feb 2024 11:32:30 +0100 Subject: [PATCH 06/55] Replaces SEClamp with new conductanceSource point process --- neurodamus/core/stimuli.py | 2 +- neurodamus/stimulus_manager.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 92debf55..6454cd92 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -434,7 +434,7 @@ 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): - self.clamp = Neuron.h.SEClamp(position, sec=cell_section) + self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) if stim_vec_mode: assert time_vec is not None and stim_vec is not None self.clamp.dur1 = time_vec[-1] diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 169e7a86..75952279 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -734,7 +734,7 @@ def __init__(self, target, stim_info: dict, cell_manager): continue # create single electrode voltage clamp at location - seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) + seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) seclamp.rs = self.rs seclamp.dur1 = self.duration seclamp.amp1 = self.vhold From a0b4aea33290f1ca3d14bbab9c8ac8e74e46d2a7 Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Tue, 27 Feb 2024 11:48:02 +0100 Subject: [PATCH 07/55] Checks if conductanceSource point process is available before trying to insert it --- neurodamus/core/stimuli.py | 19 ++++++++++++++++++- neurodamus/stimulus_manager.py | 17 ++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 6454cd92..77348aca 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -434,7 +434,24 @@ 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): - self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) + + + # Check sif new conductanceSource mechanism is available + mt = h.MechanismType(1) + mname = h.ref('') + mList = [] + for i in range(mt.count()): + mt.select(i) + mt.selected(mname) + mList.append(mname[0]) + + if 'conductanceSource' in mList + + self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) + + else: + self.clamp = Neuron.h.SEClamp(position, sec=cell_section) + if stim_vec_mode: assert time_vec is not None and stim_vec is not None self.clamp.dur1 = time_vec[-1] diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 75952279..4132e3a2 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -734,7 +734,22 @@ def __init__(self, target, stim_info: dict, cell_manager): continue # create single electrode voltage clamp at location - seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) + + # Checks if new conductanceSource mechanism is available + mt = h.MechanismType(1) + mname = h.ref('') + mList = [] + for i in range(mt.count()): + mt.select(i) + mt.selected(mname) + mList.append(mname[0]) + + # If conductanceSource not available, insert standard SEClamp + if 'conductanceSource' in mList: + seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) + else: + seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) + seclamp.rs = self.rs seclamp.dur1 = self.duration seclamp.amp1 = self.vhold From b78f5a2e1e32d43123b412bbaee3710568d850f7 Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Tue, 27 Feb 2024 16:04:47 +0100 Subject: [PATCH 08/55] Bug fixes --- neurodamus/core/stimuli.py | 8 ++++---- neurodamus/stimulus_manager.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 77348aca..f9293d95 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -437,16 +437,16 @@ def __init__(self, cell_section, position=0.5, clamp_container=None, # Check sif new conductanceSource mechanism is available - mt = h.MechanismType(1) - mname = h.ref('') + mt = Neuron.h.MechanismType(1) + mname = Neuron.h.ref('') mList = [] for i in range(mt.count()): mt.select(i) mt.selected(mname) mList.append(mname[0]) - if 'conductanceSource' in mList - + if 'conductanceSource' in mList: + self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) else: diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 4132e3a2..4ff8a42d 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -736,8 +736,8 @@ def __init__(self, target, stim_info: dict, cell_manager): # create single electrode voltage clamp at location # Checks if new conductanceSource mechanism is available - mt = h.MechanismType(1) - mname = h.ref('') + mt = Nd.h.MechanismType(1) + mname = Nd.h.ref('') mList = [] for i in range(mt.count()): mt.select(i) From 62fd6e2b549eda08353b2b46b1c12652e5e72fd8 Mon Sep 17 00:00:00 2001 From: Jorge Blanco Alonso Date: Wed, 28 Feb 2024 11:18:53 +0100 Subject: [PATCH 09/55] Fix flake8 complains --- neurodamus/core/stimuli.py | 11 ++++------- neurodamus/stimulus_manager.py | 9 ++++----- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index f9293d95..0dbf2e66 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -356,7 +356,7 @@ def shot_noise(cls, tau_D, tau_R, rate, amp_mean, var, duration, dt=0.25, base_a @classmethod def ornstein_uhlenbeck(cls, tau, sigma, mean, duration, dt=0.25, base_amp=.0, **kw): - return cls(base_amp, **kw).add_ornstein_uhlenbeck(tau, sigma, mean,duration, dt) + return cls(base_amp, **kw).add_ornstein_uhlenbeck(tau, sigma, mean, duration, dt) # Operations def __add__(self, other): @@ -434,9 +434,8 @@ 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): - - - # Check sif new conductanceSource mechanism is available + + # Checks if new conductanceSource mechanism is available mt = Neuron.h.MechanismType(1) mname = Neuron.h.ref('') mList = [] @@ -444,11 +443,9 @@ def __init__(self, cell_section, position=0.5, clamp_container=None, mt.select(i) mt.selected(mname) mList.append(mname[0]) - - if 'conductanceSource' in mList: + if 'conductanceSource' in mList: self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) - else: self.clamp = Neuron.h.SEClamp(position, sec=cell_section) diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 4ff8a42d..b508fd01 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -733,8 +733,6 @@ def __init__(self, target, stim_info: dict, cell_manager): if not sc.exists(): continue - # create single electrode voltage clamp at location - # Checks if new conductanceSource mechanism is available mt = Nd.h.MechanismType(1) mname = Nd.h.ref('') @@ -743,13 +741,14 @@ def __init__(self, target, stim_info: dict, cell_manager): mt.select(i) mt.selected(mname) mList.append(mname[0]) - + # If conductanceSource not available, insert standard SEClamp - if 'conductanceSource' in mList: + if 'conductanceSource' in mList: seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) else: + # create single electrode voltage clamp at location seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) - + seclamp.rs = self.rs seclamp.dur1 = self.duration seclamp.amp1 = self.vhold From d477fed9de3b31f46b84792d971d38236b33427d Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Wed, 28 Feb 2024 22:37:40 +0100 Subject: [PATCH 10/55] Uses hasattr() to check if conductanceSource mechanism is available --- neurodamus/core/stimuli.py | 14 +++----------- neurodamus/stimulus_manager.py | 11 +---------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 0dbf2e66..46e81678 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -434,17 +434,9 @@ 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 - mt = Neuron.h.MechanismType(1) - mname = Neuron.h.ref('') - mList = [] - for i in range(mt.count()): - mt.select(i) - mt.selected(mname) - mList.append(mname[0]) - - if 'conductanceSource' in mList: + + # Checks if new conductanceSource mechanism is available + if hasattr(Neuron.h, "conductanceSource"): self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) else: self.clamp = Neuron.h.SEClamp(position, sec=cell_section) diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index b508fd01..8b147b7e 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -733,17 +733,8 @@ def __init__(self, target, stim_info: dict, cell_manager): if not sc.exists(): continue - # Checks if new conductanceSource mechanism is available - mt = Nd.h.MechanismType(1) - mname = Nd.h.ref('') - mList = [] - for i in range(mt.count()): - mt.select(i) - mt.selected(mname) - mList.append(mname[0]) - # If conductanceSource not available, insert standard SEClamp - if 'conductanceSource' in mList: + if hasattr(Nd.h, "conductanceSource"): seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) else: # create single electrode voltage clamp at location From 4572e1effb9fdef8e7874bc837cf7b39d900a008 Mon Sep 17 00:00:00 2001 From: Jorge Blanco Alonso Date: Thu, 29 Feb 2024 13:34:10 +0100 Subject: [PATCH 11/55] Use Neuron.h instead of Nd.h --- neurodamus/core/stimuli.py | 3 +-- neurodamus/stimulus_manager.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 46e81678..739e6cff 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -434,8 +434,7 @@ 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 + # Checks if new conductanceSource mechanism is available if hasattr(Neuron.h, "conductanceSource"): self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) else: diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 8b147b7e..6414adce 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -734,7 +734,7 @@ def __init__(self, target, stim_info: dict, cell_manager): continue # If conductanceSource not available, insert standard SEClamp - if hasattr(Nd.h, "conductanceSource"): + if hasattr(Nd.h, "conductanceSource"): seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) else: # create single electrode voltage clamp at location From 5ed703731a1b343acaddf5856d90f29761adcb5e Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Tue, 27 Feb 2024 11:32:30 +0100 Subject: [PATCH 12/55] Replaces SEClamp with new conductanceSource point process --- neurodamus/core/stimuli.py | 2 +- neurodamus/stimulus_manager.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 92debf55..6454cd92 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -434,7 +434,7 @@ 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): - self.clamp = Neuron.h.SEClamp(position, sec=cell_section) + self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) if stim_vec_mode: assert time_vec is not None and stim_vec is not None self.clamp.dur1 = time_vec[-1] diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 169e7a86..75952279 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -734,7 +734,7 @@ def __init__(self, target, stim_info: dict, cell_manager): continue # create single electrode voltage clamp at location - seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) + seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) seclamp.rs = self.rs seclamp.dur1 = self.duration seclamp.amp1 = self.vhold From 76131a3c08e7ea201a6a8810baa5294f463ff632 Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Tue, 27 Feb 2024 11:48:02 +0100 Subject: [PATCH 13/55] Checks if conductanceSource point process is available before trying to insert it --- neurodamus/core/stimuli.py | 19 ++++++++++++++++++- neurodamus/stimulus_manager.py | 17 ++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 6454cd92..77348aca 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -434,7 +434,24 @@ 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): - self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) + + + # Check sif new conductanceSource mechanism is available + mt = h.MechanismType(1) + mname = h.ref('') + mList = [] + for i in range(mt.count()): + mt.select(i) + mt.selected(mname) + mList.append(mname[0]) + + if 'conductanceSource' in mList + + self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) + + else: + self.clamp = Neuron.h.SEClamp(position, sec=cell_section) + if stim_vec_mode: assert time_vec is not None and stim_vec is not None self.clamp.dur1 = time_vec[-1] diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 75952279..4132e3a2 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -734,7 +734,22 @@ def __init__(self, target, stim_info: dict, cell_manager): continue # create single electrode voltage clamp at location - seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) + + # Checks if new conductanceSource mechanism is available + mt = h.MechanismType(1) + mname = h.ref('') + mList = [] + for i in range(mt.count()): + mt.select(i) + mt.selected(mname) + mList.append(mname[0]) + + # If conductanceSource not available, insert standard SEClamp + if 'conductanceSource' in mList: + seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) + else: + seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) + seclamp.rs = self.rs seclamp.dur1 = self.duration seclamp.amp1 = self.vhold From a01f99cf8936cede6bff6ac21ed822fa4fca01ad Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Tue, 27 Feb 2024 16:04:47 +0100 Subject: [PATCH 14/55] Bug fixes --- neurodamus/core/stimuli.py | 8 ++++---- neurodamus/stimulus_manager.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 77348aca..f9293d95 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -437,16 +437,16 @@ def __init__(self, cell_section, position=0.5, clamp_container=None, # Check sif new conductanceSource mechanism is available - mt = h.MechanismType(1) - mname = h.ref('') + mt = Neuron.h.MechanismType(1) + mname = Neuron.h.ref('') mList = [] for i in range(mt.count()): mt.select(i) mt.selected(mname) mList.append(mname[0]) - if 'conductanceSource' in mList - + if 'conductanceSource' in mList: + self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) else: diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 4132e3a2..4ff8a42d 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -736,8 +736,8 @@ def __init__(self, target, stim_info: dict, cell_manager): # create single electrode voltage clamp at location # Checks if new conductanceSource mechanism is available - mt = h.MechanismType(1) - mname = h.ref('') + mt = Nd.h.MechanismType(1) + mname = Nd.h.ref('') mList = [] for i in range(mt.count()): mt.select(i) From fadf7b13ebcddb9b6d0676377868be2b1df5ae3b Mon Sep 17 00:00:00 2001 From: Jorge Blanco Alonso Date: Wed, 28 Feb 2024 11:18:53 +0100 Subject: [PATCH 15/55] Fix flake8 complains --- neurodamus/core/stimuli.py | 11 ++++------- neurodamus/stimulus_manager.py | 9 ++++----- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index f9293d95..0dbf2e66 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -356,7 +356,7 @@ def shot_noise(cls, tau_D, tau_R, rate, amp_mean, var, duration, dt=0.25, base_a @classmethod def ornstein_uhlenbeck(cls, tau, sigma, mean, duration, dt=0.25, base_amp=.0, **kw): - return cls(base_amp, **kw).add_ornstein_uhlenbeck(tau, sigma, mean,duration, dt) + return cls(base_amp, **kw).add_ornstein_uhlenbeck(tau, sigma, mean, duration, dt) # Operations def __add__(self, other): @@ -434,9 +434,8 @@ 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): - - - # Check sif new conductanceSource mechanism is available + + # Checks if new conductanceSource mechanism is available mt = Neuron.h.MechanismType(1) mname = Neuron.h.ref('') mList = [] @@ -444,11 +443,9 @@ def __init__(self, cell_section, position=0.5, clamp_container=None, mt.select(i) mt.selected(mname) mList.append(mname[0]) - - if 'conductanceSource' in mList: + if 'conductanceSource' in mList: self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) - else: self.clamp = Neuron.h.SEClamp(position, sec=cell_section) diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 4ff8a42d..b508fd01 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -733,8 +733,6 @@ def __init__(self, target, stim_info: dict, cell_manager): if not sc.exists(): continue - # create single electrode voltage clamp at location - # Checks if new conductanceSource mechanism is available mt = Nd.h.MechanismType(1) mname = Nd.h.ref('') @@ -743,13 +741,14 @@ def __init__(self, target, stim_info: dict, cell_manager): mt.select(i) mt.selected(mname) mList.append(mname[0]) - + # If conductanceSource not available, insert standard SEClamp - if 'conductanceSource' in mList: + if 'conductanceSource' in mList: seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) else: + # create single electrode voltage clamp at location seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) - + seclamp.rs = self.rs seclamp.dur1 = self.duration seclamp.amp1 = self.vhold From 3f918f49fdc35e36f98d5a535b22f7287c59f19f Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Wed, 28 Feb 2024 22:37:40 +0100 Subject: [PATCH 16/55] Uses hasattr() to check if conductanceSource mechanism is available --- neurodamus/core/stimuli.py | 14 +++----------- neurodamus/stimulus_manager.py | 11 +---------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 0dbf2e66..46e81678 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -434,17 +434,9 @@ 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 - mt = Neuron.h.MechanismType(1) - mname = Neuron.h.ref('') - mList = [] - for i in range(mt.count()): - mt.select(i) - mt.selected(mname) - mList.append(mname[0]) - - if 'conductanceSource' in mList: + + # Checks if new conductanceSource mechanism is available + if hasattr(Neuron.h, "conductanceSource"): self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) else: self.clamp = Neuron.h.SEClamp(position, sec=cell_section) diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index b508fd01..8b147b7e 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -733,17 +733,8 @@ def __init__(self, target, stim_info: dict, cell_manager): if not sc.exists(): continue - # Checks if new conductanceSource mechanism is available - mt = Nd.h.MechanismType(1) - mname = Nd.h.ref('') - mList = [] - for i in range(mt.count()): - mt.select(i) - mt.selected(mname) - mList.append(mname[0]) - # If conductanceSource not available, insert standard SEClamp - if 'conductanceSource' in mList: + if hasattr(Nd.h, "conductanceSource"): seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) else: # create single electrode voltage clamp at location From 1bec5101170823e147736df9601eaa51006edd89 Mon Sep 17 00:00:00 2001 From: Jorge Blanco Alonso Date: Thu, 29 Feb 2024 13:34:10 +0100 Subject: [PATCH 17/55] Use Neuron.h instead of Nd.h --- neurodamus/core/stimuli.py | 3 +-- neurodamus/stimulus_manager.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 46e81678..739e6cff 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -434,8 +434,7 @@ 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 + # Checks if new conductanceSource mechanism is available if hasattr(Neuron.h, "conductanceSource"): self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) else: diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 8b147b7e..6414adce 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -734,7 +734,7 @@ def __init__(self, target, stim_info: dict, cell_manager): continue # If conductanceSource not available, insert standard SEClamp - if hasattr(Nd.h, "conductanceSource"): + if hasattr(Nd.h, "conductanceSource"): seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) else: # create single electrode voltage clamp at location From 2ab4f9e9ac21d37a9cf0ff70c542d850b7bb918b Mon Sep 17 00:00:00 2001 From: joseph-tharayil Date: Tue, 12 Mar 2024 17:05:14 +0100 Subject: [PATCH 18/55] Update online-lfp.rst Adds warning about SEClamp currents not summing to zero unless the new mod file is used --- docs/online-lfp.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/online-lfp.rst b/docs/online-lfp.rst index 61bb12c7..a862671c 100644 --- a/docs/online-lfp.rst +++ b/docs/online-lfp.rst @@ -140,6 +140,8 @@ Subsequently, an ERROR will be encountered when instantiating the LFP report: To ensure accurate and valid LFP reports, make sure that the electrodes file corresponds to the circuit being used in your simulation. +- **Stimulus Electrode Compatibility**: A common use case is that current will be injected into a population to account for synaptic inputs from neural populations that are not modeled. In this case, it is neccessary that total current over the neuron sums to zero in order to produce valid extracellular recording results. For IClamp electrodes, this is always the case. However, the Neuron SEClamp class does not fulfill this criterion due to numerical issues. We have created a new point process, `new_conductance_source`, available in `neurodamus-neocortex`, which does fulfill the criterion. Therefore, If an SEClamp source is present in the simulation config file, and `new_conductance_source` is compiled, this will be used instead of the SEClamp mechanism. If `new_conductance_source` is not available, SEClamp will be used, and extracellular recording results should not be trusted. + By keeping these considerations in mind, you can ensure a smooth and successful usage of the online LFP calculation feature. Conclusion From d34378654ecae01d8e121fc238ae8c05e8a8b9f0 Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Wed, 10 Apr 2024 13:17:26 +0200 Subject: [PATCH 19/55] Default behavior is for electrodes to input membrane current instead of electrode current --- neurodamus/core/stimuli.py | 16 ++++++++++++---- neurodamus/stimulus_manager.py | 25 +++++++++++++------------ 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 739e6cff..4a64e853 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -10,12 +10,13 @@ class SignalSource: - def __init__(self, base_amp=0.0, *, delay=0, rng=None): + def __init__(self, base_amp=0.0, *, delay=0, rng=None, represents_physical_electrode=False): """ Creates a new signal source, which can create composed signals 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 """ h = Neuron.h self.stim_vec = h.Vector() @@ -23,6 +24,7 @@ def __init__(self, base_amp=0.0, *, delay=0, rng=None): self._cur_t = 0 self._base_amp = base_amp self._rng = rng + self._represents_physical_electrode = represents_physical_electrode if delay > .0: self._add_point(base_amp) self._cur_t = delay @@ -379,7 +381,13 @@ 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): - self.clamp = Neuron.h.IClamp(position, sec=cell_section) + + # 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"): + 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] @@ -434,8 +442,8 @@ 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 - if hasattr(Neuron.h, "conductanceSource"): + # 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"): self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) else: self.clamp = Neuron.h.SEClamp(position, sec=cell_section) diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 6414adce..8aa7546f 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -86,6 +86,10 @@ 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] + 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): @@ -123,7 +127,7 @@ 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} + 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, @@ -252,7 +256,7 @@ 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} + 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, @@ -455,7 +459,7 @@ def __init__(self, target, stim_info: dict, cell_manager): # generate ramp current source cs = CurrentSource.ramp(self.amp_start, self.amp_end, self.duration, - delay=self.delay) + 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 @@ -581,7 +585,7 @@ def __init__(self, target, stim_info: dict, cell_manager): # generate noise current source cs = CurrentSource.noise(self.mean, self.var, self.duration, - dt=self.dt, delay=self.delay, rng=rng) + 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 @@ -661,7 +665,7 @@ def __init__(self, target, stim_info: dict, cell_manager): # generate pulse train current source cs = CurrentSource.train(self.amp, self.freq, self.width, - self.duration, delay=self.delay) + 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 @@ -697,7 +701,7 @@ def __init__(self, target, stim_info: dict, cell_manager): # generate sinusoidal current source cs = CurrentSource.sin(self.amp, self.duration, self.freq, - step=self.dt, delay=self.delay) + 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 @@ -733,12 +737,9 @@ def __init__(self, target, stim_info: dict, cell_manager): if not sc.exists(): continue - # If conductanceSource not available, insert standard SEClamp - if hasattr(Nd.h, "conductanceSource"): - seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) - else: - # create single electrode voltage clamp at location - seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) + + # create single electrode voltage clamp at location + seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) seclamp.rs = self.rs seclamp.dur1 = self.duration From 7d2d93707359d7d400cfc4263a1fbf5f4a46d0dd Mon Sep 17 00:00:00 2001 From: Jorge Blanco Alonso Date: Wed, 10 Apr 2024 15:18:05 +0200 Subject: [PATCH 20/55] fixup! Default behavior is for electrodes to input membrane current instead of electrode current --- neurodamus/core/stimuli.py | 28 ++++++++++++++--------- neurodamus/stimulus_manager.py | 42 ++++++++++++++++++++++------------ 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 4a64e853..88a14247 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -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() @@ -381,13 +382,14 @@ 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] @@ -405,8 +407,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: @@ -442,8 +445,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) @@ -473,8 +478,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 diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 8aa7546f..95f15e88 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -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): @@ -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, @@ -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, @@ -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 @@ -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 @@ -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 @@ -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 @@ -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) From 4c1cc6d1a30b75a7dbb73cb64e7fe44c6432bf16 Mon Sep 17 00:00:00 2001 From: Jorge Blanco Alonso Date: Wed, 10 Apr 2024 15:33:05 +0200 Subject: [PATCH 21/55] fixup! Default behavior is for electrodes to input membrane current instead of electrode current --- neurodamus/core/stimuli.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 88a14247..f4c5c3e1 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -370,11 +370,12 @@ 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) @@ -429,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) From 1aaca2173ef98a9cfb9bba7c08cf6a9843d184f1 Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Wed, 10 Apr 2024 15:52:20 +0200 Subject: [PATCH 22/55] Makes ConductanceSource uppercase --- neurodamus/core/stimuli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 4a64e853..6f5f30ae 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -443,8 +443,8 @@ 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"): - self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) + if self._represents_physical_electrode == False and hasattr(Neuron.h, "ConductanceSource"): + self.clamp = Neuron.h.ConductanceSource(position, sec=cell_section) else: self.clamp = Neuron.h.SEClamp(position, sec=cell_section) From b08ac5376c973a5c75a2c61fa9de1fbdbc71407d Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Tue, 27 Feb 2024 11:32:30 +0100 Subject: [PATCH 23/55] Replaces SEClamp with new conductanceSource point process --- neurodamus/core/stimuli.py | 2 +- neurodamus/stimulus_manager.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 92debf55..6454cd92 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -434,7 +434,7 @@ 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): - self.clamp = Neuron.h.SEClamp(position, sec=cell_section) + self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) if stim_vec_mode: assert time_vec is not None and stim_vec is not None self.clamp.dur1 = time_vec[-1] diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 169e7a86..75952279 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -734,7 +734,7 @@ def __init__(self, target, stim_info: dict, cell_manager): continue # create single electrode voltage clamp at location - seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) + seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) seclamp.rs = self.rs seclamp.dur1 = self.duration seclamp.amp1 = self.vhold From 697c83a40cd610594ccb108eeb72fbd4be646d27 Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Tue, 27 Feb 2024 11:48:02 +0100 Subject: [PATCH 24/55] Checks if conductanceSource point process is available before trying to insert it --- neurodamus/core/stimuli.py | 19 ++++++++++++++++++- neurodamus/stimulus_manager.py | 17 ++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 6454cd92..77348aca 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -434,7 +434,24 @@ 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): - self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) + + + # Check sif new conductanceSource mechanism is available + mt = h.MechanismType(1) + mname = h.ref('') + mList = [] + for i in range(mt.count()): + mt.select(i) + mt.selected(mname) + mList.append(mname[0]) + + if 'conductanceSource' in mList + + self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) + + else: + self.clamp = Neuron.h.SEClamp(position, sec=cell_section) + if stim_vec_mode: assert time_vec is not None and stim_vec is not None self.clamp.dur1 = time_vec[-1] diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 75952279..4132e3a2 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -734,7 +734,22 @@ def __init__(self, target, stim_info: dict, cell_manager): continue # create single electrode voltage clamp at location - seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) + + # Checks if new conductanceSource mechanism is available + mt = h.MechanismType(1) + mname = h.ref('') + mList = [] + for i in range(mt.count()): + mt.select(i) + mt.selected(mname) + mList.append(mname[0]) + + # If conductanceSource not available, insert standard SEClamp + if 'conductanceSource' in mList: + seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) + else: + seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) + seclamp.rs = self.rs seclamp.dur1 = self.duration seclamp.amp1 = self.vhold From f9a4c5f031f6ecc600684b14b6b009f5ec6b327e Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Tue, 27 Feb 2024 16:04:47 +0100 Subject: [PATCH 25/55] Bug fixes --- neurodamus/core/stimuli.py | 8 ++++---- neurodamus/stimulus_manager.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 77348aca..f9293d95 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -437,16 +437,16 @@ def __init__(self, cell_section, position=0.5, clamp_container=None, # Check sif new conductanceSource mechanism is available - mt = h.MechanismType(1) - mname = h.ref('') + mt = Neuron.h.MechanismType(1) + mname = Neuron.h.ref('') mList = [] for i in range(mt.count()): mt.select(i) mt.selected(mname) mList.append(mname[0]) - if 'conductanceSource' in mList - + if 'conductanceSource' in mList: + self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) else: diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 4132e3a2..4ff8a42d 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -736,8 +736,8 @@ def __init__(self, target, stim_info: dict, cell_manager): # create single electrode voltage clamp at location # Checks if new conductanceSource mechanism is available - mt = h.MechanismType(1) - mname = h.ref('') + mt = Nd.h.MechanismType(1) + mname = Nd.h.ref('') mList = [] for i in range(mt.count()): mt.select(i) From d5ff3eb9ab4ac3206200ebd2645b36fd1a4bf585 Mon Sep 17 00:00:00 2001 From: Jorge Blanco Alonso Date: Wed, 28 Feb 2024 11:18:53 +0100 Subject: [PATCH 26/55] Fix flake8 complains --- neurodamus/core/stimuli.py | 11 ++++------- neurodamus/stimulus_manager.py | 9 ++++----- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index f9293d95..0dbf2e66 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -356,7 +356,7 @@ def shot_noise(cls, tau_D, tau_R, rate, amp_mean, var, duration, dt=0.25, base_a @classmethod def ornstein_uhlenbeck(cls, tau, sigma, mean, duration, dt=0.25, base_amp=.0, **kw): - return cls(base_amp, **kw).add_ornstein_uhlenbeck(tau, sigma, mean,duration, dt) + return cls(base_amp, **kw).add_ornstein_uhlenbeck(tau, sigma, mean, duration, dt) # Operations def __add__(self, other): @@ -434,9 +434,8 @@ 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): - - - # Check sif new conductanceSource mechanism is available + + # Checks if new conductanceSource mechanism is available mt = Neuron.h.MechanismType(1) mname = Neuron.h.ref('') mList = [] @@ -444,11 +443,9 @@ def __init__(self, cell_section, position=0.5, clamp_container=None, mt.select(i) mt.selected(mname) mList.append(mname[0]) - - if 'conductanceSource' in mList: + if 'conductanceSource' in mList: self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) - else: self.clamp = Neuron.h.SEClamp(position, sec=cell_section) diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 4ff8a42d..b508fd01 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -733,8 +733,6 @@ def __init__(self, target, stim_info: dict, cell_manager): if not sc.exists(): continue - # create single electrode voltage clamp at location - # Checks if new conductanceSource mechanism is available mt = Nd.h.MechanismType(1) mname = Nd.h.ref('') @@ -743,13 +741,14 @@ def __init__(self, target, stim_info: dict, cell_manager): mt.select(i) mt.selected(mname) mList.append(mname[0]) - + # If conductanceSource not available, insert standard SEClamp - if 'conductanceSource' in mList: + if 'conductanceSource' in mList: seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) else: + # create single electrode voltage clamp at location seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) - + seclamp.rs = self.rs seclamp.dur1 = self.duration seclamp.amp1 = self.vhold From d8c342299fc3c1a24297f8d3ad7ab921fbfca5c1 Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Tue, 27 Feb 2024 11:32:30 +0100 Subject: [PATCH 27/55] Replaces SEClamp with new conductanceSource point process --- neurodamus/core/stimuli.py | 16 +--------------- neurodamus/stimulus_manager.py | 18 ++---------------- 2 files changed, 3 insertions(+), 31 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 0dbf2e66..9109dacb 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -434,21 +434,7 @@ 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 - mt = Neuron.h.MechanismType(1) - mname = Neuron.h.ref('') - mList = [] - for i in range(mt.count()): - mt.select(i) - mt.selected(mname) - mList.append(mname[0]) - - if 'conductanceSource' in mList: - self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) - else: - self.clamp = Neuron.h.SEClamp(position, sec=cell_section) - + self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) if stim_vec_mode: assert time_vec is not None and stim_vec is not None self.clamp.dur1 = time_vec[-1] diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index b508fd01..75952279 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -733,22 +733,8 @@ def __init__(self, target, stim_info: dict, cell_manager): if not sc.exists(): continue - # Checks if new conductanceSource mechanism is available - mt = Nd.h.MechanismType(1) - mname = Nd.h.ref('') - mList = [] - for i in range(mt.count()): - mt.select(i) - mt.selected(mname) - mList.append(mname[0]) - - # If conductanceSource not available, insert standard SEClamp - if 'conductanceSource' in mList: - seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) - else: - # create single electrode voltage clamp at location - seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) - + # create single electrode voltage clamp at location + seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) seclamp.rs = self.rs seclamp.dur1 = self.duration seclamp.amp1 = self.vhold From 9162fcc15a82b78c88efd12869dfb7fcc2637558 Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Tue, 27 Feb 2024 11:48:02 +0100 Subject: [PATCH 28/55] Checks if conductanceSource point process is available before trying to insert it --- neurodamus/core/stimuli.py | 19 ++++++++++++++++++- neurodamus/stimulus_manager.py | 17 ++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 9109dacb..c4a003fe 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -434,7 +434,24 @@ 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): - self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) + + + # Check sif new conductanceSource mechanism is available + mt = h.MechanismType(1) + mname = h.ref('') + mList = [] + for i in range(mt.count()): + mt.select(i) + mt.selected(mname) + mList.append(mname[0]) + + if 'conductanceSource' in mList + + self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) + + else: + self.clamp = Neuron.h.SEClamp(position, sec=cell_section) + if stim_vec_mode: assert time_vec is not None and stim_vec is not None self.clamp.dur1 = time_vec[-1] diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 75952279..4132e3a2 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -734,7 +734,22 @@ def __init__(self, target, stim_info: dict, cell_manager): continue # create single electrode voltage clamp at location - seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) + + # Checks if new conductanceSource mechanism is available + mt = h.MechanismType(1) + mname = h.ref('') + mList = [] + for i in range(mt.count()): + mt.select(i) + mt.selected(mname) + mList.append(mname[0]) + + # If conductanceSource not available, insert standard SEClamp + if 'conductanceSource' in mList: + seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) + else: + seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) + seclamp.rs = self.rs seclamp.dur1 = self.duration seclamp.amp1 = self.vhold From 4e4968d26e4b5e4daa0b8b7449c83b4ed409a994 Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Tue, 27 Feb 2024 16:04:47 +0100 Subject: [PATCH 29/55] Bug fixes --- neurodamus/core/stimuli.py | 8 ++++---- neurodamus/stimulus_manager.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index c4a003fe..713bb8cf 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -437,16 +437,16 @@ def __init__(self, cell_section, position=0.5, clamp_container=None, # Check sif new conductanceSource mechanism is available - mt = h.MechanismType(1) - mname = h.ref('') + mt = Neuron.h.MechanismType(1) + mname = Neuron.h.ref('') mList = [] for i in range(mt.count()): mt.select(i) mt.selected(mname) mList.append(mname[0]) - if 'conductanceSource' in mList - + if 'conductanceSource' in mList: + self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) else: diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 4132e3a2..4ff8a42d 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -736,8 +736,8 @@ def __init__(self, target, stim_info: dict, cell_manager): # create single electrode voltage clamp at location # Checks if new conductanceSource mechanism is available - mt = h.MechanismType(1) - mname = h.ref('') + mt = Nd.h.MechanismType(1) + mname = Nd.h.ref('') mList = [] for i in range(mt.count()): mt.select(i) From 92b517f7603802c9ce59f27702e54096531975e1 Mon Sep 17 00:00:00 2001 From: Jorge Blanco Alonso Date: Wed, 28 Feb 2024 11:18:53 +0100 Subject: [PATCH 30/55] Fix flake8 complains --- neurodamus/core/stimuli.py | 9 +++------ neurodamus/stimulus_manager.py | 9 ++++----- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 713bb8cf..0dbf2e66 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -434,9 +434,8 @@ 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): - - - # Check sif new conductanceSource mechanism is available + + # Checks if new conductanceSource mechanism is available mt = Neuron.h.MechanismType(1) mname = Neuron.h.ref('') mList = [] @@ -444,11 +443,9 @@ def __init__(self, cell_section, position=0.5, clamp_container=None, mt.select(i) mt.selected(mname) mList.append(mname[0]) - - if 'conductanceSource' in mList: + if 'conductanceSource' in mList: self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) - else: self.clamp = Neuron.h.SEClamp(position, sec=cell_section) diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 4ff8a42d..b508fd01 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -733,8 +733,6 @@ def __init__(self, target, stim_info: dict, cell_manager): if not sc.exists(): continue - # create single electrode voltage clamp at location - # Checks if new conductanceSource mechanism is available mt = Nd.h.MechanismType(1) mname = Nd.h.ref('') @@ -743,13 +741,14 @@ def __init__(self, target, stim_info: dict, cell_manager): mt.select(i) mt.selected(mname) mList.append(mname[0]) - + # If conductanceSource not available, insert standard SEClamp - if 'conductanceSource' in mList: + if 'conductanceSource' in mList: seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) else: + # create single electrode voltage clamp at location seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) - + seclamp.rs = self.rs seclamp.dur1 = self.duration seclamp.amp1 = self.vhold From 2115a6ed74d7f98cc97b7b52eeea82fbeb79dfa8 Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Wed, 28 Feb 2024 22:37:40 +0100 Subject: [PATCH 31/55] Uses hasattr() to check if conductanceSource mechanism is available --- neurodamus/core/stimuli.py | 14 +++----------- neurodamus/stimulus_manager.py | 11 +---------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 0dbf2e66..46e81678 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -434,17 +434,9 @@ 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 - mt = Neuron.h.MechanismType(1) - mname = Neuron.h.ref('') - mList = [] - for i in range(mt.count()): - mt.select(i) - mt.selected(mname) - mList.append(mname[0]) - - if 'conductanceSource' in mList: + + # Checks if new conductanceSource mechanism is available + if hasattr(Neuron.h, "conductanceSource"): self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) else: self.clamp = Neuron.h.SEClamp(position, sec=cell_section) diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index b508fd01..8b147b7e 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -733,17 +733,8 @@ def __init__(self, target, stim_info: dict, cell_manager): if not sc.exists(): continue - # Checks if new conductanceSource mechanism is available - mt = Nd.h.MechanismType(1) - mname = Nd.h.ref('') - mList = [] - for i in range(mt.count()): - mt.select(i) - mt.selected(mname) - mList.append(mname[0]) - # If conductanceSource not available, insert standard SEClamp - if 'conductanceSource' in mList: + if hasattr(Nd.h, "conductanceSource"): seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) else: # create single electrode voltage clamp at location From e85a9a59db47fbf2cdb8d8da64f530f13b83568f Mon Sep 17 00:00:00 2001 From: Jorge Blanco Alonso Date: Thu, 29 Feb 2024 13:34:10 +0100 Subject: [PATCH 32/55] Use Neuron.h instead of Nd.h --- neurodamus/core/stimuli.py | 3 +-- neurodamus/stimulus_manager.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 46e81678..739e6cff 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -434,8 +434,7 @@ 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 + # Checks if new conductanceSource mechanism is available if hasattr(Neuron.h, "conductanceSource"): self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) else: diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 8b147b7e..6414adce 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -734,7 +734,7 @@ def __init__(self, target, stim_info: dict, cell_manager): continue # If conductanceSource not available, insert standard SEClamp - if hasattr(Nd.h, "conductanceSource"): + if hasattr(Nd.h, "conductanceSource"): seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) else: # create single electrode voltage clamp at location From 3499d94ae3941c7504becc5667f4f559eba9a591 Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Tue, 27 Feb 2024 11:48:02 +0100 Subject: [PATCH 33/55] Checks if conductanceSource point process is available before trying to insert it --- neurodamus/core/stimuli.py | 16 ++++++++++++++-- neurodamus/stimulus_manager.py | 16 +++++++++++++--- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 739e6cff..c4a003fe 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -434,9 +434,21 @@ 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 - if hasattr(Neuron.h, "conductanceSource"): + + + # Check sif new conductanceSource mechanism is available + mt = h.MechanismType(1) + mname = h.ref('') + mList = [] + for i in range(mt.count()): + mt.select(i) + mt.selected(mname) + mList.append(mname[0]) + + if 'conductanceSource' in mList + self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) + else: self.clamp = Neuron.h.SEClamp(position, sec=cell_section) diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 6414adce..4132e3a2 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -733,13 +733,23 @@ def __init__(self, target, stim_info: dict, cell_manager): if not sc.exists(): continue + # create single electrode voltage clamp at location + + # Checks if new conductanceSource mechanism is available + mt = h.MechanismType(1) + mname = h.ref('') + mList = [] + for i in range(mt.count()): + mt.select(i) + mt.selected(mname) + mList.append(mname[0]) + # If conductanceSource not available, insert standard SEClamp - if hasattr(Nd.h, "conductanceSource"): + if 'conductanceSource' in mList: seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) else: - # create single electrode voltage clamp at location seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) - + seclamp.rs = self.rs seclamp.dur1 = self.duration seclamp.amp1 = self.vhold From 3982126390d3b78cf067d7c568ff5988868b8a55 Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Tue, 27 Feb 2024 16:04:47 +0100 Subject: [PATCH 34/55] Bug fixes --- neurodamus/core/stimuli.py | 8 ++++---- neurodamus/stimulus_manager.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index c4a003fe..713bb8cf 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -437,16 +437,16 @@ def __init__(self, cell_section, position=0.5, clamp_container=None, # Check sif new conductanceSource mechanism is available - mt = h.MechanismType(1) - mname = h.ref('') + mt = Neuron.h.MechanismType(1) + mname = Neuron.h.ref('') mList = [] for i in range(mt.count()): mt.select(i) mt.selected(mname) mList.append(mname[0]) - if 'conductanceSource' in mList - + if 'conductanceSource' in mList: + self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) else: diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 4132e3a2..4ff8a42d 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -736,8 +736,8 @@ def __init__(self, target, stim_info: dict, cell_manager): # create single electrode voltage clamp at location # Checks if new conductanceSource mechanism is available - mt = h.MechanismType(1) - mname = h.ref('') + mt = Nd.h.MechanismType(1) + mname = Nd.h.ref('') mList = [] for i in range(mt.count()): mt.select(i) From 4f3a8a24e80efc237ec10e42ecc6e1058804c3b5 Mon Sep 17 00:00:00 2001 From: Jorge Blanco Alonso Date: Wed, 28 Feb 2024 11:18:53 +0100 Subject: [PATCH 35/55] Fix flake8 complains --- neurodamus/core/stimuli.py | 9 +++------ neurodamus/stimulus_manager.py | 9 ++++----- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 713bb8cf..0dbf2e66 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -434,9 +434,8 @@ 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): - - - # Check sif new conductanceSource mechanism is available + + # Checks if new conductanceSource mechanism is available mt = Neuron.h.MechanismType(1) mname = Neuron.h.ref('') mList = [] @@ -444,11 +443,9 @@ def __init__(self, cell_section, position=0.5, clamp_container=None, mt.select(i) mt.selected(mname) mList.append(mname[0]) - - if 'conductanceSource' in mList: + if 'conductanceSource' in mList: self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) - else: self.clamp = Neuron.h.SEClamp(position, sec=cell_section) diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 4ff8a42d..b508fd01 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -733,8 +733,6 @@ def __init__(self, target, stim_info: dict, cell_manager): if not sc.exists(): continue - # create single electrode voltage clamp at location - # Checks if new conductanceSource mechanism is available mt = Nd.h.MechanismType(1) mname = Nd.h.ref('') @@ -743,13 +741,14 @@ def __init__(self, target, stim_info: dict, cell_manager): mt.select(i) mt.selected(mname) mList.append(mname[0]) - + # If conductanceSource not available, insert standard SEClamp - if 'conductanceSource' in mList: + if 'conductanceSource' in mList: seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) else: + # create single electrode voltage clamp at location seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) - + seclamp.rs = self.rs seclamp.dur1 = self.duration seclamp.amp1 = self.vhold From a2a7cab999372a167b6bce0d56129ec7b7090b9d Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Wed, 28 Feb 2024 22:37:40 +0100 Subject: [PATCH 36/55] Uses hasattr() to check if conductanceSource mechanism is available --- neurodamus/core/stimuli.py | 14 +++----------- neurodamus/stimulus_manager.py | 11 +---------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 0dbf2e66..46e81678 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -434,17 +434,9 @@ 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 - mt = Neuron.h.MechanismType(1) - mname = Neuron.h.ref('') - mList = [] - for i in range(mt.count()): - mt.select(i) - mt.selected(mname) - mList.append(mname[0]) - - if 'conductanceSource' in mList: + + # Checks if new conductanceSource mechanism is available + if hasattr(Neuron.h, "conductanceSource"): self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) else: self.clamp = Neuron.h.SEClamp(position, sec=cell_section) diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index b508fd01..8b147b7e 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -733,17 +733,8 @@ def __init__(self, target, stim_info: dict, cell_manager): if not sc.exists(): continue - # Checks if new conductanceSource mechanism is available - mt = Nd.h.MechanismType(1) - mname = Nd.h.ref('') - mList = [] - for i in range(mt.count()): - mt.select(i) - mt.selected(mname) - mList.append(mname[0]) - # If conductanceSource not available, insert standard SEClamp - if 'conductanceSource' in mList: + if hasattr(Nd.h, "conductanceSource"): seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) else: # create single electrode voltage clamp at location From e6118c98561401b5acdae6a9b3f7f504f23766b8 Mon Sep 17 00:00:00 2001 From: Jorge Blanco Alonso Date: Thu, 29 Feb 2024 13:34:10 +0100 Subject: [PATCH 37/55] Use Neuron.h instead of Nd.h --- neurodamus/core/stimuli.py | 3 +-- neurodamus/stimulus_manager.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 46e81678..739e6cff 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -434,8 +434,7 @@ 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 + # Checks if new conductanceSource mechanism is available if hasattr(Neuron.h, "conductanceSource"): self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) else: diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 8b147b7e..6414adce 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -734,7 +734,7 @@ def __init__(self, target, stim_info: dict, cell_manager): continue # If conductanceSource not available, insert standard SEClamp - if hasattr(Nd.h, "conductanceSource"): + if hasattr(Nd.h, "conductanceSource"): seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) else: # create single electrode voltage clamp at location From 89d7bcacc39b48840d0255d867608361347c854e Mon Sep 17 00:00:00 2001 From: joseph-tharayil Date: Tue, 12 Mar 2024 17:05:14 +0100 Subject: [PATCH 38/55] Update online-lfp.rst Adds warning about SEClamp currents not summing to zero unless the new mod file is used --- docs/online-lfp.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/online-lfp.rst b/docs/online-lfp.rst index 61bb12c7..a862671c 100644 --- a/docs/online-lfp.rst +++ b/docs/online-lfp.rst @@ -140,6 +140,8 @@ Subsequently, an ERROR will be encountered when instantiating the LFP report: To ensure accurate and valid LFP reports, make sure that the electrodes file corresponds to the circuit being used in your simulation. +- **Stimulus Electrode Compatibility**: A common use case is that current will be injected into a population to account for synaptic inputs from neural populations that are not modeled. In this case, it is neccessary that total current over the neuron sums to zero in order to produce valid extracellular recording results. For IClamp electrodes, this is always the case. However, the Neuron SEClamp class does not fulfill this criterion due to numerical issues. We have created a new point process, `new_conductance_source`, available in `neurodamus-neocortex`, which does fulfill the criterion. Therefore, If an SEClamp source is present in the simulation config file, and `new_conductance_source` is compiled, this will be used instead of the SEClamp mechanism. If `new_conductance_source` is not available, SEClamp will be used, and extracellular recording results should not be trusted. + By keeping these considerations in mind, you can ensure a smooth and successful usage of the online LFP calculation feature. Conclusion From eb7cdf87862c508cb1bf3177ec651237302efac5 Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Wed, 10 Apr 2024 13:17:26 +0200 Subject: [PATCH 39/55] Default behavior is for electrodes to input membrane current instead of electrode current --- neurodamus/core/stimuli.py | 16 ++++++++++++---- neurodamus/stimulus_manager.py | 25 +++++++++++++------------ 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 739e6cff..4a64e853 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -10,12 +10,13 @@ class SignalSource: - def __init__(self, base_amp=0.0, *, delay=0, rng=None): + def __init__(self, base_amp=0.0, *, delay=0, rng=None, represents_physical_electrode=False): """ Creates a new signal source, which can create composed signals 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 """ h = Neuron.h self.stim_vec = h.Vector() @@ -23,6 +24,7 @@ def __init__(self, base_amp=0.0, *, delay=0, rng=None): self._cur_t = 0 self._base_amp = base_amp self._rng = rng + self._represents_physical_electrode = represents_physical_electrode if delay > .0: self._add_point(base_amp) self._cur_t = delay @@ -379,7 +381,13 @@ 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): - self.clamp = Neuron.h.IClamp(position, sec=cell_section) + + # 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"): + 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] @@ -434,8 +442,8 @@ 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 - if hasattr(Neuron.h, "conductanceSource"): + # 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"): self.clamp = Neuron.h.conductanceSource(position, sec=cell_section) else: self.clamp = Neuron.h.SEClamp(position, sec=cell_section) diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 6414adce..8aa7546f 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -86,6 +86,10 @@ 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] + 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): @@ -123,7 +127,7 @@ 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} + 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, @@ -252,7 +256,7 @@ 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} + 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, @@ -455,7 +459,7 @@ def __init__(self, target, stim_info: dict, cell_manager): # generate ramp current source cs = CurrentSource.ramp(self.amp_start, self.amp_end, self.duration, - delay=self.delay) + 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 @@ -581,7 +585,7 @@ def __init__(self, target, stim_info: dict, cell_manager): # generate noise current source cs = CurrentSource.noise(self.mean, self.var, self.duration, - dt=self.dt, delay=self.delay, rng=rng) + 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 @@ -661,7 +665,7 @@ def __init__(self, target, stim_info: dict, cell_manager): # generate pulse train current source cs = CurrentSource.train(self.amp, self.freq, self.width, - self.duration, delay=self.delay) + 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 @@ -697,7 +701,7 @@ def __init__(self, target, stim_info: dict, cell_manager): # generate sinusoidal current source cs = CurrentSource.sin(self.amp, self.duration, self.freq, - step=self.dt, delay=self.delay) + 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 @@ -733,12 +737,9 @@ def __init__(self, target, stim_info: dict, cell_manager): if not sc.exists(): continue - # If conductanceSource not available, insert standard SEClamp - if hasattr(Nd.h, "conductanceSource"): - seclamp = Nd.h.conductanceSource(tpoint_list.x[sec_id], sec=sc.sec) - else: - # create single electrode voltage clamp at location - seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) + + # create single electrode voltage clamp at location + seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) seclamp.rs = self.rs seclamp.dur1 = self.duration From 8d11cb24667eea264e4ae7792bd9fde521f10695 Mon Sep 17 00:00:00 2001 From: Jorge Blanco Alonso Date: Wed, 10 Apr 2024 15:18:05 +0200 Subject: [PATCH 40/55] fixup! Default behavior is for electrodes to input membrane current instead of electrode current --- neurodamus/core/stimuli.py | 28 ++++++++++++++--------- neurodamus/stimulus_manager.py | 42 ++++++++++++++++++++++------------ 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 4a64e853..88a14247 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -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() @@ -381,13 +382,14 @@ 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] @@ -405,8 +407,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: @@ -442,8 +445,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) @@ -473,8 +478,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 diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 8aa7546f..95f15e88 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -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): @@ -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, @@ -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, @@ -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 @@ -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 @@ -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 @@ -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 @@ -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) From c282a46250e37c9ced7c91eb4a3aec5213505ac3 Mon Sep 17 00:00:00 2001 From: Jorge Blanco Alonso Date: Wed, 10 Apr 2024 15:33:05 +0200 Subject: [PATCH 41/55] fixup! Default behavior is for electrodes to input membrane current instead of electrode current --- neurodamus/core/stimuli.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index 88a14247..f4c5c3e1 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -370,11 +370,12 @@ 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) @@ -429,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) From 5851c5db234c85d4701d1ee8151c660f76d209be Mon Sep 17 00:00:00 2001 From: Jorge Blanco Alonso Date: Wed, 10 Apr 2024 15:59:50 +0200 Subject: [PATCH 42/55] Change ConductanceSource name --- neurodamus/core/stimuli.py | 4 ++-- neurodamus/stimulus_manager.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/neurodamus/core/stimuli.py b/neurodamus/core/stimuli.py index f4c5c3e1..c9bc0118 100644 --- a/neurodamus/core/stimuli.py +++ b/neurodamus/core/stimuli.py @@ -451,8 +451,8 @@ def __init__(self, cell_section, position=0.5, clamp_container=None, 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) + 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) diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index 95f15e88..b0f79ad6 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -464,7 +464,7 @@ def __init__(self, target, stim_info: dict, cell_manager): cs = CurrentSource.ramp( self.amp_start, self.amp_end, self.duration, delay=self.delay, - represents_physical_electrode=self.represents_physical_electrode + physical_electrode=self.represents_physical_electrode ) # attach current source to section cs.attach_to(sc.sec, tpoint_list.x[sec_id]) @@ -592,7 +592,7 @@ def __init__(self, target, stim_info: dict, cell_manager): # 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 + physical_electrode=self.represents_physical_electrode ) # attach current source to section cs.attach_to(sc.sec, tpoint_list.x[sec_id]) @@ -675,7 +675,7 @@ def __init__(self, target, stim_info: dict, cell_manager): cs = CurrentSource.train( self.amp, self.freq, self.width, self.duration, delay=self.delay, - represents_physical_electrode=self.represents_physical_electrode + physical_electrode=self.represents_physical_electrode ) # attach current source to section cs.attach_to(sc.sec, tpoint_list.x[sec_id]) @@ -713,7 +713,7 @@ def __init__(self, target, stim_info: dict, cell_manager): # 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 + physical_electrode=self.represents_physical_electrode ) # attach current source to section cs.attach_to(sc.sec, tpoint_list.x[sec_id]) From c4030936d61185bf4f12a05c0993e73010f43c0f Mon Sep 17 00:00:00 2001 From: Jorge Blanco Alonso Date: Wed, 10 Apr 2024 16:15:16 +0200 Subject: [PATCH 43/55] Fix parameter name --- neurodamus/stimulus_manager.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index b0f79ad6..40f44f29 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -126,7 +126,7 @@ def __init__(self, target, stim_info: dict, cell_manager): 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 + 'physical_electrode': self.represents_physical_electrode } # inject Ornstein-Uhlenbeck signal if stim_info["Mode"] == "Conductance": @@ -258,7 +258,7 @@ def __init__(self, target, stim_info: dict, cell_manager): 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 + 'physical_electrode': self.represents_physical_electrode } # generate shot noise current source if stim_info["Mode"] == "Conductance": @@ -752,7 +752,6 @@ def __init__(self, target, stim_info: dict, cell_manager): # create single electrode voltage clamp at location seclamp = Nd.h.SEClamp(tpoint_list.x[sec_id], sec=sc.sec) - seclamp.rs = self.rs seclamp.dur1 = self.duration seclamp.amp1 = self.vhold From 1a42a94c3bb7f9a10a953ff618fb2dbd91d3b967 Mon Sep 17 00:00:00 2001 From: Jorge Blanco Alonso Date: Thu, 11 Apr 2024 15:31:16 +0200 Subject: [PATCH 44/55] Stimulus keys are in CamelCase --- neurodamus/stimulus_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neurodamus/stimulus_manager.py b/neurodamus/stimulus_manager.py index b57a1377..2b40b8a3 100644 --- a/neurodamus/stimulus_manager.py +++ b/neurodamus/stimulus_manager.py @@ -85,7 +85,7 @@ 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) + self.represents_physical_electrode = stim_info.get('RepresentsPhysicalElectrode', False) @StimulusManager.register_type From 46682c449f69cf1d6b153cc443748377390f5510 Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Mon, 15 Apr 2024 18:04:53 +0200 Subject: [PATCH 45/55] Adds test for new stimulus sources --- tests/scientific/test_stimulus_injection.py | 64 ++++++++++++++++ .../stimulus_injection/circuit_config.json | 30 ++++++++ .../simulation_config_conductancesource.json | 74 +++++++++++++++++++ .../simulation_config_iclamp.json | 73 ++++++++++++++++++ ...mulation_config_membranecurrentsource.json | 73 ++++++++++++++++++ .../simulation_config_seclamp.json | 74 +++++++++++++++++++ 6 files changed, 388 insertions(+) create mode 100644 tests/scientific/test_stimulus_injection.py create mode 100644 tests/simulations/stimulus_injection/circuit_config.json create mode 100644 tests/simulations/stimulus_injection/simulation_config_conductancesource.json create mode 100644 tests/simulations/stimulus_injection/simulation_config_iclamp.json create mode 100644 tests/simulations/stimulus_injection/simulation_config_membranecurrentsource.json create mode 100644 tests/simulations/stimulus_injection/simulation_config_seclamp.json diff --git a/tests/scientific/test_stimulus_injection.py b/tests/scientific/test_stimulus_injection.py new file mode 100644 index 00000000..621dd265 --- /dev/null +++ b/tests/scientific/test_stimulus_injection.py @@ -0,0 +1,64 @@ +import pytest +import h5py +import os +import numpy as np +from pathlib import Path + +SIM_DIR = Path(__file__).parent.parent.absolute() / "simulations" / "stimulus_injection" + +# Read the soma report and return a list with the voltages +def _read_sonata_soma_report(report_name): + import libsonata + report = libsonata.SomaReportReader(report_name) + pop_name = report.get_population_names()[0] + ids = report[pop_name].get_node_ids() + data = report[pop_name].get(node_ids=[ids[0]]) + return numpy.array(data.data).flatten().tolist() + +def test_current_injection_coreneuron(): + + from neurodamus import Neurodamus + from neurodamus.replay import SpikeManager + + config_file = str(SIM_DIR / "simulation_config_iclamp.json") + os.chdir(SIM_DIR) + nd = Neurodamus(config_file, disable_reports=False, simulator="CORENEURON", + output_path="output_coreneuron") + nd.run() + + soma_report_path = os.path.join(nd._run_conf["OutputRoot"], "voltage.h5") + voltage_vec_iclamp = _read_sonata_soma_report(soma_report_path) + + config_file = str(SIM_DIR / "simulation_config_membranecurrentsource.json") + os.chdir(SIM_DIR) + nd = Neurodamus(config_file, disable_reports=False, simulator="CORENEURON", + output_path="output_coreneuron") + nd.run() + + soma_report_path = os.path.join(nd._run_conf["OutputRoot"], "voltage.h5") + voltage_vec_membranecurrentsource = _read_sonata_soma_report(soma_report_path) + +def test_conductance_injection_coreneuron(): + + from neurodamus import Neurodamus + from neurodamus.replay import SpikeManager + + config_file = str(SIM_DIR / "simulation_config_seclamp.json") + os.chdir(SIM_DIR) + nd = Neurodamus(config_file, disable_reports=False, simulator="CORENEURON", + output_path="output_coreneuron") + nd.run() + + soma_report_path = os.path.join(nd._run_conf["OutputRoot"], "voltage.h5") + voltage_vec_seclamp = _read_sonata_soma_report(soma_report_path) + + config_file = str(SIM_DIR / "simulation_config_conductancesource.json") + os.chdir(SIM_DIR) + nd = Neurodamus(config_file, disable_reports=False, simulator="CORENEURON", + output_path="output_coreneuron") + nd.run() + + soma_report_path = os.path.join(nd._run_conf["OutputRoot"], "voltage.h5") + voltage_vec_conductancesource = _read_sonata_soma_report(soma_report_path) + + diff --git a/tests/simulations/stimulus_injection/circuit_config.json b/tests/simulations/stimulus_injection/circuit_config.json new file mode 100644 index 00000000..16735200 --- /dev/null +++ b/tests/simulations/stimulus_injection/circuit_config.json @@ -0,0 +1,30 @@ +{ + "manifest": { + "$BASE_DIR": "/gpfs/bbp.cscs.ch/project/proj83/tharayil/generationCode/create_lfp_weights_for_neurodamus/examples/compare-to-reference-solutions/data/simulation/configuration", + "$NETWORK_NODES_DIR": "$BASE_DIR/networks/nodes", + "$NETWORK_EDGES_DIR":"$BASE_DIR/networks/edges", + "$MORPHOLOGIES": "$BASE_DIR/components/morphologies" + }, + "components": { + "morphologies_dir": "$MORPHOLOGIES", + "biophysical_neuron_models_dir": "$BASE_DIR/components/biophysical_model_templates" + }, + "node_sets_file": "$BASE_DIR/node_sets.json", + "networks": { + "nodes": [ + { + "nodes_file": "$NETWORK_NODES_DIR/S1nonbarrel_neurons/nodes.h5", + "populations": { + "S1nonbarrel_neurons": { + "alternate_morphologies": { + "neurolucida-asc": "$MORPHOLOGIES/ascii" + }, + "type": "biophysical" + } + } + } + ], + "edges": [ + ] + } +} diff --git a/tests/simulations/stimulus_injection/simulation_config_conductancesource.json b/tests/simulations/stimulus_injection/simulation_config_conductancesource.json new file mode 100644 index 00000000..b5fa04ad --- /dev/null +++ b/tests/simulations/stimulus_injection/simulation_config_conductancesource.json @@ -0,0 +1,74 @@ +{ + "run": { + "dt": 0.025, + "tstop": 100, + "random_seed": 851, + "run_mode":"WholeCell", + "integration_method":2 + }, + + "conditions": { + "extracellular_calcium": 1.05, + "v_init": -80.0, + "spike_location": "AIS", + "mechanisms": { + "ProbAMPANMDA_EMS": { + "init_depleted": true, + "minis_single_vesicle": true + }, + "ProbGABAAB_EMS": { + "init_depleted": true, + "minis_single_vesicle": true + } + } + }, + + "target_simulator": "CORENEURON", + "network": "circuit_config.json", + "node_set": "Cell", + "output": { + "output_dir": "output_sonata" + }, + + "inputs": { + "Stimulus2": { + "input_type": "conductance", + "module": "ornstein_uhlenbeck", + "mean":0.05, + "sigma":0.01, + "tau":0.1, + "delay":50, + "duration":2100, + "node_set": "Cell", + "represents_physical_electrode":false + } + + }, + + "reports": { + + "current": { + "type": "summation", + "cells": "Cell", + "sections": "all", + "variable_name": "i_membrane", + "unit":"nA", + "dt": 0.025, + "start_time": 0.0, + "end_time": 5000.0 + }, + + "voltage":{ + "type":"compartment", + "cells":"Cell", + "variable_name":"v", + "sections":"all", + "unit":"mV", + "dt":0.025, + "start_time":0.0, + "end_time":5000 + } + + } + +} diff --git a/tests/simulations/stimulus_injection/simulation_config_iclamp.json b/tests/simulations/stimulus_injection/simulation_config_iclamp.json new file mode 100644 index 00000000..dc78e4a1 --- /dev/null +++ b/tests/simulations/stimulus_injection/simulation_config_iclamp.json @@ -0,0 +1,73 @@ +{ + "run": { + "dt": 0.025, + "tstop": 100, + "random_seed": 851, + "run_mode":"WholeCell", + "integration_method":2 + }, + + "conditions": { + "extracellular_calcium": 1.05, + "v_init": -80.0, + "spike_location": "AIS", + "mechanisms": { + "ProbAMPANMDA_EMS": { + "init_depleted": true, + "minis_single_vesicle": true + }, + "ProbGABAAB_EMS": { + "init_depleted": true, + "minis_single_vesicle": true + } + } + }, + + "target_simulator": "CORENEURON", + "network": "circuit_config.json", + "node_set": "Cell", + "output": { + "output_dir": "_output_sonata" + }, + + "inputs": { + "Stimulus2": { + "input_type": "current_clamp", + "module": "noise", + "mean":0.05, + "variance":0.01, + "delay": 50, + "duration": 2100, + "node_set": "Cell", + "represents_physical_electrode":false + } + + }, + + "reports": { + + "current": { + "type": "summation", + "cells": "Cell", + "sections": "all", + "variable_name": "i_membrane", + "unit":"nA", + "dt": 0.025, + "start_time": 0.0, + "end_time": 5000.0 + }, + + "voltage":{ + "type":"compartment", + "cells":"Cell", + "variable_name":"v", + "sections":"all", + "unit":"mV", + "dt":0.025, + "start_time":0.0, + "end_time":5000 + } + + } + +} diff --git a/tests/simulations/stimulus_injection/simulation_config_membranecurrentsource.json b/tests/simulations/stimulus_injection/simulation_config_membranecurrentsource.json new file mode 100644 index 00000000..6ed18749 --- /dev/null +++ b/tests/simulations/stimulus_injection/simulation_config_membranecurrentsource.json @@ -0,0 +1,73 @@ +{ + "run": { + "dt": 0.025, + "tstop": 100, + "random_seed": 851, + "run_mode":"WholeCell", + "integration_method":2 + }, + + "conditions": { + "extracellular_calcium": 1.05, + "v_init": -80.0, + "spike_location": "AIS", + "mechanisms": { + "ProbAMPANMDA_EMS": { + "init_depleted": true, + "minis_single_vesicle": true + }, + "ProbGABAAB_EMS": { + "init_depleted": true, + "minis_single_vesicle": true + } + } + }, + + "target_simulator": "CORENEURON", + "network": "circuit_config.json", + "node_set": "Cell", + "output": { + "output_dir": "output_sonata" + }, + + "inputs": { + "Stimulus2": { + "input_type": "current_clamp", + "module": "noise", + "mean":0.05, + "variance":0.01, + "delay":50, + "duration":2100, + "node_set": "Cell", + "represents_physical_electrode":true + } + + }, + + "reports": { + + "current": { + "type": "summation", + "cells": "Cell", + "sections": "all", + "variable_name": "i_membrane", + "unit":"nA", + "dt": 0.025, + "start_time": 0.0, + "end_time": 5000.0 + }, + + "voltage":{ + "type":"compartment", + "cells":"Cell", + "variable_name":"v", + "sections":"all", + "unit":"mV", + "dt":0.025, + "start_time":0.0, + "end_time":5000 + } + + } + +} diff --git a/tests/simulations/stimulus_injection/simulation_config_seclamp.json b/tests/simulations/stimulus_injection/simulation_config_seclamp.json new file mode 100644 index 00000000..79e2a3a0 --- /dev/null +++ b/tests/simulations/stimulus_injection/simulation_config_seclamp.json @@ -0,0 +1,74 @@ +{ + "run": { + "dt": 0.025, + "tstop": 100, + "random_seed": 851, + "run_mode":"WholeCell", + "integration_method":2 + }, + + "conditions": { + "extracellular_calcium": 1.05, + "v_init": -80.0, + "spike_location": "AIS", + "mechanisms": { + "ProbAMPANMDA_EMS": { + "init_depleted": true, + "minis_single_vesicle": true + }, + "ProbGABAAB_EMS": { + "init_depleted": true, + "minis_single_vesicle": true + } + } + }, + + "target_simulator": "CORENEURON", + "network": "circuit_config.json", + "node_set": "Cell", + "output": { + "output_dir": "output_sonata" + }, + + "inputs": { + "Stimulus2": { + "input_type": "conductance", + "module": "ornstein_uhlenbeck", + "mean":0.05, + "sigma":0.01, + "tau":0.1, + "delay":50, + "duration":2100, + "node_set": "Cell", + "represents_physical_electrode":true + } + + }, + + "reports": { + + "current": { + "type": "summation", + "cells": "Cell", + "sections": "all", + "variable_name": "i_membrane", + "unit":"nA", + "dt": 0.025, + "start_time": 0.0, + "end_time": 5000.0 + }, + + "voltage":{ + "type":"compartment", + "cells":"Cell", + "variable_name":"v", + "sections":"all", + "unit":"mV", + "dt":0.025, + "start_time":0.0, + "end_time":5000 + } + + } + +} From 83c7c613d84d7d87d3ba9be61878483353ea29e2 Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Mon, 15 Apr 2024 18:54:22 +0200 Subject: [PATCH 46/55] Bugfix --- tests/scientific/test_stimulus_injection.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/scientific/test_stimulus_injection.py b/tests/scientific/test_stimulus_injection.py index 621dd265..8440d2d8 100644 --- a/tests/scientific/test_stimulus_injection.py +++ b/tests/scientific/test_stimulus_injection.py @@ -38,6 +38,8 @@ def test_current_injection_coreneuron(): soma_report_path = os.path.join(nd._run_conf["OutputRoot"], "voltage.h5") voltage_vec_membranecurrentsource = _read_sonata_soma_report(soma_report_path) + numpy.testing.assert_equal(voltage_vec_iclamp,voltage_vec_membranecurrentsource) + def test_conductance_injection_coreneuron(): from neurodamus import Neurodamus @@ -61,4 +63,4 @@ def test_conductance_injection_coreneuron(): soma_report_path = os.path.join(nd._run_conf["OutputRoot"], "voltage.h5") voltage_vec_conductancesource = _read_sonata_soma_report(soma_report_path) - + numpy.testing.assert_equal(voltage_vec_seclamp,voltage_vec_conductancesource) From 7ced8cfdd0816d3cc0214f882fafb27b6cbbe42a Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Mon, 15 Apr 2024 21:53:55 +0200 Subject: [PATCH 47/55] Minor bugfixes --- tests/scientific/test_stimulus_injection.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/scientific/test_stimulus_injection.py b/tests/scientific/test_stimulus_injection.py index 8440d2d8..be256b10 100644 --- a/tests/scientific/test_stimulus_injection.py +++ b/tests/scientific/test_stimulus_injection.py @@ -1,11 +1,10 @@ import pytest import h5py import os -import numpy as np +import numpy from pathlib import Path SIM_DIR = Path(__file__).parent.parent.absolute() / "simulations" / "stimulus_injection" - # Read the soma report and return a list with the voltages def _read_sonata_soma_report(report_name): import libsonata @@ -16,7 +15,7 @@ def _read_sonata_soma_report(report_name): return numpy.array(data.data).flatten().tolist() def test_current_injection_coreneuron(): - + from neurodamus import Neurodamus from neurodamus.replay import SpikeManager @@ -24,13 +23,13 @@ def test_current_injection_coreneuron(): os.chdir(SIM_DIR) nd = Neurodamus(config_file, disable_reports=False, simulator="CORENEURON", output_path="output_coreneuron") + nd.run() soma_report_path = os.path.join(nd._run_conf["OutputRoot"], "voltage.h5") voltage_vec_iclamp = _read_sonata_soma_report(soma_report_path) - + # config_file = str(SIM_DIR / "simulation_config_membranecurrentsource.json") - os.chdir(SIM_DIR) nd = Neurodamus(config_file, disable_reports=False, simulator="CORENEURON", output_path="output_coreneuron") nd.run() @@ -41,7 +40,7 @@ def test_current_injection_coreneuron(): numpy.testing.assert_equal(voltage_vec_iclamp,voltage_vec_membranecurrentsource) def test_conductance_injection_coreneuron(): - + from neurodamus import Neurodamus from neurodamus.replay import SpikeManager @@ -55,7 +54,6 @@ def test_conductance_injection_coreneuron(): voltage_vec_seclamp = _read_sonata_soma_report(soma_report_path) config_file = str(SIM_DIR / "simulation_config_conductancesource.json") - os.chdir(SIM_DIR) nd = Neurodamus(config_file, disable_reports=False, simulator="CORENEURON", output_path="output_coreneuron") nd.run() From bbc107920e25db274bb13ec270c81a7ff234e7c2 Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Mon, 15 Apr 2024 22:59:11 +0200 Subject: [PATCH 48/55] Fixes bugs in stimulus test --- .gitignore | 5 +++++ tests/scientific/test_stimulus_injection.py | 22 +++++++++---------- .../simulation_config_conductancesource.json | 6 ++--- .../simulation_config_iclamp.json | 6 ++--- ...mulation_config_membranecurrentsource.json | 6 ++--- .../simulation_config_seclamp.json | 6 ++--- 6 files changed, 24 insertions(+), 27 deletions(-) diff --git a/.gitignore b/.gitignore index c72761b0..817befa6 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,11 @@ __pycache__/* */.ipynb_checkpoints/* .vscode spack-* +.ipynb_checkpoints +*.SUCCESS +output_coreneuron* +._* +.DS_Store # Project files .ropeproject diff --git a/tests/scientific/test_stimulus_injection.py b/tests/scientific/test_stimulus_injection.py index be256b10..2c285422 100644 --- a/tests/scientific/test_stimulus_injection.py +++ b/tests/scientific/test_stimulus_injection.py @@ -12,7 +12,7 @@ def _read_sonata_soma_report(report_name): pop_name = report.get_population_names()[0] ids = report[pop_name].get_node_ids() data = report[pop_name].get(node_ids=[ids[0]]) - return numpy.array(data.data).flatten().tolist() + return numpy.array(data.data).flatten() def test_current_injection_coreneuron(): @@ -22,7 +22,7 @@ def test_current_injection_coreneuron(): config_file = str(SIM_DIR / "simulation_config_iclamp.json") os.chdir(SIM_DIR) nd = Neurodamus(config_file, disable_reports=False, simulator="CORENEURON", - output_path="output_coreneuron") + output_path="output_coreneuron_iclamp") nd.run() @@ -30,11 +30,11 @@ def test_current_injection_coreneuron(): voltage_vec_iclamp = _read_sonata_soma_report(soma_report_path) # config_file = str(SIM_DIR / "simulation_config_membranecurrentsource.json") - nd = Neurodamus(config_file, disable_reports=False, simulator="CORENEURON", - output_path="output_coreneuron") - nd.run() + nd2 = Neurodamus(config_file, disable_reports=False, simulator="CORENEURON", + output_path="output_coreneuron_membranecurrentsource") + nd2.run() - soma_report_path = os.path.join(nd._run_conf["OutputRoot"], "voltage.h5") + soma_report_path = os.path.join(nd2._run_conf["OutputRoot"], "voltage.h5") voltage_vec_membranecurrentsource = _read_sonata_soma_report(soma_report_path) numpy.testing.assert_equal(voltage_vec_iclamp,voltage_vec_membranecurrentsource) @@ -47,18 +47,18 @@ def test_conductance_injection_coreneuron(): config_file = str(SIM_DIR / "simulation_config_seclamp.json") os.chdir(SIM_DIR) nd = Neurodamus(config_file, disable_reports=False, simulator="CORENEURON", - output_path="output_coreneuron") + output_path="output_coreneuron_seclamp") nd.run() soma_report_path = os.path.join(nd._run_conf["OutputRoot"], "voltage.h5") voltage_vec_seclamp = _read_sonata_soma_report(soma_report_path) config_file = str(SIM_DIR / "simulation_config_conductancesource.json") - nd = Neurodamus(config_file, disable_reports=False, simulator="CORENEURON", - output_path="output_coreneuron") - nd.run() + nd2 = Neurodamus(config_file, disable_reports=False, simulator="CORENEURON", + output_path="output_coreneuron_conductancesource") + nd2.run() - soma_report_path = os.path.join(nd._run_conf["OutputRoot"], "voltage.h5") + soma_report_path = os.path.join(nd2._run_conf["OutputRoot"], "voltage.h5") voltage_vec_conductancesource = _read_sonata_soma_report(soma_report_path) numpy.testing.assert_equal(voltage_vec_seclamp,voltage_vec_conductancesource) diff --git a/tests/simulations/stimulus_injection/simulation_config_conductancesource.json b/tests/simulations/stimulus_injection/simulation_config_conductancesource.json index b5fa04ad..70bc20d1 100644 --- a/tests/simulations/stimulus_injection/simulation_config_conductancesource.json +++ b/tests/simulations/stimulus_injection/simulation_config_conductancesource.json @@ -1,7 +1,7 @@ { "run": { "dt": 0.025, - "tstop": 100, + "tstop": 10, "random_seed": 851, "run_mode":"WholeCell", "integration_method":2 @@ -37,7 +37,7 @@ "mean":0.05, "sigma":0.01, "tau":0.1, - "delay":50, + "delay":5, "duration":2100, "node_set": "Cell", "represents_physical_electrode":false @@ -50,7 +50,6 @@ "current": { "type": "summation", "cells": "Cell", - "sections": "all", "variable_name": "i_membrane", "unit":"nA", "dt": 0.025, @@ -62,7 +61,6 @@ "type":"compartment", "cells":"Cell", "variable_name":"v", - "sections":"all", "unit":"mV", "dt":0.025, "start_time":0.0, diff --git a/tests/simulations/stimulus_injection/simulation_config_iclamp.json b/tests/simulations/stimulus_injection/simulation_config_iclamp.json index dc78e4a1..3faab2dd 100644 --- a/tests/simulations/stimulus_injection/simulation_config_iclamp.json +++ b/tests/simulations/stimulus_injection/simulation_config_iclamp.json @@ -1,7 +1,7 @@ { "run": { "dt": 0.025, - "tstop": 100, + "tstop": 10, "random_seed": 851, "run_mode":"WholeCell", "integration_method":2 @@ -36,7 +36,7 @@ "module": "noise", "mean":0.05, "variance":0.01, - "delay": 50, + "delay": 5, "duration": 2100, "node_set": "Cell", "represents_physical_electrode":false @@ -49,7 +49,6 @@ "current": { "type": "summation", "cells": "Cell", - "sections": "all", "variable_name": "i_membrane", "unit":"nA", "dt": 0.025, @@ -61,7 +60,6 @@ "type":"compartment", "cells":"Cell", "variable_name":"v", - "sections":"all", "unit":"mV", "dt":0.025, "start_time":0.0, diff --git a/tests/simulations/stimulus_injection/simulation_config_membranecurrentsource.json b/tests/simulations/stimulus_injection/simulation_config_membranecurrentsource.json index 6ed18749..5c5b1be2 100644 --- a/tests/simulations/stimulus_injection/simulation_config_membranecurrentsource.json +++ b/tests/simulations/stimulus_injection/simulation_config_membranecurrentsource.json @@ -1,7 +1,7 @@ { "run": { "dt": 0.025, - "tstop": 100, + "tstop": 10, "random_seed": 851, "run_mode":"WholeCell", "integration_method":2 @@ -36,7 +36,7 @@ "module": "noise", "mean":0.05, "variance":0.01, - "delay":50, + "delay":5, "duration":2100, "node_set": "Cell", "represents_physical_electrode":true @@ -49,7 +49,6 @@ "current": { "type": "summation", "cells": "Cell", - "sections": "all", "variable_name": "i_membrane", "unit":"nA", "dt": 0.025, @@ -61,7 +60,6 @@ "type":"compartment", "cells":"Cell", "variable_name":"v", - "sections":"all", "unit":"mV", "dt":0.025, "start_time":0.0, diff --git a/tests/simulations/stimulus_injection/simulation_config_seclamp.json b/tests/simulations/stimulus_injection/simulation_config_seclamp.json index 79e2a3a0..f5780389 100644 --- a/tests/simulations/stimulus_injection/simulation_config_seclamp.json +++ b/tests/simulations/stimulus_injection/simulation_config_seclamp.json @@ -1,7 +1,7 @@ { "run": { "dt": 0.025, - "tstop": 100, + "tstop": 10, "random_seed": 851, "run_mode":"WholeCell", "integration_method":2 @@ -37,7 +37,7 @@ "mean":0.05, "sigma":0.01, "tau":0.1, - "delay":50, + "delay":5, "duration":2100, "node_set": "Cell", "represents_physical_electrode":true @@ -50,7 +50,6 @@ "current": { "type": "summation", "cells": "Cell", - "sections": "all", "variable_name": "i_membrane", "unit":"nA", "dt": 0.025, @@ -62,7 +61,6 @@ "type":"compartment", "cells":"Cell", "variable_name":"v", - "sections":"all", "unit":"mV", "dt":0.025, "start_time":0.0, From cdab66b2541db17db6787b0c2e373045e5ba1822 Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Tue, 16 Apr 2024 12:00:43 +0200 Subject: [PATCH 49/55] Fixes segfault --- .../scientific/test_conductance_injection.py | 44 +++++++++++++ tests/scientific/test_current_injection.py | 44 +++++++++++++ tests/scientific/test_stimulus_injection.py | 64 ------------------- 3 files changed, 88 insertions(+), 64 deletions(-) create mode 100644 tests/scientific/test_conductance_injection.py create mode 100644 tests/scientific/test_current_injection.py delete mode 100644 tests/scientific/test_stimulus_injection.py diff --git a/tests/scientific/test_conductance_injection.py b/tests/scientific/test_conductance_injection.py new file mode 100644 index 00000000..1bf86c27 --- /dev/null +++ b/tests/scientific/test_conductance_injection.py @@ -0,0 +1,44 @@ +import os +import numpy +from pathlib import Path + +SIM_DIR = Path(__file__).parent.parent.absolute() +SIM_DIR = SIM_DIR / "simulations" / "stimulus_injection" +# Read the soma report and return the voltages + + +def _read_sonata_soma_report(report_name): + import libsonata + report = libsonata.SomaReportReader(report_name) + pop_name = report.get_population_names()[0] + ids = report[pop_name].get_node_ids() + data = report[pop_name].get(node_ids=[ids[0]]) + return numpy.array(data.data).flatten() + + +def test_conductance_injection_coreneuron(): + + from neurodamus import Neurodamus + + config_file = str(SIM_DIR / "simulation_config_seclamp.json") + os.chdir(SIM_DIR) + nd = Neurodamus(config_file, disable_reports=False, + simulator="CORENEURON", + output_path="output_coreneuron_seclamp") + + nd.run() + + soma_report_path = os.path.join(nd._run_conf["OutputRoot"], "voltage.h5") + voltage_vec_seclamp = _read_sonata_soma_report(soma_report_path) + # + config_file = str(SIM_DIR / "simulation_config_conductancesource.json") + nd2 = Neurodamus(config_file, disable_reports=False, + simulator="CORENEURON", + output_path="output_coreneuron_conductancesource") + nd2.run() + + soma_report_path = os.path.join(nd2._run_conf["OutputRoot"], "voltage.h5") + voltage_vec_conductancesource = _read_sonata_soma_report(soma_report_path) + + numpy.testing.assert_equal(voltage_vec_seclamp, + voltage_vec_conductancesource) diff --git a/tests/scientific/test_current_injection.py b/tests/scientific/test_current_injection.py new file mode 100644 index 00000000..8b22b26e --- /dev/null +++ b/tests/scientific/test_current_injection.py @@ -0,0 +1,44 @@ +import os +import numpy +from pathlib import Path + +SIM_DIR = Path(__file__).parent.parent.absolute() +SIM_DIR = SIM_DIR / "simulations" / "stimulus_injection" +# Read the soma report and return the voltages + + +def _read_sonata_soma_report(report_name): + import libsonata + report = libsonata.SomaReportReader(report_name) + pop_name = report.get_population_names()[0] + ids = report[pop_name].get_node_ids() + data = report[pop_name].get(node_ids=[ids[0]]) + return numpy.array(data.data).flatten() + + +def test_current_injection_coreneuron(): + + from neurodamus import Neurodamus + + config_file = str(SIM_DIR / "simulation_config_iclamp.json") + os.chdir(SIM_DIR) + nd = Neurodamus(config_file, disable_reports=False, + simulator="CORENEURON", + output_path="output_coreneuron_iclamp") + + nd.run() + + soma_report_path = os.path.join(nd._run_conf["OutputRoot"], "voltage.h5") + voltage_vec_iclamp = _read_sonata_soma_report(soma_report_path) + # + config_file = str(SIM_DIR / "simulation_config_membranecurrentsource.json") + nd2 = Neurodamus(config_file, disable_reports=False, + simulator="CORENEURON", + output_path="output_coreneuron_membranecurrentsource") + nd2.run() + + soma_report_path = os.path.join(nd2._run_conf["OutputRoot"], "voltage.h5") + voltage_vec_currentsource = _read_sonata_soma_report(soma_report_path) + + numpy.testing.assert_equal(voltage_vec_iclamp, + voltage_vec_currentsource) diff --git a/tests/scientific/test_stimulus_injection.py b/tests/scientific/test_stimulus_injection.py deleted file mode 100644 index 2c285422..00000000 --- a/tests/scientific/test_stimulus_injection.py +++ /dev/null @@ -1,64 +0,0 @@ -import pytest -import h5py -import os -import numpy -from pathlib import Path - -SIM_DIR = Path(__file__).parent.parent.absolute() / "simulations" / "stimulus_injection" -# Read the soma report and return a list with the voltages -def _read_sonata_soma_report(report_name): - import libsonata - report = libsonata.SomaReportReader(report_name) - pop_name = report.get_population_names()[0] - ids = report[pop_name].get_node_ids() - data = report[pop_name].get(node_ids=[ids[0]]) - return numpy.array(data.data).flatten() - -def test_current_injection_coreneuron(): - - from neurodamus import Neurodamus - from neurodamus.replay import SpikeManager - - config_file = str(SIM_DIR / "simulation_config_iclamp.json") - os.chdir(SIM_DIR) - nd = Neurodamus(config_file, disable_reports=False, simulator="CORENEURON", - output_path="output_coreneuron_iclamp") - - nd.run() - - soma_report_path = os.path.join(nd._run_conf["OutputRoot"], "voltage.h5") - voltage_vec_iclamp = _read_sonata_soma_report(soma_report_path) - # - config_file = str(SIM_DIR / "simulation_config_membranecurrentsource.json") - nd2 = Neurodamus(config_file, disable_reports=False, simulator="CORENEURON", - output_path="output_coreneuron_membranecurrentsource") - nd2.run() - - soma_report_path = os.path.join(nd2._run_conf["OutputRoot"], "voltage.h5") - voltage_vec_membranecurrentsource = _read_sonata_soma_report(soma_report_path) - - numpy.testing.assert_equal(voltage_vec_iclamp,voltage_vec_membranecurrentsource) - -def test_conductance_injection_coreneuron(): - - from neurodamus import Neurodamus - from neurodamus.replay import SpikeManager - - config_file = str(SIM_DIR / "simulation_config_seclamp.json") - os.chdir(SIM_DIR) - nd = Neurodamus(config_file, disable_reports=False, simulator="CORENEURON", - output_path="output_coreneuron_seclamp") - nd.run() - - soma_report_path = os.path.join(nd._run_conf["OutputRoot"], "voltage.h5") - voltage_vec_seclamp = _read_sonata_soma_report(soma_report_path) - - config_file = str(SIM_DIR / "simulation_config_conductancesource.json") - nd2 = Neurodamus(config_file, disable_reports=False, simulator="CORENEURON", - output_path="output_coreneuron_conductancesource") - nd2.run() - - soma_report_path = os.path.join(nd2._run_conf["OutputRoot"], "voltage.h5") - voltage_vec_conductancesource = _read_sonata_soma_report(soma_report_path) - - numpy.testing.assert_equal(voltage_vec_seclamp,voltage_vec_conductancesource) From 6a547db813d6ed9747e9e313ad32d174ecfd735d Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Mon, 29 Apr 2024 17:22:10 +0200 Subject: [PATCH 50/55] Try removing conductance test --- init.py | 27 ++++++++++++ .../scientific/test_conductance_injection.py | 44 ------------------- 2 files changed, 27 insertions(+), 44 deletions(-) create mode 100644 init.py delete mode 100644 tests/scientific/test_conductance_injection.py diff --git a/init.py b/init.py new file mode 100644 index 00000000..0ea3075c --- /dev/null +++ b/init.py @@ -0,0 +1,27 @@ +""" +Neurodamus is a software for handling neuronal simulation using neuron. + +Copyright (c) 2018 Blue Brain Project, EPFL. +All rights reserved +""" +import sys +from neurodamus import commands +from neurodamus.utils.cli import extract_arguments +from neuron import h +import logging + + +def main(): + args = [] + try: + args = extract_arguments(sys.argv) + except ValueError as err: + logging.error(err) + return 1 + + return commands.neurodamus(args) + + +if __name__ == "__main__": + # Returns exit code and calls MPI.Finalize + h.quit(main()) diff --git a/tests/scientific/test_conductance_injection.py b/tests/scientific/test_conductance_injection.py deleted file mode 100644 index 1bf86c27..00000000 --- a/tests/scientific/test_conductance_injection.py +++ /dev/null @@ -1,44 +0,0 @@ -import os -import numpy -from pathlib import Path - -SIM_DIR = Path(__file__).parent.parent.absolute() -SIM_DIR = SIM_DIR / "simulations" / "stimulus_injection" -# Read the soma report and return the voltages - - -def _read_sonata_soma_report(report_name): - import libsonata - report = libsonata.SomaReportReader(report_name) - pop_name = report.get_population_names()[0] - ids = report[pop_name].get_node_ids() - data = report[pop_name].get(node_ids=[ids[0]]) - return numpy.array(data.data).flatten() - - -def test_conductance_injection_coreneuron(): - - from neurodamus import Neurodamus - - config_file = str(SIM_DIR / "simulation_config_seclamp.json") - os.chdir(SIM_DIR) - nd = Neurodamus(config_file, disable_reports=False, - simulator="CORENEURON", - output_path="output_coreneuron_seclamp") - - nd.run() - - soma_report_path = os.path.join(nd._run_conf["OutputRoot"], "voltage.h5") - voltage_vec_seclamp = _read_sonata_soma_report(soma_report_path) - # - config_file = str(SIM_DIR / "simulation_config_conductancesource.json") - nd2 = Neurodamus(config_file, disable_reports=False, - simulator="CORENEURON", - output_path="output_coreneuron_conductancesource") - nd2.run() - - soma_report_path = os.path.join(nd2._run_conf["OutputRoot"], "voltage.h5") - voltage_vec_conductancesource = _read_sonata_soma_report(soma_report_path) - - numpy.testing.assert_equal(voltage_vec_seclamp, - voltage_vec_conductancesource) From 5eda17a69dd5004136f8ce160721951a438cfd3c Mon Sep 17 00:00:00 2001 From: Jorge Blanco Alonso Date: Wed, 1 May 2024 16:57:55 +0200 Subject: [PATCH 51/55] Add stimulus injection test based on usecase3 circuit --- init.py | 27 ---- tests/scientific/test_current_injection.py | 119 ++++++++++++++---- .../stimulus_injection/circuit_config.json | 30 ----- .../simulation_config_conductancesource.json | 72 ----------- .../simulation_config_iclamp.json | 71 ----------- ...mulation_config_membranecurrentsource.json | 71 ----------- .../simulation_config_seclamp.json | 72 ----------- 7 files changed, 92 insertions(+), 370 deletions(-) delete mode 100644 init.py delete mode 100644 tests/simulations/stimulus_injection/circuit_config.json delete mode 100644 tests/simulations/stimulus_injection/simulation_config_conductancesource.json delete mode 100644 tests/simulations/stimulus_injection/simulation_config_iclamp.json delete mode 100644 tests/simulations/stimulus_injection/simulation_config_membranecurrentsource.json delete mode 100644 tests/simulations/stimulus_injection/simulation_config_seclamp.json diff --git a/init.py b/init.py deleted file mode 100644 index 0ea3075c..00000000 --- a/init.py +++ /dev/null @@ -1,27 +0,0 @@ -""" -Neurodamus is a software for handling neuronal simulation using neuron. - -Copyright (c) 2018 Blue Brain Project, EPFL. -All rights reserved -""" -import sys -from neurodamus import commands -from neurodamus.utils.cli import extract_arguments -from neuron import h -import logging - - -def main(): - args = [] - try: - args = extract_arguments(sys.argv) - except ValueError as err: - logging.error(err) - return 1 - - return commands.neurodamus(args) - - -if __name__ == "__main__": - # Returns exit code and calls MPI.Finalize - h.quit(main()) diff --git a/tests/scientific/test_current_injection.py b/tests/scientific/test_current_injection.py index 8b22b26e..3e220387 100644 --- a/tests/scientific/test_current_injection.py +++ b/tests/scientific/test_current_injection.py @@ -1,10 +1,70 @@ -import os +import json import numpy -from pathlib import Path +import os +import pytest +from tempfile import NamedTemporaryFile + + +@pytest.fixture +def sonata_config_files(sonata_config, input_type): + config_files = [] + for represents_physical_electrode in [True, False]: + # Create a deep copy of sonata_config for each configuration to avoid conflicts + config_copy = json.loads(json.dumps(sonata_config)) + + stimulus_config = { + "input_type": input_type, + "delay": 5, + "duration": 2100, + "node_set": "l4pc", + "represents_physical_electrode": represents_physical_electrode + } + + if input_type == "current_clamp": + stimulus_config.update({ + "module": "noise", + "mean": 0.05, + "variance": 0.01 + }) + elif input_type == "conductance": + stimulus_config.update({ + "module": "ornstein_uhlenbeck", + "mean": 0.05, + "sigma": 0.01, + "tau": 0.1 + }) -SIM_DIR = Path(__file__).parent.parent.absolute() -SIM_DIR = SIM_DIR / "simulations" / "stimulus_injection" -# Read the soma report and return the voltages + config_copy["inputs"] = {"Stimulus": stimulus_config} + config_copy["reports"] = { + "current": { + "type": "summation", + "cells": "l4pc", + "variable_name": "i_membrane", + "unit": "nA", + "dt": 0.1, + "start_time": 0.0, + "end_time": 50.0 + }, + "voltage": { + "type": "compartment", + "cells": "l4pc", + "variable_name": "v", + "unit": "mV", + "dt": 0.1, + "start_time": 0.0, + "end_time": 50.0 + } + } + + with NamedTemporaryFile("w", suffix='.json', delete=False) as config_file: + json.dump(config_copy, config_file) + config_files.append(config_file.name) + + yield tuple(config_files) + + # Cleanup + for config_file in config_files: + os.unlink(config_file) def _read_sonata_soma_report(report_name): @@ -16,29 +76,34 @@ def _read_sonata_soma_report(report_name): return numpy.array(data.data).flatten() -def test_current_injection_coreneuron(): - - from neurodamus import Neurodamus - - config_file = str(SIM_DIR / "simulation_config_iclamp.json") - os.chdir(SIM_DIR) - nd = Neurodamus(config_file, disable_reports=False, - simulator="CORENEURON", - output_path="output_coreneuron_iclamp") +def _run_simulation(config_file): + import subprocess + output_dir = "output_current_conductance" + command = [ + "neurodamus", + config_file, + f"--output-path={output_dir}" + ] + config_dir = os.path.dirname(config_file) + subprocess.run(command, cwd=config_dir, check=True) + soma_report_path = os.path.join(config_dir, output_dir, "voltage.h5") + return _read_sonata_soma_report(soma_report_path) - nd.run() - soma_report_path = os.path.join(nd._run_conf["OutputRoot"], "voltage.h5") - voltage_vec_iclamp = _read_sonata_soma_report(soma_report_path) - # - config_file = str(SIM_DIR / "simulation_config_membranecurrentsource.json") - nd2 = Neurodamus(config_file, disable_reports=False, - simulator="CORENEURON", - output_path="output_coreneuron_membranecurrentsource") - nd2.run() +@pytest.mark.parametrize("input_type", [ + "current_clamp", + "conductance", +]) +def test_current_conductance_injection(sonata_config_files): + """ + Test the consistency of voltage traces between original and new configurations + (set by 'represents_physical_electrode': true/false) + under different types of input (current clamp and conductance). + """ + import numpy.testing as npt + config_file_original, config_file_new = sonata_config_files - soma_report_path = os.path.join(nd2._run_conf["OutputRoot"], "voltage.h5") - voltage_vec_currentsource = _read_sonata_soma_report(soma_report_path) + voltage_vec_original = _run_simulation(config_file_original) + voltage_vec_new = _run_simulation(config_file_new) - numpy.testing.assert_equal(voltage_vec_iclamp, - voltage_vec_currentsource) + npt.assert_equal(voltage_vec_original, voltage_vec_new) diff --git a/tests/simulations/stimulus_injection/circuit_config.json b/tests/simulations/stimulus_injection/circuit_config.json deleted file mode 100644 index 16735200..00000000 --- a/tests/simulations/stimulus_injection/circuit_config.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "manifest": { - "$BASE_DIR": "/gpfs/bbp.cscs.ch/project/proj83/tharayil/generationCode/create_lfp_weights_for_neurodamus/examples/compare-to-reference-solutions/data/simulation/configuration", - "$NETWORK_NODES_DIR": "$BASE_DIR/networks/nodes", - "$NETWORK_EDGES_DIR":"$BASE_DIR/networks/edges", - "$MORPHOLOGIES": "$BASE_DIR/components/morphologies" - }, - "components": { - "morphologies_dir": "$MORPHOLOGIES", - "biophysical_neuron_models_dir": "$BASE_DIR/components/biophysical_model_templates" - }, - "node_sets_file": "$BASE_DIR/node_sets.json", - "networks": { - "nodes": [ - { - "nodes_file": "$NETWORK_NODES_DIR/S1nonbarrel_neurons/nodes.h5", - "populations": { - "S1nonbarrel_neurons": { - "alternate_morphologies": { - "neurolucida-asc": "$MORPHOLOGIES/ascii" - }, - "type": "biophysical" - } - } - } - ], - "edges": [ - ] - } -} diff --git a/tests/simulations/stimulus_injection/simulation_config_conductancesource.json b/tests/simulations/stimulus_injection/simulation_config_conductancesource.json deleted file mode 100644 index 70bc20d1..00000000 --- a/tests/simulations/stimulus_injection/simulation_config_conductancesource.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "run": { - "dt": 0.025, - "tstop": 10, - "random_seed": 851, - "run_mode":"WholeCell", - "integration_method":2 - }, - - "conditions": { - "extracellular_calcium": 1.05, - "v_init": -80.0, - "spike_location": "AIS", - "mechanisms": { - "ProbAMPANMDA_EMS": { - "init_depleted": true, - "minis_single_vesicle": true - }, - "ProbGABAAB_EMS": { - "init_depleted": true, - "minis_single_vesicle": true - } - } - }, - - "target_simulator": "CORENEURON", - "network": "circuit_config.json", - "node_set": "Cell", - "output": { - "output_dir": "output_sonata" - }, - - "inputs": { - "Stimulus2": { - "input_type": "conductance", - "module": "ornstein_uhlenbeck", - "mean":0.05, - "sigma":0.01, - "tau":0.1, - "delay":5, - "duration":2100, - "node_set": "Cell", - "represents_physical_electrode":false - } - - }, - - "reports": { - - "current": { - "type": "summation", - "cells": "Cell", - "variable_name": "i_membrane", - "unit":"nA", - "dt": 0.025, - "start_time": 0.0, - "end_time": 5000.0 - }, - - "voltage":{ - "type":"compartment", - "cells":"Cell", - "variable_name":"v", - "unit":"mV", - "dt":0.025, - "start_time":0.0, - "end_time":5000 - } - - } - -} diff --git a/tests/simulations/stimulus_injection/simulation_config_iclamp.json b/tests/simulations/stimulus_injection/simulation_config_iclamp.json deleted file mode 100644 index 3faab2dd..00000000 --- a/tests/simulations/stimulus_injection/simulation_config_iclamp.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "run": { - "dt": 0.025, - "tstop": 10, - "random_seed": 851, - "run_mode":"WholeCell", - "integration_method":2 - }, - - "conditions": { - "extracellular_calcium": 1.05, - "v_init": -80.0, - "spike_location": "AIS", - "mechanisms": { - "ProbAMPANMDA_EMS": { - "init_depleted": true, - "minis_single_vesicle": true - }, - "ProbGABAAB_EMS": { - "init_depleted": true, - "minis_single_vesicle": true - } - } - }, - - "target_simulator": "CORENEURON", - "network": "circuit_config.json", - "node_set": "Cell", - "output": { - "output_dir": "_output_sonata" - }, - - "inputs": { - "Stimulus2": { - "input_type": "current_clamp", - "module": "noise", - "mean":0.05, - "variance":0.01, - "delay": 5, - "duration": 2100, - "node_set": "Cell", - "represents_physical_electrode":false - } - - }, - - "reports": { - - "current": { - "type": "summation", - "cells": "Cell", - "variable_name": "i_membrane", - "unit":"nA", - "dt": 0.025, - "start_time": 0.0, - "end_time": 5000.0 - }, - - "voltage":{ - "type":"compartment", - "cells":"Cell", - "variable_name":"v", - "unit":"mV", - "dt":0.025, - "start_time":0.0, - "end_time":5000 - } - - } - -} diff --git a/tests/simulations/stimulus_injection/simulation_config_membranecurrentsource.json b/tests/simulations/stimulus_injection/simulation_config_membranecurrentsource.json deleted file mode 100644 index 5c5b1be2..00000000 --- a/tests/simulations/stimulus_injection/simulation_config_membranecurrentsource.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "run": { - "dt": 0.025, - "tstop": 10, - "random_seed": 851, - "run_mode":"WholeCell", - "integration_method":2 - }, - - "conditions": { - "extracellular_calcium": 1.05, - "v_init": -80.0, - "spike_location": "AIS", - "mechanisms": { - "ProbAMPANMDA_EMS": { - "init_depleted": true, - "minis_single_vesicle": true - }, - "ProbGABAAB_EMS": { - "init_depleted": true, - "minis_single_vesicle": true - } - } - }, - - "target_simulator": "CORENEURON", - "network": "circuit_config.json", - "node_set": "Cell", - "output": { - "output_dir": "output_sonata" - }, - - "inputs": { - "Stimulus2": { - "input_type": "current_clamp", - "module": "noise", - "mean":0.05, - "variance":0.01, - "delay":5, - "duration":2100, - "node_set": "Cell", - "represents_physical_electrode":true - } - - }, - - "reports": { - - "current": { - "type": "summation", - "cells": "Cell", - "variable_name": "i_membrane", - "unit":"nA", - "dt": 0.025, - "start_time": 0.0, - "end_time": 5000.0 - }, - - "voltage":{ - "type":"compartment", - "cells":"Cell", - "variable_name":"v", - "unit":"mV", - "dt":0.025, - "start_time":0.0, - "end_time":5000 - } - - } - -} diff --git a/tests/simulations/stimulus_injection/simulation_config_seclamp.json b/tests/simulations/stimulus_injection/simulation_config_seclamp.json deleted file mode 100644 index f5780389..00000000 --- a/tests/simulations/stimulus_injection/simulation_config_seclamp.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "run": { - "dt": 0.025, - "tstop": 10, - "random_seed": 851, - "run_mode":"WholeCell", - "integration_method":2 - }, - - "conditions": { - "extracellular_calcium": 1.05, - "v_init": -80.0, - "spike_location": "AIS", - "mechanisms": { - "ProbAMPANMDA_EMS": { - "init_depleted": true, - "minis_single_vesicle": true - }, - "ProbGABAAB_EMS": { - "init_depleted": true, - "minis_single_vesicle": true - } - } - }, - - "target_simulator": "CORENEURON", - "network": "circuit_config.json", - "node_set": "Cell", - "output": { - "output_dir": "output_sonata" - }, - - "inputs": { - "Stimulus2": { - "input_type": "conductance", - "module": "ornstein_uhlenbeck", - "mean":0.05, - "sigma":0.01, - "tau":0.1, - "delay":5, - "duration":2100, - "node_set": "Cell", - "represents_physical_electrode":true - } - - }, - - "reports": { - - "current": { - "type": "summation", - "cells": "Cell", - "variable_name": "i_membrane", - "unit":"nA", - "dt": 0.025, - "start_time": 0.0, - "end_time": 5000.0 - }, - - "voltage":{ - "type":"compartment", - "cells":"Cell", - "variable_name":"v", - "unit":"mV", - "dt":0.025, - "start_time":0.0, - "end_time":5000 - } - - } - -} From b4f0f3e067252b715ee245a4c95ddd48fd20fec6 Mon Sep 17 00:00:00 2001 From: Jorge Blanco Alonso Date: Wed, 1 May 2024 17:29:10 +0200 Subject: [PATCH 52/55] base_memory consumption reduced --- .gitignore | 5 ----- tests/integration-e2e/test_dry_run_workflow.py | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 817befa6..c72761b0 100644 --- a/.gitignore +++ b/.gitignore @@ -13,11 +13,6 @@ __pycache__/* */.ipynb_checkpoints/* .vscode spack-* -.ipynb_checkpoints -*.SUCCESS -output_coreneuron* -._* -.DS_Store # Project files .ropeproject diff --git a/tests/integration-e2e/test_dry_run_workflow.py b/tests/integration-e2e/test_dry_run_workflow.py index c0335feb..fa247318 100644 --- a/tests/integration-e2e/test_dry_run_workflow.py +++ b/tests/integration-e2e/test_dry_run_workflow.py @@ -24,7 +24,7 @@ def test_dry_run_workflow(USECASE3): assert 20.0 <= nd._dry_run_stats.cell_memory_total <= 30.0 assert 0.0 <= nd._dry_run_stats.synapse_memory_total <= 1.0 - assert 80.0 <= nd._dry_run_stats.base_memory <= 120.0 + assert 70.0 <= nd._dry_run_stats.base_memory <= 120.0 expected_items = { 'L4_PC-dSTUT': 2, 'L4_MC-dSTUT': 1, From aaf45da4b7edb3d68d8078bb8421c378ddcc658f Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Thu, 2 May 2024 10:10:41 +0200 Subject: [PATCH 53/55] Adds physical electrode statement to test stimulus config --- tests/simulations/v5_sonata/simulation_config.json | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/simulations/v5_sonata/simulation_config.json b/tests/simulations/v5_sonata/simulation_config.json index c7efd394..eba6c640 100644 --- a/tests/simulations/v5_sonata/simulation_config.json +++ b/tests/simulations/v5_sonata/simulation_config.json @@ -83,7 +83,7 @@ "spike_file": "input.h5", "delay": 0, "duration": 30000, - "node_set": "Mosaic" + "node_set": "Mosaic", }, "ThresholdExc": { "module": "noise", @@ -92,7 +92,8 @@ "variance": 0.001, "delay": 0.0, "duration": 30000, - "node_set": "Excitatory" + "node_set": "Excitatory", + "represents_physical_electrode":true }, "ThresholdInh": { "module": "noise", @@ -101,14 +102,16 @@ "variance": 0.001, "delay": 0.0, "duration": 30000, - "node_set": "Inhibitory" + "node_set": "Inhibitory", + "represents_physical_electrode":true }, "hypamp_mosaic": { "module": "hyperpolarizing", "input_type": "current_clamp", "delay": 0.0, "duration": 30000, - "node_set": "Mosaic" + "node_set": "Mosaic", + "represents_physical_electrode":true } }, "reports": { From 58eb8fa632fc9ddc2f9518052ac70cfe6cd48f5e Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Thu, 2 May 2024 10:48:35 +0200 Subject: [PATCH 54/55] Fixes typo --- tests/simulations/v5_sonata/simulation_config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/simulations/v5_sonata/simulation_config.json b/tests/simulations/v5_sonata/simulation_config.json index eba6c640..a8d9d516 100644 --- a/tests/simulations/v5_sonata/simulation_config.json +++ b/tests/simulations/v5_sonata/simulation_config.json @@ -83,7 +83,7 @@ "spike_file": "input.h5", "delay": 0, "duration": 30000, - "node_set": "Mosaic", + "node_set": "Mosaic" }, "ThresholdExc": { "module": "noise", From 1bc8d818a855bd7b5049ac157bb81eb3f5ae825f Mon Sep 17 00:00:00 2001 From: Tharayil Joseph Date: Wed, 8 May 2024 23:57:02 +0200 Subject: [PATCH 55/55] Updates docs --- docs/online-lfp.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/online-lfp.rst b/docs/online-lfp.rst index 03fdae05..577ecb7f 100644 --- a/docs/online-lfp.rst +++ b/docs/online-lfp.rst @@ -130,7 +130,11 @@ Subsequently, an ERROR will be encountered when instantiating the LFP report: To ensure accurate and valid LFP reports, make sure that the electrodes file corresponds to the circuit being used in your simulation. -- **Stimulus Electrode Compatibility**: A common use case is that current will be injected into a population to account for synaptic inputs from neural populations that are not modeled. In this case, it is neccessary that total current over the neuron sums to zero in order to produce valid extracellular recording results. For IClamp electrodes, this is always the case. However, the Neuron SEClamp class does not fulfill this criterion due to numerical issues. We have created a new point process, `new_conductance_source`, available in `neurodamus-neocortex`, which does fulfill the criterion. Therefore, If an SEClamp source is present in the simulation config file, and `new_conductance_source` is compiled, this will be used instead of the SEClamp mechanism. If `new_conductance_source` is not available, SEClamp will be used, and extracellular recording results should not be trusted. +- **Stimulus Electrode Compatibility**: A common use case is that current will be injected into a population to account for synaptic inputs from neural populations that are not modeled. In this case,the injected current should be considered a membrane current rather than an electrode current, and it is neccessary that total current over the neuron sums to zero in order to produce valid extracellular recording results. The Neuron SEClamp class does not fulfill these criteria due to numerical issues. We have created a new point process, `ConductanceSource`, available in `neurodamus-neocortex`, which does fulfill the criteria. If an conductance source stimulus is present in the simulation config file, `ConductanceSource` will be used by default instead of the SEClamp mechanism. The injected current will be reported as part of the `i_membrane` variable, rather than as an electrode current. + +However, it may be the case that the user wishes to model a physical electrode, rather than missing synaptic input, using the conductance source mechanism. In this case, the total current over the neuron is nonzero, and the injected current should not be considered a membrane current. For this reason, we have added the key `represents_phsyical_electrode` to the stimulus block. With the key-value pair `represents_physical_electrode:true`, SEClamp will be used rather than ConductanceSource. + +Similarly, current sources may also be used to model the effects of missing synaptic inputs. We have created a new point process, `MembraneCurrentSource`, which is used instead of IClamp if the key `represents_phsyical_electrode` is set to false or is not set. `MembraneCurrentSource` behaves identically to IClamp, but is considered a membrane current, and is therefore accounted for in the calculation of the extracellular signal. It is not reported on as an electrode current. Setting `represents_physical_electrode:true` will result in using IClamp instead of `MembraneCurrentSource` By keeping these considerations in mind, you can ensure a smooth and successful usage of the online LFP calculation feature.