-
Notifications
You must be signed in to change notification settings - Fork 55
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] MAINT: remove move_to_pos #314
Conversation
There is a slight mismatch with original "ground truth" dipole if we do this but I would argue this is more correct. Any thoughts @rythorpe @cjayb @ntolley ? we could update the old "ground truth" measurement now that we've stress-tested HNN-core and we know it can reproduce the old HNN outputs faithfully |
It would be super useful to learn something about the reason that was implemented in the first place! It seems utterly bizarre to not treat x and y coords symmetrically. My concern with just removing it is that this seems like yet another tweak that has a specific and thus "intended" purpose, even though it will most likely be wrong for most other simulations with other goals. perhaps something to do with CSD analysis? |
I agree, we should not merge this until we are sure what was the original intention. My impression was that it was meant for visualization. However, this visualization does not exist any more either in the GUI and there is an equivalent viz in hnn-core that does not depend on this. My impression was that the outputs change only slightly because of numerical precision issues when using @samnemo and @stephanie-r-jones any opinions? |
You're right that those pt3dchange calls were only written to move the neurons vertically for visualization purposes & shouldn't influence the dipole calculations or circuit connectivity.
…________________________________
From: Mainak Jas ***@***.***>
Sent: Thursday, April 8, 2021 3:48 PM
To: jonescompneurolab/hnn-core ***@***.***>
Cc: Neymotin, Samuel (NKI) ***@***.***>; Mention ***@***.***>
Subject: Re: [jonescompneurolab/hnn-core] [WIP] MAINT: remove move_to_pos (#314)
ATTENTION: This email came from an external source. Do not open attachments or click on links from unknown senders or unexpected emails.
I agree, we should not merge this until we are sure what was the original intention. My impression was that it was meant for visualization. However, this visualization does not exist any more either in the GUI and there is an equivalent viz<https://protect2.fireeye.com/v1/url?k=75b75ce3-2a2c65a4-75b5a5d6-000babd9fa3f-097ecbaac3a4f728&q=1&e=f0cee2d6-b3c1-487f-aed1-dc6fd5d29e12&u=https%3A%2F%2Fjonescompneurolab.github.io%2Fhnn-core%2Fstable%2F_images%2Fsphx_glr_plot_simulate_evoked_001.png> in hnn-core that does not depend on this.
My impression was that the outputs change only slightly because of numerical precision issues when using h.pt3dchange. This would reflects how floating points are treated differently in Python vs C. The translation operation should not change anything such as _pardistance<https://protect2.fireeye.com/v1/url?k=d7917fe3-880a46a4-d79386d6-000babd9fa3f-b0118c0f28820ea7&q=1&e=f0cee2d6-b3c1-487f-aed1-dc6fd5d29e12&u=https%3A%2F%2Fgithub.jparrowsec.cn%2Fjonescompneurolab%2Fhnn-core%2Fblob%2Fmaster%2Fhnn_core%2Fcell.py%23L359> and dipole computation<https://protect2.fireeye.com/v1/url?k=7550119d-2acb28da-7552e8a8-000babd9fa3f-d404d4966b8e1eaa&q=1&e=f0cee2d6-b3c1-487f-aed1-dc6fd5d29e12&u=https%3A%2F%2Fgithub.jparrowsec.cn%2Fjonescompneurolab%2Fhnn-core%2Fblob%2Fmaster%2Fhnn_core%2Fcell.py%23L209> as it does not change relative distances? I tried doing h.pt3dchange(x, y, z) to test this hypothesis and that failed the tests too. So, not 100% sure what's going on but I'm still betting my money on rounding issues ...
[image]<https://protect2.fireeye.com/v1/url?k=a6c07337-f95b4a70-a6c28a02-000babd9fa3f-293002a3c36c8009&q=1&e=f0cee2d6-b3c1-487f-aed1-dc6fd5d29e12&u=https%3A%2F%2Fuser-images.githubusercontent.com%2F15852194%2F114084137-d4980a80-987d-11eb-8e62-5a44bb480328.png>
@samnemo<https://protect2.fireeye.com/v1/url?k=f8cb11e3-a75028a4-f8c9e8d6-000babd9fa3f-7c09ccc20961410f&q=1&e=f0cee2d6-b3c1-487f-aed1-dc6fd5d29e12&u=https%3A%2F%2Fgithub.jparrowsec.cn%2Fsamnemo> and @stephanie-r-jones<https://protect2.fireeye.com/v1/url?k=6095c137-3f0ef870-60973802-000babd9fa3f-d3706d2b77311ce3&q=1&e=f0cee2d6-b3c1-487f-aed1-dc6fd5d29e12&u=https%3A%2F%2Fgithub.jparrowsec.cn%2Fstephanie-r-jones> any opinions?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<https://protect2.fireeye.com/v1/url?k=72f7dc5e-2d6ce519-72f5256b-000babd9fa3f-945e9e8781c075ca&q=1&e=f0cee2d6-b3c1-487f-aed1-dc6fd5d29e12&u=https%3A%2F%2Fgithub.jparrowsec.cn%2Fjonescompneurolab%2Fhnn-core%2Fpull%2F314%23issuecomment-816116128>, or unsubscribe<https://protect2.fireeye.com/v1/url?k=f690e351-a90bda16-f6921a64-000babd9fa3f-50893644532a188b&q=1&e=f0cee2d6-b3c1-487f-aed1-dc6fd5d29e12&u=https%3A%2F%2Fgithub.jparrowsec.cn%2Fnotifications%2Funsubscribe-auth%2FACS5H2A62KFBSKETT4VRLODTHYB7BANCNFSM42SCGKWQ>.
________________________________
IMPORTANT NOTICE: This e-mail is meant only for the use of the intended recipient. It may contain confidential information which is legally privileged or otherwise protected by law. If you received this e-mail in error or from someone who was not authorized to send it to you, you are strictly prohibited from reviewing, using, disseminating, distributing or copying the e-mail. PLEASE NOTIFY US IMMEDIATELY OF THE ERROR BY RETURN E-MAIL AND DELETE THIS MESSAGE FROM YOUR SYSTEM. Thank you for your cooperation.
|
I'm fairly certain @jasmainak is right about the discrepancy being caused by rounding error. To demonstrate this, I've printed Before/after:
Now, if we only move the root compartment (i.e., the soma) of each neuron instead of all sections individually, NEURON should move the whole tree without introducing the rounding error caused by converting floats (except for any rounding error introduced into the soma itself). def move_to_pos(self):
"""Move cell to position."""
x0 = self.soma.x3d(0)
y0 = self.soma.y3d(0)
z0 = self.soma.z3d(0)
dx = self.pos[0] * 100 - x0
dy = self.pos[2] - y0
dz = self.pos[1] * 100 - z0
root_sec = self.soma
for i in range(root_sec.n3d()):
h.pt3dchange(i, root_sec.x3d(i) + dx, root_sec.y3d(i) + dy,
root_sec.z3d(i) + dz, root_sec.diam3d(i),
sec=root_sec) As expected, this throws a similar error as this PR, albeit with fewer mismatched elements. I think the difference here is caused by the fact that we still introduced a small amount of rounding error into the somas themselves while avoiding it in all other segments.
|
3fd8db8
to
77d4b31
Compare
Codecov Report
@@ Coverage Diff @@
## master #314 +/- ##
==========================================
- Coverage 89.85% 89.80% -0.05%
==========================================
Files 13 13
Lines 2473 2462 -11
==========================================
- Hits 2222 2211 -11
Misses 251 251
Continue to review full report at Codecov.
|
Sure enough, this makes sense to me. My vote is to move forward with removing the |
Isn't the correct fix to remove So the conclusion is that This will affect the LFP calculation too. |
yep, I'll remove |
Great! This means I'll take a look at removing the |
so it looks like Neuron 8.0 also produces some slight differences in results. Not sure it would be straightforward or worth it to track this since none of us are Neuron developers and/or have development version installed. I propose that we accept this slight difference and update the ground truth. What do you guys think? Question is -- do we update the "ground truth" and require NEURON 8.0 from next release of hnn-core? If we still want to support older NEURON version, we should have two different "ground truths" to compare against. Another possibility is that we could have a "tolerance" parameter, but it's possible that some small bugs pass unnoticed since a tiny change in one missing parameter does not always have a big impact on the simulation output. All these issues point to the problems of comparing the outputs rather than testing the internals using unit tests. Should we plan to have a "test-a-thon" (hackathon where we write tests) and try to phase out or relax the "ground truth" criteria after that? |
BTW, I just remembered that we used to actually have the dev version of Neuron on Travis in the past. These are the steps you have to follow. And then git bisect the heck out of it. Anybody wants to give it a shot? |
I think we should resolve this before implementing the updated calcium version. Would it be worth attempting to position each cell to its final destination upon construction (i.e., rather than creating the cell and then moving it), or is the goal to completely get rid of actually positioning the Neuron cell object? |
How does this work with the LFP calculation? Are the positions in Neuron used for LFP calculation @cjayb ? |
Yes, "real" cell positions are needed for LFP: they are used to calculate the distances to the electrode tips. |
could we make cell spacing an argument to Instead of changing it through |
How about a On the other hand, why not just decide that in My point: if there's no good reason for our cells to lie flat in the XY-plane, why not just re-align them and be done with it? LFP calculation is affected by the distances, but also geometry: our cells are effectively 2D, as there are only 2 basal dendrites, and the 'oblique' apical stump is in-plane with them. |
I'm working on a different branch at the moment that refactors how cells, their positions, and their gids are assigned. Let's save implementing a cell spacing argument at the network-level for that PR and just resolve the What do you think of just changing |
+1 for redefining |
If we load a different neuron at some point in the future, we'd have to make sure that the conversion from Neuron y axis to our z-axis is done ... |
+1 for this |
I'm not sure there really is a "Neuron convention"? In any case, a morphology-reader should not assume anything, but be told: morph_L5 = read_cell_morphology(filename_L5, cell_type='pyramidal', apical_orientation=(0, 1, 0))
net = Network(..., morphology={'L5Pyr': morph_L5, 'L2Pyr': ...}) It'll be a while before this becomes relevant, but the above would be pretty transparent, no? |
I suppose Neuron convention is whatever is specified here: https://www.neuron.yale.edu/neuron/static/py_doc/modelspec/programmatic/topology/geometry.html#pt3dadd. If we decide not to use it in the future, we can fly free! |
@rythorpe in terms of plan of action, I think step 1 is to get this PR into mergeable step so we can remove |
@jasmainak you mean remove Am I clear to rebase and push? |
yep you can rebase and push. I am not touching this PR. remember that the positions in space don't affect the dipole calculation. They only affect the LFP calculation ... |
Sure, but the plan is still to maintain consistent positioning between what is specified in |
right, I suppose you'd just have to modify this line: Line 259 in 5c1d2a2
to: h.pt3dadd(self.pos[0] + pt[0],
self.pos[1] + pt[2], # Cell z-coordinate is matplotlib y-coordinate / or change cell definition
self.pos[2] + pt[1], 1, sec=sec) or some such thing |
I was originally thinking of updating What's the best way to update the data? PR to the "test_data" branch? |
Yep, PR to "test_data" branch would be the best way! |
can you rebase this PR @rythorpe ? |
anything else to do for the PR to be MRG? |
I rebased last night, have we merged to master since then? |
oh indeed, I restarted the CI to redownload the new test data |
Once CI's turn green, I think we're good to go. |
I'm going to go ahead and merge since tests are passing and this PR is something we've all weighed in on. |
Perfect, thanks @rythorpe for taking it to the finish line! |
You did almost all of the real work here @jasmainak! Stayed tuned for a follow up PR re: cell spacing. |
dx = self.pos[0] - self.p_secs['soma']['sec_pts'][0][0] | ||
dy = self.pos[2] - self.p_secs['soma']['sec_pts'][0][1] | ||
dz = self.pos[1] - self.p_secs['soma']['sec_pts'][0][2] | ||
|
||
for sec_name in p_secs: | ||
sec = h.Section(name=f'{self.name}_{sec_name}') | ||
self.sections[sec_name] = sec | ||
|
||
h.pt3dclear(sec=sec) | ||
for pt in p_secs[sec_name]['sec_pts']: | ||
h.pt3dadd(pt[0], pt[1], pt[2], 1, sec=sec) | ||
h.pt3dadd(pt[0] + dx, | ||
pt[1] + dy, | ||
pt[2] + dz, 1, sec=sec) |
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 consequences of these lines are very confusing to me (still: I realise nothing has changed in that respect in this PR). Are we reorienting the apical sections to align with the Z-axis here?
In any case, we now have a situation where net.pos_dict
, Cell.pos
and the Section
end points are inconsistent, right?
@rythorpe are you planning to address this in the follow-up you mention? I'm working on some qualified opinions about the spacing-issue too, based on "reduced" model literature.
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.
yes, we should be reorienting the apical sections to align with the Z-axis ... but maybe it's not the case?
The Section
end points are specified relative to the Cell.pos
or net.pos_dict
...
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.
now that I think of it, to reorient along the Z-axis, you'd need to do:
dy = self.pos[1] - self.p_secs['soma']['sec_pts'][0][2]
what might be more clear though is to apply a trans
matrix first:
trans = [[1, 0, 0], [0, 0, 1], [0, 1, 0]]
self.p_secs['soma']['sec_pts'] = np.dot(trans, self.p_secs['soma']['sec_pts'])
there is a wealth of functions we can copy from MNE :) There is even a function to align along a target axis:
that we can use to our advantage
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'm not sure I understand your question @cjayb. Are you asking about the implementation in this PR or what we plan to do in later PRs?
If we change the section endpoints in params_default.py
, I think we should do that in a separate PR.
closes #202