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
Enabling use of up/down asymmetric images #54
Conversation
…ions (basis sets --> _bs_)
Both Travis and AppVeyor seem to have similar errors
As per #36, I have renamed certain functions, including |
You are correct. See |
Thanks for the tip @stggh! Travis seems to fail when From what I understand about the number of basis sets necessary to resolve the image, if Maybe @DanHickstein can look into updating |
Nice work @DhrubajyotiDas! Currently, TravisCI and Appveyor just automatically run the tests that are located in
which is much faster than waiting for Travis. (I always forget this command, but luckily @rth wrote it down here: https://github.com/PyAbel/PyAbel/blob/master/CONTRIBUTING.md) You are right that we now believe it to be foolish to run Basex with On the topic of tests, I think that it would also be a good idea to include a test that ensures that both the symmetric and asymmetric BASEX transforms return (nearly) identical results. Should we consider merging everything into one centering function? I can see that the current centering function does not satisfy the need for returning asymmetric images, but can't the current function be modified fairly easily? Currently, it takes the parameter I suppose that we may also want to give the user the option to only specify the center column, and also it might be nice to allow the image to be cropped to the maximum size possible given the specified center (in which case the output size need not be specified). The function could default to BTW, the consensus was actually to move the centering functions out of the transform functions (i.e., |
' This behaviour is currently not tested and should not be used\ | ||
unless you know exactly what you are doing. Setting nbf="auto" is best for now.') | ||
nbf = [nbf]*2 # Setting identical number of vert and horz functions | ||
elif type(nbf) == list: |
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.
also in the case nbf is a tuple, maybe rather do something like elif isinstance(nbf, (list, tuple)):
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.
Made this change. Thanks!
@DanHickstein Thanks for the feedback! I agree that the default symmetry setting should be Currently, the user can specify the center as
The size of the image output from my centering function @rth Thanks for the suggestions! I'll add the unit tests and send up a few more commits. Currently both symmetric and asymmetric BASEX show excellent agreement for a Gaussian function. EDIT: I'll get back to you on the question of |
Awesome work guys! @rth, I think that our new convention is actually that I didn't realize before that your No need to worry about this for this PR, but in the future we can make the change. Same thing for the centering function. Let's combine the two functions later. I'm glad that @rth asked about the basis functions. I've read the paper many times, and I think that I understand the simple matrix multiplications that take place during the actual transform. But I really have no idea what's going on with the generation of the basis functions. If you can shed light on this, it would be much appreciated. |
@rth and @DanHickstein Regarding the vertical basis functions, here are the relevant sections from the original Dribinksi et al. paper Let's look at the To clarify the notation, the basis sets that were being calculated earlier
are equivalent to the RHS of Eq 14 and 15 respectively. Unfortunately, the expressions as provided are hard to evaluate numerically (lots of things go haywire when for example, Once we have values for rho_k and X_ki (saved inside What happens in the case of Once we have X_ki and Z_mj, we can calculate A and B (featured in Eq 13), which are the No up/down symmetry case: In this situation, we cannot reuse The new A and B in this case are given by Once we have A and B, the image reconstruction is identical. Regarding @rth's concern
This is directly addressed in the next paragraph of the paper (Pg. 2636), where the authors state that the two transformations (matrix A and B) are completely independent, and work on the raw data matrix P independently. Because of the way the three matrices A, P, and B are multiplied to calculate the matrix of coefficients C (Eq 13 in the clipped image above), every row of P sees a single, uncorrelated element from A and from B. The rows are therefore calculated independently; in fact, I am pretty sure that if the rows were not independent, you couldn't write P = XCZ Hope this helped clear things up! P.S. The linear algebra is also pretty confusing to me, but I think I managed to work it out explicitly for a small 5 by 5 image by hand and it seemed to work. |
@rth I'm still working on squashing the |
@DhrubajyotiDas Thank you for this very extensive explanations! I understand it better now. I think when we do the documentation, we should include your comment above in the technical subsection of the BASEX algorithm, as this is the first real connexion we have between the Python (or Matlab) code and the Dribinksi et al. paper. So this would be very useful for someone who would want to understand how the BASEX implementation works (in particular with respect to the basis set generation). Thanks again for your comment. |
@DhrubajyotiDas, Thanks for this detailed analysis of the BASEX algorithm! I feel like I almost understand what's going on now! It would be great if you could include some comments in the code to indicate which sections of the code are performing which equations in the paper. Also, if the variables can be renamed in order to offer better agreement with the paper, I think that we should do this. There is nothing sacred about the current variable names – in general, we just adopted whatever the authors of the original matlab code used – and I suspect that they were working quickly and not giving much thought to code readability. Maybe a crazy thought, but, if we have the asymmetric transform, is there any reason to keep the symmetric transform? If the user wants a symmetric transform, it seems like we could just average the top and bottom half of the image, and pass the averaged half-image to the asymmetric BASEX algorithm. I would expect that it would run even faster since it would, for example, be performing the transform on a 500x1000 image instead of the full 1000x1000 pixel image. More importantly, there is a lot of duplicated code between the symmetric and asymmetric transforms, and it would be nice to keep just one well-documented basis set generation function. A few more features we can think about implementing:
Thanks again for your great work on this! Merry Christmas everyone! |
In relation to item 2), IMO the naming convention:
is now somewhat redundant in light of the I would like to suggest that we now drop the f/i-prefix and just pass the boolean parameter |
@DanHickstein Regarding your comment:
I agree, the asymmetric transform is a superset of the symmetric transform, and averaging the top and bottom halves of the given image and performing an asymmetric transform on that ought to be equivalent to performing a symmetric transform on the entire image. I have yet to verify this explicitly, but if it turns out to be true (and I believe it will), we should be able to condense a lot of the code into a single approach. I think a cleaner way to handle this would be to open a new PR for these after the changes in this PR have been merged, just to keep the git history clean. Regarding the speed-up in transforming an averaged half-image versus a full-image, I don't think there will be that much of an impact during the actual inversions, since those are just matrix multiplications and are very fast as it is. The basis-set generation will be (slightly) faster, but most of the computational time is spent on calculating the horizontal functions (related to the horizontal width of the image), which will be the same between the half and full images.
This is definitely possible. I can think of two ways of doing this: a) Generate basis sets from b) Mirror the input raw data to make a full horizontal slice from My personal preference would be for Option b), mainly in the interests of maintaining code legibility. The basis set generation code is pretty esoteric as it is, and a new mechanism for dealing with half-images could be hard to digest.
I think the original Matlab script had the command to implement the forward transform using the calculated matrices. It's here in the current code Regarding calculating the forward transform directly from inverted raw_data, I don't think BASEX provides a direct method of calculating the forward Abel transform. However, one technique that I can think of is to do something analogous to what is currently happening (when the given raw_data is already forward transformed):
I don't know yet how to do this, but I suspect it could be as simple as switching
I haven't had a chance to investigate this (traveling for the holidays), but I plan to look into this once I get back (early January). Hopefully then I'll finally be able to incorporate some of Roman's recommended changes to this PR and close this to work on the new stuff we have discussed so far, including the naming conventions that @stggh mentioned in his last comment. |
Happy New Year everybody!
Well the Matlab basis set generation consisted of 3 loops. The inner one got vectorized in the current Python implementation. We might factorize one more, which would be much faster, although I'm not sure how easy that would be. I didn't see anything immediate when writing this a while back, but it might be worth getting back to it at some point later. @DhrubajyotiDas Can we merge this PR then? |
Yes, I think this PR can be merged now, and some of @DanHickstein's suggestions tackled with a separate PR. Who pushes the big green button usually? |
Yes, a separate PR for the other changes is fine. @DhrubajyotiDas, I leave it to you do push the "big green button"! :) And great work on this! Thank you! |
Enabling use of up/down asymmetric images
Huzzah! |
Dumb Q: Is there actually big green button? |
There actually is/was a big green button that says |
I avoid the command line for the most part. I use the GitHub app on the Mac. Also, the web interface offers nice functionality for opening and merging pull requests. @stggh may not see the big green button, since I don't think that he has write access to the repo. |
@DanHickstein same here as far as command-line trepidation goes. I use the Sourcetree app on Windows, and it seems to get the job done, except for that weird merge issue I had a few weeks ago that @rth bailed me out from. I do like the functionality of the Github web-interface quite a bit. |
For my part, I also do everything git related in the command line. However, for merging pull requests on github I don't think there is another solution than pushing the "big green button" in the github web-interface (it just disappeared after this PR was merged)... |
This PR address #27. It contains an implementation of the BASEX algorithm for Abel-inverting images which do not possess up/down symmetry. Up/down symmetry is defined as
f(r,-z) = f(r,z)
. The underlying BASEX algorithm only requires the images being inverted to have axial symmetry, i.e.f(-r) = f(r)
. This PR enables using PyAbel for this more general case.The major changes can be summarized as
vertical_symmetry = <True, False, or None>
(see changed function definition here). The default setting isvertical_symmetry=False
so PyAbel should work just as before if the end user does not change anything.n
is decomposed inton_horz
andn_vert
(see lines here through here)nbf
is treated asnbf_horz
andnbf_vert
(here). Usingnbf = 'auto'
is strongly recommended for now.