-
Laura Nervo authored
Signed-off-by:
Laura Nervo <laura.nervo@esrf.fr>
Laura Nervo authoredSigned-off-by:
Laura Nervo <laura.nervo@esrf.fr>
gtIndexFwdSimGrains.m 6.81 KiB
function grain = gtIndexFwdSimGrains(grain, parameters, fsimID)
% GTINDEXFWDSIMGRAINS Forward simulates the spot positions for all
% reflections in all grains.
%
% grain = gtIndexFwdSimGrains(grain, [parameters], [fsimID])
% ----------------------------------------------------------
% It should be run after gtIndexAddInfo, like below:
%
% index = load('4_grains/phase_##/index.mat')
% grain = gtIndexAddInfo(index.grain, phaseid, parameters);
%
% INPUT
% grain = <cell> structure containing grain information
% parameters = <struct> parameters as in the parameters file
% fsimID = <double> forward simulation id - in case we want to forward simulate
% on more than one detector {1}
%
% OUTPUT
% grain.fsim = <struct> added field containing fwd simulation data:
% .cu = <double> U coordinate of center
% .cv = <double> U coordinate of center
% .cw = <double> W (image no.) coordinate of center
% .eta = <double> eta diffraction angle in degrees
% .sinth = <double> sin(theta)
% .plref = <double> plane normal in reference crystal (unstrained theoretical)
% .refind = <double> linear index of reflection in grain
% .thetatype = <double> thetatype
if ~exist('parameters','var') || isempty(parameters)
parameters = load('parameters.mat');
parameters = parameters.parameters;
end
if ~exist('fsimID','var') || isempty(fsimID)
fsimID = 1;
end
labgeo = parameters.labgeo;
if ~isfield(labgeo, 'detorig')
labgeo.detorig = gtGeoDetOrig(labgeo);
end
if ~isfield(labgeo, 'detnorm')
labgeo.detnorm = cross(labgeo.detdiru, labgeo.detidirv);
end
samgeo = parameters.samgeo;
cryst = parameters.cryst(grain{1}.phaseid);
energy = parameters.acq.energy;
omstep = 180/parameters.acq.nproj;
% Scaling for Lab -> Detector transformation (mm -> pixels)
detscaleu = 1/labgeo.pixelsizeu;
detscalev = 1/labgeo.pixelsizev;
% Rotation tensor components
rotcomp = gtMathsRotationMatrixComp(labgeo.rotdir','col');
% Detector projection matrix
Qdet = gtFedDetectorProjectionTensor(labgeo.detdiru', labgeo.detdirv', ...
detscaleu, detscalev);
% B matrix for transformation from (hkl) to Cartesian Crystal reference
Bmat = gtCrystHKL2CartesianMatrix(cryst.latticepar);
% Coordinates of the plane normals in the Cartesian Crystal system
pl_ref = gtCrystHKL2Cartesian(double(cryst.hklsp), Bmat);
refind0 = 1:size(pl_ref,2);
% D-spacings in the reference crystal for the given reflections
dsp_ref = gtCrystDSpacing(double(cryst.hkl(:,cryst.thetatypesp)), Bmat);
% Rotation tensor describing crystal orientation; calculate all grains
% at once for speed-up.
% (gtCrystRodriguesVector and gtFedRod2RotTensor used together
% gives the transformation tensor from CRYSTAL TO SAMPLE coordinates)
Rvec = gtIndexAllGrainValues(grain,'R_vector',[],1,1:3);
cry2sam = gtFedRod2RotTensor(Rvec');
% Parallel loop through grains
parfor ii = 1:length(grain)
% Plane normals in the Sample reference
pl_sam = cry2sam(:,:,ii) * pl_ref;
% Impose strain on grain
if ~isfield(grain{ii},'strain')
grain{ii}.strain.strainT = NaN(3,3);
end
if any(isnan(grain{ii}.strain.strainT(:)))
%fprintf('No strain info in grain #%d. Using as measured plane normals.\n',ii)
pl_samd = pl_sam;
drel = ones(1,size(pl_sam,2));
else
% New deformed plane normals and relative elongations
[pl_samd, drel] = gtStrainPlaneNormals(pl_sam, grain{ii}.strain.strainT);
end
% d-spacing after applying the strain tensor
dsp_d = drel .* dsp_ref;
% Bragg angles theta in the deformed state
sinth = 0.5*gtConvEnergyToWavelength(energy)./dsp_d;
% The plane normals need to be brought in the Lab reference where the
% beam direction and rotation axis are defined.
% Use the Sample -> Lab orientation transformation assuming omega=0;
% (vector length preserved for free vectors)
sam2lab = [samgeo.dirx; samgeo.diry; samgeo.dirz]';
pl_labd = sam2lab*pl_samd;
% Predict omega angles: 4 for each (hkl) plane normal (the Friedel pairs are
% om1-om3 and om2-om4); -(hkl) plane normals are assumed not to be in the list
[om4, pllab4, ~, rot4, omind4] = gtFedPredictOmegaMultiple(...
pl_labd, sinth, labgeo.beamdir', labgeo.rotdir', rotcomp, []);
% warning('Check function here! Possible bug!')
% Delete those where no reflection occurs
todel = (isnan(om4(1,:)) | isnan(om4(3,:)));
om4(:,todel) = [];
omind4(:,todel) = [];
sinth(todel) = [];
pllab4(:,todel,:) = [];
rot4(:,:,todel,:) = [];
plref = pl_ref(:,~todel);
refind = refind0(~todel);
thtype = cryst.thetatypesp(~todel);
hklsp = cryst.hklsp(:,~todel);
om = reshape(om4',[],1)';
plref4 = [plref, plref, plref, plref];
sinth4 = [sinth, sinth, sinth, sinth];
thtype4 = [thtype, thtype, thtype, thtype];
refind4 = [refind, refind, refind, refind];
% Diffraction vectors in Lab and Sample
dveclab = gtFedPredictDiffVecMultiple(reshape(pllab4,3,[]), labgeo.beamdir');
%dvecsam = gtGeoLab2Sam(dveclab', om, labgeo,...
% parameters.samgeo, 1, 1)';
% Etend grain center
gc_sam = grain{ii}.center';
gc_sam = gc_sam(:,ones(size(dveclab,2),1));
% Absolute detector coordinates U,V in pixels
uv = gtFedPredictUVMultiple(rot4, dveclab, gc_sam, labgeo.detrefpos', ...
labgeo.detnorm', Qdet, [labgeo.detrefu; labgeo.detrefv])
% Keep only those spots that fall on the detector
keep = (uv(1,:) >= 1) & (labgeo.detsizeu >= uv(1,:)) & ...
(uv(2,:) >= 1) & (labgeo.detsizev >= uv(2,:));
% Absolute coordinates U,V,W (pixel,pixel,image); to account for
% measurement errors, do not correct for the image number
% to be mod(om,360)/omstep
grain{ii}.fsim(fsimID).cu = uv(1,keep);
grain{ii}.fsim(fsimID).cv = uv(2,keep);
grain{ii}.fsim(fsimID).cw = om(keep)/omstep;
grain{ii}.fsim(fsimID).com = om(keep);
grain{ii}.fsim(fsimID).eta = gtGeoEtaFromDiffVec(dveclab(:,keep)', labgeo)';
grain{ii}.fsim(fsimID).sinth = sinth4(keep);
grain{ii}.fsim(fsimID).plref = plref4(:,keep);
grain{ii}.fsim(fsimID).refind = refind4(:,keep);
grain{ii}.fsim(fsimID).thetatype = thtype4(keep);
grain{ii}.fsim(fsimID).dveclab = reshape(dveclab,3,[],4);
%grain{ii}.fsim(fsimID).dvecsam = reshape(dvecsam,3,[],4);
end % end parfor loop
%toc
end % of main function