Newer
Older
function [Rout, goodrids, goodlines, Rdist, Redge] = ...
Peter Reischig
committed
gtCrystRodriguesTestCore(rline, rid, fzone_acc, fzone_ext, tol_Rdist)
% FUNCTION [Rout, goodrids, goodlines, Rdist, Redge] = ...
Peter Reischig
committed
% gtCrystRodriguesTestCore(rline, rid, fzone_acc, fzone_ext, tol)
%
% 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.
%
% Note that this procedure is independent from how the Rodrigues vectors
% were calculated or their relation to crystal orientations.
%
%
% INPUT
% rline - lines in Rodrigues space (n,6)
% rid - reflection id-s of rlines; it is used to identify which
% lines belong to the same plane normal, as one reflection
% can have multiple lines; its values can be any numbers,
% as long as there is one unique number for one reflection;
% size (n,1)
% fzone_acc - the exact fundamental zone in Rodrigues space
% fzone_ext - extended fundamental zone to account for inaccuracy of
% data
Peter Reischig
committed
% tol_Rdist - max. distance between intersecting lines in Rodrigues
% space (accounts for data inaccuracy)
%
% OUTPUT
% Rout - fitted Rodrigues vector
% goodrids - list of unique reflection id-s that fit the solution
% goodlines - list of line indices 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
%
tol_Rdist = tol_Rdist + 1e-15;
nof_lines = size(rline,1);
% No. of unique reflection id-s
nurid = length(unique(rid));
Rout = [];
Rdist = [];
Redge = [];
goodrids = [];
goodlines = [];
Peter Reischig
committed
% Tolerance for two lines to be considered parallel in Rod. space.
% A reasonable constant value has to be chosen dependent on 'tol_Rdist'
% that scales with the expected angular error. Here it is used directly and
% it seems to work to find the parallel lines:
tol_cos = cos(tol_Rdist);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Find line intersections -> base nodes
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% The distances, dot products and intersection points of all pair
% combinations of the input lines are calculated.
Ld = zeros(nof_lines); % distance of Rlines pairwise
Lc = zeros(nof_lines); % angle of Rlines pairwise
[Lidb,Lida] = meshgrid(1:nof_lines);
% Reflection id-s as in the input
Rida = rid(:,ones(1,nof_lines));
Ridb = Rida';
% Determine intersections of all lines with one another in Rodr. space
for ii = 1:nof_lines-1
% distance pair-wise
Ld(ii,ii+1:end) = gtMathsLinesDists(rline(ii,:),rline(ii+1:end,:));
% dot product of the direction vectors pair-wise (=cosine of the angles)
Lc(ii,ii+1:end) = sum(rline(ii(ones(nof_lines-ii,1)),4:6).*rline(ii+1:end,4:6),2);
end
% Which lines are identical pair-wise (small distance and angle)
% -> double detection of Friedel pairs or wrong indexing
Lp = (Ld <= tol_Rdist) & (abs(Lc) >= tol_cos);
% Make matrices symmetric
Ld = Ld + Ld';
Lp = Lp | Lp';
% Which lines are closer than the tolerance ?
Lnear = (Ld <= tol_Rdist);
Lnear(sub2ind([nof_lines nof_lines], 1:nof_lines, 1:nof_lines)) = false;
Peter Reischig
committed
% Intersections of the lines that are close but not identical (parallel)
% constitute the base set:
baseset = Lnear & (~Lp);
Peter Reischig
committed
% Line indices in the base set
LAbase = Lida(baseset);
LBbase = Lidb(baseset);
Peter Reischig
committed
% Reflection id-s in the base set
RAbase = Rida(baseset);
RBbase = Ridb(baseset);
Peter Reischig
committed
% Find intersection points of the base set -> Nodes coordinates Nbase
Nbase = zeros(length(LAbase),3);
LBbaseuni = unique(LBbase);
for ii = 1:length(LBbaseuni)
% Do the identical indices at once
inds = (LBbase == LBbaseuni(ii));
Nbase(inds,:) = gtMathsLinePairsIntersections(rline(LBbaseuni(ii),:), ...
rline(LAbase(inds),:));
end
% Which nodes are in the (extended) fundamental zone ?
inzone = gtMathsIsPointInPolyhedron(Nbase,fzone_ext);
% Keep only base nodes in the fund. zone
Nbase = Nbase(inzone,:); % Base node coordinates
LAbase = LAbase(inzone); % Line A id-s corresponding to base nodes
LBbase = LBbase(inzone); % Line B id-s corresponding to base nodes
RAbase = RAbase(inzone); % Reflection A id-s corresponding to base nodes
RBbase = RBbase(inzone); % Reflection B id-s corresponding to base node
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Find neighbouring base nodes
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Check which base nodes are close to each other -> neighbouring nodes
Peter Reischig
committed
told = tol_Rdist^2;
nof_Nbase = size(Nbase,1); % no. of nodes
Nneib = false(nof_Nbase); % neighbouring nodes
% !!! This could be a parfor loop
for 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);
Nneib(ii,:) = distok;
end
% Set diagonals to false
Nneib(sub2ind([nof_Nbase nof_Nbase],1:nof_Nbase,1:nof_Nbase)) = false;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Find the highest concentration of neighbouring nodes
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Loop through neighbouring nodes to find the highest agglomeration
Nnurids = zeros(nof_Nbase,1); % number of planes belonging to the nodes
finish = false;
Peter Reischig
committed
intsc.Rvec = [];
% 'Nneib' is a logical array, true where the two nodes are neighbours.
% Loop as long as there are nodes remaining to be checked
while any(Nneib(:)) % !!! check if this loop is needed; maybe can squeeze Nneib
Nurids = cell(1,nof_Nbase);
Nlis = cell(1,nof_Nbase);
% Loop through all nodes
for ii = 1:nof_Nbase
inb = Nneib(:,ii); % indices of (remaining) neighbouring nodes
urids = RAbase(inb); % reflection A id-s of remaining neighbours
urids = [urids; RBbase(inb)]; % add reflection B id-s of remaining neighbours
urids = unique(urids); % all reflections id-s that are close to node ii
Nurids{ii} = urids; % ref id-s being close to this node
Nnurids(ii) = length(urids); % no. of those ref id-s
linds = LAbase(inb); % line A indices of remaining neighbours
linds = [linds; LBbase(inb)]; % line B indices of remaining neighbours
linds = unique(linds); % all line indices close to node ii
Nlis{ii} = linds; % uniqued line indices close to node ii
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
% if urids includes all plane normals
if length(urids)==nurid
% Rodrigues vector is the fitted intersection of those lines
Rvec = gtMathsLinesIntersection(rline(linds,:))';
% 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 reflections
if finish
intsc.lines = linds;
intsc.urids = urids;
intsc.Rvec = Rvec;
break % while loop
end
% node index with most reflection id-s
[~,ibn] = max(Nnurids);
% Rodrigues vector
Rvec = gtMathsLinesIntersection(rline(Nlis{ibn},:))';
% Test if Rvec is in the accurate fund. zone
if gtMathsIsPointInPolyhedron(Rvec,fzone_acc)
intsc.lines = Nlis{ibn};
intsc.urids = Nurids{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.urids = Nurids{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 = Rvec - Rsecs(1,:);
Rsecdist1 = sqrt(Rsecdist1*Rsecdist1');
Rsecdist2 = Rvec - Rsecs(2,:);
Rsecdist2 = sqrt(Rsecdist2*Rsecdist2');
% 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 isempty(intsc.Rvec)
return
end
%%%%%%%%%%%%%%%%%%%%%%%
%% Finish up
%%%%%%%%%%%%%%%%%%%%%%%
Rout = intsc.Rvec;
goodrids = intsc.urids;
goodlines = intsc.lines;
% This probably should not happen, but for safety
if length(goodlines) > length(goodrids)
Peter Reischig
committed
disp('WARNING! Multiple signed hkl-s found for some reflections.')
[goodrids,ind] = unique(rid(goodlines));
goodlines = goodlines(ind);
end
% Minimum distance from edge of exact fundamental zone:
% Fundamental zone face directions should be normalised before input
%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 = Rout(ones(size(fzone_acc,1),1),:) - fzone_acc(:,1:3);
% Signed distances between Rout point and fund. zone faces
Rdistall = sum(diffRout.*fzone_acc(:,4:6),2);
% Distance between Rout and nearest fund. zone face
Rdist = min(abs(Rdistall));
% Distance smaller than tolerance ?
Redge = Rdist <= tol_Rdist;
% 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 % of function