-
Notifications
You must be signed in to change notification settings - Fork 12
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 ability to record synaptic currents #523
Conversation
FYI here's the currents and voltages from the tutorial network Seems reasonable to me? I'll admit I'm just guessing on the units for the synaptic current 😄 |
Nice! Just had a superficial look and it looks like not a lot of changes had to be made for the above to work. Units should be the standard current units if I am not mistaken (see here) so nA seems right. Regarding your lingerning thoughts:
Lemme me know when you want a review :) |
Awesome, thanks a lot for getting this started @ntolley! I think the following would be important to test:
fully_connect(net.cell("all"), net.cell("all"), IonotropicSynapse())
net.copy_node_property_to_edges("global_cell_index")
df = net.edges
df = df.query("pre_global_cell_index in [3, 4]")
net.select(edges=df.index).record("Ionotropic_s")
fully_connect(net.cell("all"), net.cell("all"), IonotropicSynapse())
fully_connect(net.cell("all"), net.cell("all"), TanhSynapse())
df = net.edges
df = df.query("SynapseType == 'IonotropicSynapse'")
net.select(edges=df.index).record("Ionotropic_s") Let me know if anything is unclear! |
@@ -2422,7 +2426,8 @@ def __init__( | |||
) | |||
|
|||
self.channels = self._channels_in_view(pointer) | |||
self.membrane_current_names = [c._name for c in self.channels] | |||
self.membrane_current_names = [c.current_name for c in self.channels] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Think this was a bug, it wasn't actually possible to record channels currents from a View
because of the naming
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch!
3e8722d
to
94ea4a3
Compare
Got sent down a rabbit hole that led to #533, unfortunately edges aren't being updated in the |
jaxley/modules/base.py
Outdated
@@ -2490,7 +2495,7 @@ def _set_inds_in_view( | |||
].unique() | |||
pre = base_edges["pre_global_comp_index"].isin(incl_comps).to_numpy() | |||
post = base_edges["post_global_comp_index"].isin(incl_comps).to_numpy() | |||
possible_edges_in_view = base_edges.index.to_numpy()[(pre & post).flatten()] | |||
possible_edges_in_view = base_edges.index.to_numpy()[(pre | post).flatten()] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@michaeldeistler @jnsbck this is the culprit for #533 ! Essentially if you're indexing net.cell(0)
, then it's impossible for a view of that cell to include the compartments of another cell (unless it's an autapse)
I think this is a question of how you want this to behave. I've changed it to an "or" condition, so net.cell(0).edges
will include both synapses onto this cell, as well as synapses it makes with other cells
For the purposes of this PR, it would make sense to only include the edges of the post synaptic cell, however you could argue for different expected behaviors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I decided to just go forward with only appending the post synaptic target so that I could finish the tasks for this PR. We can discuss if that's actually the desired behavior for the View
@@ -1207,9 +1208,14 @@ def _get_state_names(self) -> Tuple[List, List]: | |||
|
|||
Returns states seperated by comps and edges.""" | |||
channel_states = [name for c in self.channels for name in c.channel_states] | |||
synapse_states = [name for s in self.synapses for name in s.synapse_states] | |||
synapse_states = [ | |||
name for s in self.synapses if s is not None for name in s.synapse_states |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the not None
filter is necessary since self.synapses
is populated with [None]
under certain conditions
I'll admit I don't totally understand why it's necessary just yet, although I saw the comment about it preserving indexing 😄
I think I've fixed most of the issues! The new tests are passing so this is ready for a review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is awesome, thanks a ton!
A few comments below, mostly minor things. I suggest we stick to pre & post
for now, we could change this behavior in another PR if we want to. Also, please add an entry in the changelog describing the new feature and the bug fixes :)
Good to go once changes are addressed! Thanks again!
@@ -2422,7 +2426,8 @@ def __init__( | |||
) | |||
|
|||
self.channels = self._channels_in_view(pointer) | |||
self.membrane_current_names = [c._name for c in self.channels] | |||
self.membrane_current_names = [c.current_name for c in self.channels] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch!
jaxley/modules/base.py
Outdated
post = base_edges["post_global_comp_index"].isin(incl_comps).to_numpy() | ||
possible_edges_in_view = base_edges.index.to_numpy()[(pre & post).flatten()] | ||
possible_edges_in_view = base_edges.index.to_numpy()[(post).flatten()] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's revert this to pre & post
, see my response in #533
net.cell(2).branch(0).loc(0.0).record("v") | ||
net.IonotropicSynapse.edge(1).record("IonotropicSynapse_s") | ||
net.cell(2).branch(0).loc(0.0).record("HH_m") | ||
net.cell(1).branch(0).loc(0.0).record("v") | ||
net.TestSynapse.edge(0).record("TestSynapse_c") | ||
net.cell(1).branch(0).loc(0.0).record("HH_m") | ||
net.cell(1).branch(0).loc(0.0).record("i_HH") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks!
Think all the comments have been addressed, thanks @michaeldeistler @jnsbck for the help with this PR 🙌 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks a lot!
Awesome! Thanks for tackling this! 🚀 |
Closes #363 and #533
As discussed with @jnsbck in #515, this PR adds
synapse_current_names
as an attribute to the base module, and then appends this to the synapse states in_get_state_names()
. The end goal is for currents to be recordable via:Some lingering thoughts:
View
class. Will it be necessary to add aself._synapses_in_view()
property for this to work properly?