Newer
Older
Nicola Vigano
committed
function sf = gtDefShapeFunctionsCreateNW(sampler, eta_resoltion, varargin)
% FUNCTION sf = gtDefShapeFunctionsCreateNW(sampler, eta_resoltion, varargin)
%
conf = struct( ...
'data_type', 'double', ...
'fast_inverse', false, ...
'fast_lines', false, ...
Nicola Vigano
committed
'compute_w_sfs', false );
conf = parse_pv_pairs(conf, varargin);
p = sampler.parameters;
if (~exist('eta_resoltion', 'var') || isempty(eta_resoltion))
eta_resoltion = 1;
end
Nicola Vigano
committed
det_ind = sampler.detector_index;
om_step = gtAcqGetOmegaStep(p, det_ind);
Nicola Vigano
committed
om_step_rod = tand(om_step / 2);
space_res = tand(sampler.estimate_maximum_resolution() ./ 2);
eta_step = 2 * atand(space_res(1)) / eta_resoltion;
oversampling = 11;
oversampling_w = oversampling;
step_w = 1 / oversampling_w;
shift_w = 0.5 - step_w / 2;
oversampling_n = (oversampling - 1) / eta_resoltion + 1;
step_n = 1 / oversampling_n;
shift_n = 0.5 - step_n / 2;
Nicola Vigano
committed
sub_space_size = tand(sampler.sampling_res / 2);
Nicola Vigano
committed
% Let's first compute the W extent
half_rspace_sizes = sub_space_size / 2;
ref_gr = sampler.get_reference_grain();
Nicola Vigano
committed
ref_ond = ref_gr.proj(det_ind).ondet;
ref_inc = ref_gr.proj(det_ind).included;
ref_sel = ref_gr.proj(det_ind).selected;
ref_ab_sel = ref_ond(ref_inc(ref_sel));
ref_ab_inc = ref_ond(ref_inc);
num_blobs = numel(find(ref_sel));
pl_samd = ref_gr.allblobs(det_ind).plorig(ref_ab_sel, :);
Nicola Vigano
committed
g = gtMathsRod2OriMat(ref_gr.R_vector');
pl_cry = gtVectorLab2Cryst(pl_samd, g)';
% pl_labd = gtGeoSam2Lab(pl_samd, eye(3), self.parameters.labgeo, self.parameters.samgeo, true)';
Nicola Vigano
committed
fprintf('Computing bounds of NW shape functions: ')
c = tic();
tot_orientations = numel(sampler.lattice.gr);
oris_bounds_size = [size(sampler.lattice.gr, 1), size(sampler.lattice.gr, 2), size(sampler.lattice.gr, 3)] + 1;
oris_lims_min = sampler.lattice.gr{1, 1, 1}.R_vector - half_rspace_sizes;
oris_lims_max = sampler.lattice.gr{end, end, end}.R_vector + half_rspace_sizes;
oris_steps_x = linspace(oris_lims_min(1), oris_lims_max(1), oris_bounds_size(1));
oris_steps_y = linspace(oris_lims_min(2), oris_lims_max(2), oris_bounds_size(2));
oris_steps_z = linspace(oris_lims_min(3), oris_lims_max(3), oris_bounds_size(3));
oris_bounds = cell(oris_bounds_size);
Nicola Vigano
committed
for dy = 1:oris_bounds_size(2)
Nicola Vigano
committed
r_vec = [oris_steps_x(dx), oris_steps_y(dy), oris_steps_z(dz)];
oris_bounds{dx, dy, dz} = struct( ...
'phaseid', ref_gr.phaseid, ...
'center', ref_gr.center, 'R_vector', r_vec );
end
end
end
chunk_size = 250;
for ii = 1:chunk_size:numel(oris_bounds)
end_chunk = min(ii+chunk_size, numel(oris_bounds));
num_chars_gr_ii = fprintf('%05d/%05d', ii, numel(oris_bounds));
oris_bounds(ii:end_chunk) = gtCalculateGrain_p( ...
oris_bounds(ii:end_chunk), p, ...
Nicola Vigano
committed
'ref_omind', ref_gr.allblobs(det_ind).omind, ...
'included', ref_ab_inc );
Nicola Vigano
committed
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
fprintf(repmat('\b', [1 num_chars_gr_ii]));
end
fprintf('Done in %g seconds.\n', toc(c))
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
if (conf.compute_w_sfs)
num_poins = max(ceil(sub_space_size ./ space_res ./ 2), 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_w = (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_grid_w = reshape(pos_x, 1, [], 1);
pos_x_grid_w = pos_x_grid_w(1, :, ones(1, num_poins(2)));
pos_y_grid_w = reshape(pos_y, 1, 1, []);
pos_y_grid_w = pos_y_grid_w(1, ones(1, num_poins(1)), :);
pos_z_grid_w = zeros(1, num_poins(1), num_poins(2));
tot_sampling_points_w = num_poins(1) * num_poins(2);
ones_tot_sp_w = ones(tot_sampling_points_w, 1);
end
Nicola Vigano
committed
ref_ws = ref_gr.allblobs(det_ind).omega(ref_ab_sel) ./ om_step;
Nicola Vigano
committed
% 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();
% selecting Ws to find the interval
ori_bounds = [oris_bounds{:}];
allblobs = [ori_bounds(:).allblobs];
w_tabs_int = [allblobs(:).omega];
Nicola Vigano
committed
w_tabs_int = w_tabs_int(ref_sel, :) ./ om_step;
Nicola Vigano
committed
w_tabs_int = gtGrainAnglesTabularFix360deg(w_tabs_int, ref_ws, p);
w_tabs_int = reshape(w_tabs_int, [], oris_bounds_size(1), oris_bounds_size(2), oris_bounds_size(3));
Nicola Vigano
committed
ref_ns = ref_gr.allblobs(det_ind).eta(ref_ab_sel);
Nicola Vigano
committed
n_tabs_int = [allblobs(:).eta];
Nicola Vigano
committed
n_tabs_int = n_tabs_int(ref_sel, :);
Nicola Vigano
committed
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
n_tabs_int = gtGrainAnglesTabularFix360deg(n_tabs_int, ref_ns);
n_tabs_int = n_tabs_int ./ eta_step;
n_tabs_int = reshape(n_tabs_int, [], oris_bounds_size(1), oris_bounds_size(2), oris_bounds_size(3));
rotcomp_w = gtMathsRotationMatrixComp(p.labgeo.rotdir', 'col');
if (conf.compute_w_sfs)
rotcomp_z = gtMathsRotationMatrixComp([0, 0, 1]', 'col');
% Precomputing A matrix components for all the used omegas
ref_round_int_ws = round(ref_ws + 0.5) - 0.5;
ref_round_ws = ref_round_int_ws .* om_step;
rot_samp_w = gtMathsRotationTensor(ref_round_ws, rotcomp_w);
beamdirs = p.labgeo.beamdir * reshape(rot_samp_w, 3, []);
beamdirs = reshape(beamdirs, 3, [])';
Ac_part_w = beamdirs * rotcomp_z.cos;
As_part_w = beamdirs * rotcomp_z.sin;
Acc_part_w = beamdirs * rotcomp_z.const;
Ac_part_w = Ac_part_w(:, :, ones_tot_sp_w);
As_part_w = As_part_w(:, :, ones_tot_sp_w);
Acc_part_w = Acc_part_w(:, :, ones_tot_sp_w);
end
fprintf('\b\b: Done in %g seconds.\n', toc(c))
sf = cell(tot_orientations, 1);
[o_x, o_y, o_z] = ind2sub(oris_bounds_size-1, 1:tot_orientations);
fprintf('Computing NW shape functions: ')
c = tic();
for ii_g = 1:tot_orientations
if (mod(ii_g, chunk_size/10) == 1)
currtime = toc(c);
num_chars = fprintf('%05d/%05d (%g s, ETA %g s)', ...
ii_g, tot_orientations, currtime, ...
toc(c) / (ii_g - 1) * tot_orientations - currtime);
end
gr = sampler.lattice.gr{ii_g};
Nicola Vigano
committed
t = gr.allblobs(det_ind).theta(ref_sel);
n = gr.allblobs(det_ind).eta(ref_sel);
w = gr.allblobs(det_ind).omega(ref_sel);
Nicola Vigano
committed
rot_w = gtMathsRotationTensor(w, rotcomp_w);
Nicola Vigano
committed
n_1 = gr.allblobs(det_ind).eta(ref_sel) + eta_step;
Nicola Vigano
committed
rot_w_1 = gtMathsRotationTensor(w + om_step, rotcomp_w);
Nicola Vigano
committed
ominds = gr.allblobs(det_ind).omind(ref_sel);
ssp = ((ominds == 1) | (ominds == 2));
ss12 = ssp - ~ssp;
h = ss12(:, [1 1 1]) .* pl_cry';
Nicola Vigano
committed
% Extracting ospace boundaries for the given voxel
w_tab_int = w_tabs_int(:, o_x(ii_g):o_x(ii_g)+1, o_y(ii_g):o_y(ii_g)+1, o_z(ii_g):o_z(ii_g)+1);
w_tab_int = reshape(w_tab_int, [], 8);
n_tab_int = n_tabs_int(:, o_x(ii_g):o_x(ii_g)+1, o_y(ii_g):o_y(ii_g)+1, o_z(ii_g):o_z(ii_g)+1);
n_tab_int = reshape(n_tab_int, [], 8);
lims_w_proj_g_int = round([min(w_tab_int, [], 2), max(w_tab_int, [], 2)]);
lims_n_proj_g_int = round([min(n_tab_int, [], 2), max(n_tab_int, [], 2)]);
num_ws = lims_w_proj_g_int(:, 2) - lims_w_proj_g_int(:, 1) + 1;
num_ns = lims_n_proj_g_int(:, 2) - lims_n_proj_g_int(:, 1) + 1;
[ref_r0, ref_r_dir] = compute_rod_line(t, n, rot_w, h, p.labgeo, p.samgeo);
[ref_r0_n, ref_r_dir_n] = compute_rod_line(t, n_1, rot_w, h, p.labgeo, p.samgeo);
[ref_r0_w, ref_r_dir_w] = compute_rod_line(t, n, rot_w_1, h, p.labgeo, p.samgeo);
Nicola Vigano
committed
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
ref_r0_diff_n = ref_r0_n - ref_r0;
ref_r0_diff_w = ref_r0_w - ref_r0;
ref_r_dir_diff_n = ref_r_dir_n - ref_r_dir;
ref_r_dir_diff_w = ref_r_dir_w - ref_r_dir;
ref_inv_r_dir = 1 ./ ref_r_dir;
% Translating everything to the origin
ref_r0 = ref_r0 - gr.R_vector(ones(numel(t), 1), :);
if (conf.compute_w_sfs)
num_dws = num_ws + 1;
num_dns = num_ns + 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_w_samp = [pos_x_grid_w; pos_y_grid_w; pos_z_grid_w];
r_vecs_w_samp = reshape(r_vecs_w_samp, 3, []);
r_vecs_w_samp = gr.R_vector(ones_tot_sp_w, :)' + r_vecs_w_samp;
gs_w = gtMathsRod2OriMat(r_vecs_w_samp);
% Unrolling and transposing the matrices at the same time
% because we need g^-1
gs_w = reshape(gs_w, 3, [])';
ys = gs_w * 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_w .* ys, 2);
As = sum(As_part_w .* ys, 2);
Acc = sum(Acc_part_w .* ys, 2);
Ac = reshape(Ac, num_blobs, tot_sampling_points_w);
As = reshape(As, num_blobs, tot_sampling_points_w);
Acc = reshape(Acc, num_blobs, tot_sampling_points_w);
D = Ac .^ 2 + As .^ 2;
Nicola Vigano
committed
sinths = ss12 .* gr.allblobs(det_ind).sintheta(ref_sel);
Nicola Vigano
committed
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
sinths = sinths(:, ones(tot_sampling_points_w, 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));
ss13 = ssp - ~ssp;
ss13 = ss13(:, ones(tot_sampling_points_w, 1));
% Shift along z in orientation space, to align with the images
% in proections space
dz = (-As + ss13 .* ok .* E) ./ (CC - Ac);
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 .* om_step / 2);
end
sf_bls_nw = gtFwdSimBlobDefinition('sf_nw', num_blobs);
% 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
ws = ((lims_w_proj_g_int(ii_b, 1)-shift_w):step_w:(lims_w_proj_g_int(ii_b, 2)+shift_w)) .* om_step;
ones_ws = ones(oversampling_w * num_ws(ii_b), 1);
ns = ((lims_n_proj_g_int(ii_b, 1)-shift_n):step_n:(lims_n_proj_g_int(ii_b, 2)+shift_n)) .* eta_step;
ones_ns = ones(oversampling_n * num_ns(ii_b), 1);
% It is always in x, because this is still in lab
% coords!
tot_vecs = oversampling_w * num_ws(ii_b) * oversampling_n * num_ns(ii_b);
ones_tvecs = ones(tot_vecs, 1);
if (conf.fast_lines)
vars_ns = (ns - n(ii_b)) / eta_step;
vars_ns = vars_ns([1 1 1], :);
vars_ws = (ws - w(ii_b)) / om_step;
vars_ws = vars_ws([1 1 1], :);
Nicola Vigano
committed
% The system has already been translated to the origin
rep_r0s = ref_r0(ii_b, :)';
rep_r0s = rep_r0s(:, ones_ns, ones_ws);
Nicola Vigano
committed
vars_r0_ns = vars_ns .* ref_r0_diff_n(ii_b * ones_ns, :)';
vars_r0_ns = vars_r0_ns(:, :, ones_ws);
Nicola Vigano
committed
vars_r0_ws = vars_ws .* ref_r0_diff_w(ii_b * ones_ws, :)';
vars_r0_ws = reshape(vars_r0_ws, 3, 1, []);
vars_r0_ws = vars_r0_ws(:, ones_ns, :);
Nicola Vigano
committed
% r0 should be defined = (h x y) / (1 + h . y)
approx_r0 = rep_r0s + vars_r0_ns + vars_r0_ws;
r0 = reshape(approx_r0, 3, [])';
Nicola Vigano
committed
rep_r_dirs = ref_r_dir(ii_b * ones_tvecs, :);
Nicola Vigano
committed
vars_r_dir_ns = vars_ns .* ref_r_dir_diff_n(ii_b * ones_ns, :)';
vars_r_dir_ns = vars_r_dir_ns(:, :, ones_ws);
vars_r_dir_ns = reshape(vars_r_dir_ns, 3, [])';
Nicola Vigano
committed
vars_r_dir_ws = vars_ws .* ref_r_dir_diff_w(ii_b * ones_ws, :)';
vars_r_dir_ws = reshape(vars_r_dir_ws, 3, 1, []);
vars_r_dir_ws = vars_r_dir_ws(:, ones_ns, :);
vars_r_dir_ws = reshape(vars_r_dir_ws, 3, [])';
Nicola Vigano
committed
d_vers_nw = vars_r_dir_ns + vars_r_dir_ws;
Nicola Vigano
committed
% r should be defined = r0 + t * (h + y) / (1 + h . y)
r_dir = rep_r_dirs + d_vers_nw;
else
y_lab = gtGeoPlLabFromThetaEta(t(ii_b * ones_ns), ns', p.labgeo);
rot_ws = gtMathsRotationTensor(ws, rotcomp_w);
rot_ws = reshape(rot_ws, 3, []);
y_sam = y_lab * rot_ws;
y_sam = reshape(y_sam, oversampling_n * num_ns(ii_b), 3, oversampling_w * num_ws(ii_b));
y_sam = permute(y_sam, [1 3 2]);
y_sam = reshape(y_sam, [], 3);
renorms = 1 + y_sam * h(ii_b, :)';
renorms = renorms(:, [1 1 1]);
hh = h(ii_b * ones_tvecs, :);
% r0 is defined = (h x y) / (1 + h . y)
r0 = gtMathsCross(hh, y_sam) ./ renorms - gr.R_vector(ones_tvecs, :);
% r is defined = r0 + t * (h + y) / (1 + h . y)
r_dir = (hh + y_sam) ./ renorms;
% r_dir = gtMathsNormalizeVectorsList(r_dir);
end
Nicola Vigano
committed
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
% Translating r0s to the closest point to the average R
% vector, on the line r
dot_r0_avgR = sum((0 - r0) .* r_dir, 2);
r0 = r0 + r_dir .* dot_r0_avgR(:, [1 1 1]);
% Let's now find directions and limits
minus_dirs = r_dir < 0;
u_lims = half_rspace_sizes(ones_tvecs, :);
u_lims(minus_dirs) = -u_lims(minus_dirs);
l_lims = -u_lims;
if (conf.fast_inverse)
inv_r_dir = ref_inv_r_dir(ii_b * ones_tvecs, :);
tmp_d_inv_r = d_vers_nw .* inv_r_dir;
% Approximate inverse: taylor expansion to the 1st
% order, which is NOT good enough close to zero
% inv_r_dir = (1 - tmp_d_inv_r) .* inv_r_dir;
% Approximate inverse: taylor expansion to the 2nd
% order, which seems to be good enough close to zero
inv_r_dir = (1 - (1 - tmp_d_inv_r) .* tmp_d_inv_r) .* inv_r_dir;
else
inv_r_dir = 1 ./ r_dir;
end
len_to_ulims = (u_lims - r0) .* inv_r_dir;
len_to_llims = (l_lims - r0) .* inv_r_dir;
len_to_ulims = min(len_to_ulims, [], 2);
len_to_llims = max(len_to_llims, [], 2);
n_ints = len_to_ulims - len_to_llims;
n_ints(n_ints < 0) = 0;
n_ints = reshape(n_ints, [oversampling_n, num_ns(ii_b), oversampling_w, num_ws(ii_b)]);
n_ints = sum(sum(n_ints, 1), 3);
n_ints = reshape(n_ints, [num_ns(ii_b), num_ws(ii_b)]);
sum_n_ints = gtMathsSumNDVol(n_ints);
n_ints = n_ints ./ sum_n_ints;
n_ints = cast(n_ints, conf.data_type);
Nicola Vigano
committed
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
if (conf.compute_w_sfs)
d = (ws_disps(ii_b, 1):om_step_rod:ws_disps(ii_b, 2))';
d = d(:, ones(tot_sampling_points_w, 1)) + dz(ii_b * ones(num_dws(ii_b), 1), :);
w_upper_limits = min(d(2:end, :), half_rspace_sizes(3));
w_lower_limits = max(d(1:end-1, :), -half_rspace_sizes(3));
% integration is simple and linear: for every w and
% xy-position, we consider the corresponding segment on the
% z-direction
w_ints = w_upper_limits - w_lower_limits;
w_ints(w_ints < 0) = 0;
w_ints = renorm_coeff_w * sum(w_ints, 2)';
disp([sum(n_ints, 1), w_ints])
pause
end
sf_bls_nw(ii_b).bbnim = lims_n_proj_g_int(ii_b, :) .* eta_step;
sf_bls_nw(ii_b).bbwim = lims_w_proj_g_int(ii_b, :);
sf_bls_nw(ii_b).intm = n_ints;
sf_bls_nw(ii_b).bbsize = [num_ns(ii_b) num_ws(ii_b)];
end
sf{ii_g} = sf_bls_nw;
if (mod(ii_g, chunk_size/10) == 1)
fprintf(repmat('\b', [1, num_chars]));
end
end
fprintf(repmat(' ', [1, num_chars]));
fprintf(repmat('\b', [1, num_chars]));
fprintf('Done in %g seconds.\n', toc(c))
Nicola Vigano
committed
function [r0, r_dir] = compute_rod_line(thetas, etas, rot_w, h, labgeo, samgeo)
y_lab = gtGeoPlLabFromThetaEta(thetas, etas, labgeo);
y_sam = gtGeoLab2Sam(y_lab, rot_w, labgeo, samgeo, true);
Nicola Vigano
committed
renorms = 1 + sum(y_sam .* h, 2);
renorms = renorms(:, [1 1 1]);
Nicola Vigano
committed
% r0 is defined = (h x y) / (1 + h . y)
r0 = gtMathsCross(h, y_sam) ./ renorms;
Nicola Vigano
committed
% r is defined = r0 + t * (h + y) / (1 + h . y)
r_dir = (h + y_sam) ./ renorms;
r_dir = gtMathsNormalizeVectorsList(r_dir);