-
Nicola Vigano authored
Orientation-Sampling: reduced sampling strategies to two types: numpoints and resolution, each with and without ODF estimation Signed-off-by:
Nicola Vigano <nicola.vigano@esrf.fr>
Nicola Vigano authoredOrientation-Sampling: reduced sampling strategies to two types: numpoints and resolution, each with and without ODF estimation Signed-off-by:
Nicola Vigano <nicola.vigano@esrf.fr>
GtOrientationSampling.m 58.35 KiB
classdef GtOrientationSampling < handle
properties
lattice = struct('gr', {});
lattice_ss = {};
ss_factor = [1 1 1];
stats;
R_vectors;
fedpars = [];
parameters = [];
ref_gr = [];
% redundant info that helps in forward compatibility
bl;
ondet;
included;
selected;
detector_index = 1;
verbose = false;
end
methods
function self = GtOrientationSampling(parameters, ref_gr, varargin)
self.parameters = parameters;
self.ref_gr = ref_gr;
self = parse_pv_pairs(self, varargin);
if (isfield(ref_gr.proj(self.detector_index), 'bl'))
self.bl = ref_gr.proj(self.detector_index).bl;
else
self.bl = ref_gr.bl;
end
if (isfield(ref_gr.proj(self.detector_index), 'selected'))
self.ondet = ref_gr.proj(self.detector_index).ondet;
self.included = ref_gr.proj(self.detector_index).included;
self.selected = ref_gr.proj(self.detector_index).selected;
else
self.ondet = ref_gr.ondet;
self.included = ref_gr.included;
self.selected = ref_gr.selected;
end
end
function make_grid_numpoints_estim_ODF(self, type, edge_points, even, oversize)
gvdm_tmp = self.guess_ODF_BB();
if (~exist('oversize', 'var'))
oversize = [];
end
if (~exist('even', 'var'))
even = [];
end
self.make_grid_numpoints(type, edge_points, gvdm_tmp, even, oversize);
end
function make_grid_numpoints(self, type, edge_points, gvdm, even, oversize)
if (~exist('oversize', 'var'))
oversize = 1.1;
end
if (exist('even', 'var') && ~isempty(even) && even)
[~, ~, dranges] = self.get_deformation_stats(gvdm);
[~, min_ii] = min(dranges);
other_iis = [1:min_ii-1 min_ii+1:3];
min_spacing = dranges(min_ii) * oversize / min_edge_points;
other_edge_points = ceil(dranges(other_iis) * oversize / min_spacing);
edge_points(min_ii) = min_edge_points;
edge_points(other_iis(1)) = other_edge_points(1);
edge_points(other_iis(2)) = other_edge_points(2);
elseif (numel(edge_points) == 1)
edge_points = edge_points([1 1 1]);
end
self.make_grid(type, edge_points, gvdm, oversize)
end
% function make_res_even_simple_grid(self, type, min_edge_points, gvdm, oversize)
% [~, ~, dranges] = self.get_deformation_stats(gvdm);
%
% if (~exist('oversize', 'var'))
% oversize = 1.1;
% end
%
% max_resolution = self.estimate_maximum_resolution();
% % max_res_ratios = max_resolution / min(max_resolution);
% % dranges = dranges ./ max_res_ratios;
%
% [~, min_ii] = min(dranges);
% other_iis = [1:min_ii-1 min_ii+1:3];
% if (min_edge_points > 0)
% min_spacing = dranges(min_ii) * oversize / min_edge_points;
% other_edge_points = ceil(dranges(other_iis) * oversize / min_spacing);
% edge_points(min_ii) = min_edge_points;
% edge_points(other_iis(1)) = other_edge_points(1);
% edge_points(other_iis(2)) = other_edge_points(2);
% else
% size_bb = 2 * atand(dranges * oversize);
% chosen_res = max_resolution / (abs(min_edge_points) + (min_edge_points == 0));
% edge_points = ceil(size_bb ./ chosen_res) + 1;
% end
%
% self.make_grid(type, edge_points, gvdm, oversize)
% end
function make_grid_resolution_estim_ODF(self, type, resolution, oversize)
if (~exist('oversize', 'var'))
oversize = 1.1;
end
gvdm_tmp = self.guess_ODF_BB();
self.make_grid_resolution(type, resolution, gvdm_tmp, oversize)
end
function make_grid_resolution(self, type, resolution, gvdm, oversize)
[~, ~, dranges] = self.get_deformation_stats(gvdm);
if (~exist('oversize', 'var'))
oversize = 1.1;
end
resolution_rod = tand(resolution / 2);
bb_size_rod = dranges * oversize;
edge_points = max(ceil(bb_size_rod ./ resolution_rod) + 1, 2);
self.make_grid(type, edge_points, gvdm, oversize)
end
function make_grid(self, type, edge_points, gvdm, oversize)
[dmean, dcenters, dranges] = self.get_deformation_stats(gvdm);
self.print_sampling_details(dranges, oversize, edge_points)
self.lattice = struct('gr', {});
self.R_vectors = {};
type = lower(type);
switch(type)
case 'cubic'
sampling_ranges{3} = GtOrientationSampling.get_cubic_range(edge_points(3), oversize);
sampling_ranges{2} = GtOrientationSampling.get_cubic_range(edge_points(2), oversize);
sampling_ranges{1} = GtOrientationSampling.get_cubic_range(edge_points(1), oversize);
self.produce_R_vectors_even_simple_grid(sampling_ranges, dcenters, dranges)
case 'fcc'
case 'bcc'
sampling_ranges{3} = GtOrientationSampling.get_cubic_range(edge_points(3), oversize);
sampling_ranges{2} = GtOrientationSampling.get_cubic_range(edge_points(2), oversize);
sampling_ranges{1} = GtOrientationSampling.get_cubic_range(edge_points(1), oversize);
self.produce_R_vectors_simple_grid(sampling_ranges, dcenters, dranges, 1)
sampling_ranges{3} = GtOrientationSampling.get_bcc_center_range(edge_points(3), oversize);
sampling_ranges{2} = GtOrientationSampling.get_bcc_center_range(edge_points(2), oversize);
sampling_ranges{1} = GtOrientationSampling.get_bcc_center_range(edge_points(1), oversize);
self.produce_R_vectors_simple_grid(sampling_ranges, dcenters, dranges, 2)
otherwise
error('GtOrientationSampling:make_simple_grid', ...
'Unknown lattice structure: %s', type)
end
if (self.verbose && usejava('jvm'))
self.plot_sampling(gvdm, dmean);
end
% Slow part which is based on gtCalculateGrain: could be improved!
self.produce_geometry();
self.produce_stats(type);
if (self.verbose && usejava('jvm'))
self.print_stats();
end
if (self.verbose && usejava('jvm'))
self.plot_blob_coverage();
end
end
function make_supersampling_simple_grid(self, directions, factor)
self.ss_factor = [1 1 1];
self.ss_factor(directions) = factor;
orient_voxel_size = self.stats.sampling.gaps;
half_voxel_size = orient_voxel_size ./ 2;
steps = orient_voxel_size ./ self.ss_factor;
half_steps = steps ./ 2;
for ii_o = 1:numel(self.lattice)
size_or = size(self.lattice(ii_o).gr);
self.lattice_ss(ii_o).gr = cell(size_or);
for ii_g = 1:numel(self.lattice(ii_o).gr)
gr = self.lattice(ii_o).gr{ii_g};
beg_pos = gr.R_vector - half_voxel_size + half_steps;
end_pos = gr.R_vector + half_voxel_size - half_steps;
range_x = beg_pos(1):steps(1):end_pos(1);
range_y = beg_pos(2):steps(2):end_pos(2);
range_z = beg_pos(3):steps(3):end_pos(3);
gr_ss = cell(self.ss_factor);
for ii_z = 1:self.ss_factor(3)
for ii_y = 1:self.ss_factor(2)
r_vecs = [ ...
range_x', ...
range_y(ii_y) * ones(self.ss_factor(1), 1), ...
range_z(ii_z) * ones(self.ss_factor(1), 1)];
for ii_x = 1:self.ss_factor(1)
gr_ss{ii_x, ii_y, ii_z} = struct( ...
'R_vector', {r_vecs(ii_x, :)}, ...
'center', {gr.center}, ...
'phaseid', {gr.phaseid}, ...
'allblobs', {[]} );
end
end
end
self.lattice_ss(ii_o).gr{ii_g} = gr_ss;
end
end
if (self.verbose && usejava('jvm'))
self.plot_supersampling();
end
self.produce_geometry_supersampling();
end
function valid = is_valid(self, type, edge_points)
valid = strcmpi(self.stats.sampling.type, type) ...
&& all(size(self.lattice(1).gr) == edge_points([1 1 1]));
end
function [or, or_ss] = get_orientations(self)
or = {};
for ii = 1:numel(self.lattice)
or = [or(:); self.lattice(ii).gr(:)];
end
or_ss = {};
for ii = 1:numel(self.lattice_ss)
or_ss = [or_ss(:); self.lattice_ss(ii).gr(:)];
end
end
function ref_gr = get_reference_grain(self)
ref_gr = self.ref_gr;
end
function r_vectors = get_R_vectors(self)
r_vectors = self.R_vectors;
end
function or_size = get_orientation_sampling_size(self)
num_lattices = numel(self.lattice);
or_size = cell(num_lattices, 1);
for ii = 1:num_lattices
or_size{ii} = [ ...
size(self.lattice(ii).gr, 1), ...
size(self.lattice(ii).gr, 2), ...
size(self.lattice(ii).gr, 3) ];
end
end
function tot_orient = get_total_num_orientations(self)
tot_orient = sum(arrayfun(@(x)numel(x.gr), self.lattice));
end
function [avg_R_vecs, avg_R_vecs_int, stddev_R_vecs] = getAverageOrientations(self, vols)
[avg_R_vecs, avg_R_vecs_int, stddev_R_vecs] = ...
GtOrientationSampling.computeAverageOrientations(self.get_orientations(), vols);
end
function avg_R_vec = getAverageOrientation(self, vols)
avg_R_vec = GtOrientationSampling.computeAverageOrientation(self.get_orientations(), vols);
end
function odf = getODF(self, vols)
odf = GtOrientationSampling.computeODF(self.get_orientations(), vols);
end
function [gvdm_tmp, verts, all_plane_normals] = guess_ODF_BB(self, use_corners, use_etas)
if (~exist('use_corners', 'var') || isempty(use_corners))
use_corners = true;
end
if (~exist('use_etas', 'var') || isempty(use_etas))
use_etas = false;
end
omega_step = gtGetOmegaStepDeg(self.parameters, self.detector_index);
samgeo = self.parameters.samgeo;
labgeo = self.parameters.labgeo;
detgeo = self.parameters.detgeo(self.detector_index);
bls = self.bl(self.selected);
g = gtMathsRod2OriMat(self.ref_gr.R_vector);
sel = self.ondet(self.included(self.selected));
num_refl = numel(sel);
if (~num_refl)
error('GtOrientationSampling:guess_ODF_BB:wrong_argument', ...
'No reflections selected! So, no estimation can be performed!')
end
% Taking theoretical omegas instead of experimental ones!
w = self.ref_gr.allblobs.omega(sel);
n = self.ref_gr.allblobs.eta(sel);
t = self.ref_gr.allblobs.theta(sel);
gc_sam = self.ref_gr.center(ones(numel(w), 1), :);
% can we determine the maximum eta spread?
uv = self.ref_gr.allblobs.detector(self.detector_index).uvw(sel, 1:2);
gc_lab = gtGeoSam2Lab(gc_sam, w, labgeo, samgeo, false);
% Computing the etas according to the corners of the blobs
u_min_max = cat(1, bls(:).mbbu);
v_min_max = cat(1, bls(:).mbbv);
pos_corner_bl = [u_min_max(:, 1) - 0.5, v_min_max(:, 1) - 0.5];
pos_corner_br = [u_min_max(:, 1) - 0.5, v_min_max(:, 2) + 0.5];
pos_corner_tl = [u_min_max(:, 2) + 0.5, v_min_max(:, 1) - 0.5];
pos_corner_tr = [u_min_max(:, 2) + 0.5, v_min_max(:, 2) + 0.5];
diffvec_corner_bl = gtGeoDet2Lab(pos_corner_bl, detgeo, false) - gc_lab;
diffvec_corner_br = gtGeoDet2Lab(pos_corner_br, detgeo, false) - gc_lab;
diffvec_corner_tl = gtGeoDet2Lab(pos_corner_tl, detgeo, false) - gc_lab;
diffvec_corner_tr = gtGeoDet2Lab(pos_corner_tr, detgeo, false) - gc_lab;
n_bl = gtGeoEtaFromDiffVec(diffvec_corner_bl, labgeo);
n_br = gtGeoEtaFromDiffVec(diffvec_corner_br, labgeo);
n_tl = gtGeoEtaFromDiffVec(diffvec_corner_tl, labgeo);
n_tr = gtGeoEtaFromDiffVec(diffvec_corner_tr, labgeo);
n_m_corners = min([n_bl, n_br, n_tl, n_tr], [], 2);
n_p_corners = max([n_bl, n_br, n_tl, n_tr], [], 2);
% Computing the etas according to the size of the blob
gc_det_pos = gtGeoGrainCenterSam2Det(self.ref_gr.center, w, self.parameters);
cosnc = abs(cosd(n)) >= 0.5;
dn = zeros(size(n));
bls_bbm = cat(1, bls(:).mbbsize);
% 1st component is the horizontal, while the 2nd is the
% vertical !!
dn(cosnc) = bls_bbm(cosnc, 1) ./ abs(cosd(n(cosnc)));
dn(~cosnc) = bls_bbm(~cosnc, 2) ./ abs(sind(n(~cosnc)));
dn = dn ./ (2 * sqrt(sum((uv - gc_det_pos) .^ 2, 2)));
dn = atand(dn);
% Let's take a small deviation in eta, to find the plane that
% determines the limits in orientation-space
n_m_symm = n - dn;
n_p_symm = n + dn;
if (use_corners)
n_m = n_m_corners;
n_p = n_p_corners;
else
n_m = n_m_symm;
n_p = n_p_symm;
end
% We retrieve the signed y (instead of the unsigned one):
% y = self.ref_gr.allblobs.plorig(sel, :)';
y0_exp_lab = gtGeoPlLabFromThetaEta(t, n, labgeo);
y0_exp_sam = gtGeoLab2Sam(y0_exp_lab, w, labgeo, samgeo, true);
y = y0_exp_sam';
% % Useful to validate the previously introduced flip of eta
% ominds = self.ref_gr.allblobs.omind(sel);
% ssp = ((ominds == 1) | (ominds == 2));
% ss12 = ssp - ~ssp;
%
% y_l = self.ref_gr.allblobs.pllab(sel, :);
% y_s = self.ref_gr.allblobs.pl(sel, :);
% y_o = self.ref_gr.allblobs.plorig(sel, :);
% [y0_exp_lab, y_l, y0_exp_lab-y_l]
% [y0_exp_sam, y_s, y0_exp_sam-y_s, ss12(:, [1 1 1]) .* y_o]
% Should be identical to pl_cry
hhs = gtVectorLab2Cryst(y', g);
ym_exp_lab = gtGeoPlLabFromThetaEta(t, n_m, labgeo);
yp_exp_lab = gtGeoPlLabFromThetaEta(t, n_p, labgeo);
% r0s related to the extreeme omegas
r0ws_ex = zeros(2 * num_refl, 3);
% r01s related to the extreeme omegas
r0ns_ex = zeros(2 * num_refl, 3);
% versors of r (classic) related to the extreeme omegas
rcs_ex_w = zeros(2 * num_refl, 3);
% versors of the perpendicular to the rs in the extreeme omegas
% (~ parallel to eta)
rns_ex_w = zeros(2 * num_refl, 3);
% versors of the perpendicular to the rs in the extreeme etas
% (~ parallel to onegas)
rws_ex_w = zeros(2 * num_refl, 3);
sub_ws_abs = cat(1, bls(:).mbbw);
% sub_w_abs will contain the two bounding omegas for the given
% reflection.
sub_ws_abs = (sub_ws_abs + repmat([-0.5, 0.5], [num_refl, 1])) * omega_step;
for ii_r = 1:num_refl
sub_w_abs = sub_ws_abs(ii_r, :);
% the y vectors for the central eta, at the bounding omegas
y0_exp_sam = gtGeoLab2Sam(y0_exp_lab([ii_r ii_r], :), ...
sub_w_abs, labgeo, samgeo, true);
% the y vectors for the lower eta, at the bounding omegas
ym_exp_sam = gtGeoLab2Sam(ym_exp_lab([ii_r ii_r], :), ...
sub_w_abs, labgeo, samgeo, true);
% the y vectors for the upper eta, at the bounding omegas
yp_exp_sam = gtGeoLab2Sam(yp_exp_lab([ii_r ii_r], :), ...
sub_w_abs, labgeo, samgeo, true);
hh = hhs(ii_r, :);
norms_0c = (1 + hh * y0_exp_sam')';
norms_0c = norms_0c(:, [1 1 1]);
norms_0m = (1 + hh * ym_exp_sam')';
norms_0m = norms_0m(:, [1 1 1]);
norms_0p = (1 + hh * yp_exp_sam')';
norms_0p = norms_0p(:, [1 1 1]);
% r0 is defined = (h x y) / (1 + h . y)
r0c = gtMathsCross(hh, y0_exp_sam) ./ norms_0c;
r0m = gtMathsCross(hh, ym_exp_sam) ./ norms_0m;
r0p = gtMathsCross(hh, yp_exp_sam) ./ norms_0p;
% r is defined = r0 + t * (h + y) / (1 + h . y)
r_dir_c = (hh([1 1], :) + y0_exp_sam) ./ norms_0c;
r_dir_m = (hh([1 1], :) + ym_exp_sam) ./ norms_0m;
r_dir_p = (hh([1 1], :) + yp_exp_sam) ./ norms_0p;
r_dir_c = gtMathsNormalizeVectorsList(r_dir_c);
r_dir_m = gtMathsNormalizeVectorsList(r_dir_m);
r_dir_p = gtMathsNormalizeVectorsList(r_dir_p);
% Translating r0s to the closest point to the average R
% vector, on the line r
dot_r0c_avgR = sum((self.ref_gr.R_vector([1 1], :) - r0c) .* r_dir_c, 2);
dot_r0m_avgR = sum((self.ref_gr.R_vector([1 1], :) - r0m) .* r_dir_m, 2);
dot_r0p_avgR = sum((self.ref_gr.R_vector([1 1], :) - r0p) .* r_dir_p, 2);
r0c = r0c + r_dir_c .* dot_r0c_avgR(:, [1 1 1]);
r0m = r0m + r_dir_m .* dot_r0m_avgR(:, [1 1 1]);
r0p = r0p + r_dir_p .* dot_r0p_avgR(:, [1 1 1]);
% Delimiters in w
r0ws_ex(ii_r*2-1:ii_r*2, :) = r0c;
% Delimiters in n
r0ns_ex(ii_r*2-1:ii_r*2, :) = [sum(r0m, 1); sum(r0p, 1)] / 2;
rcs_ex_w(ii_r*2-1:ii_r*2, :) = r_dir_c;
% It will be used for recentering the r0w, on top of the
% average point and get a colinear plane norm to the
% distance of the plane to the average point
r_dir_n = r0p - r0m;
r_dir_n_norm = sqrt(sum(r_dir_n .^ 2, 2));
rns_ex_w(ii_r*2-1:ii_r*2, :) = r_dir_n ./ r_dir_n_norm(:, [1 1 1]);
% Same as the previous, but for the points r0n
r_dir_w = [r0m(end, :) - r0m(1, :); r0p(end, :) - r0p(1, :)];
r_dir_w_norm = sqrt(sum(r_dir_w .^ 2, 2));
rws_ex_w(ii_r*2-1:ii_r*2, :) = r_dir_w ./ r_dir_w_norm(:, [1 1 1]);
end
% Let's find the closest point to the average R vector on the plane
avg_R_vec_exp = self.ref_gr.R_vector(ones(size(r0ws_ex, 1), 1), :);
trasl_ex_points_w = avg_R_vec_exp - r0ws_ex;
trasl_ex_points_w = sum(trasl_ex_points_w .* rns_ex_w, 2) ./ sqrt(sum(rns_ex_w .^ 2, 2));
trasl_ex_points_w = r0ws_ex + trasl_ex_points_w(:, [1 1 1]) .* rns_ex_w;
if (use_etas)
trasl_ex_points_n = avg_R_vec_exp - r0ns_ex;
trasl_ex_points_n = sum(trasl_ex_points_n .* rws_ex_w, 2) ./ sqrt(sum(rws_ex_w .^ 2, 2));
trasl_ex_points_n = r0ns_ex + trasl_ex_points_n(:, [1 1 1]) .* rws_ex_w;
all_plane_normals = [ ...
trasl_ex_points_w - avg_R_vec_exp; ...
trasl_ex_points_n - avg_R_vec_exp ];
else
all_plane_normals = trasl_ex_points_w - avg_R_vec_exp;
end
% Computing the circumscribing polyhedron in Orientation-space
verts = gtMathsGetPolyhedronVerticesFromPlaneNormals(all_plane_normals);
verts = verts + self.ref_gr.R_vector(ones(size(verts, 1), 1), :);
% f = figure();
% ax = axes('parent', f);
% hold(ax, 'on')
% scatter3(ax, trasl_ex_points_w(:, 1), trasl_ex_points_w(:, 2), trasl_ex_points_w(:, 3), 'b')
% if (use_etas)
% scatter3(ax, trasl_ex_points_n(:, 1), trasl_ex_points_n(:, 2), trasl_ex_points_n(:, 3), 'y')
% end
% scatter3(ax, verts(:, 1), verts(:, 2), verts(:, 3), 'r')
% hold(ax, 'off')
% bbox_r0s = [min(trasl_ex_points, [], 1), max(trasl_ex_points, [], 1)];
% bbox_r0s = [bbox_r0s(1:3), bbox_r0s(4:6) - bbox_r0s(1:3)];
% or_bbox = bbox_r0s;
bbox_verts = [min(verts, [], 1), max(verts, [], 1)];
bbox_verts = [bbox_verts(1:3), bbox_verts(4:6) - bbox_verts(1:3)];
or_bbox = bbox_verts;
gvdm_tmp = [];
for cz = 0:1
for cy = 0:1
for cx = 0:1
gvdm_tmp = [gvdm_tmp, (or_bbox(1:3)' + [cx; cy; cz] .* or_bbox(4:6)')]; %#ok<AGROW>
end
end
end
end
function resolution = estimate_maximum_resolution(self)
sel = self.ondet(self.included(self.selected));
n = self.ref_gr.allblobs.eta(sel);
t = self.ref_gr.allblobs.theta(sel);
detgeo = self.parameters.detgeo(self.detector_index);
delta_pixel = abs(cosd(n)) .* detgeo.pixelsizeu + abs(sind(n)) .* detgeo.pixelsizev;
xy_resolution = atand(delta_pixel ./ (norm(detgeo.detrefpos) .* tand(2 .* t)));
xy_resolution = min(xy_resolution);
z_resolution = gtGetOmegaStepDeg(self.parameters, self.detector_index);
resolution = [xy_resolution, xy_resolution, z_resolution];
end
function num_interp = suggest_num_interp(self, z_res)
if (~exist('z_res', 'var') || isempty(z_res))
z_res = 2 * atand(self.stats.sampling.gaps(3));
end
om_step = gtGetOmegaStepDeg(self.parameters);
% The factor 1.5 allows at least a minimum amount of crosstalk among
% the orientations
num_interp = max(z_res / om_step * 1.5, 1); % / self.ss_factor(3)
end
function num_interp = minimum_num_interp(self, z_res)
if (~exist('z_res', 'var') || isempty(z_res))
z_res = 2 * atand(self.stats.sampling.gaps(3));
end
om_step = gtGetOmegaStepDeg(self.parameters);
num_interp = max(z_res / om_step, 1); % / self.ss_factor(3)
end
function sampler = regenerate_displaced(self, new_center)
detgeo = self.parameters.detgeo;
labgeo = self.parameters.labgeo;
samgeo = self.parameters.samgeo;
sampler = self;
% Let's update the reference grain
sampler.ref_gr.center = new_center;
rot_s2l = permute(sampler.ref_gr.allblobs.srot, [2 1 3]);
gcsam_v = new_center(ones(1, size(rot_s2l, 3)), :);
gclab_v = gtGeoSam2Lab(gcsam_v, rot_s2l, labgeo, samgeo, false);
num_dets = numel(detgeo);
for n = 1:num_dets
sampler.ref_gr.allblobs.detector(n).uvw(:, 1:2) = gtFedPredictUVMultiple( ...
[], sampler.ref_gr.allblobs.dvec', gclab_v', ...
detgeo(n).detrefpos', detgeo(n).detnorm', detgeo(n).Qdet, ...
[detgeo(n).detrefu, detgeo(n).detrefv]')';
end
% And now let's take care of the sampled orientations
grid_gr = self.get_orientations();
grid_gr = [grid_gr{:}];
num_orients = numel(grid_gr);
ab = [grid_gr(:).allblobs];
rot_l2s = cat(3, ab(:).srot);
rot_s2l = permute(rot_l2s, [2 1 3]);
dveclab = cat(1, ab(:).dvec);
gcsam_v = new_center(ones(1, size(rot_s2l, 3)), :);
gclab_v = gtGeoSam2Lab(gcsam_v, rot_s2l, labgeo, samgeo, false);
uv_tot = cell(num_dets, 1);
for n = 1:num_dets
uv_tot{n} = gtFedPredictUVMultiple([], dveclab', gclab_v', ...
detgeo(n).detrefpos', detgeo(n).detnorm', detgeo(n).Qdet, ...
[detgeo(n).detrefu, detgeo(n).detrefv]');
uv_tot{n} = reshape(uv_tot{n}, 2, [], num_orients);
uv_tot{n} = permute(uv_tot{n}, [2 1 3]);
end
for ii_g = 1:num_orients
sampler.lattice(1).gr{ii_g}.center = new_center;
for n = 1:num_dets
sampler.lattice(1).gr{ii_g}.allblobs.detector(n).uvw(:, 1:2) = uv_tot{n}(:, :, ii_g);
end
end
end
function [delta_omegas, proj_lims] = get_omega_deviations(self, with_shape_functions)
if (~exist('with_shape_functions', 'var') || isempty(with_shape_functions))
with_shape_functions = false;
end
if (with_shape_functions)
sub_space_size = self.stats.sampling.gaps;
half_rspace_sizes = sub_space_size / 2;
min_bounds = self.lattice(1).gr{1, 1, 1}.R_vector - half_rspace_sizes;
max_bounds = self.lattice(1).gr{end, end, end}.R_vector + half_rspace_sizes;
bounds_x = [min_bounds(1), max_bounds(1)];
bounds_y = [min_bounds(2), max_bounds(2)];
bounds_z = [min_bounds(3), max_bounds(3)];
grs = cell(2, 2, 2);
for dx = 1:2
for dy = 1:2
for dz = 1:2
r_vec = [bounds_x(dx), bounds_y(dy), bounds_z(dz)];
grs{dx, dy, dz} = struct( ...
'phaseid', self.ref_gr.phaseid, ...
'center', self.ref_gr.center, 'R_vector', r_vec );
end
end
end
grs = gtCalculateGrain_p(grs, self.parameters, ...
'ref_omind', self.ref_gr.allblobs.omind, ...
'included', self.ondet(self.included(self.selected)) );
grs = [grs{:}];
else
grs = [self.lattice(1).gr{:}];
end
ab = [grs(:).allblobs];
w_tab = [ab(:).omega] / gtGetOmegaStepDeg(self.parameters, self.detector_index);
sel = self.ondet(self.included(self.selected));
ref_int_ws = self.ref_gr.allblobs.detector(self.detector_index).uvw(sel, 3);
w_tab = gtGrainAnglesTabularFix360deg(w_tab, ref_int_ws, self.parameters);
max_ws = ceil(max(w_tab, [], 2));
min_ws = floor(min(w_tab, [], 2));
proj_lims = [min_ws, max_ws];
delta_omegas = max_ws - min_ws + 1;
end
function [delta_uvs, proj_uv_lims] = get_uv_deviations(self)
grs = [self.lattice(1).gr{:}];
num_blobs = numel(find(self.selected));
num_oris = numel(grs);
uv_tab = zeros(num_blobs, 2, num_oris);
for ii_o = 1:num_oris
uv_tab(:, :, ii_o) = grs(ii_o).allblobs.detector(self.detector_index).uvw(:, 1:2);
end
min_proj_uv = reshape(min(floor(uv_tab), [], 3), [], 1, 2);
max_proj_uv = reshape(max(ceil(uv_tab), [], 3), [], 1, 2);
proj_uv_lims = [min_proj_uv, max_proj_uv];
delta_uvs = reshape(proj_uv_lims(:, 2, :) - proj_uv_lims(:, 1, :), [], 2);
end
function bytes = get_memory_consumption_geometry(self)
bytes = GtBenchmarks.getSizeVariable(self.lattice) ...
+ GtBenchmarks.getSizeVariable(self.lattice_ss) ...
+ GtBenchmarks.getSizeVariable(self.R_vectors);
end
function bytes = get_memory_consumption_graindata(self)
bytes = GtBenchmarks.getSizeVariable(self.ref_gr);
end
end
methods (Access = protected)
function produce_R_vectors_simple_grid(self, sampling_range, dcenters, dranges, o_ii)
if (~exist('o_ii', 'var'))
o_ii = 1;
end
num_comps = numel(sampling_range);
try
self.R_vectors{o_ii} = zeros(num_comps ^ 3, 3);
catch mexc
fprintf('Trying to allocate a [%d, 3] array.. but without enough memory!\n', ...
num_comps ^ 3)
rethrow(mexc)
end
points = zeros(num_comps, 3);
dcenters = dcenters(ones(1, num_comps), :);
dranges = dranges(ones(1, num_comps), :);
self.lattice(o_ii).gr = cell(num_comps, num_comps, num_comps);
l_ii = 0;
for z_ii = 1:num_comps
for y_ii = 1:num_comps
points(:, 1) = sampling_range(:);
points(:, 2) = sampling_range(y_ii);
points(:, 3) = sampling_range(z_ii);
R_vecs = dcenters + points .* dranges;
self.R_vectors{o_ii}(l_ii+1:l_ii+num_comps, :) = R_vecs;
l_ii = l_ii + num_comps;
end
end
end
function produce_R_vectors_even_simple_grid(self, sampling_ranges, dcenters, dranges, o_ii)
if (~exist('o_ii', 'var'))
o_ii = 1;
end
num_z_comps = numel(sampling_ranges{3});
num_y_comps = numel(sampling_ranges{2});
num_x_comps = numel(sampling_ranges{1});
try
self.R_vectors{o_ii} = zeros(num_z_comps * num_y_comps * num_x_comps, 3);
catch mexc
fprintf('Trying to allocate a [%d, 3] array.. but without enough memory!\n', ...
num_z_comps * num_y_comps * num_x_comps)
rethrow(mexc)
end
points = zeros(num_x_comps, 3);
dcenters = dcenters(ones(1, num_x_comps), :);
dranges = dranges(ones(1, num_x_comps), :);
self.lattice(o_ii).gr = cell(num_x_comps, num_y_comps, num_z_comps);
l_ii = 0;
for z_ii = 1:num_z_comps
for y_ii = 1:num_y_comps
points(:, 1) = sampling_ranges{1}(:);
points(:, 2) = sampling_ranges{2}(y_ii);
points(:, 3) = sampling_ranges{3}(z_ii);
R_vecs = dcenters + points .* dranges;
self.R_vectors{o_ii}(l_ii+1:l_ii+num_x_comps, :) = R_vecs;
l_ii = l_ii + num_x_comps;
end
end
end
function produce_geometry(self)
grain_center = self.get_grain_center();
ref_omind = self.ref_gr.allblobs.omind;
ref_included = self.ondet(self.included(self.selected));
fprintf('Computing geometries: ')
c = tic();
for o_ii = 1:numel(self.lattice)
num_orients = numel(self.lattice(o_ii).gr);
num_chars_o = fprintf('order %d/%d: (%d) ', o_ii-1, numel(self.lattice), num_orients);
order_gvdm = self.R_vectors{o_ii};
num_chars_gr = fprintf('creating initial structures..');
for ii = 1:num_orients
self.lattice(o_ii).gr{ii} = struct( ...
'R_vector', order_gvdm(ii, :), ...
'center', grain_center, ...
'phaseid', self.ref_gr.phaseid );
end
fprintf(repmat('\b', [1 num_chars_gr]));
fprintf(repmat(' ', [1 num_chars_gr]));
fprintf(repmat('\b', [1 num_chars_gr]));
switch(2)
case 3 % All in once
num_chars_gr = fprintf('gtCalculateGrain in parallel..');
self.lattice(o_ii).gr = gtCalculateGrain_p( ...
self.lattice(o_ii).gr, self.parameters, ...
'ref_omind', ref_omind, 'included', ref_included );
case 2 % In chunks
num_chars_gr = fprintf('gtCalculateGrain in chunks: ');
chunk_size = 1000;
for ii = 1:chunk_size:num_orients
end_chunk = min(ii+chunk_size, num_orients);
num_chars_gr_ii = fprintf('%05d/%05d', ii, num_orients);
self.lattice(o_ii).gr(ii:end_chunk) = gtCalculateGrain_p( ...
self.lattice(o_ii).gr(ii:end_chunk), self.parameters, ...
'ref_omind', ref_omind, 'included', ref_included );
fprintf(repmat('\b', [1 num_chars_gr_ii]));
end
fprintf(repmat(' ', [1 num_chars_gr_ii]));
fprintf(repmat('\b', [1 num_chars_gr_ii]));
case 1 % One by One
num_chars_gr = fprintf('gtCalculateGrain: ');
for ii = 1:num_orients
num_chars_gr_ii = fprintf('%05d/%05d', ii, num_orients);
self.lattice(o_ii).gr{ii} = gtCalculateGrain( ...
self.lattice(o_ii).gr{ii}, self.parameters, ...
'ref_omind', ref_omind, 'included', ref_included );
fprintf(repmat('\b', [1 num_chars_gr_ii]));
end
fprintf(repmat(' ', [1 num_chars_gr_ii]));
fprintf(repmat('\b', [1 num_chars_gr_ii]));
end
fprintf(repmat('\b', [1 num_chars_gr]));
fprintf(repmat(' ', [1 num_chars_gr]));
fprintf(repmat('\b', [1 num_chars_gr]));
fprintf(repmat('\b', [1 num_chars_o]));
end
total_orient = sum(arrayfun(@(x)numel(x.gr), self.lattice));
fprintf(' (orders: %d, total orientations: %04d, in %3.1f s) Done.\n', ...
numel(self.lattice), total_orient, toc(c));
end
function produce_geometry_supersampling(self)
ref_omind = self.ref_gr.allblobs.omind;
ref_included = self.ondet(self.included(self.selected));
fprintf('Computing super-sampling geometries: ')
c = tic();
for o_ii = 1:numel(self.lattice_ss)
num_orients = numel(self.lattice_ss(o_ii).gr);
num_chars_o = fprintf('order %d/%d: (%d) orientation: ', o_ii-1, numel(self.lattice_ss), num_orients);
for g_ii = 1:num_orients
num_chars_gr_ii = fprintf('%05d/%05d', g_ii, num_orients);
self.lattice_ss(o_ii).gr{g_ii} = gtCalculateGrain_p( ...
self.lattice_ss(o_ii).gr{g_ii}, self.parameters, ...
'ref_omind', ref_omind, 'included', ref_included );
fprintf(repmat('\b', [1 num_chars_gr_ii]));
end
fprintf(repmat('\b', [1 num_chars_o]));
end
total_orient = sum(arrayfun(@(x)numel(x.gr), self.lattice_ss));
fprintf(' (orders: %d, total orientations: %04d, in %3.1f s) Done.\n', ...
numel(self.lattice), total_orient, toc(c));
end
function produce_stats(self, type)
self.stats.sampling.type = type;
switch(type)
case 'cubic'
% self.compute_pixel_distances_simple_grid();
self.compute_blob_coverage_simple_grid();
self.compute_sampling_distances_cubic();
case 'fcc'
case 'bcc'
% self.compute_pixel_distances_bcc();
self.compute_blob_coverage_simple_grid();
self.compute_sampling_distances_bcc();
end
end
function compute_sampling_distances_cubic(self)
self.stats.sampling.gaps(1) = self.lattice.gr{2, 1, 1}.R_vector(1) - self.lattice.gr{1, 1, 1}.R_vector(1);
self.stats.sampling.gaps(2) = self.lattice.gr{1, 2, 1}.R_vector(2) - self.lattice.gr{1, 1, 1}.R_vector(2);
self.stats.sampling.gaps(3) = self.lattice.gr{1, 1, 2}.R_vector(3) - self.lattice.gr{1, 1, 1}.R_vector(3);
self.stats.sampling.bbox_size = self.lattice.gr{end}.R_vector - self.lattice.gr{1}.R_vector;
self.stats.sampling.bbox_shift = self.lattice.gr{1}.R_vector;
end
function compute_sampling_distances_bcc(self)
self.stats.sampling.gaps = self.lattice(2).gr{1}.R_vector - self.lattice(1).gr{1}.R_vector;
self.stats.sampling.bbox_size = self.lattice(1).gr{end}.R_vector - self.lattice(1).gr{1}.R_vector;
self.stats.sampling.bbox_shift = self.lattice(1).gr{1}.R_vector;
end
function compute_pixel_distances_simple_grid(self)
max_dist_u = 0;
max_dist_v = 0;
max_angle_u = 0;
max_angle_v = 0;
for z_ii = 1:size(self.lattice(1).gr, 3)
for y_ii = 1:size(self.lattice(1).gr, 2)
for x_ii = 1:size(self.lattice(1).gr, 1)-1
gr1 = self.lattice(1).gr{x_ii, y_ii, z_ii};
gr2 = self.lattice(1).gr{x_ii+1, y_ii, z_ii};
[gr12_dist, gr12_angle] = self.compute_max_proj_pixel_dist(gr1, gr2);
max_dist_u = max(max_dist_u, gr12_dist);
max_angle_u = max(max_angle_u, gr12_angle);
end
end
for y_ii = 1:size(self.lattice(1).gr, 2)-1
for x_ii = 1:size(self.lattice(1).gr, 1)
gr1 = self.lattice(1).gr{x_ii, y_ii, z_ii};
gr2 = self.lattice(1).gr{x_ii, y_ii+1, z_ii};
[gr12_dist, gr12_angle] = self.compute_max_proj_pixel_dist(gr1, gr2);
max_dist_v = max(max_dist_v, gr12_dist);
max_angle_v = max(max_angle_v, gr12_angle);
end
end
end
self.stats.proj.max_pixel_dist_u = max_dist_u;
self.stats.proj.max_pixel_dist_v = max_dist_v;
self.stats.proj.max_angle_u = max_angle_u;
self.stats.proj.max_angle_v = max_angle_v;
self.stats.sample.avg_dist = self.compute_average_sample_distance();
end
function compute_pixel_distances_bcc(self)
max_dist_x = 0;
max_dist_y = 0;
max_angle_x = 0;
max_angle_y = 0;
for z_ii = 1:size(self.lattice(2).gr, 3)
for y_ii = 1:size(self.lattice(2).gr, 2)
for x_ii = 1:size(self.lattice(2).gr, 1)
gr1 = self.lattice(1).gr{x_ii, y_ii, z_ii};
gr2 = self.lattice(2).gr{x_ii, y_ii, z_ii};
[gr12_dist, gr12_angle] = self.compute_max_proj_pixel_dist(gr1, gr2);
max_dist_x = max(max_dist_x, gr12_dist);
max_angle_x = max(max_angle_x, gr12_angle);
end
end
for y_ii = 1:size(self.lattice(2).gr, 2)
for x_ii = 1:size(self.lattice(2).gr, 1)
gr1 = self.lattice(1).gr{x_ii+1, y_ii, z_ii};
gr2 = self.lattice(2).gr{x_ii, y_ii, z_ii};
[gr12_dist, gr12_angle] = self.compute_max_proj_pixel_dist(gr1, gr2);
max_dist_x = max(max_dist_x, gr12_dist);
max_angle_x = max(max_angle_x, gr12_angle);
end
end
for y_ii = 1:size(self.lattice(2).gr, 2)
for x_ii = 1:size(self.lattice(2).gr, 1)
gr1 = self.lattice(1).gr{x_ii, y_ii+1, z_ii};
gr2 = self.lattice(2).gr{x_ii, y_ii, z_ii};
[gr12_dist, gr12_angle] = self.compute_max_proj_pixel_dist(gr1, gr2);
max_dist_x = max(max_dist_x, gr12_dist);
max_angle_x = max(max_angle_x, gr12_angle);
end
end
for y_ii = 1:size(self.lattice(2).gr, 2)
for x_ii = 1:size(self.lattice(2).gr, 1)
gr1 = self.lattice(1).gr{x_ii+1, y_ii+1, z_ii};
gr2 = self.lattice(2).gr{x_ii, y_ii, z_ii};
[gr12_dist, gr12_angle] = self.compute_max_proj_pixel_dist(gr1, gr2);
max_dist_x = max(max_dist_x, gr12_dist);
max_angle_x = max(max_angle_x, gr12_angle);
end
end
end
self.stats.proj.max_pixel_dist_u = max_dist_x;
self.stats.proj.max_pixel_dist_v = max_dist_y;
self.stats.proj.max_angle_u = max_angle_x;
self.stats.proj.max_angle_v = max_angle_y;
self.stats.sample.avg_dist = self.compute_average_sample_distance();
end
function dist = compute_average_sample_distance(self)
dist = 0;
tot_orient = get_total_num_orientations(self);
for o_ii = 1:numel(self.lattice)
for z_ii = 1:size(self.lattice(o_ii).gr, 3)
for y_ii = 1:size(self.lattice(o_ii).gr, 2)
for x_ii = 1:size(self.lattice(o_ii).gr, 1)
ab = self.lattice(o_ii).gr{x_ii, y_ii, z_ii}.allblobs;
if (isfield(ab, 'detector'))
positions = ab.detector(1).proj_geom(:, 4:6);
else
positions = ab.proj_geom(:, 4:6);
end
dist = dist + sum(sqrt(sum(positions .^ 2, 2))) / size(positions, 1);
end
end
end
end
dist = dist / tot_orient;
end
function [dist, angle] = compute_max_proj_pixel_dist(self, gr1, gr2)
if (isfield(gr1.allblobs, 'detector'))
geom1 = gr1.allblobs.detector(1).proj_geom;
geom2 = gr2.allblobs.detector(1).proj_geom;
else
geom1 = gr1.allblobs.proj_geom;
geom2 = gr2.allblobs.proj_geom;
end
dirs1 = geom1(:, 1:3);
dirs2 = geom2(:, 1:3);
det_pos1 = geom1(:, 4:6);
det_pos2 = geom2(:, 4:6);
lengths1 = sqrt(sum(det_pos1 .^ 2, 2));
lengths2 = sqrt(sum(det_pos2 .^ 2, 2));
disps1 = dirs1 .* lengths1(:, [1 1 1]) - det_pos1;
disps2 = dirs2 .* lengths2(:, [1 1 1]) - det_pos2;
% Approximately
disps = disps1 - disps2;
[dist, ~] = max(sqrt(sum(disps .^ 2, 2)));
% rot_dirs = cross(det_pos2, det_pos1);
% norm_rot_dirs = sqrt(sum(rot_dirs .^ 2, 2));
% rot_dirs = rot_dirs ./ norm_rot_dirs(:, [1 1 1]);
%
% renorm_det_pos = lengths1 .* lengths2;
% dot_det_pos = det_pos1 .* det_pos2;
% rot_angles = abs(acos(sum(dot_det_pos, 2) ./ renorm_det_pos));
%
% rotated_dirs2 = zeros(size(dirs2));
%
% for r_ii = 1:numel(rot_angles)
% rot_comp = gtMathsRotationMatrixComp(rot_dirs(r_ii, :), 'row');
% rot_tensor = gtMathsRotationTensor(rot_angles(r_ii), rot_comp);
%
% rotated_dirs2(r_ii, :) = dirs2(r_ii, :) * rot_tensor;
% end
%
% angles = acos(sum(dirs1 .* rotated_dirs2, 2));
angles = abs(acos(sum(dirs1 .* dirs2, 2)));
[angle, ~] = max(angles);
end
function compute_blob_coverage_simple_grid(self)
omega_step = self.get_omega_step_deg();
bls = self.bl(self.selected);
num_blobs = numel(bls);
max_depth_blobs = 0;
for b_ii = 1:num_blobs
max_depth_blobs = max(max_depth_blobs, size(bls(b_ii).intm, 3));
end
switch(self.stats.sampling.type)
case 'cubic'
num_z_comps = size(self.lattice.gr, 3);
% Coverage of the slices in blobs (by Z layer of the sampling)
self.stats.pics.blob_coverage_map = cell(num_z_comps);
end
% Total intensity of each slice in a blob
self.stats.pics.blob_intensity = zeros(num_blobs, max_depth_blobs);
% Coverage of the slices in blobs (generic)
self.stats.pics.blob_coverage = zeros(num_blobs, max_depth_blobs);
min_blob_pos = zeros(num_blobs, 1);
max_blob_pos = zeros(num_blobs, 1);
for b_ii = 1:num_blobs
depth_blob = size(bls(b_ii).intm, 3);
min_blob_pos(b_ii) = floor((max_depth_blobs - depth_blob)/2) + 1;
max_blob_pos(b_ii) = min_blob_pos(b_ii) + depth_blob - 1;
self.stats.pics.blob_intensity(b_ii, min_blob_pos(b_ii):max_blob_pos(b_ii)) ...
= squeeze(sum(sum(bls(b_ii).intm, 2), 1));
end
limits = cat(1, bls(:).bbwim);
for o_ii = 1:numel(self.lattice)
for z_ii = 1:size(self.lattice(o_ii).gr, 3)
switch(self.stats.sampling.type)
case 'cubic'
self.stats.pics.blob_coverage_map{z_ii} = zeros(num_blobs, max_depth_blobs);
end
for y_ii = 1:size(self.lattice(o_ii).gr, 2)
for x_ii = 1:size(self.lattice(o_ii).gr, 1)
ab = self.lattice(o_ii).gr{x_ii, y_ii, z_ii}.allblobs;
omegas = ab.omega / omega_step;
within_lims = find(omegas >= limits(:, 1) & omegas <= limits(:, 2));
pos_in_blobs = round(omegas(within_lims)) - limits(within_lims, 1) + 1;
pos_in_coverage = pos_in_blobs + min_blob_pos(within_lims) - 1;
indx = sub2ind(size(self.stats.pics.blob_coverage), within_lims, pos_in_coverage);
switch(self.stats.sampling.type)
case 'cubic'
self.stats.pics.blob_coverage_map{z_ii}(indx) = ...
self.stats.pics.blob_coverage_map{z_ii}(indx) + 1;
end
self.stats.pics.blob_coverage(indx) = 1;
end
end
end
end
% Intensity reached by at least one orientation
self.stats.pics.blob_covered_intensity = ...
self.stats.pics.blob_intensity .* self.stats.pics.blob_coverage;
% Intensity NOT reached by any orientation
self.stats.pics.blob_uncovered_intensity = ...
self.stats.pics.blob_intensity .* (1 - self.stats.pics.blob_coverage);
end
function plot_blob_coverage(self)
f1 = figure();
lims = [min(self.stats.pics.blob_intensity(:)) max(self.stats.pics.blob_intensity(:))];
ax1 = subplot(1, 4, 1, 'parent', f1);
imagesc(self.stats.pics.blob_covered_intensity, 'parent', ax1, lims);
title(ax1, 'Covered Intensity');
ax2 = subplot(1, 4, 2, 'parent', f1);
imagesc(self.stats.pics.blob_uncovered_intensity, 'parent', ax2, lims);
title(ax2, 'Uncovered Intensity');
ax2 = subplot(1, 4, 3, 'parent', f1);
imagesc(self.stats.pics.blob_coverage, 'parent', ax2);
title(ax2, 'Coverage');
ax2 = subplot(1, 4, 4, 'parent', f1);
imagesc(self.stats.pics.blob_intensity, 'parent', ax2);
title(ax2, 'Intensity');
switch(self.stats.sampling.type)
case 'cubic'
num_z_comps = size(self.lattice.gr, 3);
% Let's visualize the maps separately
grid_rows = floor(sqrt(num_z_comps));
grid_cols = ceil(num_z_comps / grid_rows);
f2 = figure();
for ii = 1:num_z_comps
ax = subplot(grid_rows, grid_cols, ii, 'parent', f2);
imagesc(self.stats.pics.blob_coverage_map{ii}, 'parent', ax);
title(ax, sprintf('Coverage of Z Layer %d', ii));
end
otherwise
end
drawnow();
end
function plot_sampling(self, gvdm, dmean)
points = self.R_vectors;
points = cat(1, points{:});
figure %, scatter3(points(:, 1), points(:, 2), points(:, 3))
hold on
scatter3(gvdm(1, :)', gvdm(2, :)', gvdm(3, :)', 20, 'c')
scatter3(points(:, 1), points(:, 2), points(:, 3), 20, 'r')
scatter3(mean(points(:, 1)), mean(points(:, 2)), mean(points(:, 3)), 30, 'm', 'filled')
scatter3(dmean(1), dmean(2), dmean(3), 30, 'g', 'filled')
hold off
drawnow();
end
function plot_supersampling(self)
points = [self.lattice.gr{:}];
points = cat(1, points.R_vector);
points_os = [self.lattice_ss.gr{:}];
points_os = [points_os{:}];
points_os = cat(1, points_os.R_vector);
figure %, scatter3(points(:, 1), points(:, 2), points(:, 3))
hold on
scatter3(points(:, 1), points(:, 2), points(:, 3), 20, 'c')
scatter3(points_os(:, 1), points_os(:, 2), points_os(:, 3), 20, 'r')
hold off
drawnow();
end
function print_sampling_details(self, dranges, oversize, edge_points)
if (numel(edge_points) == 1)
edge_points = edge_points([1 1 1]);
end
size_bb = 2 * atand(dranges * oversize);
max_resolution = self.estimate_maximum_resolution();
max_res_sampling_points = ceil(size_bb ./ max_resolution) + 1;
current_resolution = size_bb ./ (edge_points-1);
num_interp_range = current_resolution(3) / max_resolution(3);
num_interp_range = [num_interp_range, num_interp_range * 2];
detected_num_interp = self.parameters.rec.grains.options.num_interp;
if (detected_num_interp < 0)
detected_num_interp = abs(detected_num_interp) * self.minimum_num_interp(current_resolution(3));
elseif (~detected_num_interp)
detected_num_interp = self.suggest_num_interp(current_resolution(3));
end
fprintf('\nOrientation-sapce sampling details:\n')
fprintf('- Bounding-box size (deg): [%g, %g, %g]\n', size_bb)
fprintf('- Maximum estimated resolution (deg): [%g, %g, %g] (Sampling points: [%d, %d, %d] => %d)\n', ...
max_resolution, max_res_sampling_points, prod(max_res_sampling_points));
fprintf('- Resolution (deg): [%g, %g, %g] (Sampling points: [%d, %d, %d] => %d)\n', ...
current_resolution, edge_points, prod(edge_points));
fprintf('- Suggested num_interp interval: [%g, %g], detected: %g\n\n', ...
num_interp_range, detected_num_interp);
end
function print_stats(self)
fprintf('Sampling:\n - lattice type: "%s" (size: %d, %d, %d)\n', ...
self.stats.sampling.type, size(self.lattice(1).gr));
fprintf(' - Gaps: x %e, y %e, z %e\n', ...
self.stats.sampling.gaps(1), ...
self.stats.sampling.gaps(2), ...
self.stats.sampling.gaps(3) );
fprintf(' - BBox: size (%e, %e, %e), shift (%e, %e, %e)\n', ...
self.stats.sampling.bbox_size, ...
self.stats.sampling.bbox_shift )
fprintf('Average smple distance: %g (pixels)\n', ...
self.stats.sample.avg_dist)
fprintf('Max projection pixel distances: x %f, y %f\n', ...
self.stats.proj.max_pixel_dist_u, ...
self.stats.proj.max_pixel_dist_v );
fprintf('Max projection angle distances: x %e (deg %f), y %e (deg %f)\n', ...
self.stats.proj.max_angle_u, ...
(180/pi*self.stats.proj.max_angle_u), ...
self.stats.proj.max_angle_v, ...
(180/pi*self.stats.proj.max_angle_v) );
end
function omega_step = get_omega_step_deg(self)
omega_step = 180 / self.parameters.acq.nproj;
end
function omega_step = get_omega_step_rad(self)
omega_step = pi / self.parameters.acq.nproj;
end
function gc = get_grain_center(self)
if (~isempty(self.fedpars))
gc = self.fedpars.vox000sam' + ...
(self.fedpars.grainsize' ./ 2 + [0.5; 0.5; 0.5]) .* self.parameters.recgeo.voxsize';
gc = gc';
else
gc = self.ref_gr.center; % .* self.parameters.recgeo.voxsize;
end
end
function [raw_depths, weighted_depths] = get_blob_depths(self)
% Try to account for Forentz factor, at least to avoid that max
% blows up. Computation is only approximated, so doesn't really
% count
indx = self.ondet(self.included(self.selected));
etas = self.ref_gr.allblobs.eta(indx);
factors = abs(sind(etas));
raw_depths = cellfun(@(x){sum(sum(abs(x), 1), 2)}, {self.bl(self.selected).intm}');
raw_depths = cellfun(@(x)(find(x >= 0, 1, 'last') - find(x >= 0, 1, 'first') + 1), raw_depths);
% raw_depths = cellfun(@(x)size(x, 3), {self.bl(self.selected).intm}') - 2;
weighted_depths = raw_depths .* factors;
end
function [max_blob_depth, min_blob_depth] = get_range_blob_depth(self)
max_blob_depth = 0;
min_blob_depth = +Inf;
num_blobs = numel(self.bl);
etas = self.ref_gr.allblobs.eta(self.ondet(self.included(self.selected)));
for b_ii = 1:num_blobs
% 2 is the pading we apply in forward simulation
current_blob_depth = (size(self.bl(b_ii).intm, 3) - 2);
lorentz_factored_depth = current_blob_depth * abs(sind(etas(b_ii)));
max_blob_depth = max(max_blob_depth, lorentz_factored_depth);
min_blob_depth = min(min_blob_depth, current_blob_depth);
end
end
end
methods (Access = protected, Static)
function range = get_cubic_range(edge_num, oversize)
if (~exist('oversize', 'var'))
oversize = 1.1;
end
limit = (edge_num - 1) / 2;
range = (-limit:limit) / (limit * 2) * oversize;
end
function range = get_bcc_center_range(edge_num, oversize)
if (~exist('oversize', 'var'))
oversize = 1.1;
end
limit_bcc = (edge_num - 1) / 2;
limit = (edge_num - 2) / 2;
range = (-limit:limit) / (limit_bcc * 2) * oversize;
end
end
methods (Access = public, Static)
function [avg_R_vecs, avg_R_vecs_int, stddev_R_vecs] = computeAverageOrientations(ors, or_vols, selected)
if (~exist('selected', 'var') || isempty(selected))
selected = true(size(or_vols));
end
final_vol_size = [size(or_vols{1}, 1), size(or_vols{1}, 2), size(or_vols{1}, 3)];
avg_R_vecs = zeros([final_vol_size, 3]);
avg_R_vecs_int = zeros(final_vol_size);
stddev_R_vecs = zeros(final_vol_size);
if (iscell(ors))
ors_sel = [ors{selected}];
% Converting to gvdm
gvdm_tmp = cat(1, ors_sel(:).R_vector)';
else
gvdm_tmp = ors(:, selected);
end
% computing weighted average orientation
for ii = 1:numel(or_vols)
weights = or_vols{ii};
r_vec = cat(4, ...
gvdm_tmp(1, ii) * ones(final_vol_size), ...
gvdm_tmp(2, ii) * ones(final_vol_size), ...
gvdm_tmp(3, ii) * ones(final_vol_size) );
avg_R_vecs_int = avg_R_vecs_int + weights;
avg_R_vecs = avg_R_vecs + weights(:, :, :, [1 1 1]) .* r_vec;
end
avg_R_vecs_int_norm = avg_R_vecs_int + (avg_R_vecs_int == 0);
avg_R_vecs = avg_R_vecs ./ avg_R_vecs_int_norm(:, :, :, [1 1 1]);
% computing weighted standard deviations
for ii = 1:numel(or_vols)
r_vec = cat(4, ...
gvdm_tmp(1, ii) * ones(final_vol_size), ...
gvdm_tmp(2, ii) * ones(final_vol_size), ...
gvdm_tmp(3, ii) * ones(final_vol_size) );
square_dists = sum((r_vec - avg_R_vecs) .^ 2, 4);
weights = or_vols{ii};
stddev_R_vecs = stddev_R_vecs + weights .* square_dists;
end
stddev_R_vecs = stddev_R_vecs ./ avg_R_vecs_int_norm;
end
function avg_R_vec = computeAverageOrientation(gr, vols)
gr_sel = [gr{:}];
R_vecs = cat(1, gr_sel(:).R_vector);
vol_ints = GtOrientationSampling.computeODF(gr, vols);
vol_ints = reshape(vol_ints, [], 1);
vol_ints = vol_ints(:, [1 1 1]);
avg_R_vec = sum(R_vecs .* vol_ints, 1) ./ sum(vol_ints, 1);
end
function odf = computeODF(ors, vols)
odf = zeros(size(ors));
odf(:) = cellfun(@(x)gtMathsSumNDVol(x), vols);
end
function [dmean, dcenters, dranges] = get_deformation_stats(gvdm)
dmean = mean(gvdm, 2)';
dcenters = (max(gvdm, [], 2)' + min(gvdm, [], 2)') / 2;
dranges = max(gvdm, [], 2)' - min(gvdm, [], 2)';
end
end
end