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

Uniform sampling of orientation space using cubochoric coordinates #221

Merged
merged 12 commits into from
Sep 7, 2021

Conversation

hakonanes
Copy link
Member

@hakonanes hakonanes commented Sep 4, 2021

Description of the change

This PR adds sampling of a point group's Rodrigues Fundamental Zone (RFZ) using cubochoric coordinates as an alternative method in the orix.sampling.get_sample_fundamental() function. The sampling is presented in a paper by Singh and De Graef (2016) and is available in EMsoft's EMsampleRFZ command line program.

I've checked the quaternions returned in this PR's implementation to the quaternions from EMsampleRFZ for all proper point groups (1, 2, 222, 4, 422, 3, 32, 6, 622, 23, 432) for N from 10 to 100 in steps of 10 (N is the number of steps of the semi-length of the cubochoric cell), and get identical quaternions for all samplings apart from for 2 and 32. For these two, I get the same number of quaternions, but they are slightly different. Plotting the RFZ it seems like either (1) orix' OrientationRegion is defined differently than in EMsoft, or (2) the EMsoft sampling for these two point groups aren't correct... Because plotting the orientations returned from EMsoft within the RFZ defined in orix shows that there are parts of the zone not filled by EMsoft, while they are by the implementation in this PR. I've looked at the implementation in EMsoft, and the only difference is in the final selection of which rotations calculated from cubochoric coordinates are inside the RFZ: In EMsoft, this selection is done with Rodrigues vectors before final conversion to quaternions, while in orix this selection is done after the final conversion to quaternions.

Suggestions (would like your input on, @pc494):

  1. I've used the sampling from EMsoft with great success previously. I suggest the cubochoric sampling becomes the default sampling in get_sample_fundamental().
  2. I want to use this sampling in the kikuchipy documentation, and thus would like to release v0.7 not long after this is in, hopefully within next weekend. Is this possible from your end? I can do the release if you don't have time or don't want to.

I've also allowed keyword arguments to be passed to get_sample_fundamental(), which are passed on to the selected sampling method. This way, instead of passing the "resolution", users of the cubochoric sampling can pass N as in EMsoft (see explanation of N above).

The sampling is implemented using Numba, so that package is added to the dependencies. With Numba we get quite nice speeds with regular for loops (which are much simpler than trying to do it vectorized!), but I couldn't find a good way to parallelize the loops... For all thinkable use cases, it shouldn't be necessary to go any faster than with one core (see timing example under Examples).

Many of the conversions in the Rowenhorst et al. (2015) are needed in the sampling and are thus implemented. I might move these to their own private module in orix.quaternion, where they belong.

Close #219.

Progress of the PR

  • Docstrings for all functions
  • Unit tests with pytest for all lines
  • Clean code style by running black via pre-commit
  • Orientation sampling notebook showing the orientations produced from different sampling methods in RFZs and rotations of the Z vector in pole figures
  • Update API reference for get_sample_fundamental().
  • Changelog update

Minimal example of the bug fix or new feature

Sampling the RFZ for point group 432 with a "resolution" of about 1.5 degrees (takes ~18 s on my laptop using 1 Intel i7-7600 core, and almost no RAM)

>>> from orix import quaternion, sampling
>>> pg = quaternion.symmetry.O
>>> rot = sampling.get_sample_fundamental(method="cubochoric", semi_edge_steps=100, point_group=pg)
>>> ori = quaternion.Orientation(rot).set_symmetry(pg)
>>> ori
Orientation (333227,) 432
[[ 0.8562 -0.3474 -0.3474 -0.1595]
 [ 0.8562 -0.3491 -0.3491 -0.1519]
 [ 0.8562 -0.3508 -0.3508 -0.1442]
 ...
 [ 0.8562  0.3508  0.3508  0.1442]
 [ 0.8562  0.3491  0.3491  0.1519]
 [ 0.8562  0.3474  0.3474  0.1595]]
>>> ori.get_random_sample(10000).scatter()

cubochoric_sampling_432_rfz

For reviewers

  • The PR title is short, concise, and will make sense 1 year later.
  • New functions are imported in corresponding __init__.py.
  • New features, API changes, and deprecations are mentioned in the
    unreleased section in CHANGELOG.rst.

@hakonanes hakonanes added the enhancement New feature or request label Sep 4, 2021
@hakonanes hakonanes added this to the v0.7.0 milestone Sep 4, 2021
@hakonanes hakonanes marked this pull request as draft September 4, 2021 17:36
@pc494
Copy link
Member

pc494 commented Sep 4, 2021

Broadly:

This is a good addition to the code base, I'm happy to review it, once we've looped round and got it merged we can set to work on a release version of orix (it's about time) - if we miss some stuff for lack of time (my end), eg. #215,#216,#218 that's okay.

Just a note, I think this is going to be slower than the 'quaternion' method for sampling small fundamental zones. Not really sure that's relevant, but thought it was worth mentioning.

Expect a first review back from me by Monday.

@hakonanes
Copy link
Member Author

hakonanes commented Sep 4, 2021

I'm happy to review it, once we've looped round and got it merged we can set to work on a release version of orix (it's about time) - if we miss some stuff for lack of time (my end), eg. #215,#216,#218 that's okay.

Great, thanks! Yeah, that sounds good. I think the IPF functionality has to wait for v0.8.

Just a note, I think this is going to be slower than the 'quaternion' method for sampling small fundamental zones. Not really sure that's relevant, but thought it was worth mentioning.

You're right in that it takes longer. I just checked now, with a resolution of 1.5 degrees for point group 432 "cubochoric" took 19.3 s and produced 251 249 quaternions, while "quaternion" took 9 s and produced 290 847 quaternions. However, "quaternion" used 2.8 GB of RAM while "cubochoric" used 0.3 GB of RAM.

Expect a first review back from me by Monday.

Thanks, but I would appreciate it if you could wait until I've removed the "Draft" labeling of this PR and marked it "Ready for review". I hope to have it ready by Monday.

@pc494
Copy link
Member

pc494 commented Sep 4, 2021

I'm happy to review it, once we've looped round and got it merged we can set to work on a release version of orix (it's about time) - if we miss some stuff for lack of time (my end), eg. #215,#216,#218 that's okay.

Great, thanks! Yeah, that sounds good. I think the IPF functionality has to wait for v0.8.

Just a note, I think this is going to be slower than the 'quaternion' method for sampling small fundamental zones. Not really sure that's relevant, but thought it was worth mentioning.

You're right in that it takes longer. I just checked now, with a resolution of 1.5 degrees for point group 432 "cubochoric" took 19.3 s and produced 251 249 quaternions, while "quaternion" took 9 s and produced 290 847 quaternions. However, "quaternion" used 2.8 GB of RAM while "cubochoric" used 0.3 GB of RAM.

Ah great, that means we've introduced more flexibility for users.

Expect a first review back from me by Monday.

Thanks, but I would appreciate it if you could wait until I've removed the "Draft" labeling of this PR and marked it "Ready for review". I hope to have it ready by Monday.

Ooops, my bad, would have noticed that when I started trying to review it, just ping me when you're ready.

@pc494 pc494 mentioned this pull request Sep 5, 2021
3 tasks
@hakonanes
Copy link
Member Author

I'm working on getting 100% coverage and a short notebook titled "Orientation sampling" to be included in the user guide. The notebook will show the fundamental zone for some point groups from the side and top, and perhaps also Z vectors in the stereographic projection rotated by the orientations.

@hakonanes
Copy link
Member Author

I've noticed that the "harr_euler" method has misspelled Haar as in the Haar measure. How should we deal with this? Should I just change it to "haar_euler" in this PR?

@pc494
Copy link
Member

pc494 commented Sep 6, 2021

Yup, would just change it directly, annoying but it is unlikely to cause anyone huge issues.

@hakonanes hakonanes marked this pull request as ready for review September 6, 2021 14:35
@hakonanes hakonanes requested a review from pc494 September 6, 2021 14:35
@hakonanes
Copy link
Member Author

I've added a user guide comparing the three sampling methods. These results clearly show that cubochoric sampling produces the most uniform sampling with the fewest samples. I've therefore set this method as the default one in get_sample_fundamental() and get_sample_local(). Any input on the wording or presentation in the notebook is appreciated.

@hakonanes
Copy link
Member Author

Copy link
Member

@pc494 pc494 left a comment

Choose a reason for hiding this comment

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

I'm happy with the code, I think the final block of the documentation isn't true though

Based on these plots we can say that the Cubochoric sampling method covers orientation space uniformly, while the Haar Euler and Quaternion methods have trouble sampling close to the identity orientation and an orientation located perpendicular to this orientation in the RFZ, respectively.

All three samples should be uniform. Possible explanations:

  1. Bug in the other two samplings
  2. Bug/problem with the way plotting works when one takes subsamples
  3. Visualizing in the RF zone gives confusing results because orientation spaces are weird.

Any thoughts?

@hakonanes
Copy link
Member Author

hakonanes commented Sep 6, 2021

Any thoughts?

I think it must be a bug, as you say. We've use the "haar_euler" method in the kikuchipy documentation, and @friedkitteh found in his master thesis that using that sampling method to generate the dictionary of simulated EBSD patterns matched poorly with grains close to the identity orientation. So based on this experience I'd say it samples poorly close to the identity orientation.

I did a quick check now, where I calculated the disorientation (smallest misorientation under symmetry) using Orientation.angle_with() to Orientation.identity(), and got this:

>>> import matplotlib.pyplot as plt
>>> import numpy as np
>>> from orix.quaternion import Orientation, symmetry
>>> from orix.sampling import get_sample_fundamental
>>> pg = symmetry.O
>>> res = 2
>>> ori_identity = Orientation.identity().set_symmetry(pg)
>>> rot_euler = get_sample_fundamental(method="haar_euler", point_group=pg, resolution=res)
>>> ori_euler = Orientation(rot_euler).set_symmetry(pg)
>>> mori_euler = np.degrees(ori_euler.angle_with(ori_identity).data)
>>> rot_quat = get_sample_fundamental(method="quaternion", point_group=pg, resolution=res)
>>> ori_quat = Orientation(rot_quat).set_symmetry(pg)
>>> mori_quat = np.degrees(ori_quat.angle_with(ori_identity).data)
>>> bins = np.linspace(0, 62, 100)
>>> fig, ax = plt.subplots(figsize=(9, 5))
>>> _ = ax.hist(mori_euler, bins, label="haar_euler", alpha=0.5)
>>> _ = ax.hist(mori_quat, bins, label="quaternion", alpha=0.5)
>>> ax.set_xlabel(r"Misorientation [$^{\circ}$]")
>>> ax.set_ylabel("Frequency")
>>> ax.legend()
>>> fig.savefig("/home/hakon/kode/orix_test/gridding/haar_measure_identity1.png")

haar_measure_identity1

After including the cubochoric one:

sampling_close_to_identity

@hakonanes
Copy link
Member Author

Should I drop the two other methods in the user guide then, and just present the cubochoric sampling?

@pc494
Copy link
Member

pc494 commented Sep 6, 2021

No, I think leave the notebook as is, I would just drop the final paragraph; users can see what the deal is from the plots. Given that this PR doesn't introduce problems (only identifies them) I'll be happy to merge early tomorrow.

NB: I ran some brief checks of my own, I'm pretty sure it's a bug/oddity somewhere with the existing sampling methods, but will get this merged, use the new code to confirm the finding and raise a suitable warning/issue. This will help us keep to the release schedule.

@hakonanes
Copy link
Member Author

The .gitignore entry of .ipynb files is a problem...

@hakonanes
Copy link
Member Author

Scratch that, the push went OK.

@hakonanes
Copy link
Member Author

hakonanes commented Sep 7, 2021

The updated notebook is here: https://orix--221.org.readthedocs.build/en/221/uniform_sampling_of_orientation_space.html

Edit: You might have to add a "?" to the end of the URI for it to fetch a new version and not use the one in web browser cache if you've visited the URI before.

@pc494
Copy link
Member

pc494 commented Sep 7, 2021

The .gitignore entry of .ipynb files is a problem...

did you end up using the -f flag?

@hakonanes
Copy link
Member Author

did you end up using the -f flag?

Hehe, yup. It's just that we don't have .ipynb in the kikuchipy .gitignore, so I only add it when pushing orix stuff, which has been a while since I've done.

@pc494 pc494 merged commit 2ba2aa4 into pyxem:master Sep 7, 2021
@hakonanes hakonanes deleted the cubochoric-orientation-sampling branch September 7, 2021 13:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

We should start to use Numba
2 participants