orix icon indicating copy to clipboard operation
orix copied to clipboard

Problem in map_into_symmetry_reduced_zone

Open maclariz opened this issue 2 years ago • 9 comments

Running map_into_symmetry_reduced_zone() on sensible data (single crystal, all similar orientations) yields the following (just a few lines shown for illustration):

[-0.9681  0.0373 -0.0222  0.2467]
[-0.9685  0.0373 -0.0222  0.2452]
[-0.9685  0.0373  0.0222 -0.2451]
[-0.9686  0.0368  0.016  -0.2455]
[-0.9688  0.0373  0.0223 -0.2442]

Fixing this manually in a quick for loop gets me to:

[-0.96812383,  0.03732545,  0.02216656, -0.24668136],
[-0.96849277,  0.03729216,  0.02222252, -0.2452289 ],
[-0.96851503,  0.03729006,  0.02222605, -0.24514094],
[-0.96856316,  0.03676689,  0.01601705, -0.24551387],
[-0.96875969,  0.03726781,  0.02226333, -0.24417231],

(which is just a numpy array)

reimporting as an Orientation object, it then just transforms back to the first. Obviously, the constant sign flips in this data on index 2 and 3 in each quaternion play merry hell with any calculations!

maclariz avatar Jun 17 '22 18:06 maclariz

@maclariz could you provide the original orientation data before calling map_into_reduced_symmetry_zone()? Also the symmetry?

harripj avatar Jun 17 '22 19:06 harripj

@harripj Here you go:

 [ 0.5101 -0.0107  0.0421 -0.859 ]
 [ 0.5114 -0.0107  0.0421 -0.8582]
 [ 0.2451 -0.0222  0.0373 -0.9685]
 [ 0.2455 -0.016   0.0368 -0.9686]
 [ 0.2442 -0.0223  0.0373 -0.9688]

maclariz avatar Jun 20 '22 09:06 maclariz

@harripj m3m (FCC)

maclariz avatar Jun 20 '22 09:06 maclariz

The following sorted out my data and resulted in a consistent set of orientations that give consistent misorientation angles:

# Take the data into a pure numpy array
ori5 = ori3.data

# Drop into a setting where index 0 (cos angle) is positive, 1 (prop to x) and 2 (prop to y) are negative
# and index 3 (prop to z) are positive
ori5[:,0] = abs(ori5[:,0])
ori5[:,1] = -abs(ori5[:,1])
ori5[:,2] = -abs(ori5[:,2])
ori5[:,3] = abs(ori5[:,3])

# Transform back into orientation object without calling symmetry
ori5 = Orientation(ori5)
ori5

# Make a new mean orientation object without symmetry
mean4_1 = all4.mean()
mean4_1

# Make new misorientation object
ori6 = ori5-mean4_1

this is in no way a general solution, but works on a dataset where all orientations are broadly similar and map into a set of distinct orientation in a roughly 30 degree range (except for the odd noisy misindexed point).

maclariz avatar Jun 20 '22 12:06 maclariz

Hi @maclariz, I just eyeballed this in my lunchtime, but I think the sign flips might just be part of how fundamental zones worked. I would be interested to know what happens if you use https://github.com/pyxem/orix/blob/2d18672bd3beccf5b9da78e1f22e944d12870c33/orix/quaternion/orientation.py#L383 to assess the distances between the rotations after applying the symmetry?

pc494 avatar Jun 21 '22 14:06 pc494

@pc494 I don't know what this really adds, but I'll give you some output from this. This is a distance matrix of 6 points in this area with the orientation flips, converted to degrees (with np.degrees):

array([[ 0.        , 33.23155212,  0.05729578, 33.2888479 ,  0.72280107,0.05729578],
       [33.23155212,  0.        , 33.17425634,  0.05729578, 33.1164664 ,33.2888479 ],
       [ 0.05729578, 33.17425634,  0.        , 33.23155212,  0.71532024, 0.11459156],
       [33.2888479 ,  0.05729578, 33.23155212,  0.        , 33.17374857, 33.34614368],
       [ 0.72280107, 33.1164664 ,  0.71532024, 33.17374857,  0.        , 0.73468719],
       [ 0.05729578, 33.2888479 ,  0.11459156, 33.34614368,  0.73468719,0.        ]])

It would seem there are some different orientations there with very small angles above the lowest, and it is probably flipping between different solutions, purely on metric of lowest angle, rather than sticking with a consistent orientation of the x,y,z axes of the cell...

maclariz avatar Jun 22 '22 09:06 maclariz

@pc494 Here is the result of .to_matrix() on the same 6 data points:

array([[[ 0.87929659, -0.4723087 , -0.06133516],
        [ 0.47562573,  0.8775068 ,  0.06133494],
        [ 0.024853  , -0.08310418,  0.99623091]],

       [[ 0.87873789,  0.47334738,  0.06133494],
        [-0.47666228,  0.87694416,  0.06133516],
        [-0.02475448, -0.08313358,  0.99623091]],

       [[ 0.87882384, -0.47318776, -0.06133516],
        [ 0.476503  ,  0.87703074,  0.06133494],
        [ 0.02476988, -0.08312899,  0.99623091]],

       [[ 0.8792108 ,  0.47246841,  0.06133494],
        [-0.4757851 ,  0.87742039,  0.06133516],
        [-0.0248376 , -0.08310878,  0.99623091]],

       [[ 0.87893279, -0.47441358, -0.04908061],
        [ 0.47676917,  0.87674227,  0.0633573 ],
        [ 0.01297348, -0.07908693,  0.9967833 ]],

       [[ 0.87976846, -0.47142916, -0.06133516],
        [ 0.47474799,  0.87798199,  0.06133494],
        [ 0.02493609, -0.08307929,  0.99623091]]])

It is simply arbitrary sign flips on axes that is messing this up.

maclariz avatar Jun 22 '22 09:06 maclariz

So if I run:

o = Orientation([[ 0.5101, -0.0107,  0.0421, -0.859 ],
                [ 0.5114, -0.0107,  0.0421, -0.8582],
                [ 0.2451, -0.0222,  0.0373, -0.9685],
                [ 0.2455, -0.016 ,  0.0368, -0.9686],
                [ 0.2442, -0.0223,  0.0373, -0.9688]], symmetry=Oh)
# distance matrix original data
d1 =o.get_distance_matrix()

# distance matrix symmetry reduced data
o2 = o.map_into_symmetry_reduced_zone()
d2 = o2.get_distance_matrix()

# compute fractional error
diff = (d2 - d1) / d1
diff[np.diag_indices(diff.shape[0])] = 0
np.abs(diff.max())
0.0175

which tells me there is <2% error between o1 and o2, which is still quite large.

@maclariz I get different results on my machine, which we should clarify before going forward:

>>> o
Orientation (5,) m-3m
[[ 0.5101 -0.0107  0.0421 -0.859 ]
 [ 0.5114 -0.0107  0.0421 -0.8582]
 [ 0.2451 -0.0222  0.0373 -0.9685]
 [ 0.2455 -0.016   0.0368 -0.9686]
 [ 0.2442 -0.0223  0.0373 -0.9688]]

>>> o2
Orientation (5,) m-3m
[[ 0.9681  0.0222  0.0373 -0.2467]
 [ 0.9685  0.0222  0.0373 -0.2452]
 [ 0.9685  0.0373  0.0222  0.2451]
 [ 0.9686  0.0368  0.016   0.2455]
 [ 0.9688  0.0373  0.0223  0.2442]]

harripj avatar Jun 22 '22 14:06 harripj

I've changed the order of which symmetry elements are applied to the left and right of (mis)orientations when reducing them to the fundamental zone in #442. After this change, I get the following result

import numpy as np
from orix.quaternion import Orientation, symmetry


o = Orientation([[ 0.5101, -0.0107,  0.0421, -0.859 ],
                [ 0.5114, -0.0107,  0.0421, -0.8582],
                [ 0.2451, -0.0222,  0.0373, -0.9685],
                [ 0.2455, -0.016 ,  0.0368, -0.9686],
                [ 0.2442, -0.0223,  0.0373, -0.9688]], symmetry=symmetry.Oh)

# distance matrix original data
d1 = o.get_distance_matrix()

# distance matrix symmetry reduced data
o2 = o.reduce()  # Replaces map_into_symmetry_reduced_zone() 
print(o2)
# Orientation (5,) m-3m
# [[ 0.9681 -0.0373  0.0222 -0.2467]
# [ 0.9685 -0.0373  0.0222 -0.2452]
# [ 0.9685 -0.0373 -0.0222  0.2451]
# [ 0.9686 -0.0368 -0.016   0.2455]
# [ 0.9688 -0.0373 -0.0223  0.2442]]

d2 = o2.get_distance_matrix()

np.allclose(d1, d2)
# True

@maclariz, @harripj, I would be very happy if you could check out the branch in #442 and try reduce() on some Orientation and Misorientation issues you might have.

hakonanes avatar Apr 06 '23 21:04 hakonanes