-
Notifications
You must be signed in to change notification settings - Fork 53
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
Inconsistency with Orientation.angle_with #276
Comments
Thanks for reporting this @soupmongoose, it looks like a bug at a first glance. Initialization of a orix/orix/quaternion/orientation.py Lines 438 to 444 in 0fa14d1
orix/orix/quaternion/orientation.py Lines 539 to 553 in 0fa14d1
I'll have a look into these routes and compare with results from MTEX when I find the time, hopefully within the weekend. |
@soupmongoose thanks for the report and thanks @hakonanes ! I can shed some light on the angle_with situation, at the moment the function is written in a way that does not take into account the For the final example I made some tests for your findings but was not able to reproduce the angles you quote in the final example: >>> from orix.quaternion import Orientation
>>> import numpy as np
>>> o1 = Orientation.from_euler([178.5 , 36.97748349 , 63.61592335])
>>> o2 = Orientation.from_euler([ 0. , 36.48968436 , 61.39659559])
>>> print('C1 symmetry misori', np.rad2deg((o1 - o2).angle.data))
>>> print('C1 symmetry angle_with', np.rad2deg(o1.angle_with(o2).data))
C1 symmetry misori [136.89201375]
C1 symmetry angle_with [136.89201375]
>>> o1.symmetry = Oh
>>> o2.symmetry = Oh
>>> print('Oh symmetry misori', np.rad2deg((o1 - o2).angle.data))
>>> print('Oh symmetry angle_with', np.rad2deg(o1.angle_with(o2).data))
Oh symmetry misori [36.81299586]
Oh symmetry angle_with [34.11563997]
from orix.quaternion import Misorientation
>>> misorientation = Misorientation(o1 * ~o2).squeeze()
>>> misorientation.symmetry = (Oh, Oh)
>>> print('Misori', np.rad2deg(misorientation.angle.data))
>>> print('Misori with symmetry reduction', np.rad2deg(misorientation.map_into_symmetry_reduced_zone().angle.data))
Misori [136.89201375]
Misori with symmetry reduction [36.81299586] In the second run of tests here it looks like |
Symmetry is taken into account via the dot product, so we find the symmetry reduced misorientation angle (disorientation angle) orix/orix/quaternion/orientation.py Lines 555 to 568 in 0fa14d1
That said, I wrote this implementation, so I would appreciate a different pair of eyes on it (: |
If I am not mistaken, This should work. o1 = Orientation.from_euler(np.radians([178.5 , 36.97748349 , 63.61592335]),symmetry=symmetry.Oh)
o2 = Orientation.from_euler(np.radians([ 0. , 36.48968436 , 61.39659559]),symmetry=symmetry.Oh)
print('Oh symmetry misori', np.rad2deg((o1 - o2).angle.data))
print('Oh symmetry angle_with', np.rad2deg(o1.angle_with(o2).data)) |
@soupmongoose you are absolutely right, thanks for correcting me! In any case there is a problem here, the correct value for the symmetry is one thing, but another problem is that the two functions are producing different results. Looking closer I think I have found a small bug: o1 = Orientation.from_euler(np.deg2rad([178.5 , 36.97748349 , 63.61592335]))
o2 = Orientation.from_euler(np.deg2rad([ 0. , 36.48968436 , 61.39659559])) In # misorientation o2 - o1 is the transformation from o1 -> o2
>>> m = o2 - o1
>>> (m * o1) * ~o2
Orientation (1,) 1
[[ 1. -0. -0. 0.]] however in orix/orix/quaternion/orientation.py Lines 555 to 568 in 0fa14d1
# in Orientation.dot
>>> m = ~o1 * o2
>>> (m * o1) * ~o2
Orientation (1,) 1
[[ 0.8087 0.274 -0.5205 -0.0015]] which is not identity. This I think is the reason for the two differing results. In >>> m = o2 * ~o1
>>> (m * o1) * ~o2
Orientation (1,) 1
[[ 1. -0. -0. 0.]] I would like to get your opinions on this @hakonanes @pc494. NB this is also present in orix/orix/quaternion/orientation.py Lines 570 to 583 in 0fa14d1
I think the line: orix/orix/quaternion/orientation.py Line 580 in 0fa14d1
should be: misorientation = other.outer(~self) Testing: >>> m = (~o1).outer(o2)
>>> (m * o1) * ~o2
Orientation (1, 1) 1
[[[ 0.8087 0.274 -0.5205 -0.0015]]]
>>> m = o2.outer(~o1)
>>> (m * o1) * ~o2
Orientation (1, 1) 1
[[[ 1. -0. -0. 0.]]] |
Okay, this is slightly off topic, but it's what I spotted in the the skim I was able to do. I think we should deprecated the overridden
writing it other ways is confusing and means there are multiple paths to the same answer. Will hopefully have time to loop back to this more a more detailed read. |
We also should be careful about how we define the misorientation as |
@soupmongoose The misorientation angle between with
You are right @harripj, thanks a bunch for spotting this bug! After making your changes, the two routes of
This is another convention we should bring up in #249: if o1 is the reference orientation, i.e. the misorientation is the rotation to bring o1 into o2, o1 should be inverted, as @harripj writes. Checking two text books I have handy (both define orientations from the sample to the crystal reference frame):
Based on this, I prefer the syntax o2 * ~o1. Scripts comparing orix to MTEX. orix: import numpy as np
from orix.quaternion import Orientation, symmetry
eulers = np.deg2rad([
[[120, 54.26282923, 45], [0, 54.73561032, 45]],
[[302, -52.35178357, -46.0036662], [0, 53.59948955, 47.5]],
[[308.5, -51.76150996, -52], [0, 51.76150996, 52]],
[[328.5, -47.2657904, -67.5], [0, 47.2657904, 67.5]],
[[178.5, 36.97748349, 63.61592335], [0, 36.48968436, 61.39659559]],
])
for i in range(eulers.shape[0]):
print(i)
o1 = Orientation.from_euler(eulers[i][0], symmetry.Oh)
o2 = Orientation.from_euler(eulers[i][1], symmetry.Oh)
m12_1 = o1 - o2
o3_1 = m12_1 * ~o2 * o1
m12_2 = ~o1 * o2
o3_2 = m12_2 * ~o2 * o1
print(m12_1.data.round(4))
print(m12_2.data.round(4))
print(o3_1.data.round(4))
print(o3_2.data.round(4))
print(np.rad2deg(m12_1.angle.data[0]))
print(np.rad2deg(o1.angle_with(o2).data[0])) orix output: 0
[[-1. 0. -0.0029 -0.0029]]
[[ 0.5 -0.0021 -0.0036 0.866 ]]
[[-5.025e-01 5.000e-04 -5.000e-03 8.646e-01]]
[[ 1. 0. -0. 0.]]
0.47278108586829465
0.47278108586796685
1
[[0.9999 0.0028 0.0082 0.0124]]
[[ 0.0077 -0.4746 0.2721 -0.837 ]]
[[-0.0017 0.4848 -0.2685 0.8324]]
[[ 1. -0. 0. 0.]]
1.7275579455731056
1.727557945573067
2
[[-1.e+00 -6.e-04 -5.e-04 -6.e-04]]
[[ 0.0009 -0.4355 0.2101 -0.8753]]
[[-2.000e-04 -4.361e-01 2.104e-01 -8.750e-01]]
[[ 1. 0. -0. 0.]]
0.11365802066515938
0.11365802066716485
3
[[-1.e+00 -2.e-04 -6.e-04 -6.e-04]]
[[-8.000e-04 -2.705e-01 7.630e-02 -9.597e-01]]
[[ 0.0014 -0.2711 0.0764 -0.9595]]
[[ 1. 0. 0. -0.]]
0.1002851900674705
0.1002851900666658
4
[[-0.9419 -0.1916 -0.1935 -0.1969]]
[[ 0.0024 -0.0116 -0.0041 -0.9999]]
[[ 0.1976 -0.2041 0.1849 -0.9408]]
[[1. 0. 0. 0.]]
39.26841870589627
39.268418705896316 MTEX: euler = [[[120, 54.26282923, 45], [0, 54.73561032, 45]],...
[[302, -52.35178357, -46.0036662], [0, 53.59948955, 47.5]],...
[[308.5, -51.76150996, -52], [0, 51.76150996, 52]],...
[[328.5, -47.2657904, -67.5], [0, 47.2657904, 67.5]],...
[[178.5, 36.97748349, 63.61592335], [0, 36.48968436, 61.39659559]]...
] * degree;
euler = reshape(euler, [3, 2, 5]);
for i=1:5
disp(i - 1)
cs = crystalSymmetry('m-3m');
o1 = orientation.byEuler(euler(:, 1, i)', cs);
o2 = orientation.byEuler(euler(:, 2, i)', cs);
m12 = inv(o1) * o2;
o3 = inv(o2) * o1 * m12;
disp([o3.phi1, o3.Phi, o3.phi2])
angle(o1, o2) / degree
end MTEX output: 0
0 0 0
ans =
0.4728
1
0 0 0
ans =
1.7276
2
0 0 0
ans =
0.1137
3
0 0 0
ans =
0.1003
4
0 0 0
ans =
39.2684 |
Prematurely hit "Comment", edited above! |
@hakonanes thanks for the detailed analysis and clarification!
I agree and in fact I think the other method (Engler and Randle) does not work for us here, which I believe is a passive vs active case? >>> o1, o2 = Orientation.random((2,))
>>> o2 * ~o1, ~o1 * o2
(Orientation (1,) 1
[[-0.0474 -0.8901 0.0946 -0.4433]],
Orientation (1,) 1
[[-0.0474 -0.3106 0.9068 -0.281 ]]) which are not the same. |
I have encountered a potential bug with certain angles between two given orientations. The orientations start as euler angles and are then converted to orix Orientations.
Example:
Then if I compare the results of
I would expect the angle difference to be very small for both but only the first way gives the expected answer of 0.4727 while angle_with returns 30.0036. It seems to not take into account the 120degree symmetry in the first euler angle.
Further euler angle examples that give similarly strange results are:
[302. , -52.35178357 , -46.0036662 ] to [ 0. , 53.59948955 , 47.5 ]
[308.5 , -51.76150996 , -52. ] to [ 0. , 51.76150996 , 52. ]
[328.5 , -47.2657904 , -67.5 ] to [ 0. , 47.2657904 , 67.5 ]
These all have large differences when using angle_with and small, more expected, differences when using (Orientation - Orientation).angle.
However (Orientation - Orientation).angle also seems to have some flaws example:
[178.5 , 36.97748349 , 63.61592335] to [ 0. , 36.48968436 , 61.39659559]
Here Orientation.angle_with gives the expected result of 1.441 while (Orientation - Orientation).angle returns 39.268; seemingly not taking into account the 180degree symmetry in the first angle.
Hopefully this is enough to understand the issue, but if not I can provide more.
The text was updated successfully, but these errors were encountered: