Newer
Older
function [Rout, good_plnorms, Rdist, Redge] = gtCrystRodriguesTest(...
plnorm, hkl, spacegroup, Bmat, shkl_flag, plot_flag, toldist)
%
% FUNCTION [Rout, good_plnorms, Rdist, Redge] = gtCrystRodriguesTest(...
% plnorm, hkl, spacegroup, Bmat, shkl_flag, plot_flag, toldist)
%
% The use of gtCrystRodriguesTestCore instead of this function is recommended.
%
% Performs an orientation test in Rodrigues space on the specified plane
% normals. Gives which plane normals constitute a consistent crystal and
% its fitted Rodrigues vector.
% Also determines how far this point is from the nearest boundary of the
% fundamental zone, and whether this distance is smaller than the specified
% limit.
%
% INPUT
% plnorm - plane normal coordinates in sample coords (nx3)
% hkl - hkl reflection types, eg. [1 1 1; 0 0 2; 2 2 0]
% OR if known, specific hkl reflections, eg. [-1 1 -1; 0 0
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
% spacegroup - crystallographic spacegroup
% Bmat - transformation matrix from HKL to Cartesian coordinates
% shkl_flag - set to true for speeding up, if the signed hkl-s
% are used
% plot_flag - if true, figure is plotted showing data in Rodrigues
% space
% toldist - tolerance for distance in Rodrigues space (if empty,
% default value is used)
%
% OUTPUT
% Rout - fitted Rodrigues vector
% good_plnorms - the good plane normals that fit the solution
% Rdist - distance between Rout and the nearest fundamental zone
% boundary plane in Rodrigues space
% Redge - true if Rdist is smaller than the specified tolerance
%
% Tolerance for distance in Rodrigues's space; default=0.02
if isempty(toldist)
tol.dist = 0.02;
else
tol.dist = toldist;
end
tol.pd = tol.dist/5; % approximate tolerance angle for parallelism (radian)
tol.pc = cos(tol.pd); % tolerance for parallelism (cosine of angle)
tol.sm = tol.dist; % safety margin in Rodr. space (tolerance to extend fund. zone)
nof_pln = size(plnorm,1); % number of plane normals
good_plnorms = false(1,nof_pln);
Rout = [];
R.l = [];
R.wpl = [];
R.enda = [];
R.endb = [];
Rdist = [];
Redge = [];
intsc.lines = [];
intsc.planes = [];
intsc.Rvec = [];
fzone_ext = gtCrystRodriguesFundZone(spacegroup,tol.sm); % fund. zone with safety margin
fzone_acc = gtCrystRodriguesFundZone(spacegroup,0); % exact fund. zone
symm = gtCrystGetSymmetryOperators([], spacegroup);
%% Determine line coordinates in Rodrigues space
% If the signed hkl is known for each plane normal
if shkl_flag
% Loop through all plane normals
for i = 1:nof_pln
% Lines coordinates
[Rvec,isec1,isec2] = gtCrystRodriguesVector(plnorm(i,:),hkl(i,:),Bmat,fzone_ext);
R.l = [R.l; Rvec]; % all lines in Rodrigues's space (may be empty)
R.wpl = [R.wpl; i*ones(size(Rvec,1),1)]; % which plane normal it belongs to
R.enda = [R.enda; isec1]; % intersection A with fund zone
R.endb = [R.endb; isec2]; % intersection B with fund zone
end
% If the signed hkl-s are unknown, and only the hkl families are known
else
% Loop through all plane normals
for i = 1:nof_pln
%[Rvec,isec1,isec2] = gtRodriguesVectors2(plnorm(i,:),hkl(i,:),spacegroup,latticepar,tol.sm);
% All signed hkl-s for given hkl family
shkls = gtCrystSignedHKLs(hkl(i,:), symm);
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
[Rvec,isec1,isec2] = gtCrystRodriguesVector(plnorm(i,:),shkls,Bmat,fzone_ext);
R.l = [R.l; Rvec]; % all lines in Rodrigues's space (may be empty)
R.wpl = [R.wpl; i*ones(size(Rvec,1),1)]; % which plane normal it belongs to
R.enda = [R.enda; isec1]; % intersection A with fund zone
R.endb = [R.endb; isec2]; % intersection B with fund zone
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Determine line intersections -> base nodes
nof_lines = length(R.wpl);
Lp = false(nof_lines); %
Ld = zeros(nof_lines); % distance of Rlines pairwise
Lc = zeros(nof_lines); % angle of Rlines pairwise
Lrx = zeros(nof_lines);
Lry = zeros(nof_lines);
Lrz = zeros(nof_lines);
% store line id-s for identification
[Lidb,Lida] = meshgrid(1:nof_lines);
Pida = repmat(R.wpl,1,nof_lines);
Pidb = Pida';
% Determine intersections of all lines with one another in Rodr. space
for i = 1:nof_lines-1
% distance pair-wise
Ld(i,i+1:end) = gtMathsLinesDists(R.l(i,:),R.l(i+1:end,:));
% dot product of the direction vectors pair-wise (=cosine of the angles)
Lc(i,i+1:end) = sum(repmat(R.l(i,4:6),nof_lines-i,1).*R.l(i+1:end,4:6),2);
% intersection points in Rodr. space
r = gtMathsLinePairsIntersections(R.l(i,:),R.l(i+1:end,:));
Lrx(i,i+1:end) = r(:,1);
Lry(i,i+1:end) = r(:,2);
Lrz(i,i+1:end) = r(:,3);
end
% Which lines are identical pair-wise (small distance and angle)
% -> double detection of Friedel pairs or wrong indexing
Lp = (Ld <= tol.pd) & (abs(Lc) >= tol.pc);
% Make matrices symmetric
Ld = Ld+Ld';
Lc = Lc+Lc';
Lp = Lp | Lp';
Lrx = Lrx+Lrx';
Lry = Lry+Lry';
Lrz = Lrz+Lrz';
% Which lines are closer than the tolerance ?
Lnear = Ld <= tol.dist;
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
for i = 1:nof_lines
Lnear(i,i) = false;
end
% Lines that are close but not identical (parallel) constitute the base set:
baseset = Lnear & (~Lp);
% Nodes are the intersection points of the base set:
Nbase = [Lrx(baseset),Lry(baseset),Lrz(baseset)];
LAbase = Lida(baseset);
LBbase = Lidb(baseset);
PLAbase = Pida(baseset);
PLBbase = Pidb(baseset);
% Which nodes are in the (extended) fundamental zone ?
% inzone = false(size(Nbase,1),1);
% for i = 1:size(Nbase,1)
% inzone(i) = gtMathsIsPointInPolyhedron(Nbase(i,:),fzone_ext);
% end
inzone = gtMathsIsPointInPolyhedron(Nbase,fzone_ext);
% Keep only base nodes in the fund. zone
Nbase = Nbase(inzone,:);
LAbase = LAbase(inzone);
LBbase = LBbase(inzone);
PLAbase = PLAbase(inzone);
PLBbase = PLBbase(inzone);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Find neighbouring nodes
% Check which base nodes are close to each other -> neighbouring nodes
told = tol.dist^2;
nof_Nbase = size(Nbase,1); % no. of nodes
Nneib = false(nof_Nbase); % neighbouring nodes
parfor ii = 1:nof_Nbase-1
dist = [Nbase(ii,1)-Nbase(:,1), ...
Nbase(ii,2)-Nbase(:,2), ...
Nbase(ii,3)-Nbase(:,3)];
dist = sum(dist.*dist,2);
distok = dist <= told;
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
Nneib(ii,:) = distok;
end
% Set diagonals to false
Nneib(sub2ind([nof_Nbase nof_Nbase],1:nof_Nbase,1:nof_Nbase)) = false;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Find the highest agglomeration of nodes
% Loop through neighbouring nodes to find the highest agglomeration
Nnpl = zeros(nof_Nbase,1); % number of planes belonging to the nodes
finish = false;
% as long as there is nodes remaining to be checked
while ismember(true,Nneib)
for i = 1:nof_Nbase
inb = Nneib(:,i); % index of remaining neighbouring nodes
pls = PLAbase(inb); % plane indices
pls = [pls; PLBbase(inb)];
pls = unique(pls); % all planes indices which come close this node
Npls{i} = pls; % store planes being close to this node
Nnpl(i) = length(pls); % no. of those planes
lis = LAbase(inb); % line indices
lis = [lis; LBbase(inb)];
lis = unique(lis); % all line indices which come close this node
Nlis{i} = lis; % lines being close to this node
% if pls includes all plane normals
if length(pls)==nof_pln
% Rodrigues vector is the fitted intersection of the lines
Rvec = gtMathsLinesIntersection(R.l(lis,:))';
% If Rvec is in the fund. zone, we found the solution
if gtMathsIsPointInPolyhedron(Rvec,fzone_acc)
finish = true;
break % for loop
end
end
end
% Solution found with all planes
if finish
intsc.lines = lis;
intsc.planes = pls';
intsc.Rvec = Rvec;
break % while loop
end
% node index with most planes
[~,ibn] = max(Nnpl);
% Rodrigues vector
Rvec = gtMathsLinesIntersection(R.l(Nlis{ibn},:))';
% Test if Rvec is in the accurate fund. zone
if gtMathsIsPointInPolyhedron(Rvec,fzone_acc)
intsc.lines = (Nlis{ibn})';
intsc.planes = (Npls{ibn})';
intsc.Rvec = Rvec;
break % while loop
end
% Test if Rvec is in the extended fund. zone
if gtMathsIsPointInPolyhedron(Rvec,fzone_ext)
intsc.lines = (Nlis{ibn})';
intsc.planes = (Npls{ibn})';
% Use its intersections with the accurate fund. zone, instead of Rvec
Rsecs = gtMathsLinePolyhedronIntersections([0 0 0 Rvec],fzone_acc);
% Distances between the two intersections and Rvec
Rsecdist1 = norm(Rvec - Rsecs(1,:));
Rsecdist2 = norm(Rvec - Rsecs(2,:));
% Use the closer intersection
if Rsecdist1 < Rsecdist2
intsc.Rvec = Rsecs(1,:);
else
intsc.Rvec = Rsecs(2,:);
end
break % while loop
end
% The node with the most plane normals doesn't provide a solution in the
% extended fund. zone. Ignore best node in the neighbourhood matrix, and start the
% loop again:
Nneib(Nneib(:,ibn),:) = false;
Nneib(:,Nneib(ibn,:)) = false;
Nneib(ibn,:) = false;
Nneib(:,ibn) = false;
end
if plot_flag
sfPlotInts(intsc,R,fzone_acc)
end
if isempty(intsc.Rvec)
return
end
Rout = intsc.Rvec;
good_plnorms(intsc.planes) = true;
% Minimum distance from edge of exact fundamental zone:
% Normalise fund. zone face direction vectors
fzonedirnorm = fzone_acc(:,4:6)./repmat(sqrt(sum(fzone_acc(:,4:6).*fzone_acc(:,4:6),2)),1,3);
% Difference vector between Rout and fund. zone face position vectors
diffRout = repmat(Rout,size(fzone_acc,1),1)-fzone_acc(:,1:3);
% Signed distances between Rout point and fund. zone faces
Rdistall = sum(diffRout.*fzonedirnorm,2);
% Distance between Rout and nearest fund. zone face
Rdist = min(abs(Rdistall));
% Distance smaller than tolerance ?
Redge = Rdist <= tol.dist;
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
% If R vector is slightly out of the fundamental zone boundaries, set it
% back on the nearest boundary plane.
% if Rdistall(minind) > 0
% Rout = Rout - Rdistall(minind)*fzone_acc(minind,4:6);
% Rdist = 0;
% end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% SUB-FUNCTIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Plotting
function sfPlotInts(intsc,R,fzone_acc)
figure, hold on, axis equal
xlabel('x')
ylabel('y')
zlabel('z')
grid
rangemin = min(fzone_acc(:,1:3));
rangemax = max(fzone_acc(:,1:3));
xlim([rangemin(1) rangemax(1)]);
ylim([rangemin(2) rangemax(2)]);
zlim([rangemin(3) rangemax(3)]);
nof_lines = size(R.l,1);
lc = autumn(nof_lines);
for i = 1:nof_lines
isec = gtMathsLinePolyhedronIntersections(R.l(i,:),fzone_acc);
if ~isempty(isec)
R.enda(i,:) = isec(1,:);
R.endb(i,:) = isec(2,:);
if ismember(i,intsc.lines)
plot3([R.enda(i,1) R.endb(i,1)],[R.enda(i,2) R.endb(i,2)],[R.enda(i,3) R.endb(i,3)],'Color','k') %lc(i,:))
else
plot3([R.enda(i,1) R.endb(i,1)],[R.enda(i,2) R.endb(i,2)],[R.enda(i,3) R.endb(i,3)],'Color',lc(i,:))
end
end
end
if ~isempty(intsc.Rvec)
plot3(intsc.Rvec(1),intsc.Rvec(2),intsc.Rvec(3),'bo')
plot3(intsc.Rvec(1),intsc.Rvec(2),intsc.Rvec(3),'bo','MarkerSize',15)
end
end