vectorized IPF color working

results also uses the vectorized form.
Still needs careful checking
This commit is contained in:
Martin Diehl 2020-06-20 17:15:13 +02:00
parent ebdb65d31f
commit 4dae3643c9
2 changed files with 27 additions and 24 deletions

View File

@ -3,7 +3,7 @@ import numpy as np
from . import Lattice from . import Lattice
from . import Rotation from . import Rotation
class Orientation: # make subclass or Rotation? class Orientation: # ToDo: make subclass of lattice and Rotation
""" """
Crystallographic orientation. Crystallographic orientation.
@ -105,12 +105,14 @@ class Orientation: # make subclass or Rotation?
is added to the left of the rotation array. is added to the left of the rotation array.
""" """
symmetry_operations = self.lattice.symmetry.symmetry_operations s = self.lattice.symmetry.symmetry_operations
s = s.reshape(s.shape[:1]+(1,)*len(self.rotation.shape)+(4,))
s = Rotation(np.broadcast_to(s,s.shape[:1]+self.rotation.quaternion.shape))
q = np.block([self.rotation.quaternion]*symmetry_operations.shape[0]) r = np.broadcast_to(self.rotation.quaternion,s.shape[:1]+self.rotation.quaternion.shape)
r = Rotation(q.reshape(symmetry_operations.shape+self.rotation.quaternion.shape)) r = Rotation(r)
return self.__class__(symmetry_operations.broadcast_to(r.shape)@r,self.lattice) return self.__class__(s@r,self.lattice)
def equivalentOrientations(self,members=[]): def equivalentOrientations(self,members=[]):
@ -156,10 +158,10 @@ class Orientation: # make subclass or Rotation?
"""Axis rotated according to orientation (using crystal symmetry to ensure location falls into SST).""" """Axis rotated according to orientation (using crystal symmetry to ensure location falls into SST)."""
if SST: # pole requested to be within SST if SST: # pole requested to be within SST
for i,o in enumerate(self.equivalentOrientations()): # test all symmetric equivalent quaternions for i,o in enumerate(self.equivalentOrientations()): # test all symmetric equivalent quaternions
pole = o.rotation*axis # align crystal direction to axis pole = o.rotation@axis # align crystal direction to axis
if self.lattice.symmetry.inSST(pole,proper): break # found SST version if self.lattice.symmetry.inSST(pole,proper): break # found SST version
else: else:
pole = self.rotation*axis # align crystal direction to axis pole = self.rotation@axis # align crystal direction to axis
return (pole,i if SST else 0) return (pole,i if SST else 0)
@ -169,7 +171,7 @@ class Orientation: # make subclass or Rotation?
color = np.zeros(3,'d') color = np.zeros(3,'d')
for o in self.equivalentOrientations(): for o in self.equivalentOrientations():
pole = o.rotation*axis # align crystal direction to axis pole = o.rotation@axis # align crystal direction to axis
inSST,color = self.lattice.symmetry.inSST(pole,color=True) inSST,color = self.lattice.symmetry.inSST(pole,color=True)
if inSST: break if inSST: break
@ -178,12 +180,18 @@ class Orientation: # make subclass or Rotation?
def IPF_color(self,axis): def IPF_color(self,axis):
"""TSL color of inverse pole figure for given axis.""" """TSL color of inverse pole figure for given axis."""
color = np.zeros(self.rotation.shape)
eq = self.equivalent eq = self.equivalent
pole = eq.rotation @ np.broadcast_to(axis,eq.rotation.shape+(3,)) pole = eq.rotation @ np.broadcast_to(axis/np.linalg.norm(axis),eq.rotation.shape+(3,))
in_SST, color = self.lattice.symmetry.in_SST(pole,color=True) in_SST, color = self.lattice.symmetry.in_SST(pole,color=True)
return color[in_SST] # ignore duplicates (occur for highly symmetric orientations)
found = np.zeros_like(in_SST[1],dtype=bool)
c = np.empty(color.shape[1:])
for s in range(in_SST.shape[0]):
c = np.where(np.expand_dims(np.logical_and(in_SST[s],~found),-1),color[s],c)
found = np.logical_or(in_SST[s],found)
return c
@staticmethod @staticmethod

View File

@ -10,6 +10,7 @@ from functools import partial
import h5py import h5py
import numpy as np import numpy as np
from numpy.lib import recfunctions as rfn
from . import VTK from . import VTK
from . import Table from . import Table
@ -733,23 +734,17 @@ class Result:
@staticmethod @staticmethod
def _add_IPFcolor(q,l): def _add_IPFcolor(q,l):
d = np.array(l) m = util.scale_to_coprime(np.array(l))
d_unit = d/np.linalg.norm(d)
m = util.scale_to_coprime(d)
colors = np.empty((len(q['data']),3),np.uint8)
lattice = q['meta']['Lattice'] o = Orientation(Rotation(rfn.structured_to_unstructured(q['data'])),
lattice = q['meta']['Lattice'])
for i,qu in enumerate(q['data']):
o = Orientation(np.array([qu['w'],qu['x'],qu['y'],qu['z']]),lattice).reduced()
colors[i] = np.uint8(o.IPFcolor(d_unit)*255)
return { return {
'data': colors, 'data': np.uint8(o.IPF_color(l)*255),
'label': 'IPFcolor_[{} {} {}]'.format(*m), 'label': 'IPFcolor_[{} {} {}]'.format(*m),
'meta' : { 'meta' : {
'Unit': 'RGB (8bit)', 'Unit': '8-bit RGB',
'Lattice': lattice, 'Lattice': q['meta']['Lattice'],
'Description': 'Inverse Pole Figure (IPF) colors along sample direction [{} {} {}]'.format(*m), 'Description': 'Inverse Pole Figure (IPF) colors along sample direction [{} {} {}]'.format(*m),
'Creator': inspect.stack()[0][3][1:] 'Creator': inspect.stack()[0][3][1:]
} }