Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MRG] Add functionality to record somatic voltage from all cells in simulation #190

Merged
merged 37 commits into from Nov 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
9eefd58
Start work on implementing somatic voltage attribute
ntolley Sep 25, 2020
4e55d99
Move vsoma attribute to Spikes class, add code to store voltages in d…
ntolley Sep 26, 2020
949ac70
BUG: Fix variable name for vsoma
ntolley Sep 26, 2020
ea9dcbb
Implement slice indexing by gid for spikes object
ntolley Sep 27, 2020
3b4001b
TST: Add test for correct gid indexing type
ntolley Sep 27, 2020
8c62fc7
DOC: Move function description comment to docstring
ntolley Sep 27, 2020
69eb83b
DOC: Add docstring for __getitem__() of Spikes class
ntolley Sep 27, 2020
cc46e73
Move voltage recording to cell class, fix aggregation of recordings f…
ntolley Oct 3, 2020
9fa9882
DOC: Remove unused variable description, flake8 fix
ntolley Oct 5, 2020
ea3c4c1
Remove unused variable
ntolley Oct 14, 2020
06a2c77
Add indexing by array-like objects along with tests
ntolley Oct 14, 2020
fc6b904
Add vsoma as a property to the Spikes class
ntolley Oct 16, 2020
dd75821
Add functionality to store the simulation time vector as an attribute…
ntolley Oct 16, 2020
f72c01e
Update firing pattern example with somatic voltage recording function…
ntolley Oct 16, 2020
364136b
Remove plot_voltage() and corresponding tests
ntolley Oct 21, 2020
22c0838
Replace h.record() t_vec definition with np.arange() using params
ntolley Oct 23, 2020
ac04cef
Add spike raster and histogram to plot_firing_pattern.py
ntolley Oct 24, 2020
d2301a7
Index example gids with gid_dict
ntolley Oct 25, 2020
123981b
Add record_vsoma paramter as an option to turn off somatic voltage re…
ntolley Oct 30, 2020
a4fd472
Enable somatic voltage recording in example
ntolley Oct 30, 2020
e6f262b
Add spike prefix to attributes of the Spikes class
ntolley Oct 30, 2020
bf24e1d
Rename Spike class attribute t_vec to times
ntolley Oct 30, 2020
1a63e46
Fix example, replace t_vec with times
ntolley Oct 30, 2020
e9460be
Remove n_times attribute from Network class
ntolley Oct 30, 2020
1a047da
Fix _ArtificalCell instantiation in test_cell.py
ntolley Nov 6, 2020
9dc50f4
flake8 fix, remove unecessary imports
ntolley Nov 7, 2020
e6d04de
Change record_vsoma input type to bool
ntolley Nov 7, 2020
2ff3721
Make record_vsoma an argument to simulate_dipole()
ntolley Nov 8, 2020
0c5fe1e
DOC: Add rec_v description
ntolley Nov 8, 2020
41d1dee
Add underscore to variables with spike prefix
ntolley Nov 8, 2020
e4e4c5c
Fix record_vsoma argument logic
ntolley Nov 8, 2020
d188b38
Flake8 fixes
ntolley Nov 8, 2020
60f4625
DOC: update whats_new.rst
ntolley Nov 8, 2020
80623ba
DOC: Update example to better explain enabling somatic voltage record…
ntolley Nov 8, 2020
4968a23
Fix variable naming from rebase
ntolley Nov 13, 2020
4e0b8e3
Fix attribute error from rebase
ntolley Nov 13, 2020
45fa194
TST: Check dimensions of vsoma after simulation
ntolley Nov 13, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/whats_new.rst
Expand Up @@ -31,6 +31,8 @@ Changelog

- Add function to compute mean spike rates with user specified calculation type, by `Nick Tolley`_ and `Mainak Jas`_ in `#155 <https://github.com/jonescompneurolab/hnn-core/pull/155>`_

- Add ability to record somatic voltages from all cells, by `Nick Tolley`_ in `#190 <https://github.com/jonescompneurolab/hnn-core/pull/190>`_

Bug
~~~

Expand Down
64 changes: 43 additions & 21 deletions examples/plot_firing_pattern.py
Expand Up @@ -15,8 +15,7 @@
# Let us import hnn_core
ntolley marked this conversation as resolved.
Show resolved Hide resolved

import hnn_core
from hnn_core import read_params, Network
from hnn_core.network_builder import NetworkBuilder
from hnn_core import read_params, Network, simulate_dipole

hnn_core_root = op.dirname(hnn_core.__file__)

Expand All @@ -26,30 +25,53 @@
params = read_params(params_fname)

###############################################################################
# Now let's build the network
# Now let's build the network with somatic voltage recordings enabled
import matplotlib.pyplot as plt

net = Network(params)
with NetworkBuilder(net) as network_builder:
network_builder.cells[0].plot_voltage()
dpls = simulate_dipole(net, n_trials=1, record_vsoma=True)

# The cells are stored in the network object as a list
cells = network_builder.cells
print(cells[:5])
###############################################################################
# The cell IDs (gids) are stored in the network object as a dictionary
gid_dict = net.gid_dict
print(net.gid_dict)
ntolley marked this conversation as resolved.
Show resolved Hide resolved

# We have different kinds of cells with different cell IDs (gids)
gids = [0, 35, 135, 170]
for gid in gids:
print(cells[gid].name)
###############################################################################
# Simulated cell responses are stored in the Spikes object as a dictionary.
trial_idx = 0
vsoma = net.spikes.vsoma[trial_idx]
print(vsoma.keys())

# We can plot the firing pattern of individual cells
network_builder.cells[0].plot_voltage()
plt.title('%s (gid=%d)' % (cells[0].name, gid))
###############################################################################
# We can plot the firing pattern of individual cells by indexing with the gid
gid = 170
times = net.spikes.times[trial_idx]
plt.figure(figsize=(4, 4))
plt.plot(times, vsoma[gid])
plt.title('%s (gid=%d)' % (net.gid_to_type(gid), gid))
plt.xlabel('Time (ms)')
plt.ylabel('Voltage (mV)')
plt.show()
ntolley marked this conversation as resolved.
Show resolved Hide resolved

###############################################################################
# Let's do this for the rest of the cell types with a new NetworkBuilder object
with NetworkBuilder(net) as network_builder:
fig, axes = plt.subplots(1, 2, sharey=True, figsize=(8, 4))
for gid, ax in zip([35, 170], axes):
network_builder.cells[gid].plot_voltage(ax)
ax.set_title('%s (gid=%d)' % (cells[gid].name, gid))
# Let's do this for the rest of the cell types
fig, axes = plt.subplots(1, 2, sharey=True, figsize=(8, 4))
for gid, ax in zip([gid_dict['L2_pyramidal'][0],
gid_dict['L5_pyramidal'][0]], axes):
ax.plot(times, vsoma[gid])
ax.set_title('%s (gid=%d)' % (net.gid_to_type(gid), gid))
ax.set_xlabel('Time (ms)')
ax.set_ylabel('Voltage (mV)')
plt.show()

###############################################################################
# The spiking activity across cell types can also be visualized with raster
# plots and histograms

# Spike raster plot
net.spikes.plot()

# Spike histogram
fig, axes = plt.subplots(1, 1, figsize=(8, 4))
net.spikes.plot_hist(ax=axes, spike_types=['L2_pyramidal', 'L5_pyramidal'])
axes.set_xlabel('Time (ms)')
67 changes: 8 additions & 59 deletions hnn_core/cell.py
Expand Up @@ -67,6 +67,9 @@ class _Cell(ABC):
The Dipole objects (see dipole.mod).
dict_currents : dict of h.Vector()
The soma currents (keys are soma_gabaa, soma_gabab etc.)
rec_v : h.Vector()
ntolley marked this conversation as resolved.
Show resolved Hide resolved
Recording of somatic voltage. Must be enabled
by running simulate_dipole(net, record_vsoma=True)
"""

def __init__(self, gid, soma_props):
Expand All @@ -75,6 +78,7 @@ def __init__(self, gid, soma_props):
self.list_IClamp = None
self.soma_props = soma_props
self.create_soma()
self.rec_v = h.Vector()

def __repr__(self):
class_name = self.__class__.__name__
Expand Down Expand Up @@ -207,6 +211,10 @@ def record_current_soma(self):
" but no self.synapses dict was found")
pass

def record_voltage_soma(self):
"""Record voltage at soma."""
self.rec_v.record(self.soma(0.5)._ref_v)

def syn_create(self, secloc, e, tau1, tau2):
"""Create an h.Exp2Syn synapse.

Expand Down Expand Up @@ -298,62 +306,3 @@ def shape_soma(self):
# self.soma.diam set above
h.pt3dadd(0, 0, 0, self.diam, sec=self.soma)
h.pt3dadd(0, self.L, 0, self.diam, sec=self.soma)

def plot_voltage(self, ax=None, delay=2, duration=100, dt=0.2,
amplitude=1, show=True):
"""Plot voltage on soma for an injected current

Parameters
----------
ax : instance of matplotlib axis | None
An axis object from matplotlib. If None,
a new figure is created.
delay : float (in ms)
The start time of the injection current.
duration : float (in ms)
The duration of the injection current.
dt : float (in ms)
The integration time step
amplitude : float (in nA)
The amplitude of the injection current.
show : bool
Call plt.show() if True. Set to False if working in
headless mode (e.g., over a remote connection).
"""
import matplotlib.pyplot as plt
from neuron import h
h.load_file('stdrun.hoc')

soma = self.soma

h.tstop = duration
h.dt = dt
h.celsius = 37

iclamp = h.IClamp(soma(0.5))
iclamp.delay = delay
iclamp.dur = duration
iclamp.amp = amplitude

v_membrane = h.Vector().record(self.soma(0.5)._ref_v)
times = h.Vector().record(h._ref_t)

print('Simulating soma voltage')
h.finitialize()

def simulation_time():
print('Simulation time: {0} ms...'.format(round(h.t, 2)))

for tt in range(0, int(h.tstop), 10):
h.CVode().event(tt, simulation_time)

h.continuerun(duration)
print('[Done]')

if ax is None:
fig, ax = plt.subplots(1, 1)
ax.plot(times, v_membrane)
ax.set_xlabel('Time (ms)')
ax.set_ylabel('Voltage (mV)')
if show:
plt.show()
10 changes: 9 additions & 1 deletion hnn_core/dipole.py
Expand Up @@ -17,7 +17,7 @@ def _hammfilt(x, winsz):
return convolve(x, win, 'same')


def simulate_dipole(net, n_trials=None):
def simulate_dipole(net, n_trials=None, record_vsoma=False):
"""Simulate a dipole given the experiment parameters.

Parameters
Expand All @@ -28,6 +28,8 @@ def simulate_dipole(net, n_trials=None):
n_trials : int | None
The number of trials to simulate. If None the value in
net.params['N_trials'] will be used
record_vsoma : bool
Option to record somatic voltages from cells

Returns
-------
Expand All @@ -48,6 +50,12 @@ def simulate_dipole(net, n_trials=None):
if n_trials < 1:
raise ValueError("Invalid number of simulations: %d" % n_trials)

if record_vsoma is not None and isinstance(record_vsoma, bool):
net.params['record_vsoma'] = record_vsoma
else:
raise TypeError("record_vsoma must be bool, got %s"
% type(record_vsoma).__name__)

Comment on lines +53 to +58
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @ntolley @jasmainak! I had a followup on this PR. Enforcing a bool here causes an issue with how the HNN GUI displays parameter values. Normally, the user enters 0 or 1, which gets saved to the params dict. Here, it changes that value and the GUI shows "False", which is not suitable for a text box. I could change the GUI to automatically reconvert to 0 or 1 pretty easily, but this seems to be the first parameter hnn-core enforces. Is that the convention you are aiming for?

BTW, I realize a better GUI solution would be checkboxes but am kind of hoping hnn-core will allow 0 or 1 and I can leave the code as-is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd defer to @jasmainak's opinion for this one, but I but I believe this has come up in the past and the decision was to avoids ints for boolean values.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, we're aiming to have this to be boolean in hnn-core. Do you mind type-casting it in HNN for now? We can convert to checkboxes in the future!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, thanks for the clarification

dpls = _BACKEND.simulate(net)

return dpls
Expand Down