function bl = gtDefFwdProjGvdm2NW(grain, ref_sel, gv, fedpars, parameters, eta_step, det_ind, verbose) if (~exist('det_ind', 'var')) det_ind = 1; end if (~exist('verbose', 'var')) verbose = true; end o = GtConditionalOutput(verbose); o.fprintf('Forward projection (%s):\n', mfilename) om_step = gtAcqGetOmegaStep(parameters, det_ind); nbl = numel(ref_sel); uinds = gv.used_ind; nv = numel(uinds); use_diffractometer = (isfield(parameters, 'diffractometer') ... && numel(parameters.diffractometer) >= det_ind ... && det_ind > 1); labgeo = parameters.labgeo; samgeo = parameters.samgeo; if (use_diffractometer) diff_acq = parameters.diffractometer(det_ind); diff_ref = parameters.diffractometer(1); rotcomp = gtMathsRotationMatrixComp(diff_acq.axes_rotation', 'col'); rotdir = diff_acq.axes_rotation'; instr_t = gtGeoDiffractometerTensor(diff_acq, 'sam2lab', ... 'reference_diffractometer', diff_ref); else rotcomp = gtMathsRotationMatrixComp(labgeo.rotdir', 'col'); rotdir = labgeo.rotdir'; end if (strcmpi(fedpars.defmethod, 'rod_rightstretch')) % In this case, the deformation is relative to [0, 0, 0], so we % need crystal plane normals if (isfield(grain.allblobs, 'plcry')) pls_orig = grain.allblobs(det_ind).plcry(ref_sel, :); else % We bring the plane normals back to the status of pl_cry pls_orig = grain.allblobs(det_ind).plorig(ref_sel, :); g = gtMathsRod2OriMat(grain.R_vector); pls_orig = gtVectorLab2Cryst(pls_orig, g); end else % Here the deformation is relative to the average oriantion, so we % need the undeformed sample plane normals pls_orig = grain.allblobs(det_ind).plorig(ref_sel, :); end if (isfield(fedpars, 'detector') ... && isfield(fedpars.detector(det_ind), 'blobs_w_interp') ... && ~isempty(fedpars.detector(det_ind).blobs_w_interp)) blobs_w_interp = fedpars.detector(det_ind).blobs_w_interp; if (numel(blobs_w_interp) ~= nbl) error([mfilename ':wrong_argument'], ... 'Number of "blobs_w_interp" (%d) doesn''t match with the number of blobs (%d)', ... numel(blobs_w_interp), nbl) end else blobs_w_interp = ones(nbl, 1); end sinths = grain.allblobs(det_ind).sintheta(ref_sel); ominds = grain.allblobs(det_ind).omind(ref_sel); if (~use_diffractometer) % 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) pls_orig = gtGeoSam2Lab(pls_orig, eye(3), labgeo, samgeo, true); end if (isfield(fedpars, 'ref_omega') && ~isempty(fedpars.ref_omega)) ref_oms = fedpars.ref_omega(ref_sel); else ref_oms = grain.allblobs(det_ind).omega(ref_sel); end w_shifts = round(ref_oms ./ om_step ./ blobs_w_interp); if (isfield(fedpars, 'ref_eta') && ~isempty(fedpars.ref_eta)) ref_ns = fedpars.ref_eta(ref_sel); else ref_ns = grain.allblobs(det_ind).eta(ref_sel); end n_shifts = round(ref_ns ./ eta_step); linear_interp = ~(isfield(fedpars, 'projector') ... && strcmpi(fedpars.projector, 'nearest')); gvpow = gv.pow(1, uinds); gvd = gv.d(:, uinds); % Deformation tensor (relative to reference state) from its components defT = gtFedDefTensorFromComps(gvd, fedpars.dcomps, fedpars.defmethod, 0); %%% Computation of indices o.fprintf(' * Computing indices and bbsizes: ') t = tic(); nw = cell(nbl, 1); nw_min = zeros(nbl, 2); nw_max = zeros(nbl, 2); valid_voxels = false(nv, nbl); for ii_b = 1:nbl num_chars = o.fprintf('%03d/%03d', ii_b, nbl); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Calculate new detector coordinates %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % New deformed plane normals and relative elongations (relative to % reference state) % !!! use plcry and not plsam to keep omega order below !!! pl_orig = pls_orig(ii_b, :)'; [pl_samd, drel] = gtStrainPlaneNormals(pl_orig, defT); % unit column vectors if (use_diffractometer) % The plane norma ls 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) pl_samd = gtGeoSam2Lab(pl_samd', instr_t, labgeo, samgeo, true)'; end % New sin(theta) sinth = sinths(ii_b) ./ drel; % Predict omega angles: 4 for each plane normal [om, pl_lab] = gtFedPredictOmegaMultiple( ... pl_samd, sinth, labgeo.beamdir', rotdir, rotcomp, ominds(ii_b)); valid_voxels(:, ii_b) = ~isnan(om); % Delete those where no reflection occurs if (any(isnan(om))) inds_bad = find(isnan(om)); gvd(:, inds_bad(1:min(10, numel(inds_bad)))) warning('gtFedFwdProjExact:bad_R_vectors', ... 'No diffraction from some elements after deformation (%d over %d) for blob %d.', ... numel(inds_bad), numel(om), ii_b) end om = gtGrainAnglesTabularFix360deg(om, ref_oms(ii_b)); w_bl = om ./ om_step; w_bl = w_bl / blobs_w_interp(ii_b); w_bl = w_bl - w_shifts(ii_b); eta = gtGeoEtaFromDiffVec(pl_lab', parameters.labgeo)'; eta = gtGrainAnglesTabularFix360deg(eta, ref_ns(ii_b)); n_bl = eta ./ eta_step; n_bl = n_bl - n_shifts(ii_b); nw{ii_b} = [n_bl; w_bl]; nw_min(ii_b, :) = min(nw{ii_b}, [], 2); nw_max(ii_b, :) = max(nw{ii_b}, [], 2); o.fprintf(repmat('\b', [1, num_chars])); end o.fprintf('Done in %g s\n', toc(t)); o.fprintf(' * Computing max BBox size and feasibilities:\n') if (linear_interp) blob_nw_sizes = ceil(nw_max) - floor(nw_min) + 1; blob_orig_nw_shifts = 1 - floor(nw_min); else blob_nw_sizes = round(nw_max) - round(nw_min) + 1; blob_orig_nw_shifts = 1 - round(nw_min); end o.fprintf(' Computed Blob N sizes: [%s]\n', sprintf(' %d', blob_nw_sizes(:, 1))); o.fprintf(' Computed Blob W sizes: [%s]\n', sprintf(' %d', blob_nw_sizes(:, 2))); bl = gtFwdSimBlobDefinition('sf_nw', nbl); %%% Blob projection o.fprintf(' * Projecting volumes: ') t = tic(); for ii_b = 1:nbl num_chars = o.fprintf('%03d/%03d', ii_b, nbl); % Detector coordinates U,V in blob nw_bl = nw{ii_b} + blob_orig_nw_shifts(ii_b * ones(1, nv), :)'; % Let's now filter valid voxels nw_bl = nw_bl(:, valid_voxels(:, ii_b))'; gvpow_v = reshape(gvpow(valid_voxels(:, ii_b)), [], 1); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Sum intensities %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Distribute value over 8 pixels if (linear_interp) [inds_nw, ints_nw] = gtMathsGetInterpolationIndices(nw_bl, ... gvpow_v, fedpars.bltype); else inds_nw = round(nw_bl); ints_nw = gvpow_v; end % Accumulate all intensities in the blob voxel-wise % 'uvw' needs to be nx1; 'ints' is now 1xnx8 try bl(ii_b).intm = accumarray(inds_nw, ints_nw, blob_nw_sizes(ii_b, :)); catch mexc fprintf(['\n\nERROR\nThe error is probably caused by the' ... ' projected intensities falling outside the blob volume.' ... '\nTry increasing the blob volume padding:' ... ' fedpars.detector(det_ind).blobsizeadd, or FIXING' ... ' YOUR CODE!!\n\n']) disp('Blob ID:') disp(ii_b) disp('Blob size:') disp(blob_nw_sizes(ii_b)) disp('Min projected NW coordinate:') fprintf('\t%g\t%g \t(rounded: %d %d )\n', ... min(nw_bl, [], 1), min(inds_nw, [], 1)) disp('Max projected W coordinate:') fprintf('\t%g \t(rounded: %d )\n', ... max(nw_bl, [], 1), max(inds_nw, [], 1)) new_exc = GtFedExceptionFwdProj(mexc, det_ind, [0 0 0]); throw(new_exc) end bl(ii_b).bbsize = blob_nw_sizes(ii_b, :); bl(ii_b).bbnim = ([nw_min(ii_b, 1), nw_max(ii_b, 1)] + n_shifts(ii_b)) .* eta_step; im_w_low_lim = w_shifts(ii_b) - blob_orig_nw_shifts(ii_b, 2) + 1; bl(ii_b).bbwim = [im_w_low_lim, im_w_low_lim + bl(ii_b).bbsize(2) - 1] * blobs_w_interp(ii_b); bl(ii_b).interpw = blobs_w_interp(ii_b); o.fprintf(repmat('\b', [1, num_chars])); end o.fprintf('Done in %g s\n', toc(t)); end