orix
orix copied to clipboard
Using scipy's Rotation object
Scipy now has a rotation object, and it might be handy to utilize it in orix
PROS:
- In my (limited) testing, it is significantly faster at calculating misorientations between orientations due to the use of Cython
- you get passive and active rotations for free (try doing
R.from_euler('ZXZ',[euler_angles])
for activeversusR.from_euler('zxz',[euler_angles])
for passive) - you get support for mrp, axis-angles, and rotation matrices for free
- Instead of having to write up detailed docstrings for quaternion methods, you can just piggyback off of scipys
- there are a lot of python classes out there for quaternions, switching to an already popular one will help reduce confusion for new users about conventions
- has built-in left-right multiplication functions to make adding SpecimenSymmetry easier
CONS:
- Scipy uses a different quaternion parameterization
(x, y, z, w)
versus orix and mtex(w, x, y, z)
. - This would require a lot of rewrites for something that would have limited immediate payoff other than a big speedup.
Let me know if you are interested in this, I wouldn't mind writing it, but it requires some fundamental changes as opposed to just adding features, so not going to do it unless you feel it would improve your code.
@argerlt thanks for opening the issue! I have used SciPy's Rotation
objects myself in the past and they work well and come with a lot of benefits as you mentioned!
One thing that made me switch to orix was that orix works with multi-dimensional orientation data, which is useful when considering things such as crystal orientation maps etc., and I don't believe this is implemented in SciPy. At least at that moment it was limited to 1d sets or rotations- please correct me if I am wrong!
We recently switched to using numpy-quaternion to handle various arithmetic, which provided a significant speed up over the previous implementation.
Personally I would be interested to see a conversion function that could be used to maintain consistent conversions between orix and SciPy's Rotation (given the parameter swaps as you said), for those interested to work with both libraries. Perhaps this could work with flattened orientation data in orix and shouldn't be too hard to implement!
Others likely have some comments on this.
@harripj ,you are right, scipy currently sticks you to 1D arrays of rotations. At one point, I thought about making a child class of scipy Rotations to change that, or contributing directly to Scipy, but never did either.
As for conversion, since scipy does quaternions differently and I never managed to get a reliable converter working, here is the lazy method I use for converting between the two:
from scipy.spatial.transform import Rotation as R
from orix.quaternion import Rotation as Rotation
scipy_oris = R.from_euler('ZXZ',orix_oris.as_euler())
orix_oris = scipy_oris.as_euler('ZXZ')
The conversion itself is slow, but it lets me use scipy's symmetry-aware misorientation calculations, which I'm more familiar with, and is faster than the old orix method (no idea about the new numpy quaterion method)
Hi @argerlt, and thanks again for raising these issues.
Importantly, orix follows the conventions in Rowenhorst et al.'s paper from 2015 (doi). This means, among other things, that rotations are interpreted in the passive sense and that the axis-angle pair ([0 0 -1], 90) equals the Bunge Euler angle triplet (pi / 2, 0, 0). This is the opposite of the default chosen in scipy.spatial.transform.Rotation
as far as I can tell. Rowenhorst et al. is referenced many places in the documentation, but we're these days documenting all conventions explicitly in user guides, starting with the crystal reference frame. The discussion is on-going in #249, but that issue is a bit long now...
significantly faster at calculating misorientations between orientations due to the use of Cython
As @harripj says, we started to depend on numpy-quaternion for most quaternion operations in orix 0.8.2 (changelog). Which version of orix did you produce the timings with?
conversion function that could be used to maintain consistent conversions between orix and SciPy's Rotation
This would be a great addition. orix already depends on SciPy.
Okay, I gave this a go with the new numpy quaternion objects and the result honestly surprised me. Here is the quick and dirty speed test I did just now:
# quick and dirty speed test for misorientation calculations
import numpy as np
import quaternion
from scipy.spatial.transform import Rotation as R
import time
angles = np.random.rand(1000000, 3)*180
#scipy way
tic = time.time()
s = R.from_euler('ZXZ', angles)
mul1 = s*s.inv()
toc = time.time() - tic
print("{:0.4f} seconds to calculate 1 million misorientations with scipy".format(toc))
# numpy-quaternion way
tic = time.time()
q = quaternion.from_euler_angles(angles)
mul2 = ~q*q
toc = time.time() - tic
print("{:0.4f} seconds to calculate 1 million misorientations with numpy quaternions".format(toc))
and here are the results I got:
5.7551 seconds to calculate 1 million misorientations with scipy
0.2077 seconds to calculate 1 million misorientations with numpy quaternions
Obviously, this doesn't cover every possible fair comparison between the two, but an over 20x speedup coupled with your point about adhering to Rowenhorst et. al. definitively torpedoes my point.
I would still point out that scipy gives a convenient one line way to convert input data taken in the active sense into the passive sense used by Orix ( R.from_euler('zxz',active_data).as_euler('ZXZ')
), but other than that, I cannot think of anything scipy's Rotation can do which orix or numpy-quaternion cannot also do just as well.
Feel free to close this issue.
@argerlt thanks for opening this issue and for doing the tests above, it's always good to get a second opinion. It confirms to me that moving to numpy-quaternion
was a good idea. If I remember there was ~2x speedup by moving over to numpy-quaternion
from the previous custom implementation of the Quaternion
class that was used in orix
, see #281.
In fact there are other benefits that we could access from using numpy-quaternion
, for example different implementations of the quaternion mean (see #207). We have also kept the original numpy-quaternion
issue open #267 as we envisage perhaps improving the functionality from that package that we use in orix
.
I would still point out that scipy gives a convenient one line way to convert input data taken in the active sense into the passive sense used by Orix
This is definitely a benefit for users working with such data- another reason we should add a conversion implementation!
This issue contains many examples of the SciPy Rotation
class' user friendliness. Therefore, I suggest to leave it open but change the discussion and scope towards implementing conversions between orix and this class in much used cases (not every imaginable case!).
We can now get an orix quaternion from a SciPy rotation using Quaternion.from_scipy_rotation()
(note the inverse interpretations of the two). I believe that addresses the main wish expressed in this discussion.
Note that this will be part of orix v0.11, which does not have a release date yet.