diff --git a/zUtil_Deformation/GtOrientationSampling.m b/zUtil_Deformation/GtOrientationSampling.m index 710671ebd26cd4cd4cc5ba78eb392a0093959797..6145aaad22df06e9a8647ad244879121dd070f38 100644 --- a/zUtil_Deformation/GtOrientationSampling.m +++ b/zUtil_Deformation/GtOrientationSampling.m @@ -510,6 +510,7 @@ classdef GtOrientationSampling < handle % omstep = gtGetOmegaStepDeg(self.parameters, self.detector_index); + omstep_rod = tand(omstep / 2); sub_space_size = self.stats.sampling.gaps; @@ -566,6 +567,28 @@ classdef GtOrientationSampling < handle ref_ws = self.ref_gr.allblobs.omega(self.ondet(self.included(ref_inds))) ./ omstep; fprintf('Precomputing shared values..') + % Forming the grid in orientation space, on the plane that is + % perpendicular to the axis of rotation (z-axis in the w case), + % where to sample the sub-regions of the orientation-space voxels + space_res = self.estimate_maximum_resolution() ./ 5; + num_poins = max(ceil(sub_space_size ./ space_res), 5); + pos_x = linspace(-half_rspace_sizes(1), half_rspace_sizes(1), num_poins(1)+1); + pos_y = linspace(-half_rspace_sizes(2), half_rspace_sizes(2), num_poins(2)+1); + + renorm_coeff = (pos_x(2) - pos_x(1)) * (pos_y(2) - pos_y(1)) / prod(sub_space_size); + + pos_x = (pos_x(1:end-1) + pos_x(2:end)) / 2; + pos_y = (pos_y(1:end-1) + pos_y(2:end)) / 2; + + pos_x_exp = reshape(pos_x, 1, [], 1); + pos_x_exp = pos_x_exp(1, :, ones(1, num_poins(2))); + pos_y_exp = reshape(pos_y, 1, 1, []); + pos_y_exp = pos_y_exp(1, ones(1, num_poins(1)), :); + pos_z_exp = zeros(1, num_poins(1), num_poins(2)); + + tot_sampling_points = num_poins(1) * num_poins(2); + ones_tot_sp = ones(tot_sampling_points, 1); + % There is no point in computing the same rotation matrices each % time, so we pre compute them here and store them for later c = tic(); @@ -575,57 +598,30 @@ classdef GtOrientationSampling < handle w_tabs_int = [allblobs(:).omega]; w_tabs_int = w_tabs_int(ref_inds, :) ./ omstep; w_tabs_int = gtGrainAnglesTabularFix360deg(w_tabs_int, ref_ws, self.parameters); - - lims_w_proj_int = [min(w_tabs_int, [], 2), max(w_tabs_int, [], 2)]; - lims_w_proj_int = [floor(lims_w_proj_int(:, 1)), ceil(lims_w_proj_int(:, 2))]; - w_tabs_int = reshape(w_tabs_int, [], oris_bounds_size(1), oris_bounds_size(2), oris_bounds_size(3)); - precomp_matrix_prods = cell(num_blobs, 1); - rotcomp_z = gtMathsRotationMatrixComp([0, 0, 1]', 'col'); rotcomp_w = gtMathsRotationMatrixComp(self.parameters.labgeo.rotdir', 'col'); % Precomputing A matrix components for all the used omegas - for ii_b = 1:num_blobs - ws_lims = (lims_w_proj_int(ii_b, 1)-0.5):(lims_w_proj_int(ii_b, 2)+0.5); - ws_lims = ws_lims .* omstep; + ref_round_int_ws = round(ref_ws + 0.5) - 0.5; + ref_round_ws = ref_round_int_ws .* omstep; + rot_w = gtMathsRotationTensor(ref_round_ws, rotcomp_w); - rot_w = gtMathsRotationTensor(ws_lims, rotcomp_w); + beamdirs = self.parameters.labgeo.beamdir * reshape(rot_w, 3, []); + beamdirs = reshape(beamdirs, 3, [])'; - beamdirs = self.parameters.labgeo.beamdir * reshape(rot_w, 3, []); - beamdirs = reshape(beamdirs, 3, [])'; + Ac_part = beamdirs * rotcomp_z.cos; + As_part = beamdirs * rotcomp_z.sin; + Acc_part = beamdirs * rotcomp_z.const; - Ac_part = beamdirs * rotcomp_z.cos; - As_part = beamdirs * rotcomp_z.sin; - Acc_part = beamdirs * rotcomp_z.const; + Ac_part = Ac_part(:, :, ones_tot_sp); + As_part = As_part(:, :, ones_tot_sp); + Acc_part = Acc_part(:, :, ones_tot_sp); - precomp_matrix_prods{ii_b} = struct( ... - 'w', [lims_w_proj_int(ii_b, 1) lims_w_proj_int(ii_b, 2)], ... - 'Ac', Ac_part, 'As', As_part, 'Acc', Acc_part ); - end fprintf('\b\b: Done in %g seconds.\n', toc(c)) - space_res = self.estimate_maximum_resolution() ./ 5; - num_poins = max(ceil(sub_space_size ./ space_res), 5); - pos_x = linspace(-half_rspace_sizes(1), half_rspace_sizes(1), num_poins(1)+1); - pos_y = linspace(-half_rspace_sizes(2), half_rspace_sizes(2), num_poins(2)+1); - - renorm_coeff = (pos_x(2) - pos_x(1)) * (pos_y(2) - pos_y(1)) / prod(sub_space_size); - - % Forming the grid in orientation space, on the plane that is - % perpendicular to the axis of rotation (z-axis in the w case), - % where to sample the sub-regions of the orientation-space voxels - pos_x = (pos_x(1:end-1) + pos_x(2:end)) / 2; - pos_y = (pos_y(1:end-1) + pos_y(2:end)) / 2; - - pos_x_exp = reshape(pos_x, 1, [], 1); - pos_x_exp = pos_x_exp(1, :, ones(1, num_poins(2))); - pos_y_exp = reshape(pos_y, 1, 1, []); - pos_y_exp = pos_y_exp(1, ones(1, num_poins(1)), :); - pos_z_exp = zeros(1, num_poins(1), num_poins(2)); - sf = cell(tot_orientations, 1); [o_x, o_y, o_z] = ind2sub(oris_bounds_size-1, 1:tot_orientations); @@ -637,8 +633,6 @@ classdef GtOrientationSampling < handle num_chars = fprintf('%05d/%05d', ii_g, tot_orientations); end - sf{ii_g}(1:num_blobs) = gtFwdSimBlobDefinition(); - gr = self.lattice.gr{ii_g}; % Extracting ospace boundaries for the given voxel @@ -647,61 +641,75 @@ classdef GtOrientationSampling < handle lims_w_proj_g_int = round([min(w_tab_int, [], 2), max(w_tab_int, [], 2)]); - % the extra index is needed for the last boundary point - As_inds = [ ... - lims_w_proj_g_int(:, 1) - lims_w_proj_int(:, 1) ... - lims_w_proj_g_int(:, 2) - lims_w_proj_int(:, 1) + 1] + 1; - % Forming the grid in orientation space, on the plane that is % perpendicular to the axis of rotation (z-axis in the w case), % where to sample the sub-regions of the orientation-space voxel % that we want to integrate. r_vecs = [pos_x_exp; pos_y_exp; pos_z_exp]; r_vecs = reshape(r_vecs, 3, []); - r_vecs = gr.R_vector(ones(1, size(r_vecs, 2)), :)' + r_vecs; + r_vecs = gr.R_vector(ones_tot_sp, :)' + r_vecs; gs = gtMathsRod2OriMat(r_vecs); % Unrolling and transposing the matrices at the same time % because we need g^-1 gs = reshape(gs, 3, [])'; - pls = gs * pl_cry; - pls = reshape(pls, 3, [], num_blobs); + ys = gs * pl_cry; + ys = reshape(ys, 3, [], num_blobs); + ys = permute(ys, [3 1 2]); + + % Starting here to compute initial shifts aligned with the + % rounded omega, by frst doing three scalar products + Ac = sum(Ac_part .* ys, 2); + As = sum(As_part .* ys, 2); + Acc = sum(Acc_part .* ys, 2); + Ac = reshape(Ac, num_blobs, tot_sampling_points); + As = reshape(As, num_blobs, tot_sampling_points); + Acc = reshape(Acc, num_blobs, tot_sampling_points); + + D = Ac .^ 2 + As .^ 2; + + % Precomputing useful values, like sinthetas ominds = gr.allblobs.omind(ref_inds); ssp = ((ominds == 1) | (ominds == 2)); ss = ssp - ~ssp; sinths = ss .* gr.allblobs.sintheta(ref_inds); + sinths = sinths(:, ones(tot_sampling_points, 1)); + + CC = Acc + sinths; + DD = D - CC .^ 2; + E = sqrt(DD); + ok = DD > 0; % Apparently it is inverted, compared to the omega prediction % function. Should be investigated ssp = ~((ominds == 1) | (ominds == 3)); ss = ssp - ~ssp; + ss = ss(:, ones(tot_sampling_points, 1)); - for ii_b = 1:num_blobs - A_inds = As_inds(ii_b, 1):As_inds(ii_b, 2); - - Ac_g_part = precomp_matrix_prods{ii_b}.Ac(A_inds, :); - As_g_part = precomp_matrix_prods{ii_b}.As(A_inds, :); - Acc_g_part = precomp_matrix_prods{ii_b}.Acc(A_inds, :); - - pls_blob = pls(:, :, ii_b); + % Shift along z in orientation space, to align with the images + % in proections space + dz = (-As + ss .* ok .* E) ./ (CC - Ac); - Ac = Ac_g_part * pls_blob; - As = As_g_part * pls_blob; - Acc = Acc_g_part * pls_blob; + ws_disps = [ ... + (lims_w_proj_g_int(:, 1) - 0.5 - ref_round_int_ws), ... + (lims_w_proj_g_int(:, 2) + 0.5 - ref_round_int_ws) ]; + ws_disps = tand(ws_disps .* omstep / 2); - D = Ac .^ 2 + As .^ 2; + num_ds = lims_w_proj_g_int(:, 2) - lims_w_proj_g_int(:, 1) + 2; - CC = Acc + sinths(ii_b); - DD = D - CC .^ 2; - E = sqrt(DD); - ok = DD > 0; + bbwims = cell(num_blobs, 1); + intms = cell(num_blobs, 1); + bbsizes = cell(num_blobs, 1); - % finding what the positions in w-space, correspond to in - % orientation-space, on the z-axis, at the sampled x and y - % positions around in the considered volume. - d = (-As + ss(ii_b) .* ok .* E) ./ (CC - Ac); + % This is the most expensive operation because the different + % sizes of the omega spread, which depends on the blob itself, + % don't allow to have vectorized operations on all the blobs at + % the same time + for ii_b = 1:num_blobs + d = (ws_disps(ii_b, 1):omstep_rod:ws_disps(ii_b, 2))'; + d = d(:, ones(tot_sampling_points, 1)) + dz(ii_b * ones(num_ds(ii_b), 1), :); upper_limits = min(d(2:end, :), half_rspace_sizes(3)); lower_limits = max(d(1:end-1, :), -half_rspace_sizes(3)); @@ -714,10 +722,17 @@ classdef GtOrientationSampling < handle ints = sum(ints, 2); ints = reshape(ints, 1, 1, []); - sf{ii_g}(ii_b).bbwim = lims_w_proj_g_int(ii_b, :); - sf{ii_g}(ii_b).intm = renorm_coeff * ints; - sf{ii_g}(ii_b).bbsize = [1, 1, numel(ints)]; + bbwims{ii_b} = lims_w_proj_g_int(ii_b, :); + intms{ii_b} = renorm_coeff * ints; + bbsizes{ii_b} = [1, 1, numel(ints)]; end + + sf_bls_w(1:num_blobs) = gtFwdSimBlobDefinition(); + [sf_bls_w(:).bbwim] = deal(bbwims{:}); + [sf_bls_w(:).intm] = deal(intms{:}); + [sf_bls_w(:).bbsize] = deal(bbsizes{:}); + sf{ii_g} = sf_bls_w; + if (mod(ii_g, chunk_size) == 1) fprintf(repmat('\b', [1, num_chars])); end