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

[ENH] Added read/write method for network object #651

Merged
merged 30 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
5d78733
Added initial read/write method for network object
raj1701 May 24, 2023
6116c4e
Added __eq__ method for cell, section and network classes
raj1701 May 25, 2023
dc10f43
Added support for attribute gid_ranges
raj1701 May 25, 2023
7b51058
Added support for pos_dict
raj1701 May 25, 2023
eae7982
Attempt to remove circle ci errors
raj1701 May 25, 2023
44f8809
Added support for cell response
raj1701 May 25, 2023
9ee149e
Added support for external drives
raj1701 May 30, 2023
5f2053b
Added test for net after simulation and resolved bug in cell response
raj1701 Jun 2, 2023
c666eb8
Refactored code
raj1701 Jun 5, 2023
4f35e6f
Added support for external biases and connectivity
raj1701 Jun 5, 2023
08b14f2
Added support for extracellular arrays, threshold and delay
raj1701 Jun 6, 2023
622bd3e
Resolve mechs issue - Attempt 1
raj1701 Jun 7, 2023
6434328
Added overwrite option and resolved params issue
raj1701 Jun 14, 2023
0c4f73a
Added read/write for simulated/unsimulated network
raj1701 Jun 15, 2023
2461b71
Resolved errors in connectivity
raj1701 Jun 15, 2023
36f0580
Added support for saving object type
raj1701 Jun 18, 2023
535b6cf
Added tests for different models
raj1701 Jun 18, 2023
af1bcc4
Added smoke tests and refactored test code
raj1701 Jun 21, 2023
33826c7
Refactored code
raj1701 Jun 21, 2023
f029f11
Documentation attempt 1 and removing load mechanisms from other place
raj1701 Jun 22, 2023
91b663a
Added authors, removed params, simplified __eq__ and shortened test s…
raj1701 Jun 28, 2023
35330e8
Documentation attempt 2 - Added support for fill doc and copy doc
raj1701 Jun 29, 2023
5deb3c2
Shifted mne code to externals and finished documentation
raj1701 Jul 6, 2023
501b81f
Resolved all conflicts and made sure tests are passing
raj1701 Aug 30, 2023
523fb8c
Replaced tmpdir with tmp_path
raj1701 Aug 30, 2023
4f90f7f
Revorked documentation
raj1701 Sep 10, 2023
96965c6
Minor fixes
raj1701 Sep 19, 2023
79ab971
Updated documentation
raj1701 Sep 19, 2023
cda152e
Added tests, refactored code and changed function signatures
raj1701 Sep 27, 2023
ea4097c
Refactored __eq__ functions
raj1701 Oct 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ Input and Output:
read_params
read_dipole
read_spikes
read_network

GUI (:py:mod:`hnn_core.gui`):
-----------------------------
Expand Down
200 changes: 200 additions & 0 deletions doc/network_file_desc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
:orphan:

.. _network_file_content:

====================
Network File Content
====================
Copy link
Collaborator

Choose a reason for hiding this comment

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

can you add some more information what the file structure is like? what is the file format etc? we need to provide some more information for users if they open the file using other tools and also for documentation


File Content Description
------------------------
hdf5 is the file format used for storing the Network object. The network is stored in a layered format. The first layer consists of the network attributes.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
hdf5 is the file format used for storing the Network object. The network is stored in a layered format. The first layer consists of the network attributes.
hdf5 is the file format used for storing the Network object. The network is stored in a multi-level format. The first level consists of the network attributes.

Using "layer" as the terminology might get confusing, as there is the biologically "layers" of the model

The attributes of the network are then broken down until the network can be representated as a collection of key value pairs. For example - cell_types is a network
attribute therefore in the first layer. The description of each cell type is in layer 2. Each cell has various sections. The description of a section is in layer 3.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
attribute therefore in the first layer. The description of each cell type is in layer 2. Each cell has various sections. The description of a section is in layer 3.
attribute therefore in the first level. The description of each cell type is in level 2. Each cell has various sections. The description of a section is in level 3.

Below are the attributes of the network.

object_type : str
Type of object (Network) saved.
N_pyr_x : int
Nr of cells (x).
N_pyr_y : int
Nr of cells (y).
Comment on lines +18 to +21
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
N_pyr_x : int
Nr of cells (x).
N_pyr_y : int
Nr of cells (y).
N_pyr_x : int
Number of cells (x).
N_pyr_y : int
Number of cells (y).

threshold : float
Firing threshold of all cells.
celsius : float
Temperature in degree celsius.
cell_types : dict of Cell Object
key : name of cell type.
value : Cell object.
gid_ranges : dict of dict
key : cell name or drive name.
value : dict.
pos_dict : dict
key : cell type name.
value : All co-ordintes of the cell types.
cell_response : Instance of Cell Response Object
The Cell Response object.
external_drives : dict of dict
key : external drive name.
value : dict.
external_biases : dict of dict
key : external bias name.
value : dict.
connectivity : list of dict
Contains connection info between cells and
cells and external drives.
rec_arrays : dict of Extracellular Arrays
key : extracellular array name.
value : Instance of Extracellular Array object.
delay : float
Synaptic delay in ms.

Cell Type Description
---------------------

cell_name : str
Name of the cell.
pos : tuple
The (x, y, z) coordinates.
sections : dict of Section
Dictionary with keys as section name.
synapses : dict of dict
Keys are name of synaptic mechanism. Each synaptic mechanism
has keys for parameters of the mechanism, e.g., 'e', 'tau1',
'tau2'.
cell_tree : dict of list
Stores the tree representation of a cell.
sect_loc : dict of list
Can have keys 'proximal' or 'distal' each containing
names of section locations that are proximal or distal.
gid : int
GID of the cell in a network (or None if not yet assigned).
dipole_pp : list of h.Dipole()
The Dipole objects (see dipole.mod).
vsec : dict
Recording of section specific voltage. Must be enabled
by running simulate_dipole(net, record_vsec=True) or
simulate_dipole(net, record_vsoma=True).
isec : dict
Contains recording of section specific currents indexed
by synapse type (keys can be soma_gabaa, soma_gabab etc.).
Must be enabled by running simulate_dipole(net, record_isec=True)
or simulate_dipole(net, record_isoma=True).
tonic_biases : list of h.IClamp
The current clamps inserted at each section of the cell
for tonic biasing inputs.

Section Description
-------------------

L : float
length of a section in microns.
diam : float
diameter of a section in microns.
cm : float
membrane capacitance in micro-Farads.
Ra : float
axial resistivity in ohm-cm.
end_pts : list of [x, y, z]
The start and stop points of the section.
syns : list of str
The synaptic mechanisms to add in this section.
mechs : dict
Mechanisms to insert in this section. The keys
are the names of the mechanisms and values
are the properties.

Gid Range Description
---------------------

start : int
Start of the gid_range.
stop : int
End of the gid_range.

External Drive Description
--------------------------

name : str
Unique name for the drive.
dynamics : dict
Parameters describing how the temporal dynamics of spike trains in the
drive. The keys are specific to the type of drive ('evoked', 'bursty',
etc.).
location : str
Target location of synapses.
cell_specific : bool
Whether each artifical drive cell has 1-to-1 (True, default) or
all-to-all (False) connection parameters.
weights_ampa : dict or None
Synaptic weights (in uS) of AMPA receptors on each targeted cell
type (dict keys).
weights_nmda : dict or None
Synaptic weights (in uS) of NMDA receptors on each targeted cell
type (dict keys).
probability : dict or float
Probability of connection between any src-target pair.
synaptic_delays : dict or float
Synaptic delay (in ms) at the column origin, dispersed laterally as
a function of the space_constant. If float, applies to all target
cell types.
event_seed : int
Optional initial seed for random number generator.
conn_seed : int
Optional initial seed for random number generator.
n_drive_cells : int | 'n_cells'
The number of drive cells that each contribute an independently
sampled synaptic spike to the network according to the Gaussian
time distribution (mu, sigma).
events : list
Contains the spike times of exogeneous inputs.

External Bias Description
-------------------------

cell_type : str
The cell type whose cells will get the tonic input.
amplitude : float
The amplitude of the input.
t0 : float
The start time of tonic input (in ms).
tstop : float
The end time of tonic input (in ms).

Connection Description
----------------------

target_types : str
Cell type of target gids.
target_gids : list of int
Identifer for targets of source cells.
num_targets : int
Number of unique target gids.
src_type : str
Cell type of source gids.
src_gids : list of int
Identifier for source cells.
num_srcs : int
Number of unique source gids.
gid_pairs : dict
dict indexed by src gids.
loc : str
Target location of synapses.
receptor : str
Synaptic receptor of connection.
nc_dict : dict
Contains information about delay, weight, lamtha etc.
allow_autapses : bool
If True, allow connecting neuron to itself.
probability : float
Probability of connection between any src-target pair.

Extracellular Array Description
-------------------------------

positions : tuple | list of tuple
The (x, y, z) coordinates (in um) of the extracellular electrodes.
conductivity : float
Extracellular conductivity, in S/m.
method : str
Approximation to use.
1 change: 1 addition & 0 deletions hnn_core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
from .cell_response import CellResponse, read_spikes
from .cells_default import pyramidal, basket
from .parallel_backends import MPIBackend, JoblibBackend
from .io import read_network

__version__ = '0.4.dev0'
118 changes: 116 additions & 2 deletions hnn_core/cell.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ def _get_gaussian_connection(src_pos, target_pos, nc_dict,
return weight, delay


def node_to_str(node):
return node[0] + "," + str(node[1])


class _ArtificialCell:
"""The ArtificialCell class for initializing a NEURON feed source.

Expand Down Expand Up @@ -220,6 +224,56 @@ def __init__(self, L, diam, Ra, cm, end_pts=None):
def __repr__(self):
return f'L={self.L}, diam={self.diam}, cm={self.cm}, Ra={self.Ra}'

def __eq__(self, other):
ntolley marked this conversation as resolved.
Show resolved Hide resolved
if not isinstance(other, Section):
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't believe this is tested explicitly

return NotImplemented
Copy link
Contributor

Choose a reason for hiding this comment

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

Oh I think this is why the pytest.raises test didn't work. You're returning NotImplemented, but you actually need to do raise NotImplemented (check out how the other errors get raised)


# Check equality for mechs
for mech_name in self.mechs.keys():
self_mech = self.mechs[mech_name]
other_mech = other.mechs[mech_name]
for attr in self_mech.keys():
if self_mech[attr] != other_mech[attr]:
return False

# Check end_pts
for self_end_pt, other_end_pt in zip(self.end_pts, other.end_pts):
if np.testing.assert_almost_equal(self_end_pt,
other_end_pt, 5) is not None:
return False

all_attrs = dir(self)
attrs_to_ignore = [x for x in all_attrs if x.startswith('_')]
attrs_to_ignore.extend(['end_pts', 'mechs', 'to_dict'])
attrs_to_check = [x for x in all_attrs if x not in attrs_to_ignore]

# Check all other attributes
for attr in attrs_to_check:
if getattr(self, attr) != getattr(other, attr):
return False

return True

def to_dict(self):
raj1701 marked this conversation as resolved.
Show resolved Hide resolved
"""Converts an object of Section class to a dictionary.

Returns
-------
dictionary form of an object of Section class.
"""
section_data = dict()
section_data['L'] = self.L
section_data['diam'] = self.diam
section_data['cm'] = self.cm
section_data['Ra'] = self.Ra
section_data['end_pts'] = self.end_pts
section_data['nseg'] = self.nseg
# Need to solve the partial function problem
# in mechs
section_data['mechs'] = self.mechs
section_data['syns'] = self.syns
return section_data

@property
def L(self):
return self._L
Expand Down Expand Up @@ -355,6 +409,68 @@ def __repr__(self):
class_name = self.__class__.__name__
return f'<{class_name} | gid={self._gid}>'

def __eq__(self, other):
if not isinstance(other, Cell):
return NotImplemented
Copy link
Contributor

Choose a reason for hiding this comment

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

needs a test

Copy link
Contributor Author

Choose a reason for hiding this comment

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

assert (net == "net") == False.
Is this test fine?


all_attrs = dir(self)
attrs_to_ignore = [x for x in all_attrs if x.startswith('_')]
attrs_to_ignore.extend(['build', 'copy', 'create_tonic_bias',
'define_shape', 'distance_section', 'gid',
'list_IClamp', 'modify_section',
'parconnect_from_src', 'plot_morphology',
'record', 'sections', 'setup_source_netcon',
'syn_create', 'to_dict'])
attrs_to_check = [x for x in all_attrs if x not in attrs_to_ignore]

# Check all other attributes
for attr in attrs_to_check:
if getattr(self, attr) != getattr(other, attr):
return False

if not (self.sections.keys() == other.sections.keys()):
return False

for key in self.sections.keys():
if self.sections[key] != other.sections[key]:
return False

return True
Copy link
Collaborator

Choose a reason for hiding this comment

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

you should add a test in test_cell.py for this ... simple way to test is:

cell2 = cell.copy()
assert cell2 == cell


def to_dict(self):
raj1701 marked this conversation as resolved.
Show resolved Hide resolved
"""Converts an object of Cell class to a dictionary.

Returns
-------
dictionary form of an object of Cell class.
"""
cell_data = dict()
cell_data['name'] = self.name
cell_data['pos'] = self.pos
cell_data['sections'] = dict()
for key in self.sections:
cell_data['sections'][key] = self.sections[key].to_dict()
cell_data['synapses'] = self.synapses
# cell_data['cell_tree'] = self.cell_tree
if self.cell_tree is None:
cell_data['cell_tree'] = None
else:
cell_tree_dict = dict()
for parent, children in self.cell_tree.items():
key = node_to_str(parent)
value = list()
for child in children:
value.append(node_to_str(child))
cell_tree_dict[key] = value
cell_data['cell_tree'] = cell_tree_dict
cell_data['sect_loc'] = self.sect_loc
cell_data['gid'] = self.gid
cell_data['dipole_pp'] = self.dipole_pp
cell_data['vsec'] = self.vsec
cell_data['isec'] = self.isec
cell_data['tonic_biases'] = self.tonic_biases
return cell_data

@property
def gid(self):
return self._gid
Expand Down Expand Up @@ -444,8 +560,6 @@ def _set_biophysics(self, sections):
if isinstance(val, list):
seg_xs, seg_vals = val[0], val[1]
for seg, seg_x, seg_val in zip(sec, seg_xs, seg_vals):
# Checking equality till 5 decimal places
np.testing.assert_almost_equal(seg.x, seg_x, 5)
setattr(seg, attr, seg_val)
else:
setattr(sec, attr, val)
Expand Down
4 changes: 3 additions & 1 deletion hnn_core/cell_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,9 @@ def __eq__(self, other):
for trial in other._spike_times]
return (times_self == times_other and
self._spike_gids == other._spike_gids and
self._spike_types == other._spike_types)
self._spike_types == other._spike_types and
self.vsec == other.vsec and
self.isec == other.isec)

def __getitem__(self, gid_item):
"""Returns a CellResponse object with a copied subset filtered by gid.
Expand Down
Loading
Loading