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 warnings for invalid connections #419

Merged
merged 9 commits into from Jul 31, 2022

Conversation

ntolley
Copy link
Contributor

@ntolley ntolley commented Aug 26, 2021

This PR adds checks inside net.add_connection to ensure the valid loc, receptor, target_type combinations are specified. Depending on the definition of the cell, certain combinations will break during simulate_dipole. For example, pyramidal cells do not have ampa synapses so if the user accidentally defines one with net.add_connection, then the simulation will break.

While writing this I am realizing there are some issues with how things are organized internally. At the moment we support proximal, distal, and soma as valid location arguments. However, soma is handled a bit strangely since it is not defined in the sect_loc attribute but still passes as a valid location because it has defined synapses:

sect_loc = {'proximal': ['apical_oblique', 'basal_2', 'basal_3'],

This brings up an important question, should we allow targeting of locations with more precision? For example loc='apical_1'. It would be fairly easy to allow, and may make adding to network_models.py easier with that sort of flexibility.

@ntolley
Copy link
Contributor Author

ntolley commented Aug 26, 2021

Also @rythorpe adding these warnings makes the legacy mode drives API to fail. Specifically, L5_basket cells don't have any synapses defined for loc='distal. Previously this was just ignored silently, such that when adding a distal drive these cells get zero weight in net._attachdrive()

sect_loc = dict(proximal=['soma'], distal=[])

weights_by_type.update({target_type: {'ampa': 0.}})

Any thoughts on a workaround?

@@ -11,6 +11,7 @@
from copy import deepcopy

import numpy as np
from numpy.testing._private.utils import raises
Copy link
Contributor Author

Choose a reason for hiding this comment

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

VSCode is getting too big for its britches, this was added automatically 😬

I'll remove it later.

Copy link
Collaborator

Choose a reason for hiding this comment

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

github autopilot? :)

@rythorpe
Copy link
Contributor

weights_by_type.update({target_type: {'ampa': 0.}})

Any thoughts on a workaround?

Is the problem that legacy mode doesn't currently add an NMDA weight for a non-specified target cell type? If so, you could just copy and paste network.py L741 except with 'nmda' instead.

valid_loc.extend(item)

valid_loc = list(set(valid_loc))
# Separation ecessary to identify valid receptors
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
# Separation ecessary to identify valid receptors
# Separation necessary to identify valid receptors

valid_loc = list(set(valid_loc))
# Separation ecessary to identify valid receptors
if loc in self.cell_types[target_type].sect_loc and \
self.cell_types[target_type].sect_loc[loc]:
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 be more explicit with the second condition? what exactly is it checking?

conn['loc'] = loc

valid_receptor = ['ampa', 'nmda', 'gabaa', 'gabab']
_check_option('receptor', receptor, valid_receptor)
valid_receptors = set(np.concatenate([
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
valid_receptors = set(np.concatenate([
valid_receptors = set(sum([

does this work?

@jasmainak
Copy link
Collaborator

should some of the checks go to check.py or does it remain in the same file?

@jasmainak
Copy link
Collaborator

This brings up an important question, should we allow targeting of locations with more precision?

Is there a real use case? Otherwise, I'd suggest just documenting it better. E.g., by saying: "loc must be either in cell.sect_loc or 'soma'" Let's not open a can of worms if not necessary

@jasmainak
Copy link
Collaborator

@ntolley this PR seems pretty easy to bring to MRG. Could be a nice one to tackle to get back into the groove?

@ntolley ntolley changed the title WIP: Add warnings for invalid connections [MRG] Add warnings for invalid connections Jul 18, 2022
@ntolley ntolley changed the title [MRG] Add warnings for invalid connections WIP: Add warnings for invalid connections Jul 18, 2022
@ntolley
Copy link
Contributor Author

ntolley commented Jul 18, 2022

@ntolley this PR seems pretty easy to bring to MRG. Could be a nice one to tackle to get back into the groove?

While it may have taken me some time to "get back into the grove" 😄 , it may be for the better that I came back to this with fresh eyes.

@jasmainak @rythorpe I've implemented a fairly clean system to allow connections to be added through net.add_connection that allows loc to be the normal targets like 'proximal' or 'distal', but now specific sections like 'apical_tuft'. It also automatically checks if the synapses exist on that section (the point of this PR).

Since everything goes through net.add_connection, it will also be possible to add drives that target specific sections now too (and maybe the tonic bias?). I think this is a really good step towards making the code more generalizable, as now the "grouped sections" like proximal and distal aren't hard-coded and instead derived from the Cell object.

Let me know what you think so far. If you like the idea of targeting specific sections with drives, I'll go ahead and remove the hard coded checks for proximal and distal.

@ntolley ntolley mentioned this pull request Jul 18, 2022
8 tasks
@jasmainak
Copy link
Collaborator

jasmainak commented Jul 18, 2022

Can you have "proximal" or "distal" defined across cell types instead of just a group of sections in one cell? Will your code be able to handle that?

@chenghuzi this a PR you might want to review :)

@ntolley
Copy link
Contributor Author

ntolley commented Jul 18, 2022

Can you elaborate on what you are thinking? With the way the API for drives is designed, as well as the structure of the Cell class, I'm not sure it's clear to me how that would work.

When you define a proximal/distal drive, the weights and delays for each cell need to be specified, so there's no way to avoid thinking in terms of the specific cells that compose the proximal/distal drive.

@jasmainak
Copy link
Collaborator

Isn't it so that currently the distal drive doesn't target L5 basket cells? I suppose the logic for that would have to be outside add_connection then ...

@ntolley
Copy link
Contributor Author

ntolley commented Jul 18, 2022

Ah I understand now. So that logic is handled here:

raise ValueError('When adding a distal drive, synaptic weight cannot '

and here:

sect_loc = dict(proximal=['soma'], distal=[])

I think I see why specifying proximal/distal at the cell level could be useful to break away these hard coded dependencies. Perhaps this is getting at @rythorpe's idea of a "constraints" file.

Perhaps the larger issue is simply moving the hard-coded specifications from drives.py into a more generalized format.

@jasmainak
Copy link
Collaborator

jasmainak commented Jul 18, 2022

Maybe one could iterate over the cell types in net.cell_types looking for "proximal"/"distal" sections ? But if you intend to have connection weights that are cell-type-specific, it's probably better to have the logic outside add_connection anyway

@codecov-commenter
Copy link

codecov-commenter commented Jul 18, 2022

Codecov Report

Merging #419 (aea5553) into master (f5d1691) will increase coverage by 0.10%.
The diff coverage is 100.00%.

@@            Coverage Diff             @@
##           master     #419      +/-   ##
==========================================
+ Coverage   89.93%   90.03%   +0.10%     
==========================================
  Files          20       20              
  Lines        3883     3893      +10     
==========================================
+ Hits         3492     3505      +13     
+ Misses        391      388       -3     
Impacted Files Coverage Δ
hnn_core/network.py 92.16% <100.00%> (+0.19%) ⬆️
hnn_core/network_builder.py 94.37% <100.00%> (ø)
hnn_core/network_models.py 100.00% <100.00%> (ø)
hnn_core/parallel_backends.py 83.14% <0.00%> (+0.82%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update f5d1691...aea5553. Read the comment docs.

@ntolley ntolley changed the title WIP: Add warnings for invalid connections [MRG] Add warnings for invalid connections Jul 18, 2022
@rythorpe
Copy link
Contributor

I like this a lot actually @ntolley. I'm definitely in favor of moving away from hardcoded definitions for "proximal" and "distal". These properties are and should be network-specific. Perhaps we could start (probably in a separate PR) by adding a new attribute to Network called Network.connectivity_constraints of type dict that takes the form

Network.connectivity_constraints = {
    'exogenous_drive_targets': {
        'proximal': ['L5_pyr_soma', 'L2_pyr_soma', 'L5_bask_soma', 'L5_bask_soma'],
        'distal': [...]
        },
    'local_net_conn_restrictions': {
        'L5_bask': ['L2_bask', 'L2_pyr'],
        'L2_bask': [...],
        ...
    }

By default, Network.connectivity_constraints would be left empty (e.g., {'exogenous_drive_targets': None, 'local_net_conn_restrictions': None}. The different network models specified in network_models.py would then set this attribute when instantiating a specific network configuration.

Comment on lines 490 to 493
Target location of synapses. Must be an element of
`Cell.sect_loc` such as 'proximal' or 'distal', which defines a
group of sections, or an existing section such as 'soma' or
'apical_tuft' (defined in `Cell.sections` for all targeted cells)
Copy link
Contributor

Choose a reason for hiding this comment

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

+1 for this. Eventually, it'd be nice to allow users to specify which cell sections apply to a given sect_loc. I can imagine a few different network changes I'd like to implement for my own project where the location (i.e., 'proximal' or 'distal') isn't necessarily intuitive.

@@ -11,7 +11,8 @@
from .externals.mne import _validate_type


def jones_2009_model(params=None, add_drives_from_params=False):
def jones_2009_model(params=None, add_drives_from_params=False,
legacy_mode=True):
Copy link
Collaborator

Choose a reason for hiding this comment

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

why did you add this here? We need to set ourselves free of the legacy ...

Copy link
Contributor Author

@ntolley ntolley Jul 20, 2022

Choose a reason for hiding this comment

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

I promise it's actually towards that goal! legacy_mode=True by default in the Network. But the old interface for jones_2009_model() didn't have the option to turn it on or off.

The reason I added it is because legacy_mode needs to be False to add a drive that targets a specific section. This is because legacy_mode=True creates a connection for all cells, even if they aren't specified in the weights dict (they just have a weight of zero). Therefore if you try to target 'apical_trunk' for example, it'll throw an error because it tries to create a connection to the basket cells when they don't have a section named 'apical_trunk'.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Would a good fix be to just make that clearer in the docstring?

Copy link
Collaborator

Choose a reason for hiding this comment

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

If you plan to deprecate it in the future, the default should be False and it should raise a deprecation warning if someone sets it to True.

Copy link
Collaborator

@jasmainak jasmainak Jul 20, 2022

Choose a reason for hiding this comment

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

It sounds like the examples are secretly using legacy_mode=True ? I think the "right" thing to do is to start a separate PR that fixes this problem, then rebase this PR after that is merged.

Copy link
Contributor

Choose a reason for hiding this comment

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

If we set default to False here, then we'll need to explicitly set legacy_mode=True for all of our examples + tests that use this network model in order to maintain consistency. Either that or we just rip the bandaid off and change the outcome of our examples + tests now.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Btw, I noticed that the new GUI currently loads the "ghost" drives ... probably because of the implicit legacy_mode=True

Copy link
Contributor

Choose a reason for hiding this comment

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

Ugh. Legacy mode is going to be the death of us.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jasmainak that's exactly what's happening. Considering this change doesn't require changes to the current code, can we deal with legacy_mode in a separate PR?

@ntolley
Copy link
Contributor Author

ntolley commented Jul 25, 2022

Just rebased this PR. Everything is good on my end if you guys are happy with the changes!

@jasmainak jasmainak merged commit d1f57b2 into jonescompneurolab:master Jul 31, 2022
@jasmainak
Copy link
Collaborator

Thanks @ntolley ! 🥳 🥳 🥳

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants