Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
function [common_refl_pl_table, common_refl_pl_celllist] = gtTwinCalcCommonReflections(parent_gr, twin_variants, hklsp, varargin)
% GTTWINCALCCOMMONREFLECTIONS Function to calculate the common reflections
% between parent grain and twin variants.
%
% common_refls = gtTwinCalcCommonReflections(twin_variants, parent_gr, tol, input_type, phase_id, output_sparse_flag)
% ----------------------------------------------------------------------------
% INPUT:
% twin_variants = <double> Orientations for twin variants.
% Default values are sigma 3 and 9
% twin variants of FCC structure
% parent_gr = <double> The orientation of the parent
% grain. Default is the origin of
% orientation space.
% OPTIONAL INPUT:
% 'tol' = <double> The tolerance to check whether
% hkls are equal.
% Default value is 0.01.
%
% 'input_type' = <string> Input orientation ({'rod'}, 'orimat', or 'quat')
% rod: input array sized 3xN
% orimat: input array sized 3x3xN
% quat: input array sized 4xN (default)
% gr_id: grain ids 1xN
% 'phase_id' = <double> phase ID. Default value is 1.
% 'output_sparse' = <logical> Output uses sparse (true) or not
% (false). Default value is false.
%
% OUTPUT:
% common_refls = A table indicates common reflections. Its rows (vertical axis)
% represent the plane families of parent grain and
% its columns (horizontal axis) represent twin variants.
% e.g. common_refls(1, 2) = 3 means parameter.cryst.hklsp(:, 1)
% of parent grain and parameter.cryst.hklsp(:, 3) of the
% 2nd twin variant have common reflections.
%
% Verison 001 23-02-2021 by ZLiu, zheheng.liu@esrf.fr
%% set default parameters
if nargin < 2 || isempty(twin_variants)
twin_variants = gtTwinCalcSigma3nVariantsQuat(2); % sigma 3n twin variants of FCC structure in crystal coordinates
end
conf = struct( ...
'tol', 0.01, ...
'input_type', 'quat', ...
'phase_id', 1, ...
'output_sparse', false);
conf = parse_pv_pairs(conf, varargin);
switch lower(conf.input_type)
case 'rod'
oriConversion = @(x) gtMathsRod2OriMat(x);
case 'orimat'
oriConversion = @(x) x;
case 'gr_id'
sample = GtSample.loadFromFile;
oriConversion = @(x) gtMathsRod2OriMat(sample.phases{conf.phase_id}.R_vector(x, :)');
case 'quat'
oriConversion = @(x) gtMathsQuat2OriMat(x);
otherwise
gtError('gtTwinCalcCommonReflections:wrong_input_type', ...
'Allowed orientation types are ''rod'', ''orimat'', or ''quat''!');
end
%% Calculate rotation matrix from twin variants to parent grain
if ~nargin || isempty(parent_gr)
g_twin_variants = permute(oriConversion(twin_variants), [2, 1, 3]);
else
g_twin_variants = gtMathsMatrixProduct(oriConversion(parent_gr), permute(oriConversion(twin_variants), [2, 1, 3]));
end
if ~exist('hklsp', 'var') || isempty(hklsp)
parameters = gtLoadParameters();
hklsp = parameters.cryst.hklsp;
elseif isstruct(hklsp)
if isfield(hklsp, 'hklsp')
hklsp = hklsp.hklsp;
elseif isfield(hklsp, 'cryst')
hklsp = hklsp.cryst.hklsp;
else
error('Wrong input of HKL information')
end
end
Parent_refl_ori = hklsp;
% Transform the hkl of twin variants into coordinates of the parent.
Twin_refl_ori = gtMathsMatrixProduct(g_twin_variants, Parent_refl_ori);
%% Check whether the orientations are parallel
% Compare each hkl_i of parent grain with each hkl_kj = R_k*hkl_j of
% twin grains.
% (||n_i - m_j||^2 < tol or ||n_i + m_j||^2 < tol) is simplified as
% ||n_i||^2 + ||n_j||^2 - 2*|n_i'*n_j| < tol
tmp_innerprod = 2 * abs(gtMathsMatrixProduct(permute(Parent_refl_ori, [2, 1, 3]), Twin_refl_ori));
tmp_sqsum_t = sum(Twin_refl_ori.^2, 1);
tmp_sqsum_p = permute(sum(Parent_refl_ori.^2, 1), [2, 1, 3]);
tmp_sum = bsxfun(@plus, tmp_sqsum_p, tmp_sqsum_t);
Common_table = bsxfun(@minus, tmp_sum, tmp_innerprod) < conf.tol;
%% Transform the 3D logical matrix into 2D matrix
% In the 2nd dimension of the 3D logical matrix "Common_table", each
% column contains maximally one nonzero element. So we can represent
% these columns by the indices of nonzero elements.
if conf.output_sparse % use full or sparse matrix
[tmp_ind1, tmp_ind_tw, tmp_ind2] = ind2sub(size(Common_table), find(Common_table));
common_refl_pl_table = sparse(tmp_ind1, tmp_ind2, tmp_ind_tw);
else
common_refl_pl_table = uint8(sum(bsxfun(@times, Common_table, 1:size(Parent_refl_ori, 2)), 2));
common_refl_pl_table = reshape(common_refl_pl_table, size(Parent_refl_ori, 2), size(g_twin_variants, 3));
end
% Extra output
if nargout > 1
common_refl_pl_celllist = cell(1, size(common_refl_pl_table, 1));
hklind_shared = find(any(common_refl_pl_table, 2));
tmpstruct = struct('grain', 0, 'HKL', [0, 0, 0]);
for ii_hkl = 1:numel(hklind_shared)
grainind_shared = find(common_refl_pl_table(hklind_shared(ii_hkl), :));
common_refl_pl_celllist{hklind_shared(ii_hkl)} = tmpstruct(ones(1, numel(grainind_shared)));
common_refl_pl_celllist{hklind_shared(ii_hkl)}(1).HKL = hklsp(:, hklind_shared(ii_hkl))';
for ii_g = 1:numel(grainind_shared)
common_refl_pl_celllist{hklind_shared(ii_hkl)}(ii_g+1) = struct(...
'grain', grainind_shared(ii_g), ...
'HKL', hklsp(:, common_refl_pl_table(hklind_shared(ii_hkl), grainind_shared(ii_g)))');
end
end
end
end