From de428efca5104616192cb90a4434b6ef860dbe36 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 18 Jul 2021 18:03:36 +0200 Subject: [PATCH] add_pole is working again --- python/damask/_orientation.py | 3 +- python/damask/_result.py | 68 +++++++++++++++-------------------- python/tests/test_Result.py | 21 +++++------ 3 files changed, 38 insertions(+), 54 deletions(-) diff --git a/python/damask/_orientation.py b/python/damask/_orientation.py index 545205c0a..448ba3159 100644 --- a/python/damask/_orientation.py +++ b/python/damask/_orientation.py @@ -843,10 +843,9 @@ class Orientation(Rotation,Crystal): Lab frame vector (or vectors if with_symmetry) along [uvw] direction or (hkl) plane normal. """ - sym_ops = self.symmetry_operations - # ToDo: simplify 'with_symmetry' v = self.to_frame(uvw=uvw,hkl=hkl) if with_symmetry: + sym_ops = self.symmetry_operations v = sym_ops.broadcast_to(sym_ops.shape+v.shape[:-1],mode='right') \ @ np.broadcast_to(v,sym_ops.shape+v.shape) return ~(self if self.shape+v.shape[:-1] == () else self.broadcast_to(self.shape+v.shape[:-1],mode='right')) \ diff --git a/python/damask/_result.py b/python/damask/_result.py index 1fa376f63..03bb34926 100644 --- a/python/damask/_result.py +++ b/python/damask/_result.py @@ -979,47 +979,35 @@ class Result: self._add_generic_pointwise(self._add_stress_second_Piola_Kirchhoff,{'P':P,'F':F}) -# The add_pole functionality needs discussion. -# The new Crystal object can perform such a calculation but the outcome depends on the lattice parameters -# as well as on whether a direction or plane is concerned (see the DAMASK_examples/pole_figure notebook). -# Below code appears to be too simplistic. - # @staticmethod - # def _add_pole(q,p,polar): - # pole = np.array(p) - # unit_pole = pole/np.linalg.norm(pole) - # m = util.scale_to_coprime(pole) - # rot = Rotation(q['data'].view(np.double).reshape(-1,4)) - # - # rotatedPole = rot @ np.broadcast_to(unit_pole,rot.shape+(3,)) # rotate pole according to crystal orientation - # xy = rotatedPole[:,0:2]/(1.+abs(unit_pole[2])) # stereographic projection - # coords = xy if not polar else \ - # np.block([np.sqrt(xy[:,0:1]*xy[:,0:1]+xy[:,1:2]*xy[:,1:2]),np.arctan2(xy[:,1:2],xy[:,0:1])]) - # return { - # 'data': coords, - # 'label': 'p^{}_[{} {} {})'.format(u'rφ' if polar else 'xy',*m), - # 'meta' : { - # 'unit': '1', - # 'description': '{} coordinates of stereographic projection of pole (direction/plane) in crystal frame'\ - # .format('Polar' if polar else 'Cartesian'), - # 'creator': 'add_pole' - # } - # } - # def add_pole(self,q,p,polar=False): - # """ - # Add coordinates of stereographic projection of given pole in crystal frame. - # - # Parameters - # ---------- - # q : str - # Name of the dataset containing the crystallographic orientation as quaternions. - # p : numpy.array of shape (3) - # Crystallographic direction or plane. - # polar : bool, optional - # Give pole in polar coordinates. Defaults to False. - # - # """ - # self._add_generic_pointwise(self._add_pole,{'q':q},{'p':p,'polar':polar}) + @staticmethod + def _add_pole(q,uvw,hkl): + c = q['meta']['c/a'] if 'c/a' in q['meta'] else 1 + pole = Orientation(q['data'], lattice=q['meta']['lattice'], a=1, c=c).to_pole(uvw=uvw,hkl=hkl) + + return { + 'data': pole, + 'label': 'p^[{} {} {}]'.format(*uvw) if uvw else 'p^({} {} {})'.format(*hkl), + 'meta' : { + 'unit': '1', + 'description': f"lab frame vector along lattice {'direction' if uvw else 'plane'}", + 'creator': 'add_pole' + } + } + def add_pole(self,q='O',*,uvw=None,hkl=None): + """ + Add lab frame vector along lattice direction [uvw] or plane normal (hkl). + + Parameters + ---------- + q : str + Name of the dataset containing the crystallographic orientation as quaternions. + Defaults to 'O'. + uvw|hkl : numpy.ndarray of shape (...,3) + Miller indices of crystallographic direction or plane normal. + + """ + self._add_generic_pointwise(self._add_pole,{'q':q},{'uvw':uvw,'hkl':hkl}) @staticmethod diff --git a/python/tests/test_Result.py b/python/tests/test_Result.py index 5f543861d..7126b4ab0 100644 --- a/python/tests/test_Result.py +++ b/python/tests/test_Result.py @@ -12,7 +12,6 @@ import vtk import numpy as np from damask import Result -from damask import Rotation from damask import Orientation from damask import tensor from damask import mechanics @@ -220,17 +219,15 @@ class TestResult: in_file = default.place('S') assert np.allclose(in_memory,in_file) - @pytest.mark.skip(reason='requires rework of lattice.f90') - @pytest.mark.parametrize('polar',[True,False]) - def test_add_pole(self,default,polar): - pole = np.array([1.,0.,0.]) - default.add_pole('O',pole,polar) - rot = Rotation(default.place('O')) - rotated_pole = rot * np.broadcast_to(pole,rot.shape+(3,)) - xy = rotated_pole[:,0:2]/(1.+abs(pole[2])) - in_memory = xy if not polar else \ - np.block([np.sqrt(xy[:,0:1]*xy[:,0:1]+xy[:,1:2]*xy[:,1:2]),np.arctan2(xy[:,1:2],xy[:,0:1])]) - in_file = default.place('p^{}_[1 0 0)'.format(u'rφ' if polar else 'xy')) + @pytest.mark.parametrize('options',[{'uvw':[1,0,0]},{'hkl':[0,1,1]}]) + def test_add_pole(self,default,options): + default.add_pole(**options) + rot = default.place('O') + in_memory = Orientation(rot,lattice=rot.dtype.metadata['lattice']).to_pole(**options) + brackets = ['[[]','[]]'] if 'uvw' in options.keys() else ['(',')'] # escape fnmatch + label = '{}{} {} {}{}'.format(brackets[0],*(list(options.values())[0]),brackets[1]) + in_file = default.place(f'p^{label}') + print(in_file - in_memory) assert np.allclose(in_memory,in_file) def test_add_rotation(self,default):