mirror of
https://github.com/c-sooyoung/fold_slice.git
synced 2026-09-17 21:49:08 +09:00
initial commit
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
% [delta_stack_prealign, obj_interf_pos_x, obj_interf_pos_y ] = get_auto_tomo(param_autotomo,surface_calib_file, omnyposfile)
|
||||
%
|
||||
% Description:
|
||||
%
|
||||
% The function (1) loads the omnyposfile file and determine the scanning
|
||||
% positions if get_auto_calibration or auto_alignment is 1 and
|
||||
% (2) loads the surface_calib_file to give an initial guess for
|
||||
% the alignemnt array (deltastack) if auto_alignment is 1
|
||||
%
|
||||
% Input:
|
||||
%
|
||||
% par. auto_alignment: 0 or 1 (default)
|
||||
% par. get_auto_calibration: 0 or 1 (default)
|
||||
% surface_calib_file (mandatory if auto_alignment=1)
|
||||
% omnyposfile (mandatory if auto_alignment=1 or get_auto_calibration=1)
|
||||
%
|
||||
% Output:
|
||||
%
|
||||
% delta_stack_prealign: used as initial guess for the alignment
|
||||
% obj_interf_pos_x and obj_interf_pos_y: Object maximum position based on interferometry
|
||||
%
|
||||
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| Except where otherwise noted, this work is licensed under a |
|
||||
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||
%| International (CC BY-NC-SA 4.0) license. |
|
||||
%| |
|
||||
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||
%| |
|
||||
%| Author: CXS group, PSI |
|
||||
%*-----------------------------------------------------------------------*
|
||||
% You may use this code with the following provisions:
|
||||
%
|
||||
% If the code is fully or partially redistributed, or rewritten in another
|
||||
% computing language this notice should be included in the redistribution.
|
||||
%
|
||||
% If this code, or subfunctions or parts of it, is used for research in a
|
||||
% publication or if it is fully or partially rewritten for another
|
||||
% computing language the authors and institution should be acknowledged
|
||||
% in written form in the publication: “Data processing was carried out
|
||||
% using the “cSAXS matlab package” developed by the CXS group,
|
||||
% Paul Scherrer Institut, Switzerland.”
|
||||
% Variations on the latter text can be incorporated upon discussion with
|
||||
% the CXS group if needed to more specifically reflect the use of the package
|
||||
% for the published work.
|
||||
%
|
||||
% A publication that focuses on describing features, or parameters, that
|
||||
% are already existing in the code should be first discussed with the
|
||||
% authors.
|
||||
%
|
||||
% This code and subroutines are part of a continuous development, they
|
||||
% are provided “as they are” without guarantees or liability on part
|
||||
% of PSI or the authors. It is the user responsibility to ensure its
|
||||
% proper use and the correctness of the results.
|
||||
|
||||
|
||||
function [delta_stack_prealign, obj_interf_pos_x, obj_interf_pos_y ] = ...
|
||||
get_auto_tomo(par,surface_calib_file, omnyposfile, theta, scanstomo)
|
||||
import beamline.read_omny_pos
|
||||
|
||||
import utils.*
|
||||
import ptycho.*
|
||||
import beamline.*
|
||||
|
||||
|
||||
obj_interf_pos_x = [];
|
||||
obj_interf_pos_y = [];
|
||||
flag_plot = 1;
|
||||
delta_stack_prealign = [];
|
||||
|
||||
|
||||
%%% To improve: Shifts of the probe are not yet considered here, see
|
||||
%%% /cSAXS_sxdm_2013_06_omny/matlab/tomo/autotomo_calibration_porous_S00506_S00930.m
|
||||
if par.auto_alignment ||par.get_auto_calibration
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%% Determine position of first pixel in the reconstructions %%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
disp('Loading omny_pos for autoalignment')
|
||||
for ii = 1:max(size(scanstomo))
|
||||
progressbar(ii, max(size(scanstomo)))
|
||||
out_orch = read_omny_pos(sprintf(omnyposfile,scanstomo(ii)));
|
||||
positions_real = [out_orch.Average_y_st_fzp*1e-6 out_orch.Average_x_st_fzp*1e-6];
|
||||
% clear positions
|
||||
% positions = positions_real./par.pixel_size;
|
||||
%
|
||||
% % Change from object to probe positions
|
||||
% positions = -positions;
|
||||
%
|
||||
% positions(:,1) = positions(:,1) - min(positions(:,1));
|
||||
% positions(:,2) = positions(:,2) - min(positions(:,2));
|
||||
% positions = round(positions);
|
||||
|
||||
%%% Object maximum position based on interferometry - sample motion
|
||||
%%% Corresponds to pos to coordinates of (1,1) pixel
|
||||
%%% increasing number means the sample was higher
|
||||
obj_interf_pos_y(ii) = max(positions_real(:,1));
|
||||
obj_interf_pos_x(ii) = max(positions_real(:,2));
|
||||
end
|
||||
end
|
||||
|
||||
if par.auto_alignment && exist(surface_calib_file, 'file')
|
||||
|
||||
%%% Read calibration file and interpolate correction to these angles
|
||||
pos_cal = load(surface_calib_file);
|
||||
delta_stack_corr_y_filt = spline(pos_cal.thetasort,pos_cal.delta_stack_corr_y_filt,theta);
|
||||
delta_stack_corr_x_filt = spline(pos_cal.thetasort,pos_cal.delta_stack_corr_x_filt,theta);
|
||||
|
||||
%%% Interferometer alignment with mirror surface corrections
|
||||
delta_stack_prealign(1,:) = delta_stack_corr_y_filt+obj_interf_pos_y;
|
||||
delta_stack_prealign(2,:) = delta_stack_corr_x_filt+obj_interf_pos_x;
|
||||
|
||||
%%% Remove constant term from y alignment
|
||||
delta_stack_prealign(1,:) = delta_stack_prealign(1,:)-mean(delta_stack_prealign(1,:));
|
||||
|
||||
%%% Remove sin term from correction in x
|
||||
[~,indsort] = sort(theta);
|
||||
auxfunc = delta_stack_prealign(2,indsort);
|
||||
auxfunc = [auxfunc -auxfunc+auxfunc(end)+auxfunc(1)];
|
||||
auxfuncft = fft(auxfunc);
|
||||
auxfuncft(3:end-1) = 0;
|
||||
auxfunc2 = ifft(auxfuncft);
|
||||
auxfunc3 = auxfunc2(1:end/2);
|
||||
delta_stack_prealign(2,indsort) = delta_stack_prealign(2,indsort) - auxfunc3;
|
||||
|
||||
delta_stack_prealign = delta_stack_prealign/par.pixel_size;
|
||||
|
||||
if flag_plot
|
||||
figure(1);
|
||||
clf;
|
||||
subplot(2,1,1)
|
||||
plot(theta,obj_interf_pos_y,'.')
|
||||
title('Interferometer y position [microns]')
|
||||
subplot(2,1,2)
|
||||
plot(theta,obj_interf_pos_x,'.')
|
||||
title('Interferometer x position [microns]')
|
||||
|
||||
figure(2);
|
||||
clf;
|
||||
subplot(2,1,1)
|
||||
plot(theta,delta_stack_prealign(1,:),'.')
|
||||
title('Correction in y [pixels]')
|
||||
subplot(2,1,2)
|
||||
plot(theta,delta_stack_prealign(2,:),'.')
|
||||
title('Correction in x [pixels]')
|
||||
end
|
||||
elseif ~exist(surface_calib_file, 'file')
|
||||
warning('Missing surface calibration file %s', surface_calib_file)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,285 @@
|
||||
% INITIALIZE_TOMO basic initialization steps of tomography -> check validity of the inputs,
|
||||
% load first projection and store its parameters, check angles, create output folders
|
||||
%
|
||||
% [par, angles_check, object] = initialize_tomo(par, scans, use_gpu, object_preprocess_fun)
|
||||
%
|
||||
% Inputs:
|
||||
% **par - basic parameters defined in template
|
||||
% **scans - list of the scans to be loaded
|
||||
% **use_gpu - (bool), dont use GPU if use_gpu == 0, (default = true )
|
||||
% **object_preprocess_fun - user defined preprocessing function applied on the loaded projections, e.g. in laminography it can be rotation, default = @(x)x
|
||||
%
|
||||
% *returns*
|
||||
% ++par updated basic parameters
|
||||
% ++angles_check
|
||||
% ++object example of one loaded projection
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| Except where otherwise noted, this work is licensed under a |
|
||||
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||
%| International (CC BY-NC-SA 4.0) license. |
|
||||
%| |
|
||||
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||
%| |
|
||||
%| Author: CXS group, PSI |
|
||||
%*-----------------------------------------------------------------------*
|
||||
% You may use this code with the following provisions:
|
||||
%
|
||||
% If the code is fully or partially redistributed, or rewritten in another
|
||||
% computing language this notice should be included in the redistribution.
|
||||
%
|
||||
% If this code, or subfunctions or parts of it, is used for research in a
|
||||
% publication or if it is fully or partially rewritten for another
|
||||
% computing language the authors and institution should be acknowledged
|
||||
% in written form in the publication: "Data processing was carried out
|
||||
% using the "cSAXS matlab package" developed by the CXS group,
|
||||
% Paul Scherrer Institut, Switzerland."
|
||||
% Variations on the latter text can be incorporated upon discussion with
|
||||
% the CXS group if needed to more specifically reflect the use of the package
|
||||
% for the published work.
|
||||
%
|
||||
% A publication that focuses on describing features, or parameters, that
|
||||
% are already existing in the code should be first discussed with the
|
||||
% authors.
|
||||
%
|
||||
% This code and subroutines are part of a continuous development, they
|
||||
% are provided "as they are" without guarantees or liability on part
|
||||
% of PSI or the authors. It is the user responsibility to ensure its
|
||||
% proper use and the correctness of the results.
|
||||
|
||||
|
||||
function [par, angles_check, object] = initialize_tomo(par, scans, use_gpu, object_preprocess_fun)
|
||||
import ptycho.*
|
||||
import io.*
|
||||
utils.verbose(struct('prefix', 'initialize'))
|
||||
%% initial checks
|
||||
if verLessThan('matlab', '9.3')
|
||||
warning on
|
||||
warning('Only Matlab versions >= 2018a are tested and supported, \nYour Matlab version is %s', version)
|
||||
pause(5)
|
||||
end
|
||||
if nargin < 3
|
||||
use_gpu = true;
|
||||
end
|
||||
|
||||
if gpuDeviceCount == 0 && use_gpu
|
||||
warning('Using CUDA enabled GPU is strongly recommended')
|
||||
pause(5)
|
||||
use_gpu = false;
|
||||
end
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%% CHECK GPU AVAILIBILITY %%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
if use_gpu
|
||||
if gpuDeviceCount == 0
|
||||
error('Code needs CUDA enabled GPU, suppress by setting input parameter "use_gpu=false" ')
|
||||
end
|
||||
if any(par.GPU_list > gpuDeviceCount)
|
||||
error('Selected GPU in GPU_list is not available')
|
||||
end
|
||||
gpu = gpuDevice(par.GPU_list(1));
|
||||
if ~verLessThan('matlab', '9.4') && gpu.ToolkitVersion < 9
|
||||
error('Code needs CUDA 9.0 to work with Matlab 2018a and newer')
|
||||
elseif verLessThan('matlab', '9.4') && gpu.ToolkitVersion < 8
|
||||
error('Code needs at least CUDA 8.0 to work with Matlab 2017b')
|
||||
end
|
||||
fprintf('=================================================== \n')
|
||||
fprintf('=== Available memory for GPU %i : %2.1fGB / %2.1fGB === \n', gpu.Index, gpu.AvailableMemory/1e9, gpu.TotalMemory/1e9)
|
||||
fprintf('=================================================== \n')
|
||||
|
||||
% check that more than 3GB of GPU mem is free and that 90% of total
|
||||
% memory is available -> make sure that this template is the only
|
||||
% process using the selected GPU
|
||||
reset(gpu)
|
||||
if ~debug() && (gpu.AvailableMemory < gpu.TotalMemory * 0.9 || gpu.AvailableMemory < 3e9)
|
||||
|
||||
utils.verbose(0,'\n\n=============== GPU report ================')
|
||||
!nvidia-smi
|
||||
warning on
|
||||
warning off backtrace
|
||||
if gpu.AvailableMemory < gpu.TotalMemory * 0.9
|
||||
warning(['Memory in GPU %i (Nvidia id:%i) is probably used by other user,'...
|
||||
'try to manunally choose GPU or kill other processes'], gpu.Index, gpu.Index-1)
|
||||
else
|
||||
warning(['Memory in GPU %i (Nvidia id:%i) is less than recommended 3GB,'...
|
||||
'try to manunally choose GPU or kill other processes'], gpu.Index, gpu.Index-1)
|
||||
end
|
||||
warning on
|
||||
|
||||
% check who is using the GPU
|
||||
%utils.report_GPU_usage(gpu.Index);
|
||||
|
||||
if ~debug() && ~par.online_tomo
|
||||
if ~strcmpi(input('Do you want to continue [y/N]', 's'), 'y')
|
||||
error('Set other GPU to use by par.GPU_list parameter')
|
||||
end
|
||||
end
|
||||
% this is only recommende value, the code should run even with
|
||||
% less, but then it gets less efficient.
|
||||
elseif (gpu.AvailableMemory < gpu.TotalMemory * 0.9 || gpu.AvailableMemory < 3e9)
|
||||
utils.report_GPU_usage
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
if nargin < 4
|
||||
object_preprocess_fun = []; % no preprocessing function
|
||||
end
|
||||
|
||||
par.use_GPU = use_gpu; % store user preferences in using GPU
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% initial values - LOAD ONE FRAME FOR DEFINING PTYCHO SCAN VALUES %%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
file = [];
|
||||
ii = 1;
|
||||
while isempty(file) && ii <= length(scans)
|
||||
file = find_projection_files_names(par, scans(ii));
|
||||
if isempty(file)
|
||||
warning(['Out of luck - Reconstruction not found']);
|
||||
ii = ii+1;
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
if isempty(file)
|
||||
error('No reconstructions found, check that analysis folder path contains scans %i-%i', min(scans), max(scans))
|
||||
end
|
||||
|
||||
%%% Read first projection to check size and reconstruction parameters
|
||||
display(['Reading file: ' file])
|
||||
[object, probe, p] = load_ptycho_recons(file);
|
||||
probe = single(probe(:,:,1)); % keep only the first mode
|
||||
|
||||
par.asize = p.asize; % probe size
|
||||
par.dims_ob_loaded = [size(object,1), size(object,2)]; % load the sizes directly from the object, note that "object_preprocess_fun" can crop/rotate the image !!
|
||||
if isfield(p, 'scanindexrange')
|
||||
p.scanidxs{1} = p.scanindexrange(1):p.scanindexrange(2);
|
||||
positions = int32(p.positions(p.scanidxs{1},:));
|
||||
indices = int32(1:length(p.scanidxs{1}));
|
||||
% get at least some estimation of the illumination intensity for different regions in the
|
||||
% projection
|
||||
par.illum_sum = utils.add_to_3D_projection(abs(probe).^2,zeros(max(p.object_size,[],1),'single'),positions,indices, true);
|
||||
else
|
||||
% if nto availible, get et least a crude guess
|
||||
par.illum_sum = ones(par.dims_ob_loaded-par.asize);
|
||||
end
|
||||
par.illum_sum = utils.crop_pad(par.illum_sum,par.dims_ob_loaded);
|
||||
par.illum_sum = par.illum_sum ./ quantile(par.illum_sum(:), 0.9); % normalize the values to keep maximum around 1
|
||||
|
||||
|
||||
% in case of unequal pixel size
|
||||
if p.dx_spec(1) ~= p.dx_spec(2)
|
||||
% upsample the data in the dimennsion with lower resolution (-> at least relax issues in tomography interpolation)
|
||||
pixel_scale = p.dx_spec ./ min(p.dx_spec) ;
|
||||
dims_ob_new = round(par.dims_ob_loaded .* pixel_scale);
|
||||
par.illum_sum = max(0,real(utils.interpolateFT(par.illum_sum, dims_ob_new)));
|
||||
object = utils.interpolateFT(par.illum_sum, dims_ob_new);
|
||||
par.asize = round(par.asize .* pixel_scale);
|
||||
probe = utils.interpolateFT(probe, par.asize);
|
||||
p.dx_spec(:) = min(p.dx_spec);
|
||||
end
|
||||
|
||||
if ~isempty(object_preprocess_fun)
|
||||
% apply custom preprocessing, e.g. rotation and flipping for
|
||||
% laminography setup
|
||||
object = object_preprocess_fun(object);
|
||||
par.illum_sum = max(0, object_preprocess_fun(par.illum_sum));
|
||||
end
|
||||
|
||||
par.dims_ob = [size(object,1), size(object,2)]; % object size after object_preprocess_fun
|
||||
|
||||
|
||||
|
||||
|
||||
par.probe = probe;
|
||||
par.lambda =p.lambda; % wavelength [m]
|
||||
par.pixel_size=p.dx_spec(1) * 2^par.downsample_projections; % reconstructed pixel size [m]
|
||||
if p.dx_spec(1)~=p.dx_spec(2)
|
||||
warning('Pixel size not symmetric - This code cannot handle')
|
||||
end
|
||||
|
||||
par.factor=par.lambda/(2*pi*par.pixel_size);
|
||||
par.factor_edensity = 1e-30*2*pi/(par.lambda^2*2.81794e-15);
|
||||
|
||||
%%% Check angles %%%
|
||||
if par.checkangles
|
||||
[par.scans_check, angles_check] = tomo_angles(projections, subtomograms, ...
|
||||
scan_num, subs_to_do); % ignores the repeated 180deg scan.
|
||||
else
|
||||
angles_check = [];
|
||||
end
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%% GENERATE SCAN STRING FOR FILES DESCRIPTION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
par.scans_string = {};
|
||||
if isfield(par, 'output_folder_prefix') && ~isempty(par.output_folder_prefix)
|
||||
par.scans_string{end+1} = par.output_folder_prefix;
|
||||
end
|
||||
|
||||
if ~isempty(par.tomo_id)
|
||||
auxstr = repmat('%i+',1,length(par.tomo_id));
|
||||
par.scans_string{end+1} = sprintf(['id_',auxstr(1:end-1)], par.tomo_id);
|
||||
elseif par.online_tomo
|
||||
par.scans_string{end+1} = sprintf('S%05d',scans(1));
|
||||
end
|
||||
|
||||
% load sample name if provided
|
||||
if ~isfield(p, 'samplename')
|
||||
par.samplename = '';
|
||||
else
|
||||
par.samplename = p.samplename;
|
||||
end
|
||||
|
||||
if ~isempty(par.samplename)
|
||||
par.scans_string{end+1} = par.samplename;
|
||||
end
|
||||
if ~par.online_tomo
|
||||
par.scans_string{end+1}= sprintf('S%05d_to_S%05d',scans(1),scans(end));
|
||||
end
|
||||
|
||||
par.scans_string = join(par.scans_string, '_');
|
||||
par.scans_string = par.scans_string{1};
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%% Output folder
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
par.output_folder= {fullfile(par.output_path, 'tomo'), par.scans_string, par.filesuffix, par.fileprefix};
|
||||
if par.online_tomo
|
||||
par.output_folder{end+1}= 'online';
|
||||
end
|
||||
|
||||
|
||||
par.output_folder = join(par.output_folder, '_');
|
||||
par.output_folder = par.output_folder{1};
|
||||
|
||||
|
||||
|
||||
if ~debug()
|
||||
utils.verbose('Output folder: %s', par.output_folder)
|
||||
if ~exist(par.output_folder,'dir')
|
||||
mkdir(par.output_folder);
|
||||
end
|
||||
[~,attr] = fileattrib(par.output_folder);
|
||||
if ~(attr.UserWrite || attr.GroupWrite)
|
||||
error('Output path %s is not writable', par.output_folder)
|
||||
end
|
||||
% For website
|
||||
subdir_online = fullfile(par.base_path,'analysis/online/tomo/');
|
||||
if ~exist(subdir_online,'dir')
|
||||
mkdir(subdir_online);
|
||||
end
|
||||
par.online_tomo_path = sprintf('%sonline_tomo_S%05d', subdir_online, min(par.scanstomo));
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,276 @@
|
||||
% INITIALIZE_TOMO_APS basic initialization steps of tomography -> check validity of the inputs,
|
||||
% load first projection and store its parameters, check angles, create output folders
|
||||
% Created by YJ Based on PSI's function
|
||||
|
||||
% [par, angles_check, object] = initialize_tomo_aps(par, scans, use_gpu, object_preprocess_fun)
|
||||
%
|
||||
% Inputs:
|
||||
% **par - basic parameters defined in template
|
||||
% **scans - list of the scans to be loaded
|
||||
% **use_gpu - (bool), dont use GPU if use_gpu == 0, (default = true )
|
||||
% **object_preprocess_fun - user defined preprocessing function applied on the loaded projections, e.g. in laminography it can be rotation, default = @(x)x
|
||||
%
|
||||
% *returns*
|
||||
% ++par updated basic parameters
|
||||
% ++angles_check
|
||||
% ++object example of one loaded projection
|
||||
|
||||
|
||||
function [par, angles_check, object] = initialize_tomo_aps(par, scans, use_gpu, object_preprocess_fun)
|
||||
|
||||
import ptycho.*
|
||||
import io.*
|
||||
utils.verbose(struct('prefix', 'initialize'))
|
||||
%% initial checks
|
||||
if verLessThan('matlab', '9.3')
|
||||
warning on
|
||||
warning('Only Matlab versions >= 2018a are tested and supported, \nYour Matlab version is %s', version)
|
||||
pause(5)
|
||||
end
|
||||
if nargin < 3
|
||||
use_gpu = true;
|
||||
end
|
||||
|
||||
if gpuDeviceCount == 0 && use_gpu
|
||||
warning('Using CUDA enabled GPU is strongly recommended')
|
||||
pause(5)
|
||||
use_gpu = false;
|
||||
end
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%% CHECK GPU AVAILIBILITY %%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
if use_gpu
|
||||
if gpuDeviceCount == 0
|
||||
error('Code needs CUDA enabled GPU, suppress by setting input parameter "use_gpu=false" ')
|
||||
end
|
||||
if any(par.GPU_list > gpuDeviceCount)
|
||||
error('Selected GPU in GPU_list is not available')
|
||||
end
|
||||
gpu = gpuDevice(par.GPU_list(1));
|
||||
if ~verLessThan('matlab', '9.4') && gpu.ToolkitVersion < 9
|
||||
error('Code needs CUDA 9.0 to work with Matlab 2018a and newer')
|
||||
elseif verLessThan('matlab', '9.4') && gpu.ToolkitVersion < 8
|
||||
error('Code needs at least CUDA 8.0 to work with Matlab 2017b')
|
||||
end
|
||||
fprintf('=================================================== \n')
|
||||
fprintf('=== Available memory for GPU %i : %2.1fGB / %2.1fGB === \n', gpu.Index, gpu.AvailableMemory/1e9, gpu.TotalMemory/1e9)
|
||||
fprintf('=================================================== \n')
|
||||
|
||||
% check that more than 3GB of GPU mem is free and that 90% of total
|
||||
% memory is available -> make sure that this template is the only
|
||||
% process using the selected GPU
|
||||
reset(gpu)
|
||||
if ~debug() && (gpu.AvailableMemory < gpu.TotalMemory * par.check_gpu_percentage || gpu.AvailableMemory < 3e9)
|
||||
|
||||
utils.verbose(0,'\n\n=============== GPU report ================')
|
||||
!nvidia-smi
|
||||
warning on
|
||||
warning off backtrace
|
||||
if gpu.AvailableMemory < gpu.TotalMemory * 0.9
|
||||
warning(['Memory in GPU %i (Nvidia id:%i) is probably used by other user,'...
|
||||
'try to manunally choose GPU or kill other processes'], gpu.Index, gpu.Index-1)
|
||||
else
|
||||
warning(['Memory in GPU %i (Nvidia id:%i) is less than recommended 3GB,'...
|
||||
'try to manunally choose GPU or kill other processes'], gpu.Index, gpu.Index-1)
|
||||
end
|
||||
warning on
|
||||
|
||||
% check who is using the GPU
|
||||
utils.report_GPU_usage(gpu.Index);
|
||||
|
||||
if ~debug() && ~par.online_tomo
|
||||
if ~strcmpi(input('Do you want to continue [y/N]', 's'), 'y')
|
||||
error('Set other GPU to use by par.GPU_list parameter')
|
||||
end
|
||||
end
|
||||
% this is only recommende value, the code should run even with
|
||||
% less, but then it gets less efficient.
|
||||
elseif (gpu.AvailableMemory < gpu.TotalMemory * 0.9 || gpu.AvailableMemory < 3e9)
|
||||
%utils.report_GPU_usage
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
if nargin < 4
|
||||
object_preprocess_fun = []; % no preprocessing function
|
||||
end
|
||||
|
||||
par.use_GPU = use_gpu; % store user preferences in using GPU
|
||||
%{
|
||||
%% First check if reconstructions exist
|
||||
proj_file_names = {};
|
||||
|
||||
hasRecon = zeros(length(scans),1);
|
||||
for ii=1:length(scans)
|
||||
progressbar(ii, length(scans))
|
||||
file = find_ML_recon_files_names(par, scans(ii)); %find ML recon outputs
|
||||
if ~isempty(file)
|
||||
hasRecon(ii) = 1;
|
||||
end
|
||||
end
|
||||
%}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% initial values - LOAD ONE FRAME FOR DEFINING PTYCHO SCAN VALUES %%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
file = [];
|
||||
ii = 1;
|
||||
while isempty(file) && ii <= length(scans)
|
||||
%file = find_projection_files_names_aps(par, scans(ii));
|
||||
file = find_ML_recon_files_names(par, scans(ii)); %find ML recon outputs
|
||||
if isempty(file)
|
||||
%warning(['Out of luck - Reconstruction not found']);
|
||||
disp(['Out of luck - Reconstruction not found']);
|
||||
ii = ii+1;
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
if isempty(file)
|
||||
error('No reconstructions found, check that analysis folder path contains scans %i-%i', min(scans), max(scans))
|
||||
end
|
||||
disp(file)
|
||||
%%% Read first projection to check size and reconstruction parameters
|
||||
display(['Reading file: ' file])
|
||||
[object, probe, dx_spec] = load_aps_ML_recons(file);
|
||||
if iscell(probe)
|
||||
probe = single(probe{1}(:,:,1)); % keep only the first mode
|
||||
else
|
||||
probe = single(probe(:,:,1)); % keep only the first mode
|
||||
|
||||
end
|
||||
par.asize = size(probe); % probe size
|
||||
|
||||
par.dims_ob_loaded = [size(object,1), size(object,2)]; % load the sizes directly from the object, note that "object_preprocess_fun" can crop/rotate the image !!
|
||||
%{
|
||||
if isfield(p, 'scanindexrange')
|
||||
p.scanidxs{1} = p.scanindexrange(1):p.scanindexrange(2);
|
||||
positions = int32(p.positions(p.scanidxs{1},:));
|
||||
indices = int32(1:length(p.scanidxs{1}));
|
||||
% get at least some estimation of the illumination intensity for different regions in the
|
||||
% projection
|
||||
par.illum_sum = utils.add_to_3D_projection(abs(probe).^2,zeros(max(p.object_size,[],1),'single'),positions,indices, true);
|
||||
else
|
||||
% if nto availible, get et least a crude guess
|
||||
par.illum_sum = ones(par.dims_ob_loaded-par.asize);
|
||||
end
|
||||
%}
|
||||
par.illum_sum = ones(par.dims_ob_loaded-par.asize);
|
||||
par.illum_sum = utils.crop_pad(par.illum_sum,par.dims_ob_loaded);
|
||||
par.illum_sum = par.illum_sum ./ quantile(par.illum_sum(:), 0.9); % normalize the values to keep maximum around 1
|
||||
|
||||
% in case of unequal pixel size
|
||||
if dx_spec(1) ~= dx_spec(2)
|
||||
% upsample the data in the dimennsion with lower resolution (-> at least relax issues in tomography interpolation)
|
||||
pixel_scale = dx_spec ./ min(dx_spec) ;
|
||||
dims_ob_new = round(par.dims_ob_loaded .* pixel_scale);
|
||||
par.illum_sum = max(0,real(utils.interpolateFT(par.illum_sum, dims_ob_new)));
|
||||
object = utils.interpolateFT(par.illum_sum, dims_ob_new);
|
||||
par.asize = round(par.asize .* pixel_scale);
|
||||
probe = utils.interpolateFT(probe, par.asize);
|
||||
dx_spec(:) = min(dx_spec);
|
||||
end
|
||||
|
||||
if ~isempty(object_preprocess_fun)
|
||||
% apply custom preprocessing, e.g. rotation and flipping for
|
||||
% laminography setup
|
||||
object = object_preprocess_fun(object);
|
||||
par.illum_sum = max(0, object_preprocess_fun(par.illum_sum));
|
||||
end
|
||||
|
||||
par.dims_ob = [size(object,1), size(object,2)]; % object size after object_preprocess_fun
|
||||
par.probe = probe;
|
||||
if ~isfield(par, 'lambda')
|
||||
par.lambda = p.lambda; % wavelength [m]
|
||||
end
|
||||
par.pixel_size=dx_spec(1) * 2^par.downsample_projections; % reconstructed pixel size [m]
|
||||
if dx_spec(1)~=dx_spec(2)
|
||||
warning('Pixel size not symmetric - This code cannot handle')
|
||||
end
|
||||
|
||||
par.factor=par.lambda/(2*pi*par.pixel_size);
|
||||
par.factor_edensity = 1e-30*2*pi/(par.lambda^2*2.81794e-15);
|
||||
|
||||
%{
|
||||
%%% Check angles %%%
|
||||
if par.checkangles
|
||||
[par.scans_check, angles_check] = tomo_angles(projections, subtomograms, ...
|
||||
scan_num, subs_to_do); % ignores the repeated 180deg scan.
|
||||
else
|
||||
angles_check = [];
|
||||
end
|
||||
%}
|
||||
angles_check = [];
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%% GENERATE SCAN STRING FOR FILES DESCRIPTION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
par.scans_string = {};
|
||||
if isfield(par, 'output_folder_prefix') && ~isempty(par.output_folder_prefix)
|
||||
par.scans_string{end+1} = par.output_folder_prefix;
|
||||
end
|
||||
|
||||
if ~isempty(par.tomo_id)
|
||||
auxstr = repmat('%i+',1,length(par.tomo_id));
|
||||
par.scans_string{end+1} = sprintf(['id_',auxstr(1:end-1)], par.tomo_id);
|
||||
elseif par.online_tomo
|
||||
par.scans_string{end+1} = sprintf('S%05d',scans(1));
|
||||
end
|
||||
%{
|
||||
% load sample name if provided
|
||||
if ~isfield(p, 'samplename')
|
||||
par.samplename = '';
|
||||
else
|
||||
par.samplename = p.samplename;
|
||||
end
|
||||
|
||||
if ~isempty(par.samplename)
|
||||
par.scans_string{end+1} = par.samplename;
|
||||
end
|
||||
%}
|
||||
if ~par.online_tomo
|
||||
par.scans_string{end+1}= sprintf('S%05d_to_S%05d',scans(1),scans(end));
|
||||
end
|
||||
|
||||
par.scans_string = join(par.scans_string, '_');
|
||||
par.scans_string = par.scans_string{1};
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%% Output folder
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
par.output_folder= {fullfile(par.output_path, 'tomo'), par.scans_string, par.filesuffix, par.fileprefix};
|
||||
if par.online_tomo
|
||||
par.output_folder{end+1}= 'online';
|
||||
end
|
||||
|
||||
|
||||
par.output_folder = join(par.output_folder, '_');
|
||||
par.output_folder = par.output_folder{1};
|
||||
|
||||
|
||||
%{
|
||||
if ~debug()
|
||||
utils.verbose('Output folder: %s', par.output_folder)
|
||||
if ~exist(par.output_folder,'dir')
|
||||
mkdir(par.output_folder);
|
||||
end
|
||||
[~,attr] = fileattrib(par.output_folder);
|
||||
if ~(attr.UserWrite || attr.GroupWrite)
|
||||
error('Output path %s is not writable', par.output_folder)
|
||||
end
|
||||
% For website
|
||||
subdir_online = fullfile(par.base_path,'analysis/online/tomo/');
|
||||
if ~exist(subdir_online,'dir')
|
||||
mkdir(subdir_online);
|
||||
end
|
||||
par.online_tomo_path = sprintf('%sonline_tomo_S%05d', subdir_online, min(par.scanstomo));
|
||||
|
||||
end
|
||||
%}
|
||||
|
||||
end
|
||||
@@ -0,0 +1,251 @@
|
||||
% INITIALIZE_TOMO_MATLAB basic initialization steps of tomography -> check validity of the inputs,
|
||||
% load first projection and store its parameters, check angles, create output folders
|
||||
% Created by YJ Based on PSI's function
|
||||
|
||||
% [par, angles_check, object] = initialize_tomo_aps(par, scans, use_gpu, object_preprocess_fun)
|
||||
%
|
||||
% Inputs:
|
||||
% **par - basic parameters defined in template
|
||||
% **scans - list of the scans to be loaded
|
||||
% **use_gpu - (bool), dont use GPU if use_gpu == 0, (default = true )
|
||||
% **object_preprocess_fun - user defined preprocessing function applied on the loaded projections, e.g. in laminography it can be rotation, default = @(x)x
|
||||
%
|
||||
% *returns*
|
||||
% ++par updated basic parameters
|
||||
% ++angles_check
|
||||
% ++object example of one loaded projection
|
||||
|
||||
|
||||
function [par, angles_check, object] = initialize_tomo_matlab(par, scans, use_gpu, object_preprocess_fun)
|
||||
|
||||
import ptycho.*
|
||||
import io.*
|
||||
utils.verbose(struct('prefix', 'initialize'))
|
||||
%% initial checks
|
||||
if verLessThan('matlab', '9.3')
|
||||
warning on
|
||||
warning('Only Matlab versions >= 2018a are tested and supported, \nYour Matlab version is %s', version)
|
||||
pause(5)
|
||||
end
|
||||
if nargin < 3
|
||||
use_gpu = true;
|
||||
end
|
||||
|
||||
if gpuDeviceCount == 0 && use_gpu
|
||||
warning('Using CUDA enabled GPU is strongly recommended')
|
||||
pause(5)
|
||||
use_gpu = false;
|
||||
end
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%% CHECK GPU AVAILIBILITY %%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
if use_gpu
|
||||
if gpuDeviceCount == 0
|
||||
error('Code needs CUDA enabled GPU, suppress by setting input parameter "use_gpu=false" ')
|
||||
end
|
||||
if any(par.GPU_list > gpuDeviceCount)
|
||||
error('Selected GPU in GPU_list is not available')
|
||||
end
|
||||
gpu = gpuDevice(par.GPU_list(1));
|
||||
if ~verLessThan('matlab', '9.4') && gpu.ToolkitVersion < 9
|
||||
error('Code needs CUDA 9.0 to work with Matlab 2018a and newer')
|
||||
elseif verLessThan('matlab', '9.4') && gpu.ToolkitVersion < 8
|
||||
error('Code needs at least CUDA 8.0 to work with Matlab 2017b')
|
||||
end
|
||||
fprintf('=================================================== \n')
|
||||
fprintf('=== Available memory for GPU %i : %2.1fGB / %2.1fGB === \n', gpu.Index, gpu.AvailableMemory/1e9, gpu.TotalMemory/1e9)
|
||||
fprintf('=================================================== \n')
|
||||
|
||||
% check that more than 3GB of GPU mem is free and that 90% of total
|
||||
% memory is available -> make sure that this template is the only
|
||||
% process using the selected GPU
|
||||
reset(gpu)
|
||||
if ~debug() && (gpu.AvailableMemory < gpu.TotalMemory * par.check_gpu_percentage || gpu.AvailableMemory < 3e9)
|
||||
|
||||
utils.verbose(0,'\n\n=============== GPU report ================')
|
||||
!nvidia-smi
|
||||
warning on
|
||||
warning off backtrace
|
||||
if gpu.AvailableMemory < gpu.TotalMemory * 0.9
|
||||
warning(['Memory in GPU %i (Nvidia id:%i) is probably used by other user,'...
|
||||
'try to manunally choose GPU or kill other processes'], gpu.Index, gpu.Index-1)
|
||||
else
|
||||
warning(['Memory in GPU %i (Nvidia id:%i) is less than recommended 3GB,'...
|
||||
'try to manunally choose GPU or kill other processes'], gpu.Index, gpu.Index-1)
|
||||
end
|
||||
warning on
|
||||
|
||||
% check who is using the GPU
|
||||
utils.report_GPU_usage(gpu.Index);
|
||||
|
||||
if ~debug() && ~par.online_tomo
|
||||
if ~strcmpi(input('Do you want to continue [y/N]', 's'), 'y')
|
||||
error('Set other GPU to use by par.GPU_list parameter')
|
||||
end
|
||||
end
|
||||
% this is only recommende value, the code should run even with
|
||||
% less, but then it gets less efficient.
|
||||
elseif (gpu.AvailableMemory < gpu.TotalMemory * 0.9 || gpu.AvailableMemory < 3e9)
|
||||
%utils.report_GPU_usage
|
||||
end
|
||||
end
|
||||
if nargin < 4
|
||||
object_preprocess_fun = []; % no preprocessing function
|
||||
end
|
||||
|
||||
par.use_GPU = use_gpu; % store user preferences in using GPU
|
||||
%{
|
||||
%% First check if reconstructions exist
|
||||
proj_file_names = {};
|
||||
|
||||
hasRecon = zeros(length(scans),1);
|
||||
for ii=1:length(scans)
|
||||
progressbar(ii, length(scans))
|
||||
file = find_ML_recon_files_names(par, scans(ii)); %find ML recon outputs
|
||||
if ~isempty(file)
|
||||
hasRecon(ii) = 1;
|
||||
end
|
||||
end
|
||||
%}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% initial values - LOAD ONE FRAME FOR DEFINING PTYCHO SCAN VALUES %%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
file = [];
|
||||
ii = 1;
|
||||
while isempty(file) && ii <= length(scans)
|
||||
%file = find_projection_files_names_aps(par, scans(ii));
|
||||
file = find_ML_recon_files_names(par, scans(ii)); %find ML recon outputs
|
||||
if isempty(file)
|
||||
%warning(['Out of luck - Reconstruction not found']);
|
||||
disp(['Out of luck - Reconstruction not found']);
|
||||
ii = ii+1;
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
if isempty(file)
|
||||
error('No reconstructions found, check that analysis folder path contains scans %i-%i', min(scans), max(scans))
|
||||
end
|
||||
%disp(file)
|
||||
%%% Read first projection to check size and reconstruction parameters
|
||||
display(['Reading file: ' file])
|
||||
[object, probe, dx_spec] = load_aps_ML_recons(file);
|
||||
if iscell(probe)
|
||||
probe = single(probe{1}(:,:,1)); % keep only the first mode
|
||||
else
|
||||
probe = single(probe(:,:,1)); % keep only the first mode
|
||||
|
||||
end
|
||||
par.asize = size(probe); % probe size
|
||||
|
||||
par.dims_ob_loaded = [size(object,1), size(object,2)]; % load the sizes directly from the object, note that "object_preprocess_fun" can crop/rotate the image !!
|
||||
%{
|
||||
if isfield(p, 'scanindexrange')
|
||||
p.scanidxs{1} = p.scanindexrange(1):p.scanindexrange(2);
|
||||
positions = int32(p.positions(p.scanidxs{1},:));
|
||||
indices = int32(1:length(p.scanidxs{1}));
|
||||
% get at least some estimation of the illumination intensity for different regions in the
|
||||
% projection
|
||||
par.illum_sum = utils.add_to_3D_projection(abs(probe).^2,zeros(max(p.object_size,[],1),'single'),positions,indices, true);
|
||||
else
|
||||
% if nto availible, get et least a crude guess
|
||||
par.illum_sum = ones(par.dims_ob_loaded-par.asize);
|
||||
end
|
||||
%}
|
||||
par.illum_sum = ones(par.dims_ob_loaded-par.asize);
|
||||
par.illum_sum = utils.crop_pad(par.illum_sum,par.dims_ob_loaded);
|
||||
par.illum_sum = par.illum_sum ./ quantile(par.illum_sum(:), 0.9); % normalize the values to keep maximum around 1
|
||||
|
||||
% in case of unequal pixel size
|
||||
if dx_spec(1) ~= dx_spec(2)
|
||||
% upsample the data in the dimennsion with lower resolution (-> at least relax issues in tomography interpolation)
|
||||
pixel_scale = dx_spec ./ min(dx_spec) ;
|
||||
dims_ob_new = round(par.dims_ob_loaded .* pixel_scale);
|
||||
par.illum_sum = max(0,real(utils.interpolateFT(par.illum_sum, dims_ob_new)));
|
||||
object = utils.interpolateFT(par.illum_sum, dims_ob_new);
|
||||
par.asize = round(par.asize .* pixel_scale);
|
||||
probe = utils.interpolateFT(probe, par.asize);
|
||||
dx_spec(:) = min(dx_spec);
|
||||
end
|
||||
|
||||
if ~isempty(object_preprocess_fun)
|
||||
% apply custom preprocessing, e.g. rotation and flipping for
|
||||
% laminography setup
|
||||
object = object_preprocess_fun(object);
|
||||
par.illum_sum = max(0, object_preprocess_fun(par.illum_sum));
|
||||
end
|
||||
|
||||
par.dims_ob = [size(object,1), size(object,2)]; % object size after object_preprocess_fun
|
||||
par.probe = probe;
|
||||
if ~isfield(par, 'lambda')
|
||||
par.lambda = p.lambda; % wavelength [m]
|
||||
end
|
||||
par.pixel_size=dx_spec(1) * 2^par.downsample_projections; % reconstructed pixel size [m]
|
||||
if dx_spec(1)~=dx_spec(2)
|
||||
warning('Pixel size not symmetric - This code cannot handle')
|
||||
end
|
||||
|
||||
par.factor=par.lambda/(2*pi*par.pixel_size);
|
||||
par.factor_edensity = 1e-30*2*pi/(par.lambda^2*2.81794e-15);
|
||||
|
||||
%{
|
||||
%%% Check angles %%%
|
||||
if par.checkangles
|
||||
[par.scans_check, angles_check] = tomo_angles(projections, subtomograms, ...
|
||||
scan_num, subs_to_do); % ignores the repeated 180deg scan.
|
||||
else
|
||||
angles_check = [];
|
||||
end
|
||||
%}
|
||||
angles_check = [];
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%% GENERATE SCAN STRING FOR FILES DESCRIPTION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
par.scans_string = {};
|
||||
if isfield(par, 'output_folder_prefix') && ~isempty(par.output_folder_prefix)
|
||||
par.scans_string{end+1} = par.output_folder_prefix;
|
||||
end
|
||||
|
||||
if ~isempty(par.tomo_id)
|
||||
auxstr = repmat('%i+',1,length(par.tomo_id));
|
||||
par.scans_string{end+1} = sprintf(['id_',auxstr(1:end-1)], par.tomo_id);
|
||||
elseif par.online_tomo
|
||||
par.scans_string{end+1} = sprintf('S%05d',scans(1));
|
||||
end
|
||||
%{
|
||||
% load sample name if provided
|
||||
if ~isfield(p, 'samplename')
|
||||
par.samplename = '';
|
||||
else
|
||||
par.samplename = p.samplename;
|
||||
end
|
||||
|
||||
if ~isempty(par.samplename)
|
||||
par.scans_string{end+1} = par.samplename;
|
||||
end
|
||||
%}
|
||||
if ~par.online_tomo
|
||||
par.scans_string{end+1}= sprintf('S%05d_to_S%05d',scans(1),scans(end));
|
||||
end
|
||||
|
||||
par.scans_string = join(par.scans_string, '_');
|
||||
par.scans_string = par.scans_string{1};
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%% Output folder
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
par.output_folder= {fullfile(par.output_path, 'tomo'), par.scans_string, par.filesuffix, par.fileprefix};
|
||||
if par.online_tomo
|
||||
par.output_folder{end+1}= 'online';
|
||||
end
|
||||
|
||||
par.output_folder = join(par.output_folder, '_');
|
||||
par.output_folder = par.output_folder{1};
|
||||
|
||||
end
|
||||
@@ -0,0 +1,146 @@
|
||||
% LOAD_ANGLES load tomopgrahy angles for given scan numbers or tomo_id
|
||||
%
|
||||
% [par, angles] = load_angles(par, scans, tomo_id, plot_angles)
|
||||
% Inputs:
|
||||
% **par tomo parameter structure
|
||||
% **scans - list of loaded scan numbers
|
||||
% **tomo_id - indetification number of the sample, default = []
|
||||
% **plot_angles - plot loaded angles, default == true
|
||||
% *returns*
|
||||
% ++par tomo parameter structure
|
||||
% ++angles loaded angles
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| Except where otherwise noted, this work is licensed under a |
|
||||
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||
%| International (CC BY-NC-SA 4.0) license. |
|
||||
%| |
|
||||
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||
%| |
|
||||
%| Author: CXS group, PSI |
|
||||
%*-----------------------------------------------------------------------*
|
||||
% You may use this code with the following provisions:
|
||||
%
|
||||
% If the code is fully or partially redistributed, or rewritten in another
|
||||
% computing language this notice should be included in the redistribution.
|
||||
%
|
||||
% If this code, or subfunctions or parts of it, is used for research in a
|
||||
% publication or if it is fully or partially rewritten for another
|
||||
% computing language the authors and institution should be acknowledged
|
||||
% in written form in the publication: “Data processing was carried out
|
||||
% using the “cSAXS matlab package” developed by the CXS group,
|
||||
% Paul Scherrer Institut, Switzerland.”
|
||||
% Variations on the latter text can be incorporated upon discussion with
|
||||
% the CXS group if needed to more specifically reflect the use of the package
|
||||
% for the published work.
|
||||
%
|
||||
% A publication that focuses on describing features, or parameters, that
|
||||
% are already existing in the code should be first discussed with the
|
||||
% authors.
|
||||
%
|
||||
% This code and subroutines are part of a continuous development, they
|
||||
% are provided “as they are” without guarantees or liability on part
|
||||
% of PSI or the authors. It is the user responsibility to ensure its
|
||||
% proper use and the correctness of the results.
|
||||
|
||||
|
||||
|
||||
function [par, angles] = load_angles(par, scans, tomo_id, plot_angles)
|
||||
if nargin < 4
|
||||
plot_angles = true;
|
||||
end
|
||||
warning on
|
||||
if nargin < 3
|
||||
tomo_id = [];
|
||||
end
|
||||
Nscans = length(scans);
|
||||
angles = nan(Nscans,1);
|
||||
if ~par.use_OMNY_file_angles
|
||||
S = io.spec_read(par.base_path,'ScanNr',scans);
|
||||
for ii = 1:Nscans
|
||||
angles(ii)=S{ii}.samroy;
|
||||
end
|
||||
else
|
||||
[S, errflag] = beamline.read_omny_angles(par.OMNY_angle_file,scans, tomo_id);
|
||||
if errflag
|
||||
disp(['Not all scans found in ' par.OMNY_angle_file])
|
||||
disp(['I will remove the angles not found and show you some plots anyway'])
|
||||
end
|
||||
angles=S.readout_angle(:).';
|
||||
scans = S.scan(:).';
|
||||
subtomos = S.subtomo_num(:).';
|
||||
if isfield(S,'tomo_id')
|
||||
if any(S.tomo_id ~= S.tomo_id(1))
|
||||
warning('tomo_id number is not the same for all scans')
|
||||
end
|
||||
par.tomo_id = unique(S.tomo_id);
|
||||
else
|
||||
par.tomo_id = [] ;
|
||||
end
|
||||
par.sample_name = S.sample_name{1};
|
||||
end
|
||||
|
||||
% remove duplicted scan numbers
|
||||
[~,ind] = unique(scans, 'last'); % take the !last! occurence of the scan, assume that the second measurement was better
|
||||
angles = angles(ind); % Angles not repeated in scan
|
||||
scans = scans(ind);
|
||||
subtomos = subtomos(ind);
|
||||
|
||||
|
||||
% take only unique angles, measure uniqueness
|
||||
if par.remove_duplicated_angles
|
||||
[~,ind] = unique(angles, 'last'); % take the !last! occurence of the angle, assume that the second measurement was better
|
||||
if length(angles) ~= length(ind)
|
||||
warning('Removed %i duplicated angles', length(angles) - length(ind))
|
||||
end
|
||||
else
|
||||
[~,ind] = sort(angles);
|
||||
end
|
||||
angles = angles(ind); % Angles not repeated in scan
|
||||
scans = scans(ind);
|
||||
subtomos = subtomos(ind);
|
||||
|
||||
if isfield(par,'angle_offset') && par.angle_offset ~=0
|
||||
angles = angles + par.angle_offset; % avoid the angles to be too well aligned with pixels, ie avoid exact angles 0, 90, 180, ...
|
||||
end
|
||||
|
||||
par.scanstomo = scans;
|
||||
par.subtomos = subtomos;
|
||||
|
||||
par.num_proj=numel(par.scanstomo);
|
||||
[anglessort,indsortangle] = sort(angles);
|
||||
|
||||
if par.sort_by_angle
|
||||
angles = angles(indsortangle);
|
||||
par.scanstomo = par.scanstomo(indsortangle);
|
||||
par.subtomos = par.subtomos(indsortangle);
|
||||
else % sort by scan number
|
||||
[~,indsortscan] = sort( par.scanstomo);
|
||||
angles = angles(indsortscan);
|
||||
par.scanstomo = par.scanstomo(indsortscan);
|
||||
par.subtomos = par.subtomos(indsortscan);
|
||||
end
|
||||
|
||||
if par.verbose_level && plot_angles
|
||||
plotting.smart_figure(1);
|
||||
subplot(2,1,1)
|
||||
plot(par.scanstomo,angles,'ob'); grid on;
|
||||
%par.scanstomo(1)
|
||||
%par.scanstomo(end)
|
||||
xlim(par.scanstomo([1,end]))
|
||||
legend('Spec angles')
|
||||
xlabel('Scan #')
|
||||
subplot(2,1,2)
|
||||
plot(diff(anglessort))
|
||||
title('Angular spacing'); grid on;
|
||||
xlim([1,par.num_proj-1])
|
||||
if par.windowautopos
|
||||
screensize = get( groot, 'Screensize' );
|
||||
win_size = [946 815];
|
||||
set(gcf,'Outerposition',[139 min(163,screensize(4)-win_size(2)) win_size]); %[left, bottom, width, height]
|
||||
end
|
||||
title('Measured angles')
|
||||
drawnow
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,148 @@
|
||||
% LOAD_ANGLES_APS load tomopgrahy angles for given scan numbers
|
||||
% Directly load from original master .h5 files
|
||||
% created by YJ based on PSI's function
|
||||
|
||||
% [par, angles] = load_angles_aps(par, scans, plot_angles)
|
||||
% Inputs:
|
||||
% **par tomo parameter structure
|
||||
% **scans - list of loaded scan numbers
|
||||
% **tomo_id - indetification number of the sample, default = []
|
||||
% **plot_angles - plot loaded angles, default == true
|
||||
% *returns*
|
||||
% ++par tomo parameter structure
|
||||
% ++angles loaded angles
|
||||
|
||||
function [par, angles] = load_angles_aps(par, scans, plot_angles)
|
||||
warning on
|
||||
Nscans = length(scans);
|
||||
angles = nan(Nscans,1);
|
||||
hasAngle = ones(Nscans,1);
|
||||
if isfield(par,par.angle.filesuffix) && ~isempty(par.angle.filesuffix)
|
||||
file_suffix = par.angle.filesuffix;
|
||||
else
|
||||
file_suffix = '_master.h5'; %default for velociprobe data outputs
|
||||
end
|
||||
|
||||
if isfield(par.angle,'h5path') && ~isempty(par.angle.h5path)
|
||||
h5path = par.angle.h5path;
|
||||
else
|
||||
h5path = '/entry/sample/goniometer/chi_start';
|
||||
end
|
||||
|
||||
%%
|
||||
wb = waitbar(0,'1','Name','Loading ptycho-tomo projection angles...',...
|
||||
'CreateCancelBtn','setappdata(gcbf,''canceling'',1)');
|
||||
setappdata(wb,'canceling',0);
|
||||
for i=1:Nscans
|
||||
% Check for clicked Cancel button
|
||||
if getappdata(wb,'canceling')
|
||||
break
|
||||
end
|
||||
|
||||
filename = strcat(par.base_path, 'ptycho/',sprintf(par.scan_string_format, scans(i)),'/',sprintf(par.scan_string_format, scans(i)),file_suffix);
|
||||
if ~isempty(filename)
|
||||
try
|
||||
angle_temp = h5read(filename,h5path);
|
||||
angles(i) = angle_temp(1);
|
||||
status = [sprintf(par.scan_string_format, scans(i)), ' angle = ',num2str(angles(i))];
|
||||
catch
|
||||
disp(['Reading angle failed for ', sprintf(par.scan_string_format, scans(i))]);
|
||||
disp(strcat('Check angle h5path:',h5path))
|
||||
disp(filename)
|
||||
status = ['Reading angle failed for ', sprintf(par.scan_string_format, scans(i))];
|
||||
end
|
||||
else
|
||||
hasAngle(i) = 0;
|
||||
disp(['No angle found for ',sprintf(par.scan_string_format, scans(i))])
|
||||
status = ['No angle found for ',sprintf(par.scan_string_format, scans(i))];
|
||||
end
|
||||
|
||||
% Update waitbar and message
|
||||
%waitbar(i/Nscans,wb,sprintf(par.scan_string_format, scans(i)))
|
||||
waitbar(i/Nscans,wb,status)
|
||||
|
||||
end
|
||||
delete(wb)
|
||||
|
||||
|
||||
% legacy code - read angles from processed h5 files
|
||||
%{
|
||||
for i=1:Nscans
|
||||
file = find_projection_files_names_aps(par, scans(i));
|
||||
if ~isempty(file)
|
||||
angles(i) = h5read(file,'/angle');
|
||||
else
|
||||
hasAngle(i) = 0;
|
||||
disp(strcat('No angle found for scan ',num2str(scans(i))))
|
||||
end
|
||||
end
|
||||
%}
|
||||
%% process angles
|
||||
% remove scan without angle
|
||||
angles = angles(hasAngle==1);
|
||||
scans = scans(hasAngle==1);
|
||||
|
||||
% remove duplicted scan numbers
|
||||
[~,ind] = unique(scans, 'last'); % take the !last! occurence of the scan, assume that the second measurement was better
|
||||
angles = angles(ind); % Angles not repeated in scan
|
||||
scans = scans(ind);
|
||||
%subtomos = subtomos(ind);
|
||||
|
||||
% take only unique angles, measure uniqueness
|
||||
if par.remove_duplicated_angles
|
||||
[~,ind] = unique(angles, 'last'); % take the !last! occurence of the angle, assume that the second measurement was better
|
||||
if length(angles) ~= length(ind)
|
||||
warning('Removed %i duplicated angles', length(angles) - length(ind))
|
||||
end
|
||||
else
|
||||
[~,ind] = sort(angles);
|
||||
end
|
||||
angles = angles(ind); % Angles not repeated in scan
|
||||
scans = scans(ind);
|
||||
%subtomos = subtomos(ind);
|
||||
|
||||
if isfield(par,'angle_offset') && par.angle_offset ~=0
|
||||
angles = angles + par.angle_offset; % avoid the angles to be too well aligned with pixels, ie avoid exact angles 0, 90, 180, ...
|
||||
end
|
||||
|
||||
par.scanstomo = scans;
|
||||
%par.subtomos = subtomos;
|
||||
|
||||
par.num_proj=numel(par.scanstomo);
|
||||
[anglessort,indsortangle] = sort(angles);
|
||||
|
||||
if par.sort_by_angle
|
||||
angles = angles(indsortangle);
|
||||
par.scanstomo = par.scanstomo(indsortangle);
|
||||
%par.subtomos = par.subtomos(indsortangle);
|
||||
else % sort by scan number
|
||||
[~,indsortscan] = sort( par.scanstomo);
|
||||
angles = angles(indsortscan);
|
||||
par.scanstomo = par.scanstomo(indsortscan);
|
||||
%par.subtomos = par.subtomos(indsortscan);
|
||||
end
|
||||
|
||||
if par.verbose_level && plot_angles
|
||||
plotting.smart_figure(1);
|
||||
subplot(2,1,1)
|
||||
plot(par.scanstomo,angles,'ob'); grid on;
|
||||
xlim(par.scanstomo([1,end]))
|
||||
%legend('Tilt angles')
|
||||
xlabel('Scan #')
|
||||
ylabel('Tilt angles')
|
||||
|
||||
subplot(2,1,2)
|
||||
plot(diff(anglessort))
|
||||
ylabel('Angle increment')
|
||||
%title('Angular spacing');
|
||||
grid on;
|
||||
xlim([1,par.num_proj-1])
|
||||
if par.windowautopos
|
||||
screensize = get( groot, 'Screensize' );
|
||||
win_size = [946 815];
|
||||
set(gcf,'Outerposition',[139 min(163,screensize(4)-win_size(2)) win_size]); %[left, bottom, width, height]
|
||||
end
|
||||
title('Measured angles')
|
||||
drawnow
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,148 @@
|
||||
% LOAD_ANGLES_APS load tomopgrahy angles for given scan numbers
|
||||
% Directly load from original mda files. useful for BNP
|
||||
% created by YJ based on PSI's function
|
||||
|
||||
% [par, angles] = load_angles(par, scans, plot_angles)
|
||||
% Inputs:
|
||||
% **par tomo parameter structure
|
||||
% **scans - list of loaded scan numbers
|
||||
% **tomo_id - indetification number of the sample, default = []
|
||||
% **plot_angles - plot loaded angles, default == true
|
||||
% *returns*
|
||||
% ++par tomo parameter structure
|
||||
% ++angles loaded angles
|
||||
|
||||
function [par, angles] = load_angles_aps_bnp(par, scans, plot_angles)
|
||||
warning on
|
||||
Nscans = length(scans);
|
||||
angles = nan(Nscans,1);
|
||||
hasAngle = ones(Nscans,1);
|
||||
%{
|
||||
if isfield(par,par.angle.filesuffix) && ~isempty(par.angle.filesuffix)
|
||||
file_suffix = par.angle.filesuffix;
|
||||
else
|
||||
file_suffix = '.mda'; %default for velociprobe data outputs
|
||||
end
|
||||
%}
|
||||
file_suffix = '.mda'; %default for velociprobe data outputs
|
||||
|
||||
%%
|
||||
wb = waitbar(0,'1','Name','Loading ptycho-tomo projection angles...',...
|
||||
'CreateCancelBtn','setappdata(gcbf,''canceling'',1)');
|
||||
setappdata(wb,'canceling',0);
|
||||
for i=1:Nscans
|
||||
% Check for clicked Cancel button
|
||||
if getappdata(wb,'canceling')
|
||||
break
|
||||
end
|
||||
scan_string_format = 'bnp_fly%04d';
|
||||
%disp(scans(i))
|
||||
filename = strcat(par.base_path, 'mda/',sprintf(scan_string_format, scans(i)),file_suffix);
|
||||
if ~isempty(filename)
|
||||
try
|
||||
%disp(filename)
|
||||
xx=mdaload(filename);
|
||||
a=(getfield(getfield(xx,'extra'),'pvs'));
|
||||
angles(i) = getfield(a(9),'values');
|
||||
status = [sprintf(par.scan_string_format, scans(i)), ' angle = ',num2str(angles(i))];
|
||||
catch
|
||||
disp(['Reading angle failed for ', sprintf(par.scan_string_format, scans(i))]);
|
||||
%disp(strcat('Check angle h5path:',h5path))
|
||||
status = ['Reading angle failed for ', sprintf(par.scan_string_format, scans(i))];
|
||||
end
|
||||
else
|
||||
hasAngle(i) = 0;
|
||||
disp(['No angle found for ',sprintf(par.scan_string_format, scans(i))])
|
||||
status = ['No angle found for ',sprintf(par.scan_string_format, scans(i))];
|
||||
|
||||
end
|
||||
|
||||
% Update waitbar and message
|
||||
%waitbar(i/Nscans,wb,sprintf(par.scan_string_format, scans(i)))
|
||||
waitbar(i/Nscans,wb,status)
|
||||
|
||||
end
|
||||
delete(wb)
|
||||
|
||||
|
||||
% legacy code - read angles from processed h5 files
|
||||
%{
|
||||
for i=1:Nscans
|
||||
file = find_projection_files_names_aps(par, scans(i));
|
||||
if ~isempty(file)
|
||||
angles(i) = h5read(file,'/angle');
|
||||
else
|
||||
hasAngle(i) = 0;
|
||||
disp(strcat('No angle found for scan ',num2str(scans(i))))
|
||||
end
|
||||
end
|
||||
%}
|
||||
%% process angles
|
||||
% remove scan without angle
|
||||
angles = angles(hasAngle==1);
|
||||
scans = scans(hasAngle==1);
|
||||
|
||||
% remove duplicted scan numbers
|
||||
[~,ind] = unique(scans, 'last'); % take the !last! occurence of the scan, assume that the second measurement was better
|
||||
angles = angles(ind); % Angles not repeated in scan
|
||||
scans = scans(ind);
|
||||
%subtomos = subtomos(ind);
|
||||
|
||||
% take only unique angles, measure uniqueness
|
||||
if par.remove_duplicated_angles
|
||||
[~,ind] = unique(angles, 'last'); % take the !last! occurence of the angle, assume that the second measurement was better
|
||||
if length(angles) ~= length(ind)
|
||||
warning('Removed %i duplicated angles', length(angles) - length(ind))
|
||||
end
|
||||
else
|
||||
[~,ind] = sort(angles);
|
||||
end
|
||||
angles = angles(ind); % Angles not repeated in scan
|
||||
scans = scans(ind);
|
||||
%subtomos = subtomos(ind);
|
||||
|
||||
if isfield(par,'angle_offset') && par.angle_offset ~=0
|
||||
angles = angles + par.angle_offset; % avoid the angles to be too well aligned with pixels, ie avoid exact angles 0, 90, 180, ...
|
||||
end
|
||||
|
||||
par.scanstomo = scans;
|
||||
%par.subtomos = subtomos;
|
||||
|
||||
par.num_proj=numel(par.scanstomo);
|
||||
[anglessort,indsortangle] = sort(angles);
|
||||
|
||||
if par.sort_by_angle
|
||||
angles = angles(indsortangle);
|
||||
par.scanstomo = par.scanstomo(indsortangle);
|
||||
%par.subtomos = par.subtomos(indsortangle);
|
||||
else % sort by scan number
|
||||
[~,indsortscan] = sort( par.scanstomo);
|
||||
angles = angles(indsortscan);
|
||||
par.scanstomo = par.scanstomo(indsortscan);
|
||||
%par.subtomos = par.subtomos(indsortscan);
|
||||
end
|
||||
|
||||
if par.verbose_level && plot_angles
|
||||
plotting.smart_figure(1);
|
||||
subplot(2,1,1)
|
||||
plot(par.scanstomo,angles,'ob'); grid on;
|
||||
xlim(par.scanstomo([1,end]))
|
||||
%legend('Tilt angles')
|
||||
xlabel('Scan #')
|
||||
ylabel('Tilt angles')
|
||||
|
||||
subplot(2,1,2)
|
||||
plot(diff(anglessort))
|
||||
ylabel('Angle increment')
|
||||
%title('Angular spacing');
|
||||
grid on;
|
||||
xlim([1,par.num_proj-1])
|
||||
if par.windowautopos
|
||||
screensize = get( groot, 'Screensize' );
|
||||
win_size = [946 815];
|
||||
set(gcf,'Outerposition',[139 min(163,screensize(4)-win_size(2)) win_size]); %[left, bottom, width, height]
|
||||
end
|
||||
title('Measured angles')
|
||||
drawnow
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,401 @@
|
||||
% LOAD_PROJECTIONS load reconstructed projections from disk to RAM
|
||||
%
|
||||
% [stack_object, theta,num_proj, par] = load_projections(par, exclude_scans, dims_ob, theta, custom_preprocess_fun)
|
||||
%
|
||||
% Inputs:
|
||||
% **par - parameter structure
|
||||
% **exclude_scans - list of scans to be excluded from loading, [] = none
|
||||
% **dims_ob - dimension of the object
|
||||
% **theta - angles of the scans
|
||||
% **custom_preprocess_fun - function to be applied on the loaded data, eg cropping , rotation, etc
|
||||
%
|
||||
% *returns*
|
||||
% ++stack_object - loaded complex-valued projections
|
||||
% ++theta - angles corresponding to the loaded projections, angles for missing projections are removed
|
||||
% ++num_proj - number of projections
|
||||
% ++par - updated parameter structure
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| Except where otherwise noted, this work is licensed under a |
|
||||
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||
%| International (CC BY-NC-SA 4.0) license. |
|
||||
%| |
|
||||
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||
%| |
|
||||
%| Author: CXS group, PSI |
|
||||
%*-----------------------------------------------------------------------*
|
||||
% You may use this code with the following provisions:
|
||||
%
|
||||
% If the code is fully or partially redistributed, or rewritten in another
|
||||
% computing language this notice should be included in the redistribution.
|
||||
%
|
||||
% If this code, or subfunctions or parts of it, is used for research in a
|
||||
% publication or if it is fully or partially rewritten for another
|
||||
% computing language the authors and institution should be acknowledged
|
||||
% in written form in the publication: "Data processing was carried out
|
||||
% using the "cSAXS matlab package" developed by the CXS group,
|
||||
% Paul Scherrer Institut, Switzerland."
|
||||
% Variations on the latter text can be incorporated upon discussion with
|
||||
% the CXS group if needed to more specifically reflect the use of the package
|
||||
% for the published work.
|
||||
%
|
||||
% A publication that focuses on describing features, or parameters, that
|
||||
% are already existing in the code should be first discussed with the
|
||||
% authors.
|
||||
%
|
||||
% This code and subroutines are part of a continuous development, they
|
||||
% are provided "as they are" without guarantees or liability on part
|
||||
% of PSI or the authors. It is the user responsibility to ensure its
|
||||
% proper use and the correctness of the results.
|
||||
|
||||
|
||||
|
||||
function [stack_object, theta,num_proj, par] = load_projections(par, exclude_scans, dims_ob, theta, custom_preprocess_fun)
|
||||
|
||||
import ptycho.*
|
||||
import utils.*
|
||||
import io.*
|
||||
import plotting.*
|
||||
|
||||
if nargin < 5
|
||||
custom_preprocess_fun = [];
|
||||
end
|
||||
if ~isempty(custom_preprocess_fun) && ishandle(custom_preprocess_fun) && ~strcmpi(func2str(custom_preprocess_fun), '@(x)x')
|
||||
custom_preprocess_fun = [] ;
|
||||
end
|
||||
|
||||
scanstomo = par.scanstomo;
|
||||
|
||||
% avoid loading scans listed in 'exclude_scans'
|
||||
if ~isempty(exclude_scans)
|
||||
ind = ismember(scanstomo, exclude_scans);
|
||||
scanstomo(ind) = [];
|
||||
theta(ind) = [];
|
||||
end
|
||||
|
||||
|
||||
|
||||
% % plot average vibrations for each of the laoded projections
|
||||
% disp('Checking stability of the projections')
|
||||
% poor_projections = prepare.plot_sample_stability(par, scanstomo, ~par.online_tomo, par.pixel_size);
|
||||
% if sum(poor_projections) && ...
|
||||
% (par.online_tomo || ~strcmpi(input(sprintf('Remove %i low stability projections: [Y/n]\n',sum(poor_projections)), 's'), 'n') )
|
||||
% theta(poor_projections) = [];
|
||||
% scanstomo(poor_projections) = [];
|
||||
% else
|
||||
% disp('All projections are fine')
|
||||
% end
|
||||
|
||||
|
||||
|
||||
verbose(1,'Checking available files')
|
||||
missing_scans = [];
|
||||
for num = 1:length(scanstomo)
|
||||
progressbar(num, length(scanstomo))
|
||||
proj_file_names{num} = find_ptycho_filename(par.analysis_path,scanstomo(num),par.fileprefix,par.filesuffix, par.file_extension);
|
||||
if isempty(proj_file_names{num})
|
||||
missing_scans(end+1) = scanstomo(num);
|
||||
end
|
||||
end
|
||||
|
||||
verbose(par.verbose_level); % return to original settings
|
||||
|
||||
figure(1)
|
||||
subplot(2,1,1)
|
||||
hold on
|
||||
plot(missing_scans, theta(ismember(scanstomo, missing_scans)), 'rx')
|
||||
hold off
|
||||
legend({'Measured angles', 'Missing projections'})
|
||||
axis tight
|
||||
|
||||
|
||||
if ~isempty(missing_scans)
|
||||
ind = ismember(scanstomo, missing_scans);
|
||||
verbose(1,['Scans not found are ' num2str(missing_scans)])
|
||||
verbose(1,['Projections not found are ' num2str(find(ind))])
|
||||
scanstomo(ind) = [];
|
||||
theta(ind) = [];
|
||||
proj_file_names(ind) = [];
|
||||
else
|
||||
verbose(1,'All projections found')
|
||||
end
|
||||
|
||||
num_proj = length(scanstomo);
|
||||
|
||||
if isfield(par, 'fp16_precision') && par.fp16_precision
|
||||
% use uint32 to store half floar precision data
|
||||
stack_object=zeros(dims_ob(1),dims_ob(2),num_proj, 'like', fp16.set(1i));
|
||||
else
|
||||
stack_object=zeros(dims_ob(1),dims_ob(2),num_proj, 'like', single(1i));
|
||||
end
|
||||
pixel_scale =zeros(num_proj,2);
|
||||
energy = zeros(num_proj,1);
|
||||
|
||||
|
||||
tic
|
||||
|
||||
if num_proj == 0
|
||||
verbose(0, 'No new projections loaded')
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
which_missing = false(1,num_proj); % Include here INDEX numbers that you want to exclude (bad reconstructions)
|
||||
%{
|
||||
%% prepare parpool
|
||||
% pool = gcp('nocreate');
|
||||
% if isempty(pool) || pool.NumWorkers < par.Nworkers
|
||||
% delete(pool);
|
||||
% pool = parpool(par.Nworkers);
|
||||
% end
|
||||
% pool.IdleTimeout = 600; % set idle timeout to 10 hours
|
||||
%
|
||||
% load at least 10 frames per worker to use well the resources
|
||||
block_size = max(1, par.Nworkers)*50;
|
||||
|
||||
|
||||
%% load data, use parfor but process blockwise to avoid lare memory use
|
||||
for block_id = 1:ceil(num_proj/block_size)
|
||||
block_inds = 1+(block_id-1)*block_size: min(num_proj, block_id*block_size);
|
||||
verbose(1,'===== Block %i / %i started ===== ', block_id, ceil(num_proj/block_size))
|
||||
utils.check_available_memory
|
||||
stack_object_block = zeros(dims_ob(1),dims_ob(2),length(block_inds), 'like', stack_object);
|
||||
|
||||
share_mem = shm(true);
|
||||
share_mem.allocate(stack_object_block);
|
||||
share_mem.detach();
|
||||
|
||||
|
||||
% ticBytes(gcp);
|
||||
|
||||
%% start a smaller block in parallel
|
||||
% parfor(num = block_inds,par.Nworkers)
|
||||
% if parfor fails, try normal loop
|
||||
for num = block_inds
|
||||
|
||||
file = proj_file_names{num};
|
||||
|
||||
if ismember(scanstomo(num), exclude_scans)
|
||||
warning(['Skipping by user request: ' file{1}])
|
||||
continue % skip the frames that are listed in exclude_scans
|
||||
end
|
||||
|
||||
if ~iscell(file)
|
||||
file = {file}; % make them all cells
|
||||
end
|
||||
|
||||
object= [];
|
||||
for jj = length(file):-1:1
|
||||
disp(['Reading file: ' file{jj}])
|
||||
% if more than one file is present, try to load the first last one that
|
||||
% does not fail
|
||||
try
|
||||
object = load_ptycho_recons(file{jj}, 'object');
|
||||
object = single(object.object);
|
||||
object = prod(object,4); % use only the eDOF object if multiple layers are available
|
||||
pixel_scale(num,:) = io.HDF.hdf5_load(file{jj}, '/reconstruction/p/dx_spec');
|
||||
energy(num) = io.HDF.hdf5_load(file{jj}, '/reconstruction/p/energy');
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if isempty(object) || all(object(:) == 0 )
|
||||
which_missing(num) = true;
|
||||
warning(['Loading failed: ' [file{:}]])
|
||||
continue
|
||||
end
|
||||
|
||||
if ~isempty(custom_preprocess_fun)
|
||||
object = custom_preprocess_fun(object);
|
||||
end
|
||||
|
||||
nx = dims_ob(2);
|
||||
ny = dims_ob(1);
|
||||
|
||||
|
||||
if size(object,2) > nx
|
||||
object = object(:,1:nx);
|
||||
elseif size(object,2) < nx
|
||||
object = padarray(object,[0 nx-size(object,2)],'post');
|
||||
end
|
||||
if size(object,1) > ny
|
||||
if par.auto_alignment|| par.get_auto_calibration
|
||||
object = object(1:ny,:);
|
||||
else
|
||||
shifty = floor((size(object,1)-ny)/2);
|
||||
object = object([1:ny]+shifty,:);
|
||||
end
|
||||
elseif size(object,1) < ny
|
||||
if par.auto_alignment||par.get_auto_calibration
|
||||
object = padarray(object,[ny-size(object,1) 0],'post');
|
||||
else
|
||||
shifty = (ny-size(object,1))/2;
|
||||
object = padarray(object,[ny-size(object,1)-floor(shifty) 0],'post');
|
||||
object = padarray(object,[floor(shifty) 0],'pre');
|
||||
end
|
||||
end
|
||||
|
||||
% if par.showrecons
|
||||
% mag=a+bs(object);
|
||||
% phase=angle(object);
|
||||
% figure(1); clf
|
||||
% imagesc(mag); axis xy equal tight ; colormap bone(256); colorbar;
|
||||
% title(['object magnitude S',sprintf('%05d',ii),', Projection ' ,sprintf('%03d',num) , ', Theta = ' sprintf('%.2f',theta(num)), ' degrees']);drawnow;
|
||||
% set(gcf,'Outerposition',[601 424 600 600])
|
||||
% figure(2); imagesc(phase); axis xy equal tight; colormap bone(256); colorbar;
|
||||
% title(['object phase S',sprintf('%05d',ii),', Projection ' ,sprintf('%03d',num) , ', Theta = ' sprintf('%.2f',theta(num)), ' degrees']);drawnow;
|
||||
% set(gcf,'Outerposition',[1 424 600 600]) %[left, bottom, width, height
|
||||
% figure(3); % imagesc3D(probe);
|
||||
% axis xy equal tight
|
||||
% set(gcf,'Outerposition',[600 49 375 375]) %[left, bottom, width, height
|
||||
% figure(4);
|
||||
% if isfield(p, 'err')
|
||||
% loglog(p.err);
|
||||
% elseif isfield(p, 'mlerror')
|
||||
% loglog(p.mlerror)
|
||||
% elseif isfield(p, 'error_metric')
|
||||
% loglog(p.error_metric(2).iteration,p.error_metric(2).value)
|
||||
% end
|
||||
% title(sprintf('Error %03d',num))
|
||||
% set(gcf,'Outerposition',[1 49 600 375]) %[left, bottom, width, height
|
||||
% drawnow;
|
||||
% end
|
||||
|
||||
if isfield(par, 'fp16_precision') && par.fp16_precision
|
||||
% convert data to fp16 precision
|
||||
object = fp16.set(object);
|
||||
end
|
||||
|
||||
% keyboard
|
||||
|
||||
% write loaded object to a small block of shared memory, avoid using
|
||||
% parpool data transfer
|
||||
share_mem_tmp = share_mem;
|
||||
[share_mem_tmp, share_mem_object] = share_mem_tmp.attach();
|
||||
tomo.set_to_array(share_mem_object, object, num - block_inds(1));
|
||||
share_mem_tmp.detach();
|
||||
|
||||
end % enf of parfor
|
||||
|
||||
% tocBytes(gcp);
|
||||
|
||||
tic
|
||||
verbose(1,'Writting to shared stack_object')
|
||||
[share_mem, stack_object_block] = share_mem.attach();
|
||||
% write loaded block to the full array, avoid memory reallocation
|
||||
tomo.set_to_array(stack_object, stack_object_block, block_inds-1);
|
||||
share_mem.free();
|
||||
toc
|
||||
|
||||
|
||||
end
|
||||
%}
|
||||
verbose(1, 'Data loaded')
|
||||
|
||||
|
||||
|
||||
verbose(1, 'Find residua')
|
||||
[Nx, Ny, Nprojections] = size(stack_object);
|
||||
|
||||
object_ROI = {ceil(1+par.asize(1)/2:Nx-par.asize(1)/2),ceil(1+par.asize(2)/2:Ny-par.asize(2)/2)};
|
||||
residua = tomo.block_fun(@(x)(squeeze(math.sum2(abs(utils.findresidues(x))>0.1))),stack_object, struct('ROI', {object_ROI}));
|
||||
|
||||
max_residua = 100;
|
||||
poor_projections = (residua(:)' > max_residua) & ~par.is_laminography ; % ignore in the case of laminography
|
||||
|
||||
if any(poor_projections)
|
||||
verbose(1, 'Found %i/%i projections with more than %i residues ', sum(poor_projections), Nprojections, max_residua)
|
||||
end
|
||||
|
||||
|
||||
if any(which_missing & ~ismember(scanstomo, exclude_scans) )
|
||||
missing = find(which_missing & ~ismember(scanstomo, exclude_scans));
|
||||
verbose(1,['Projections not found are ' num2str(missing)])
|
||||
verbose(1,['Scans not found are ' num2str(scanstomo(missing))])
|
||||
else
|
||||
verbose(1,'All projections loaded')
|
||||
end
|
||||
toc
|
||||
|
||||
% avoid also empty projections
|
||||
which_wrong = poor_projections | squeeze(math.sum2(stack_object)==0)';
|
||||
|
||||
if any(which_wrong & ~ismember(scanstomo, exclude_scans) )
|
||||
wrong = find(which_wrong & ~ismember(scanstomo, exclude_scans));
|
||||
verbose(1,['Projections failed are ' num2str(wrong)])
|
||||
verbose(1,['Scans failed are ' num2str(scanstomo(wrong))])
|
||||
else
|
||||
verbose(1,'All loaded projections are OK')
|
||||
end
|
||||
|
||||
|
||||
%%% Getting rid of missing projections %%%
|
||||
which_remove = which_missing | which_wrong;
|
||||
if any(which_remove)
|
||||
if par.online_tomo || ~strcmpi(input(sprintf('Do you want remove %i missing/wrong projections and keep going (Y/n)?',sum(which_remove)),'s'),'n')
|
||||
disp('Removing missing/wrong projections. stack_object, scanstomo, theta and num_proj are modified')
|
||||
|
||||
stack_object(:,:,which_remove) = [];
|
||||
scanstomo(which_remove)=[];
|
||||
theta(which_remove)=[];
|
||||
pixel_scale(which_remove,:) = [];
|
||||
energy(which_remove,:) = [];
|
||||
|
||||
disp('Done')
|
||||
else
|
||||
disp('Keeping empty spaces for missing projections. Problems are expected if you continue.')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
par.scanstomo = scanstomo;
|
||||
par.num_proj=numel(scanstomo);
|
||||
|
||||
pixel_scale = pixel_scale ./ mean(pixel_scale);
|
||||
|
||||
assert(par.num_proj > 0, 'No projections loaded')
|
||||
|
||||
|
||||
if all(all(abs(pixel_scale)-1 < 1e-6)) || ~any(isfinite(mean(pixel_scale)))
|
||||
%if all datasets have the same pixel scale
|
||||
pixel_scale = [1,1];
|
||||
else
|
||||
warning('Datasets do not have equal pixel sizes, auto-rescaling projections')
|
||||
% use FFT base rescaling -> apply illumination function first to remove
|
||||
% effect of the noise out of the reconstruction region
|
||||
rot_fun = @(x,sx,sy)(utils.imrescale_frft(x .* par.illum_sum, sx, sy)) ./ ( max(0,utils.imrescale_frft(par.illum_sum,sx,sy))+1e-2*max(par.illum_sum(:)));
|
||||
stack_object = tomo.block_fun(rot_fun,stack_object, pixel_scale(:,1),pixel_scale(:,2));
|
||||
pixel_scale = [1,1];
|
||||
end
|
||||
|
||||
|
||||
par.pixel_scale = pixel_scale;
|
||||
par.energy = energy;
|
||||
|
||||
%% clip the projections ampltitude by quantile filter
|
||||
if par.clip_amplitude_quantile < 1
|
||||
MAX = quantile(reshape(abs(fp16.get(stack_object(1:10:end,1:10:end,:))), [], par.num_proj), par.clip_amplitude_quantile ,1);
|
||||
MAX = reshape(MAX,1,1,par.num_proj);
|
||||
clip_fun = @(x,M)(min(abs(x),M) .* x ./ (abs(x) + 1e-5));
|
||||
stack_object = tomo.block_fun(clip_fun,stack_object, MAX, struct('use_GPU', true));
|
||||
end
|
||||
|
||||
|
||||
if size(stack_object,3) ~= length(theta) || length(theta) ~= par.num_proj
|
||||
error('Inconsistency between number of angles and projections')
|
||||
end
|
||||
|
||||
if ~isempty(par.tomo_id) && all(par.tomo_id > 0)
|
||||
% sanity safety check, all loaded angles correpont to the stored angles
|
||||
[~,theta_test] = prepare.load_angles(par, par.scanstomo, [], false);
|
||||
if max(abs(theta - theta_test)) > 180/par.num_proj/2
|
||||
error('Some angles have angles different from expected')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,568 @@
|
||||
% LOAD_PROJECTIONS_APS load reconstructed projections from disk to RAM
|
||||
% created by YJ based on PSI's function
|
||||
% [stack_object, theta,num_proj, par] = load_projections(par, exclude_scans, dims_ob, theta, custom_preprocess_fun)
|
||||
%
|
||||
% Inputs:
|
||||
% **par - parameter structure
|
||||
% **exclude_scans - list of scans to be excluded from loading, [] = none
|
||||
% **dims_ob - dimension of the object
|
||||
% **theta - angles of the scans
|
||||
% **custom_preprocess_fun - function to be applied on the loaded data, eg cropping , rotation, etc
|
||||
%
|
||||
% *returns*
|
||||
% ++stack_object - loaded complex-valued projections
|
||||
% ++theta - angles corresponding to the loaded projections, angles for missing projections are removed
|
||||
% ++num_proj - number of projections
|
||||
% ++par - updated parameter structure
|
||||
|
||||
function [stack_object, theta,num_proj, par] = load_projections_aps(par, exclude_scans, dims_ob, theta, custom_preprocess_fun)
|
||||
|
||||
import ptycho.*
|
||||
import utils.*
|
||||
import io.*
|
||||
import plotting.*
|
||||
|
||||
if nargin < 5
|
||||
custom_preprocess_fun = [];
|
||||
end
|
||||
if ~isempty(custom_preprocess_fun) && ishandle(custom_preprocess_fun) && ~strcmpi(func2str(custom_preprocess_fun), '@(x)x')
|
||||
custom_preprocess_fun = [] ;
|
||||
end
|
||||
|
||||
scanstomo = par.scanstomo;
|
||||
|
||||
% avoid loading scans listed in 'exclude_scans'
|
||||
if ~isempty(exclude_scans)
|
||||
ind = ismember(scanstomo, exclude_scans);
|
||||
scanstomo(ind) = [];
|
||||
theta(ind) = [];
|
||||
end
|
||||
|
||||
|
||||
% % plot average vibrations for each of the laoded projections
|
||||
% disp('Checking stability of the projections')
|
||||
% poor_projections = prepare.plot_sample_stability(par, scanstomo, ~par.online_tomo, par.pixel_size);
|
||||
% if sum(poor_projections) && ...
|
||||
% (par.online_tomo || ~strcmpi(input(sprintf('Remove %i low stability projections: [Y/n]\n',sum(poor_projections)), 's'), 'n') )
|
||||
% theta(poor_projections) = [];
|
||||
% scanstomo(poor_projections) = [];
|
||||
% else
|
||||
% disp('All projections are fine')
|
||||
% end
|
||||
|
||||
verbose(1,'Checking available files')
|
||||
missing_scans = [];
|
||||
proj_file_names = {};
|
||||
proj_recon_method = {};
|
||||
proj_roi = {};
|
||||
proj_scanNo = {};
|
||||
for num = 1:length(scanstomo)
|
||||
progressbar(num, length(scanstomo))
|
||||
%proj_file_names{num} = find_ptycho_filename(par.analysis_path,scanstomo(num),par.fileprefix,par.filesuffix, par.file_extension);
|
||||
%proj_file_names{num} = find_projection_files_names_aps(par, scanstomo(num));
|
||||
[proj_file_names{num},proj_recon_method{num},proj_roi{num},proj_scanNo{num}] = find_ML_recon_files_names(par, scanstomo(num));
|
||||
%disp(proj_file_names{num})
|
||||
if isempty(proj_file_names{num})
|
||||
missing_scans(end+1) = scanstomo(num);
|
||||
end
|
||||
end
|
||||
|
||||
verbose(par.verbose_level); % return to original settings
|
||||
%{
|
||||
figure(1)
|
||||
subplot(2,1,1)
|
||||
hold on
|
||||
plot(missing_scans, theta(ismember(scanstomo, missing_scans)), 'rx')
|
||||
hold off
|
||||
legend({'Measured angles', 'Missing projections'})
|
||||
axis tight
|
||||
%}
|
||||
|
||||
if ~isempty(missing_scans)
|
||||
ind = ismember(scanstomo, missing_scans);
|
||||
verbose(1,['Scans not found are ' num2str(missing_scans)])
|
||||
verbose(1,['Projections not found are ' num2str(find(ind))])
|
||||
scanstomo(ind) = [];
|
||||
theta(ind) = [];
|
||||
proj_file_names(ind) = [];
|
||||
proj_recon_method(ind) = [];
|
||||
proj_roi(ind) = [];
|
||||
proj_scanNo(ind) = [];
|
||||
else
|
||||
verbose(1,'All projections found')
|
||||
end
|
||||
|
||||
num_proj = length(scanstomo);
|
||||
object_size_orig = zeros(2,num_proj);
|
||||
if isfield(par, 'fp16_precision') && par.fp16_precision
|
||||
% use uint32 to store half floar precision data
|
||||
stack_object=zeros(dims_ob(1),dims_ob(2),num_proj, 'like', fp16.set(1i));
|
||||
else
|
||||
stack_object=zeros(dims_ob(1),dims_ob(2),num_proj, 'like', single(1i));
|
||||
end
|
||||
pixel_scale =zeros(num_proj,2);
|
||||
%energy = zeros(num_proj,1);
|
||||
|
||||
|
||||
tic
|
||||
|
||||
if num_proj == 0
|
||||
verbose(0, 'No new projections loaded')
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
which_missing = false(1,num_proj); % Include here INDEX numbers that you want to exclude (bad reconstructions)
|
||||
|
||||
utils.check_available_memory
|
||||
%%
|
||||
wb = waitbar(0,'1','Name','Loading ptycho-tomo projection...',...
|
||||
'CreateCancelBtn','setappdata(gcbf,''canceling'',1)');
|
||||
setappdata(wb,'canceling',0);
|
||||
%
|
||||
t0 = tic;
|
||||
|
||||
for num=1:num_proj
|
||||
% Update waitbar and message
|
||||
status = sprintf(par.scan_string_format, scanstomo(num));
|
||||
status = strcat(status,' (',num2str(num),'/',num2str(num_proj),') ');
|
||||
|
||||
if num>1
|
||||
timeLeft = (num_proj-num+1)*avgTimePerIter;
|
||||
|
||||
if timeLeft>3600
|
||||
time_status = sprintf(' Time left:%3.3g hour', timeLeft/3600);
|
||||
elseif timeLeft>60
|
||||
time_status = sprintf(' Time left:%3.3g min', timeLeft/60);
|
||||
else
|
||||
time_status = sprintf(' Time left:%3.3g sec', timeLeft);
|
||||
end
|
||||
status = strcat(status,time_status);
|
||||
end
|
||||
waitbar(num/num_proj,wb,status)
|
||||
|
||||
% Check for clicked Cancel button
|
||||
if getappdata(wb,'canceling')
|
||||
break
|
||||
end
|
||||
file = proj_file_names{num};
|
||||
|
||||
if ismember(scanstomo(num), exclude_scans)
|
||||
warning(['Skipping by user request: ' file{1}])
|
||||
continue % skip the frames that are listed in exclude_scans
|
||||
end
|
||||
|
||||
if ~iscell(file)
|
||||
file = {file}; % make them all cells
|
||||
end
|
||||
object= [];
|
||||
for jj = length(file):-1:1
|
||||
%disp(['Reading file: ' file{jj}])
|
||||
% if more than one file is present, try to load the first last one that
|
||||
% does not fail
|
||||
%try
|
||||
%{
|
||||
object_r = h5read(file{1},'/object_r');
|
||||
object_i = h5read(file{1},'/object_i');
|
||||
object = object_r + 1i*object_i;
|
||||
object = single(object);
|
||||
%object = prod(object,4); % use only the eDOF object if multiple layers are available
|
||||
pixel_scale(num,:) = h5read(file{1},'/dx_spec');
|
||||
%energy(num) = io.HDF.hdf5_load(file{jj}, '/reconstruction/p/energy');
|
||||
%}
|
||||
|
||||
object = load(file{1},'object');
|
||||
object = single(object.object);
|
||||
|
||||
parameter = load(file{1},'p');
|
||||
pixel_scale(num,:) = parameter.p.dx_spec; %pixel size
|
||||
|
||||
break
|
||||
%end
|
||||
end
|
||||
|
||||
%% for multislice recon - sum layers into a single projection
|
||||
if size(object,3)>1
|
||||
if isfield(par.MLrecon,'select_layers') && any(par.MLrecon.select_layers)
|
||||
object = prod(object(:,:,par.MLrecon.select_layers),3);
|
||||
else
|
||||
object = prod(object,3);
|
||||
end
|
||||
end
|
||||
|
||||
%%
|
||||
object_size_orig(:,num) = size(object);
|
||||
|
||||
if isempty(object) || all(object(:) == 0 )
|
||||
which_missing(num) = true;
|
||||
warning(['Loading failed: ' [file{:}]])
|
||||
continue
|
||||
end
|
||||
if isfield(par, 'crop_edge') && par.crop_edge>0
|
||||
object = object(1+par.crop_edge:end-par.crop_edge,1+par.crop_edge:end-par.crop_edge);
|
||||
end
|
||||
if ~isempty(custom_preprocess_fun)
|
||||
object = custom_preprocess_fun(object);
|
||||
end
|
||||
|
||||
nx = dims_ob(2);
|
||||
ny = dims_ob(1);
|
||||
|
||||
|
||||
if size(object,2) > nx
|
||||
object = object(:,1:nx);
|
||||
elseif size(object,2) < nx
|
||||
object = padarray(object,[0 nx-size(object,2)],'post');
|
||||
end
|
||||
|
||||
if size(object,1) > ny
|
||||
if par.auto_alignment|| par.get_auto_calibration
|
||||
object = object(1:ny,:);
|
||||
else
|
||||
shifty = floor((size(object,1)-ny)/2);
|
||||
object = object([1:ny]+shifty,:);
|
||||
end
|
||||
elseif size(object,1) < ny
|
||||
if par.auto_alignment||par.get_auto_calibration
|
||||
object = padarray(object,[ny-size(object,1) 0],'post');
|
||||
else
|
||||
shifty = (ny-size(object,1))/2;
|
||||
object = padarray(object,[ny-size(object,1)-floor(shifty) 0],'post');
|
||||
object = padarray(object,[floor(shifty) 0],'pre');
|
||||
end
|
||||
end
|
||||
|
||||
stack_object(:,:,num) = object;
|
||||
|
||||
% if par.showrecons
|
||||
% mag=a+bs(object);
|
||||
% phase=angle(object);
|
||||
% figure(1); clf
|
||||
% imagesc(mag); axis xy equal tight ; colormap bone(256); colorbar;
|
||||
% title(['object magnitude S',sprintf('%05d',ii),', Projection ' ,sprintf('%03d',num) , ', Theta = ' sprintf('%.2f',theta(num)), ' degrees']);drawnow;
|
||||
% set(gcf,'Outerposition',[601 424 600 600])
|
||||
% figure(2); imagesc(phase); axis xy equal tight; colormap bone(256); colorbar;
|
||||
% title(['object phase S',sprintf('%05d',ii),', Projection ' ,sprintf('%03d',num) , ', Theta = ' sprintf('%.2f',theta(num)), ' degrees']);drawnow;
|
||||
% set(gcf,'Outerposition',[1 424 600 600]) %[left, bottom, width, height
|
||||
% figure(3); % imagesc3D(probe);
|
||||
% axis xy equal tight
|
||||
% set(gcf,'Outerposition',[600 49 375 375]) %[left, bottom, width, height
|
||||
% figure(4);
|
||||
% if isfield(p, 'err')
|
||||
% loglog(p.err);
|
||||
% elseif isfield(p, 'mlerror')
|
||||
% loglog(p.mlerror)
|
||||
% elseif isfield(p, 'error_metric')
|
||||
% loglog(p.error_metric(2).iteration,p.error_metric(2).value)
|
||||
% end
|
||||
% title(sprintf('Error %03d',num))
|
||||
% set(gcf,'Outerposition',[1 49 600 375]) %[left, bottom, width, height
|
||||
% drawnow;
|
||||
% end
|
||||
|
||||
avgTimePerIter = toc(t0)/num;
|
||||
|
||||
end % enf of parfor
|
||||
delete(wb)
|
||||
%store info for ML reconstructions
|
||||
par.proj_file_names = proj_file_names;
|
||||
par.proj_recon_method = proj_recon_method;
|
||||
par.proj_roi = proj_roi;
|
||||
par.proj_scanNo = proj_scanNo;
|
||||
par.object_size_orig = object_size_orig;
|
||||
verbose(1, 'Data loaded')
|
||||
|
||||
%% parallel loading -- Not working
|
||||
%{
|
||||
%% prepare parpool
|
||||
% pool = gcp('nocreate');
|
||||
% if isempty(pool) || pool.NumWorkers < par.Nworkers
|
||||
% delete(pool);
|
||||
% pool = parpool(par.Nworkers);
|
||||
% end
|
||||
% pool.IdleTimeout = 600; % set idle timeout to 10 hours
|
||||
%
|
||||
% load at least 10 frames per worker to use well the resources
|
||||
block_size = max(1, par.Nworkers)*50;
|
||||
|
||||
|
||||
%% load data, use parfor but process blockwise to avoid lare memory use
|
||||
for block_id = 1:ceil(num_proj/block_size)
|
||||
block_inds = 1+(block_id-1)*block_size: min(num_proj, block_id*block_size);
|
||||
verbose(1,'===== Block %i / %i started ===== ', block_id, ceil(num_proj/block_size))
|
||||
utils.check_available_memory
|
||||
stack_object_block = zeros(dims_ob(1),dims_ob(2),length(block_inds), 'like', stack_object);
|
||||
|
||||
share_mem = shm(true);
|
||||
share_mem.allocate(stack_object_block);
|
||||
share_mem.detach();
|
||||
|
||||
|
||||
% ticBytes(gcp);
|
||||
|
||||
%% start a smaller block in parallel
|
||||
% parfor(num = block_inds,par.Nworkers)
|
||||
% if parfor fails, try normal loop
|
||||
for num = block_inds
|
||||
|
||||
file = proj_file_names{num};
|
||||
|
||||
if ismember(scanstomo(num), exclude_scans)
|
||||
warning(['Skipping by user request: ' file{1}])
|
||||
continue % skip the frames that are listed in exclude_scans
|
||||
end
|
||||
|
||||
if ~iscell(file)
|
||||
file = {file}; % make them all cells
|
||||
end
|
||||
|
||||
object= [];
|
||||
for jj = length(file):-1:1
|
||||
disp(['Reading file: ' file{jj}])
|
||||
% if more than one file is present, try to load the first last one that
|
||||
% does not fail
|
||||
%try
|
||||
|
||||
object_r = h5read(file{1},'/object_r');
|
||||
object_i = h5read(file{1},'/object_i');
|
||||
object = object_r + 1i*object_i;
|
||||
object = single(object);
|
||||
%object = prod(object,4); % use only the eDOF object if multiple layers are available
|
||||
pixel_scale(num,:) = h5read(file{1},'/dx_spec');
|
||||
%energy(num) = io.HDF.hdf5_load(file{jj}, '/reconstruction/p/energy');
|
||||
|
||||
break
|
||||
%end
|
||||
end
|
||||
|
||||
if isempty(object) || all(object(:) == 0 )
|
||||
which_missing(num) = true;
|
||||
warning(['Loading failed: ' [file{:}]])
|
||||
continue
|
||||
end
|
||||
|
||||
if ~isempty(custom_preprocess_fun)
|
||||
object = custom_preprocess_fun(object);
|
||||
end
|
||||
|
||||
nx = dims_ob(2);
|
||||
ny = dims_ob(1);
|
||||
|
||||
|
||||
if size(object,2) > nx
|
||||
object = object(:,1:nx);
|
||||
elseif size(object,2) < nx
|
||||
object = padarray(object,[0 nx-size(object,2)],'post');
|
||||
end
|
||||
if size(object,1) > ny
|
||||
if par.auto_alignment|| par.get_auto_calibration
|
||||
object = object(1:ny,:);
|
||||
else
|
||||
shifty = floor((size(object,1)-ny)/2);
|
||||
object = object([1:ny]+shifty,:);
|
||||
end
|
||||
elseif size(object,1) < ny
|
||||
if par.auto_alignment||par.get_auto_calibration
|
||||
object = padarray(object,[ny-size(object,1) 0],'post');
|
||||
else
|
||||
shifty = (ny-size(object,1))/2;
|
||||
object = padarray(object,[ny-size(object,1)-floor(shifty) 0],'post');
|
||||
object = padarray(object,[floor(shifty) 0],'pre');
|
||||
end
|
||||
end
|
||||
|
||||
% if par.showrecons
|
||||
% mag=a+bs(object);
|
||||
% phase=angle(object);
|
||||
% figure(1); clf
|
||||
% imagesc(mag); axis xy equal tight ; colormap bone(256); colorbar;
|
||||
% title(['object magnitude S',sprintf('%05d',ii),', Projection ' ,sprintf('%03d',num) , ', Theta = ' sprintf('%.2f',theta(num)), ' degrees']);drawnow;
|
||||
% set(gcf,'Outerposition',[601 424 600 600])
|
||||
% figure(2); imagesc(phase); axis xy equal tight; colormap bone(256); colorbar;
|
||||
% title(['object phase S',sprintf('%05d',ii),', Projection ' ,sprintf('%03d',num) , ', Theta = ' sprintf('%.2f',theta(num)), ' degrees']);drawnow;
|
||||
% set(gcf,'Outerposition',[1 424 600 600]) %[left, bottom, width, height
|
||||
% figure(3); % imagesc3D(probe);
|
||||
% axis xy equal tight
|
||||
% set(gcf,'Outerposition',[600 49 375 375]) %[left, bottom, width, height
|
||||
% figure(4);
|
||||
% if isfield(p, 'err')
|
||||
% loglog(p.err);
|
||||
% elseif isfield(p, 'mlerror')
|
||||
% loglog(p.mlerror)
|
||||
% elseif isfield(p, 'error_metric')
|
||||
% loglog(p.error_metric(2).iteration,p.error_metric(2).value)
|
||||
% end
|
||||
% title(sprintf('Error %03d',num))
|
||||
% set(gcf,'Outerposition',[1 49 600 375]) %[left, bottom, width, height
|
||||
% drawnow;
|
||||
% end
|
||||
|
||||
if isfield(par, 'fp16_precision') && par.fp16_precision
|
||||
% convert data to fp16 precision
|
||||
object = fp16.set(object);
|
||||
end
|
||||
|
||||
% keyboard
|
||||
|
||||
% write loaded object to a small block of shared memory, avoid using
|
||||
% parpool data transfer
|
||||
share_mem_tmp = share_mem;
|
||||
[share_mem_tmp, share_mem_object] = share_mem_tmp.attach();
|
||||
tomo.set_to_array(share_mem_object, object, num - block_inds(1));
|
||||
share_mem_tmp.detach();
|
||||
|
||||
end % enf of parfor
|
||||
|
||||
% tocBytes(gcp);
|
||||
|
||||
tic
|
||||
verbose(1,'Writting to shared stack_object')
|
||||
[share_mem, stack_object_block] = share_mem.attach();
|
||||
% write loaded block to the full array, avoid memory reallocation
|
||||
tomo.set_to_array(stack_object, stack_object_block, block_inds-1);
|
||||
share_mem.free();
|
||||
toc
|
||||
|
||||
|
||||
end
|
||||
|
||||
verbose(1, 'Data loaded')
|
||||
%}
|
||||
|
||||
%% examine projections
|
||||
verbose(1, 'Find residua')
|
||||
[Nx, Ny, Nprojections] = size(stack_object);
|
||||
|
||||
object_ROI = {ceil(1+par.asize(1)/2:Nx-par.asize(1)/2),ceil(1+par.asize(2)/2:Ny-par.asize(2)/2)};
|
||||
residua = tomo.block_fun(@(x)(squeeze(math.sum2(abs(utils.findresidues(x))>0.1))),stack_object, struct('ROI', {object_ROI}));
|
||||
|
||||
if isfield(par,'max_residua_limit')
|
||||
max_residua = par.max_residua_limit;
|
||||
else
|
||||
max_residua = 100;
|
||||
end
|
||||
poor_projections = (residua(:)' > max_residua) & ~par.is_laminography ; % ignore in the case of laminography
|
||||
|
||||
if any(poor_projections)
|
||||
verbose(1, 'Found %i/%i projections with more than %i residues ', sum(poor_projections), Nprojections, max_residua)
|
||||
end
|
||||
|
||||
|
||||
if any(which_missing & ~ismember(scanstomo, exclude_scans) )
|
||||
missing = find(which_missing & ~ismember(scanstomo, exclude_scans));
|
||||
verbose(1,['Projections not found are ' num2str(missing)])
|
||||
verbose(1,['Scans not found are ' num2str(scanstomo(missing))])
|
||||
else
|
||||
verbose(1,'All projections loaded')
|
||||
end
|
||||
toc
|
||||
|
||||
% avoid also empty projections
|
||||
which_wrong = poor_projections | squeeze(math.sum2(stack_object)==0)';
|
||||
|
||||
if any(which_wrong & ~ismember(scanstomo, exclude_scans) )
|
||||
wrong = find(which_wrong & ~ismember(scanstomo, exclude_scans));
|
||||
verbose(1,['Projections failed are ' num2str(wrong)])
|
||||
verbose(1,['Scans failed are ' num2str(scanstomo(wrong))])
|
||||
else
|
||||
verbose(1,'All loaded projections are OK')
|
||||
end
|
||||
|
||||
|
||||
%%% Getting rid of missing projections %%%
|
||||
which_remove = which_missing | which_wrong;
|
||||
if any(which_remove)
|
||||
if par.online_tomo || ~strcmpi(input(sprintf('Do you want remove %i missing/wrong projections and keep going (Y/n)?',sum(which_remove)),'s'),'n')
|
||||
disp('Removing missing/wrong projections. stack_object, scanstomo, theta and num_proj are modified')
|
||||
|
||||
stack_object(:,:,which_remove) = [];
|
||||
scanstomo(which_remove)=[];
|
||||
theta(which_remove)=[];
|
||||
pixel_scale(which_remove,:) = [];
|
||||
%energy(which_remove,:) = [];
|
||||
|
||||
disp('Done')
|
||||
else
|
||||
disp('Keeping empty spaces for missing projections. Problems are expected if you continue.')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
par.scanstomo = scanstomo;
|
||||
par.num_proj=numel(scanstomo);
|
||||
|
||||
pixel_scale = pixel_scale ./ mean(pixel_scale);
|
||||
|
||||
assert(par.num_proj > 0, 'No projections loaded')
|
||||
|
||||
|
||||
if all(all(abs(pixel_scale)-1 < 1e-6)) || ~any(isfinite(mean(pixel_scale)))
|
||||
%if all datasets have the same pixel scale
|
||||
pixel_scale = [1,1];
|
||||
else
|
||||
warning('Datasets do not have equal pixel sizes, auto-rescaling projections')
|
||||
% use FFT base rescaling -> apply illumination function first to remove
|
||||
% effect of the noise out of the reconstruction region
|
||||
rot_fun = @(x,sx,sy)(utils.imrescale_frft(x .* par.illum_sum, sx, sy)) ./ ( max(0,utils.imrescale_frft(par.illum_sum,sx,sy))+1e-2*max(par.illum_sum(:)));
|
||||
stack_object = tomo.block_fun(rot_fun,stack_object, pixel_scale(:,1),pixel_scale(:,2));
|
||||
pixel_scale = [1,1];
|
||||
end
|
||||
|
||||
|
||||
par.pixel_scale = pixel_scale;
|
||||
%par.energy = energy;
|
||||
|
||||
%% clip the projections ampltitude by quantile filter
|
||||
if par.clip_amplitude_quantile < 1
|
||||
MAX = quantile(reshape(abs(fp16.get(stack_object(1:10:end,1:10:end,:))), [], par.num_proj), par.clip_amplitude_quantile ,1);
|
||||
MAX = reshape(MAX,1,1,par.num_proj);
|
||||
clip_fun = @(x,M)(min(abs(x),M) .* x ./ (abs(x) + 1e-5));
|
||||
stack_object = tomo.block_fun(clip_fun,stack_object, MAX, struct('use_GPU', true));
|
||||
end
|
||||
|
||||
if size(stack_object,3) ~= length(theta) || length(theta) ~= par.num_proj
|
||||
error('Inconsistency between number of angles and projections')
|
||||
end
|
||||
|
||||
|
||||
%{
|
||||
if ~isempty(par.tomo_id) && all(par.tomo_id > 0)
|
||||
% sanity safety check, all loaded angles correpont to the stored angles
|
||||
[~,theta_test] = prepare.load_angles(par, par.scanstomo, [], false);
|
||||
if max(abs(theta - theta_test)) > 180/par.num_proj/2
|
||||
error('Some angles have angles different from expected')
|
||||
end
|
||||
end
|
||||
%}
|
||||
|
||||
|
||||
%% replot angle
|
||||
plot_angles = true;
|
||||
if par.verbose_level && plot_angles
|
||||
plotting.smart_figure(1);
|
||||
subplot(2,1,1)
|
||||
plot(par.scanstomo,theta,'ob'); grid on;
|
||||
xlim(par.scanstomo([1,end]))
|
||||
%legend('Tilt angles')
|
||||
xlabel('Scan #')
|
||||
ylabel('Tilt angles')
|
||||
|
||||
%[anglessort,~] = sort(theta);
|
||||
|
||||
subplot(2,1,2)
|
||||
plot(diff(theta))
|
||||
ylabel('Angle increment')
|
||||
%title('Angular spacing');
|
||||
grid on;
|
||||
xlim([1,par.num_proj-1])
|
||||
if par.windowautopos
|
||||
screensize = get( groot, 'Screensize' );
|
||||
win_size = [946 815];
|
||||
set(gcf,'Outerposition',[139 min(163,screensize(4)-win_size(2)) win_size]); %[left, bottom, width, height]
|
||||
end
|
||||
title('Measured angles')
|
||||
drawnow
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,452 @@
|
||||
% LOAD_PROJECTIONS_FAST load reconstructed projections from disk to RAM
|
||||
%
|
||||
% [stack_object, theta,num_proj, par] = load_projections_fast(par, exclude_scans, dims_ob, theta, custom_preprocess_fun)
|
||||
%
|
||||
% Inputs:
|
||||
% **par - parameter structure
|
||||
% **exclude_scans - list of scans to be excluded from loading, [] = none
|
||||
% **dims_ob - dimension of the object
|
||||
% **theta - angles of the scans
|
||||
% **custom_preprocess_fun - function to be applied on the loaded data, eg cropping , rotation, etc
|
||||
%
|
||||
% *returns*
|
||||
% ++stack_object - loaded complex-valued projections
|
||||
% ++theta - angles corresponding to the loaded projections, angles for missing projections are removed
|
||||
% ++num_proj - number of projections
|
||||
% ++par - updated parameter structure
|
||||
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| Except where otherwise noted, this work is licensed under a |
|
||||
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||
%| International (CC BY-NC-SA 4.0) license. |
|
||||
%| |
|
||||
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||
%| |
|
||||
%| Author: CXS group, PSI |
|
||||
%*-----------------------------------------------------------------------*
|
||||
% You may use this code with the following provisions:
|
||||
%
|
||||
% If the code is fully or partially redistributed, or rewritten in another
|
||||
% computing language this notice should be included in the redistribution.
|
||||
%
|
||||
% If this code, or subfunctions or parts of it, is used for research in a
|
||||
% publication or if it is fully or partially rewritten for another
|
||||
% computing language the authors and institution should be acknowledged
|
||||
% in written form in the publication: "Data processing was carried out
|
||||
% using the "cSAXS matlab package" developed by the CXS group,
|
||||
% Paul Scherrer Institut, Switzerland."
|
||||
% Variations on the latter text can be incorporated upon discussion with
|
||||
% the CXS group if needed to more specifically reflect the use of the package
|
||||
% for the published work.
|
||||
%
|
||||
% A publication that focuses on describing features, or parameters, that
|
||||
% are already existing in the code should be first discussed with the
|
||||
% authors.
|
||||
%
|
||||
% This code and subroutines are part of a continuous development, they
|
||||
% are provided "as they are" without guarantees or liability on part
|
||||
% of PSI or the authors. It is the user responsibility to ensure its
|
||||
% proper use and the correctness of the results.
|
||||
|
||||
|
||||
|
||||
function [stack_object, theta,num_proj, par] = load_projections_fast(par, exclude_scans, dims_ob, theta, custom_preprocess_fun)
|
||||
|
||||
import ptycho.*
|
||||
import utils.*
|
||||
import io.*
|
||||
import plotting.imagesc3D
|
||||
utils.verbose(struct('prefix', 'loading'))
|
||||
|
||||
if nargin < 5
|
||||
custom_preprocess_fun = [];
|
||||
end
|
||||
if ~isempty(custom_preprocess_fun) && ishandle(custom_preprocess_fun) && ~strcmpi(func2str(custom_preprocess_fun), '@(x)x')
|
||||
custom_preprocess_fun = [] ;
|
||||
end
|
||||
|
||||
scanstomo = par.scanstomo;
|
||||
|
||||
% avoid loading scans listed in 'exclude_scans'
|
||||
if ~isempty(exclude_scans)
|
||||
ind = ismember(scanstomo, exclude_scans);
|
||||
%% clear values corresponding to excluded scans
|
||||
scanstomo(ind) = [];
|
||||
theta(ind) = [];
|
||||
par.subtomos(ind) = [];
|
||||
end
|
||||
|
||||
|
||||
|
||||
% % plot average vibrations for each of the loaded projections
|
||||
% utils.verbose(0,'Checking stability of the projections')
|
||||
% poor_projections = prepare.plot_sample_stability(par, scanstomo, ~par.online_tomo, par.pixel_size);
|
||||
% if sum(poor_projections) && ...
|
||||
% (par.online_tomo || ~strcmpi(input(sprintf('Remove %i low stability projections: [Y/n]\n',sum(poor_projections)), 's'), 'n') )
|
||||
% theta(poor_projections) = [];
|
||||
% scanstomo(poor_projections) = [];
|
||||
% else
|
||||
% utils.verbose(0,'All projections are fine')
|
||||
% end
|
||||
|
||||
|
||||
|
||||
verbose(0,'Checking available files')
|
||||
verbose(0); % make it quiet
|
||||
missing_scans = [];
|
||||
proj_file_names = cell(length(scanstomo),1);
|
||||
for num = 1:length(scanstomo)
|
||||
progressbar(num, length(scanstomo))
|
||||
filename = find_projection_files_names(par, scanstomo(num));
|
||||
if isempty(filename)
|
||||
missing_scans(end+1) = scanstomo(num);
|
||||
continue
|
||||
end
|
||||
proj_file_names{num} = filename;
|
||||
|
||||
end
|
||||
|
||||
verbose(par.verbose_level); % return to original settings
|
||||
|
||||
if ~isempty(missing_scans)
|
||||
plotting.smart_figure(1)
|
||||
subplot(2,1,1)
|
||||
hold on
|
||||
plot(missing_scans, theta(ismember(scanstomo, missing_scans)), 'rx', 'Linewidth', 2)
|
||||
hold off
|
||||
legend({'Measured angles', 'Missing scans'})
|
||||
axis tight
|
||||
drawnow
|
||||
|
||||
ind = ismember(scanstomo, missing_scans);
|
||||
verbose(1,['Scans not found are ' num2str(missing_scans)])
|
||||
verbose(1,['Projections not found are ' num2str(find(ind))])
|
||||
%% clear values corresponding to measured but missing scans (not reconstructed)
|
||||
scanstomo(ind) = [];
|
||||
theta(ind) = [];
|
||||
proj_file_names(ind) = [];
|
||||
par.subtomos(ind) = [];
|
||||
else
|
||||
verbose(1,'All projections found')
|
||||
end
|
||||
|
||||
num_proj = length(scanstomo);
|
||||
|
||||
if isfield(par, 'fp16_precision') && par.fp16_precision
|
||||
dtype = uint16(1i); % use uint32 to store half floar precision data
|
||||
else
|
||||
dtype= single(1i);
|
||||
end
|
||||
|
||||
downsample = 2^par.downsample_projections; % calculate downsample factor for binning , default par.downsample_projections = 0;
|
||||
|
||||
pixel_size =zeros(num_proj,2);
|
||||
energy = zeros(num_proj,1);
|
||||
stack_object=zeros(ceil(dims_ob(1) / downsample),ceil(dims_ob(2) / downsample),num_proj, 'like', dtype);
|
||||
residua = zeros(num_proj,1);
|
||||
|
||||
%disp(size(stack_object))
|
||||
tic
|
||||
|
||||
|
||||
% load at least 10 frames per worker to use well the resources
|
||||
block_size = max(1, feature('numcores'))*4;
|
||||
|
||||
object_ROI = {ceil(1+par.asize(1)/2/downsample):ceil((dims_ob(1)-par.asize(1)/2)/downsample),ceil(1+par.asize(2)/2/downsample):ceil((dims_ob(2)-par.asize(2)/2)/downsample)};
|
||||
|
||||
verbose(1,'Loading projections ...')
|
||||
|
||||
missing_all = [];
|
||||
t0 = tic;
|
||||
%% load data, use parfor but process blockwise to avoid large memory use and also allow user stopping during MEX reading
|
||||
for block_id = 1:ceil(num_proj/block_size)
|
||||
block_inds = 1+(block_id-1)*block_size: min(num_proj, block_id*block_size);
|
||||
utils.progressbar(block_id, ceil(num_proj/block_size))
|
||||
|
||||
if strcmpi(par.file_extension, 'h5') && ~verLessThan('matlab', '9.4') && ...
|
||||
(isfield(par, 'use_mex_loader') && par.use_mex_loader ) % only matlab newer than R2018a is supported
|
||||
object_block = [];
|
||||
try
|
||||
% fast MEX loader, sometimes it tends to fail and needs to
|
||||
% be run again to load the data corectly
|
||||
[object_block,missing_tmp] = mex_read(par.dims_ob_loaded, proj_file_names(block_inds), par.Nthreads_mexread);
|
||||
catch Err
|
||||
disp('Error in loading using MEX, falling back to matlab reader, try to reduce par.Nthreads_mexread is this warning repeats often')
|
||||
disp(Err)
|
||||
end
|
||||
|
||||
% if loading was not succeful ..
|
||||
if isempty(object_block)
|
||||
[object_block, missing_tmp] = matlab_read(par.dims_ob_loaded, proj_file_names(block_inds));
|
||||
end
|
||||
else
|
||||
% loading using matlab for original MAT file data or old matlab
|
||||
[object_block, missing_tmp] = matlab_read(par.dims_ob_loaded, proj_file_names(block_inds));
|
||||
end
|
||||
missing_all = [missing_all, block_inds(missing_tmp)];
|
||||
|
||||
|
||||
% read additional information
|
||||
for jj = setdiff(block_inds, block_inds(missing_tmp)) % remove missing projection from loading
|
||||
if strcmpi(par.file_extension, 'h5')
|
||||
try
|
||||
pixel_size(jj,:) = h5read(proj_file_names{jj}, '/reconstruction/p/dx_spec');
|
||||
energy(jj) = h5read(proj_file_names{jj}, '/reconstruction/p/energy');
|
||||
catch err
|
||||
disp(err)
|
||||
keyboard
|
||||
end
|
||||
else
|
||||
% load it from the matlab file is not supported (it is too slow)
|
||||
pixel_size(jj,:) = par.pixel_size;
|
||||
energy(jj) = nan;
|
||||
end
|
||||
end
|
||||
|
||||
%% apply custom data proprocessing and caculate basic statistics, DO IT ON GPU
|
||||
[object_block, residua(block_inds,1), projection_value(block_inds)] = ...
|
||||
tomo.block_fun(@process_projection_block, object_block, custom_preprocess_fun, par, object_ROI,pixel_size(block_inds,:), struct('verbose_level', 0));
|
||||
|
||||
% convert data to fp16 precision if requested
|
||||
if isfield(par, 'fp16_precision') && par.fp16_precision
|
||||
object_block = fp16.set(object_block);
|
||||
end
|
||||
|
||||
|
||||
|
||||
stack_object(:,:,block_inds) = object_block;
|
||||
|
||||
end
|
||||
|
||||
pixel_size = min(pixel_size,[],2); % projection were already rescaled to provide the same pixel size in each dimension
|
||||
|
||||
verbose(1, 'Data loaded in %is', round(toc(t0)))
|
||||
|
||||
% downsample the illum_sum if requested
|
||||
if downsample > 0
|
||||
par.illum_sum = utils.binning_2D(crop_pad(par.illum_sum, ceil(dims_ob/downsample)*downsample) , downsample);
|
||||
par.asize = ceil(par.asize / downsample);
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
failed_projections = projection_value < 0.1*median(projection_value) | ismember(1:num_proj, missing_all) | ~isfinite(projection_value);
|
||||
|
||||
if any(failed_projections )
|
||||
verbose(0,['Projections failed are ' num2str(find(failed_projections))])
|
||||
verbose(0,['Scans failed are ' num2str(scanstomo(failed_projections))])
|
||||
else
|
||||
verbose(0,'All loaded projections seems OK')
|
||||
end
|
||||
|
||||
|
||||
[Nprojections] = size(stack_object,3);
|
||||
poor_projections = false;
|
||||
|
||||
if ~par.is_laminography
|
||||
% laminography has a more complex definition of field of view ->
|
||||
% currently not implemented
|
||||
|
||||
poor_projections = (residua(:)' > par.max_residua_limit) ; % ignore in the case of laminography
|
||||
verbose(1, 'Found %i/%i projections with more than %i residues ', sum(poor_projections), Nprojections, par.max_residua_limit)
|
||||
if any(poor_projections)
|
||||
verbose(1,['Projections with residua are ' num2str(find(poor_projections))])
|
||||
verbose(1,['Scans with residua are ' num2str(scanstomo(poor_projections))])
|
||||
end
|
||||
end
|
||||
verbose(1, 'Find residua done')
|
||||
|
||||
|
||||
% avoid also empty projections
|
||||
which_remove = poor_projections | failed_projections;
|
||||
|
||||
%%% Getting rid of missing projections %%%
|
||||
if any(which_remove)
|
||||
|
||||
[Nx,Ny,~] = size(stack_object);
|
||||
title_extra = {};
|
||||
for ii = 1:num_proj
|
||||
if which_remove(ii)
|
||||
title_extra{end+1} = sprintf(' N residua: %i',residua(ii));
|
||||
end
|
||||
end
|
||||
|
||||
verbose(1,' %i failed projections shown in figure(1) \n', sum(which_remove))
|
||||
|
||||
tomo.show_projections(stack_object(:,:,which_remove), theta(which_remove), par, 'fnct', @angle, ...
|
||||
'title', 'Projection to be removed','plot_residua', true, 'title_extra', title_extra, ...
|
||||
'rectangle_pos', [par.asize(2)/2,Ny-par.asize(2)/2, par.asize(1)/2,Nx-par.asize(1)/2], 'figure_id', 1)
|
||||
|
||||
|
||||
|
||||
if par.online_tomo || debug() || ~strcmpi(input(sprintf('Do you want remove %i failed/wrong projections and keep going (Y/n)?',sum(which_remove)),'s'),'n')
|
||||
verbose(0,'Removing failed/wrong projections. stack_object, scanstomo, theta and num_proj are modified')
|
||||
|
||||
stack_object(:,:,which_remove) = [];
|
||||
scanstomo(which_remove)=[];
|
||||
theta(which_remove)=[];
|
||||
pixel_size(which_remove,:) = [];
|
||||
energy(which_remove,:) = [];
|
||||
residua(which_remove)=[];
|
||||
par.subtomos(which_remove) = [];
|
||||
|
||||
verbose(0,'Done')
|
||||
else
|
||||
verbose(0,'Keeping empty spaces for failed projections. Problems are expected if you continue.')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
par.scanstomo = scanstomo;
|
||||
par.num_proj=numel(scanstomo);
|
||||
|
||||
% store number of residua for later processing
|
||||
par.nresidua_per_frame = residua(:)';
|
||||
|
||||
pixel_scale = pixel_size ./ min(pixel_size(:)); % just in case that the axis do not have indetical pixel size, NOT TESTED YET
|
||||
|
||||
assert(par.num_proj > 0, 'No projections loaded')
|
||||
|
||||
|
||||
if all(all(abs(pixel_scale)-1 < 1e-6)) || ~any(isfinite(mean(pixel_scale)))
|
||||
%if all datasets have the same pixel scale
|
||||
pixel_scale = [1,1];
|
||||
else
|
||||
warning('Datasets do not have equal pixel sizes, auto-rescaling projections')
|
||||
% use FFT base rescaling -> apply illumination function first to remove
|
||||
% effect of the noise out of the reconstruction region
|
||||
rot_fun = @(x,sx,sy)(utils.imrescale_frft(x .* par.illum_sum, sx, sy)) ./ ( max(0,utils.imrescale_frft(par.illum_sum,sx,sy))+1e-2*max(par.illum_sum(:)));
|
||||
stack_object = tomo.block_fun(rot_fun,stack_object, pixel_scale(:,1),pixel_scale(:,2));
|
||||
pixel_scale = [1,1];
|
||||
end
|
||||
|
||||
|
||||
par.pixel_scale = pixel_scale;
|
||||
par.energy = energy;
|
||||
|
||||
|
||||
|
||||
if size(stack_object,3) ~= length(theta) || length(theta) ~= par.num_proj
|
||||
error('Inconsistency between number of angles and projections')
|
||||
end
|
||||
utils.verbose(struct('prefix', 'template'))
|
||||
|
||||
|
||||
end
|
||||
|
||||
function [object_block, residua, projection_value] = process_projection_block(object_block, custom_preprocess_fun, par, object_ROI, pixel_size)
|
||||
% auxiliary function used to apply various preprocessing steps, ie custom_preprocess_fun, binning, clipping and residua calculation on the
|
||||
% object_block on GPU -> avoid CPU-GPU transfer overhead
|
||||
% returns:
|
||||
% object_block - processed complex valued projections
|
||||
% residua - number of residua in each frame
|
||||
% projection_value - average amplitude of the projection
|
||||
% pixel_size in each dimension
|
||||
|
||||
% apply additional processing, e.g. rotation
|
||||
if ~isempty(custom_preprocess_fun)
|
||||
object_block = custom_preprocess_fun(object_block);
|
||||
end
|
||||
|
||||
if any(pixel_size(:,1) ~= pixel_size(:,2))
|
||||
% in the case of asymmetric pixel size,
|
||||
% upsample the data in the dimennsion with lower resolution (-> at least relax issues in tomography interpolation)
|
||||
pixel_scale = pixel_size ./ min(pixel_size,[],2) ;
|
||||
assert(all(std(pixel_scale) < 1e-3), 'Variable resolution between projection and asymmetric pixel size is not implemented')
|
||||
|
||||
Npix = size(object_block);
|
||||
dims_ob_new = round(Npix(1:2) .* pixel_scale(1,:));
|
||||
object_block = utils.interpolateFT(object_block, dims_ob_new);
|
||||
end
|
||||
|
||||
Npix = size(object_block);
|
||||
downsample = 2^par.downsample_projections;
|
||||
% downsample the data if requested
|
||||
if downsample > 1
|
||||
object_block = utils.binning_2D(utils.crop_pad(object_block, ceil(Npix/downsample)*downsample) , downsample);
|
||||
end
|
||||
|
||||
%% clip the projections amplitude by quantile filter
|
||||
if par.clip_amplitude_quantile > 0 && par.clip_amplitude_quantile < 1
|
||||
MAX = quantile(reshape(abs(object_block(1:10:end,1:10:end,:)), [], Npix(3)), par.clip_amplitude_quantile ,1);
|
||||
MAX = reshape(MAX,1,1,[]);
|
||||
clip_fun = @(x,M)(min(abs(x),M) .* x ./ (abs(x) + 1e-5));
|
||||
object_block = clip_fun(object_block, MAX);
|
||||
end
|
||||
|
||||
residua = squeeze(math.sum2(abs(utils.findresidues(object_block(object_ROI{:},:)))>0.1));
|
||||
projection_value = squeeze(math.sum2(abs(object_block)));
|
||||
|
||||
end
|
||||
|
||||
function [object_block, missing] = matlab_read(dims_ob, proj_file_names)
|
||||
% projection loading using matlab
|
||||
% Inputs:
|
||||
% dims_ob - projection size
|
||||
% proj_file_names - cell of filenames to be loaded
|
||||
% Outputs:
|
||||
% object_block - loaded projection
|
||||
% missing - list of missing (failed) projections
|
||||
|
||||
object_block = zeros([dims_ob,length(proj_file_names)], 'like', single(1i));
|
||||
loaded = false(length(proj_file_names),1);
|
||||
for jj = 1:length(proj_file_names)
|
||||
utils.verbose(2,['Reading file: ' proj_file_names{jj}])
|
||||
try
|
||||
object = io.load_ptycho_recons(proj_file_names{jj}, 'object');
|
||||
object = single(object.object);
|
||||
object = prod(object,4); % use only the eDOF object if multiple layers are available
|
||||
object_block(:,:,jj) = utils.crop_pad(object, dims_ob);
|
||||
loaded(jj) = true;
|
||||
catch
|
||||
utils.verbose(-1,'Loading of file %s failed', proj_file_names{jj})
|
||||
end
|
||||
end
|
||||
missing = find(~loaded);
|
||||
end
|
||||
|
||||
|
||||
|
||||
function [object_block, missing] = mex_read(dims_ob, proj_file_names, Nthreads)
|
||||
% fast projection loader by MEX with paralelization
|
||||
% Inputs:
|
||||
% dims_ob - projection size
|
||||
% proj_file_names - cell of filenames to be loaded
|
||||
% Nthreads - number of threads used to load the projections in parallel
|
||||
% Outputs:
|
||||
% object_block - loaded projection
|
||||
% missing - list of missing (failed) projections
|
||||
|
||||
Nthreads = min(length(proj_file_names),Nthreads );
|
||||
|
||||
proj_file_names = reshape(proj_file_names, 1,[]);
|
||||
|
||||
% load complex-valued projections using parallel MEX
|
||||
try
|
||||
[object_block, missing] = io.ptycho_read(Nthreads, 'single', dims_ob, '/reconstruction/object', proj_file_names);
|
||||
catch err
|
||||
if strcmpi(err.identifier, 'ptycho:read:failed')
|
||||
Nthreads = 5;
|
||||
[object_block, missing] = io.ptycho_read(Nthreads, 'single', dims_ob, '/reconstruction/object', proj_file_names);
|
||||
warning off backtrace
|
||||
warning('===================================================================================================================================')
|
||||
warning('Loading of projections failed due to too high multithreading, if this warning repeats, consider lowering par.Nthreads_mexread value')
|
||||
warning('===================================================================================================================================')
|
||||
warning on backtrace
|
||||
else
|
||||
rethrow(err)
|
||||
end
|
||||
end
|
||||
assert(ndims(object_block) <= 5, 'Unexpected dimensionality of inputs')
|
||||
|
||||
object_block = permute(object_block, [2,1,3,4,5]); % transpose loaded reconstructions
|
||||
object_block = prod(object_block,4) ; % get one eDoF frame if ML reconstruction is used
|
||||
object_block = squeeze(object_block); % get rid of extra dimensions
|
||||
|
||||
assert(ndims(object_block) == 3, 'Unexpected dimensionality of inputs')
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,400 @@
|
||||
% LOAD_PROJECTIONS_MATLAB load reconstructed projections from disk to RAM
|
||||
% created by YJ based on PSI's function
|
||||
% [stack_object, theta,num_proj, par] = load_projections_matlab(par, exclude_scans, dims_ob, theta, custom_preprocess_fun)
|
||||
%
|
||||
% Inputs:
|
||||
% **par - parameter structure
|
||||
% **exclude_scans - list of scans to be excluded from loading, [] = none
|
||||
% **dims_ob - dimension of the object
|
||||
% **theta - angles of the scans
|
||||
% **custom_preprocess_fun - function to be applied on the loaded data, eg cropping , rotation, etc
|
||||
%
|
||||
% *returns*
|
||||
% ++stack_object - loaded complex-valued projections
|
||||
% ++theta - angles corresponding to the loaded projections, angles for missing projections are removed
|
||||
% ++num_proj - number of projections
|
||||
% ++par - updated parameter structure
|
||||
|
||||
function [stack_object, theta,num_proj, par] = load_projections_matlab(par, exclude_scans, dims_ob, theta, custom_preprocess_fun)
|
||||
|
||||
import ptycho.*
|
||||
import utils.*
|
||||
import io.*
|
||||
import plotting.*
|
||||
|
||||
if nargin < 5
|
||||
custom_preprocess_fun = [];
|
||||
end
|
||||
if ~isempty(custom_preprocess_fun) && ishandle(custom_preprocess_fun) && ~strcmpi(func2str(custom_preprocess_fun), '@(x)x')
|
||||
custom_preprocess_fun = [] ;
|
||||
end
|
||||
|
||||
scanstomo = par.scanstomo;
|
||||
if isfield(par,'energy')
|
||||
energy = par.energy;
|
||||
else
|
||||
energy = zeros(length(theta),1);
|
||||
end
|
||||
|
||||
% avoid loading scans listed in 'exclude_scans'
|
||||
if ~isempty(exclude_scans)
|
||||
ind = ismember(scanstomo, exclude_scans);
|
||||
scanstomo(ind) = [];
|
||||
theta(ind) = [];
|
||||
energy(ind) = [];
|
||||
end
|
||||
|
||||
% % plot average vibrations for each of the laoded projections
|
||||
% disp('Checking stability of the projections')
|
||||
% poor_projections = prepare.plot_sample_stability(par, scanstomo, ~par.online_tomo, par.pixel_size);
|
||||
% if sum(poor_projections) && ...
|
||||
% (par.online_tomo || ~strcmpi(input(sprintf('Remove %i low stability projections: [Y/n]\n',sum(poor_projections)), 's'), 'n') )
|
||||
% theta(poor_projections) = [];
|
||||
% scanstomo(poor_projections) = [];
|
||||
% else
|
||||
% disp('All projections are fine')
|
||||
% end
|
||||
|
||||
verbose(1,'Checking available files')
|
||||
missing_scans = [];
|
||||
proj_file_names = {};
|
||||
proj_recon_method = {};
|
||||
proj_roi = {};
|
||||
proj_scanNo = {};
|
||||
for num = 1:length(scanstomo)
|
||||
progressbar(num, length(scanstomo))
|
||||
%proj_file_names{num} = find_ptycho_filename(par.analysis_path,scanstomo(num),par.fileprefix,par.filesuffix, par.file_extension);
|
||||
%proj_file_names{num} = find_projection_files_names_aps(par, scanstomo(num));
|
||||
[proj_file_names{num},proj_recon_method{num},proj_roi{num},proj_scanNo{num}] = find_ML_recon_files_names(par, scanstomo(num));
|
||||
%disp(proj_file_names{num})
|
||||
if isempty(proj_file_names{num})
|
||||
missing_scans(end+1) = scanstomo(num);
|
||||
end
|
||||
end
|
||||
|
||||
verbose(par.verbose_level); % return to original settings
|
||||
%{
|
||||
figure(1)
|
||||
subplot(2,1,1)
|
||||
hold on
|
||||
plot(missing_scans, theta(ismember(scanstomo, missing_scans)), 'rx')
|
||||
hold off
|
||||
legend({'Measured angles', 'Missing projections'})
|
||||
axis tight
|
||||
%}
|
||||
|
||||
if ~isempty(missing_scans)
|
||||
ind = ismember(scanstomo, missing_scans);
|
||||
verbose(1,['Scans not found are ' num2str(missing_scans)])
|
||||
verbose(1,['Projections not found are ' num2str(find(ind))])
|
||||
scanstomo(ind) = [];
|
||||
theta(ind) = [];
|
||||
proj_file_names(ind) = [];
|
||||
proj_recon_method(ind) = [];
|
||||
proj_roi(ind) = [];
|
||||
proj_scanNo(ind) = [];
|
||||
energy(ind) = [];
|
||||
else
|
||||
verbose(1,'All projections found')
|
||||
end
|
||||
|
||||
num_proj = length(scanstomo);
|
||||
object_size_orig = zeros(2,num_proj);
|
||||
if isfield(par, 'fp16_precision') && par.fp16_precision
|
||||
% use uint32 to store half floar precision data
|
||||
stack_object=zeros(dims_ob(1),dims_ob(2),num_proj, 'like', fp16.set(1i));
|
||||
else
|
||||
stack_object=zeros(dims_ob(1),dims_ob(2),num_proj, 'like', single(1i));
|
||||
end
|
||||
pixel_size =zeros(num_proj,2);
|
||||
|
||||
tic
|
||||
|
||||
if num_proj == 0
|
||||
verbose(0, 'No new projections loaded')
|
||||
return
|
||||
end
|
||||
|
||||
which_missing = false(1,num_proj); % Include here INDEX numbers that you want to exclude (bad reconstructions)
|
||||
|
||||
utils.check_available_memory
|
||||
%%
|
||||
wb = waitbar(0,'1','Name','Loading ptycho-tomo projection...',...
|
||||
'CreateCancelBtn','setappdata(gcbf,''canceling'',1)');
|
||||
setappdata(wb,'canceling',0);
|
||||
%
|
||||
t0 = tic;
|
||||
|
||||
for num=1:num_proj
|
||||
% Update waitbar and message
|
||||
status = sprintf(par.scan_string_format, scanstomo(num));
|
||||
status = strcat(status,' (',num2str(num),'/',num2str(num_proj),') ');
|
||||
|
||||
if num>1
|
||||
timeLeft = (num_proj-num+1)*avgTimePerIter;
|
||||
|
||||
if timeLeft>3600
|
||||
time_status = sprintf(' Time left:%3.3g hour', timeLeft/3600);
|
||||
elseif timeLeft>60
|
||||
time_status = sprintf(' Time left:%3.3g min', timeLeft/60);
|
||||
else
|
||||
time_status = sprintf(' Time left:%3.3g sec', timeLeft);
|
||||
end
|
||||
status = strcat(status,time_status);
|
||||
end
|
||||
waitbar(num/num_proj,wb,status)
|
||||
|
||||
% Check for clicked Cancel button
|
||||
if getappdata(wb,'canceling')
|
||||
break
|
||||
end
|
||||
file = proj_file_names{num};
|
||||
|
||||
if ismember(scanstomo(num), exclude_scans)
|
||||
warning(['Skipping by user request: ' file{1}])
|
||||
continue % skip the frames that are listed in exclude_scans
|
||||
end
|
||||
|
||||
if ~iscell(file)
|
||||
file = {file}; % make them all cells
|
||||
end
|
||||
object= [];
|
||||
for jj = length(file):-1:1
|
||||
for ii=1:3
|
||||
try
|
||||
object = load(file{1},'object');
|
||||
object = single(object.object);
|
||||
|
||||
parameter = load(file{1},'p');
|
||||
pixel_size(num,:) = parameter.p.dx_spec; %pixel size
|
||||
break
|
||||
catch
|
||||
%warning(['Loading failed: ' [file{1}]])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if isempty(object) || all(object(:) == 0 )
|
||||
which_missing(num) = true;
|
||||
warning(['Loading failed: ' [file{:}]])
|
||||
continue
|
||||
end
|
||||
|
||||
% for multislice recon - sum layers into a single projection
|
||||
if size(object,3)>1
|
||||
if isfield(par.MLrecon,'select_layers') && any(par.MLrecon.select_layers)
|
||||
object = prod(object(:,:,par.MLrecon.select_layers),3);
|
||||
else
|
||||
object = prod(object,3);
|
||||
end
|
||||
end
|
||||
|
||||
%%
|
||||
object_size_orig(:,num) = size(object);
|
||||
if isfield(par, 'crop_edge') && par.crop_edge>0
|
||||
object = object(1+par.crop_edge:end-par.crop_edge,1+par.crop_edge:end-par.crop_edge);
|
||||
end
|
||||
if ~isempty(custom_preprocess_fun)
|
||||
object = custom_preprocess_fun(object);
|
||||
end
|
||||
|
||||
nx = dims_ob(2);
|
||||
ny = dims_ob(1);
|
||||
|
||||
if size(object,2) > nx
|
||||
object = object(:,1:nx);
|
||||
elseif size(object,2) < nx
|
||||
object = padarray(object,[0 nx-size(object,2)],'post');
|
||||
end
|
||||
|
||||
if size(object,1) > ny
|
||||
if par.auto_alignment|| par.get_auto_calibration
|
||||
object = object(1:ny,:);
|
||||
else
|
||||
shifty = floor((size(object,1)-ny)/2);
|
||||
object = object([1:ny]+shifty,:);
|
||||
end
|
||||
elseif size(object,1) < ny
|
||||
if par.auto_alignment||par.get_auto_calibration
|
||||
object = padarray(object,[ny-size(object,1) 0],'post');
|
||||
else
|
||||
shifty = (ny-size(object,1))/2;
|
||||
object = padarray(object,[ny-size(object,1)-floor(shifty) 0],'post');
|
||||
object = padarray(object,[floor(shifty) 0],'pre');
|
||||
end
|
||||
end
|
||||
|
||||
stack_object(:,:,num) = object;
|
||||
|
||||
% if par.showrecons
|
||||
% mag=a+bs(object);
|
||||
% phase=angle(object);
|
||||
% figure(1); clf
|
||||
% imagesc(mag); axis xy equal tight ; colormap bone(256); colorbar;
|
||||
% title(['object magnitude S',sprintf('%05d',ii),', Projection ' ,sprintf('%03d',num) , ', Theta = ' sprintf('%.2f',theta(num)), ' degrees']);drawnow;
|
||||
% set(gcf,'Outerposition',[601 424 600 600])
|
||||
% figure(2); imagesc(phase); axis xy equal tight; colormap bone(256); colorbar;
|
||||
% title(['object phase S',sprintf('%05d',ii),', Projection ' ,sprintf('%03d',num) , ', Theta = ' sprintf('%.2f',theta(num)), ' degrees']);drawnow;
|
||||
% set(gcf,'Outerposition',[1 424 600 600]) %[left, bottom, width, height
|
||||
% figure(3); % imagesc3D(probe);
|
||||
% axis xy equal tight
|
||||
% set(gcf,'Outerposition',[600 49 375 375]) %[left, bottom, width, height
|
||||
% figure(4);
|
||||
% if isfield(p, 'err')
|
||||
% loglog(p.err);
|
||||
% elseif isfield(p, 'mlerror')
|
||||
% loglog(p.mlerror)
|
||||
% elseif isfield(p, 'error_metric')
|
||||
% loglog(p.error_metric(2).iteration,p.error_metric(2).value)
|
||||
% end
|
||||
% title(sprintf('Error %03d',num))
|
||||
% set(gcf,'Outerposition',[1 49 600 375]) %[left, bottom, width, height
|
||||
% drawnow;
|
||||
% end
|
||||
|
||||
avgTimePerIter = toc(t0)/num;
|
||||
|
||||
end % enf of parfor
|
||||
delete(wb)
|
||||
%store info for ML reconstructions
|
||||
par.proj_file_names = proj_file_names;
|
||||
par.proj_recon_method = proj_recon_method;
|
||||
par.proj_roi = proj_roi;
|
||||
par.proj_scanNo = proj_scanNo;
|
||||
par.object_size_orig = object_size_orig;
|
||||
verbose(1, 'Data loaded')
|
||||
|
||||
%% examine projections
|
||||
verbose(1, 'Find residua')
|
||||
[Nx, Ny, Nprojections] = size(stack_object);
|
||||
|
||||
object_ROI = {ceil(1+par.asize(1)/2:Nx-par.asize(1)/2),ceil(1+par.asize(2)/2:Ny-par.asize(2)/2)};
|
||||
residua = tomo.block_fun(@(x)(squeeze(math.sum2(abs(utils.findresidues(x))>0.1))),stack_object, struct('ROI', {object_ROI}));
|
||||
|
||||
if isfield(par,'max_residua_limit')
|
||||
max_residua = par.max_residua_limit;
|
||||
else
|
||||
max_residua = 100;
|
||||
end
|
||||
poor_projections = (residua(:)' > max_residua) & ~par.is_laminography ; % ignore in the case of laminography
|
||||
|
||||
if any(poor_projections)
|
||||
verbose(1, 'Found %i/%i projections with more than %i residues ', sum(poor_projections), Nprojections, max_residua)
|
||||
end
|
||||
|
||||
if any(which_missing & ~ismember(scanstomo, exclude_scans) )
|
||||
missing = find(which_missing & ~ismember(scanstomo, exclude_scans));
|
||||
verbose(1,['Projections not found are ' num2str(missing)])
|
||||
verbose(1,['Scans not found are ' num2str(scanstomo(missing))])
|
||||
else
|
||||
verbose(1,'All projections loaded')
|
||||
end
|
||||
toc
|
||||
|
||||
% avoid also empty projections
|
||||
which_wrong = poor_projections | squeeze(math.sum2(stack_object)==0)';
|
||||
|
||||
if any(which_wrong & ~ismember(scanstomo, exclude_scans) )
|
||||
wrong = find(which_wrong & ~ismember(scanstomo, exclude_scans));
|
||||
verbose(1,['Projections failed are ' num2str(wrong)])
|
||||
verbose(1,['Scans failed are ' num2str(scanstomo(wrong))])
|
||||
else
|
||||
verbose(1,'All loaded projections are OK')
|
||||
end
|
||||
|
||||
%%% Getting rid of missing projections %%%
|
||||
which_remove = which_missing | which_wrong;
|
||||
if any(which_remove)
|
||||
if par.online_tomo || ~strcmpi(input(sprintf('Do you want remove %i missing/wrong projections and keep going (Y/n)?',sum(which_remove)),'s'),'n')
|
||||
disp('Removing missing/wrong projections. stack_object, scanstomo, theta and num_proj are modified')
|
||||
|
||||
stack_object(:,:,which_remove) = [];
|
||||
scanstomo(which_remove)=[];
|
||||
theta(which_remove)=[];
|
||||
pixel_size(which_remove,:) = [];
|
||||
energy(which_remove,:) = [];
|
||||
|
||||
disp('Done')
|
||||
else
|
||||
disp('Keeping empty spaces for missing projections. Problems are expected if you continue.')
|
||||
end
|
||||
end
|
||||
|
||||
par.scanstomo = scanstomo;
|
||||
par.num_proj=numel(scanstomo);
|
||||
|
||||
pixel_scale = pixel_size ./ mean(pixel_size);
|
||||
|
||||
assert(par.num_proj > 0, 'No projections loaded')
|
||||
|
||||
if all(all(abs(pixel_scale)-1 < 1e-6)) || ~any(isfinite(mean(pixel_scale)))
|
||||
%if all datasets have the same pixel scale
|
||||
pixel_scale = [1,1];
|
||||
else
|
||||
warning('Datasets do not have equal pixel sizes!')
|
||||
%warning('Datasets do not have equal pixel sizes, auto-rescaling projections')
|
||||
|
||||
% use FFT base rescaling -> apply illumination function first to remove
|
||||
% effect of the noise out of the reconstruction region
|
||||
|
||||
%rot_fun = @(x,sx,sy)(utils.imrescale_frft(x .* par.illum_sum, sx, sy)) ./ ( max(0,utils.imrescale_frft(par.illum_sum,sx,sy))+1e-2*max(par.illum_sum(:)));
|
||||
%stack_object = tomo.block_fun(rot_fun,stack_object, pixel_scale(:,1),pixel_scale(:,2));
|
||||
%pixel_scale = [1,1];
|
||||
end
|
||||
|
||||
par.pixel_scale = pixel_scale;
|
||||
par.pixel_size = pixel_size;
|
||||
par.energy = energy;
|
||||
|
||||
%% clip the projections ampltitude by quantile filter
|
||||
if par.clip_amplitude_quantile < 1
|
||||
MAX = quantile(reshape(abs(fp16.get(stack_object(1:10:end,1:10:end,:))), [], par.num_proj), par.clip_amplitude_quantile ,1);
|
||||
MAX = reshape(MAX,1,1,par.num_proj);
|
||||
clip_fun = @(x,M)(min(abs(x),M) .* x ./ (abs(x) + 1e-5));
|
||||
stack_object = tomo.block_fun(clip_fun,stack_object, MAX, struct('use_GPU', true));
|
||||
end
|
||||
|
||||
if size(stack_object,3) ~= length(theta) || length(theta) ~= par.num_proj
|
||||
error('Inconsistency between number of angles and projections')
|
||||
end
|
||||
|
||||
%{
|
||||
if ~isempty(par.tomo_id) && all(par.tomo_id > 0)
|
||||
% sanity safety check, all loaded angles correpont to the stored angles
|
||||
[~,theta_test] = prepare.load_angles(par, par.scanstomo, [], false);
|
||||
if max(abs(theta - theta_test)) > 180/par.num_proj/2
|
||||
error('Some angles have angles different from expected')
|
||||
end
|
||||
end
|
||||
%}
|
||||
|
||||
%% replot angle
|
||||
plot_angles = true;
|
||||
if par.verbose_level && plot_angles
|
||||
plotting.smart_figure(1);
|
||||
subplot(2,1,1)
|
||||
plot(par.scanstomo,theta,'ob'); grid on;
|
||||
xlim(par.scanstomo([1,end]))
|
||||
%legend('Tilt angles')
|
||||
xlabel('Scan #')
|
||||
ylabel('Tilt angles')
|
||||
|
||||
%[anglessort,~] = sort(theta);
|
||||
|
||||
subplot(2,1,2)
|
||||
plot(diff(theta))
|
||||
ylabel('Angle increment')
|
||||
%title('Angular spacing');
|
||||
grid on;
|
||||
xlim([1,par.num_proj-1])
|
||||
if par.windowautopos
|
||||
screensize = get( groot, 'Screensize' );
|
||||
win_size = [946 815];
|
||||
set(gcf,'Outerposition',[139 min(163,screensize(4)-win_size(2)) win_size]); %[left, bottom, width, height]
|
||||
end
|
||||
title('Measured angles')
|
||||
drawnow
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,68 @@
|
||||
% LOAD_PROJECTIONS_NUM_APS load reconstructed projections numbers
|
||||
% created by YJ based on PSI's function
|
||||
% Only read scan numbers, usedful for debugging
|
||||
% Inputs:
|
||||
% **par - parameter structure
|
||||
% **exclude_scans - list of scans to be excluded from loading, [] = none
|
||||
% **theta - angles of the scans
|
||||
|
||||
function [scanstomo] = load_projections_num_aps(par, exclude_scans, theta)
|
||||
|
||||
import ptycho.*
|
||||
import utils.*
|
||||
import io.*
|
||||
import plotting.*
|
||||
|
||||
scanstomo = par.scanstomo;
|
||||
|
||||
% avoid loading scans listed in 'exclude_scans'
|
||||
if ~isempty(exclude_scans)
|
||||
ind = ismember(scanstomo, exclude_scans);
|
||||
scanstomo(ind) = [];
|
||||
theta(ind) = [];
|
||||
end
|
||||
|
||||
verbose(1,'Checking available files')
|
||||
missing_scans = [];
|
||||
proj_file_names = {};
|
||||
proj_recon_method = {};
|
||||
proj_roi = {};
|
||||
proj_scanNo = {};
|
||||
for num = 1:length(scanstomo)
|
||||
progressbar(num, length(scanstomo))
|
||||
%proj_file_names{num} = find_ptycho_filename(par.analysis_path,scanstomo(num),par.fileprefix,par.filesuffix, par.file_extension);
|
||||
%proj_file_names{num} = find_projection_files_names_aps(par, scanstomo(num));
|
||||
[proj_file_names{num},proj_recon_method{num},proj_roi{num},proj_scanNo{num}] = find_ML_recon_files_names(par, scanstomo(num));
|
||||
%disp(proj_file_names{num})
|
||||
if isempty(proj_file_names{num})
|
||||
missing_scans(end+1) = scanstomo(num);
|
||||
end
|
||||
end
|
||||
|
||||
verbose(par.verbose_level); % return to original settings
|
||||
|
||||
if ~isempty(missing_scans)
|
||||
ind = ismember(scanstomo, missing_scans);
|
||||
verbose(1,['Scans not found are ' num2str(missing_scans)])
|
||||
verbose(1,['Projections not found are ' num2str(find(ind))])
|
||||
scanstomo(ind) = [];
|
||||
theta(ind) = [];
|
||||
proj_file_names(ind) = [];
|
||||
proj_recon_method(ind) = [];
|
||||
proj_roi(ind) = [];
|
||||
proj_scanNo(ind) = [];
|
||||
else
|
||||
verbose(1,'All projections found')
|
||||
end
|
||||
|
||||
num_proj = length(scanstomo);
|
||||
|
||||
|
||||
tic
|
||||
|
||||
if num_proj == 0
|
||||
verbose(0, 'No new projections loaded')
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,87 @@
|
||||
% MAKE_SYNTHETIC_PROJECTIONS creates projections that can be used as
|
||||
% initial guess for ptychography reconstruction in order to solver
|
||||
% iterativelly the ptychotomo task
|
||||
%
|
||||
% merged = make_synthetic_projections(stack_object, sinogram_abs, sinogram_phase,total_shift,object_ROI)
|
||||
%
|
||||
% Inputs:
|
||||
% **stack_object - measured projections
|
||||
% **sinogram_abs - aligned absorbtion sinogram
|
||||
% **sinogram_phase - aligned phase sinogram
|
||||
% **total_shift - reconstructed shifts oft the measured projections
|
||||
% **object_ROI - reliable region of the projections
|
||||
% Outputs:
|
||||
% merged - merged projections using stack_object, sinogram_abs and sinogram_phase
|
||||
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| Except where otherwise noted, this work is licensed under a |
|
||||
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||
%| International (CC BY-NC-SA 4.0) license. |
|
||||
%| |
|
||||
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||
%| |
|
||||
%| Author: CXS group, PSI |
|
||||
%*-----------------------------------------------------------------------*
|
||||
% You may use this code with the following provisions:
|
||||
%
|
||||
% If the code is fully or partially redistributed, or rewritten in another
|
||||
% computing language this notice should be included in the redistribution.
|
||||
%
|
||||
% If this code, or subfunctions or parts of it, is used for research in a
|
||||
% publication or if it is fully or partially rewritten for another
|
||||
% computing language the authors and institution should be acknowledged
|
||||
% in written form in the publication: "Data processing was carried out
|
||||
% using the "cSAXS matlab package" developed by the CXS group,
|
||||
% Paul Scherrer Institut, Switzerland."
|
||||
% Variations on the latter text can be incorporated upon discussion with
|
||||
% the CXS group if needed to more specifically reflect the use of the package
|
||||
% for the published work.
|
||||
%
|
||||
% A publication that focuses on describing features, or parameters, that
|
||||
% are already existing in the code should be first discussed with the
|
||||
% authors.
|
||||
%
|
||||
% This code and subroutines are part of a continuous development, they
|
||||
% are provided "as they are" without guarantees or liability on part
|
||||
% of PSI or the authors. It is the user responsibility to ensure its
|
||||
% proper use and the correctness of the results.
|
||||
|
||||
|
||||
function merged = make_synthetic_projections(stack_object, sinogram_abs, sinogram_phase,total_shift,object_ROI)
|
||||
|
||||
[Nlayers,Nw,~] = size(sinogram_abs);
|
||||
Npx_proj = [size(stack_object,1),size(stack_object,2)];
|
||||
|
||||
assert(length(object_ROI{1}) == Nlayers && length(object_ROI{2}) == Nw, 'Reconstructed tomograms have to contain the full field of view, ie vert_range = object_ROI{1}' )
|
||||
|
||||
if isreal(sinogram_abs) && isreal(sinogram_phase)
|
||||
sinogram_abs = exp(-sinogram_abs);
|
||||
sinogram_phase = exp(-1i*sinogram_phase);
|
||||
else
|
||||
sinogram_phase = sinogram_abs ./ (abs(sinogram_abs)+1e-3);
|
||||
sinogram_abs = abs(sinogram_abs);
|
||||
end
|
||||
|
||||
|
||||
% find reliability region
|
||||
win = tukeywin(Nw, 0.2)'.*tukeywin(Nlayers, 0.2);
|
||||
win = utils.crop_pad(win, Npx_proj);
|
||||
% find amplitude correction
|
||||
corr = math.sum2(abs(stack_object(object_ROI{:},:)) .* sinogram_abs) ./ math.sum2(sinogram_abs.^2);
|
||||
% merge phase and amplitude from tomo and measurements
|
||||
merged = win.*utils.crop_pad(sinogram_phase,Npx_proj) + (1-win).*stack_object ./ (abs(stack_object)+1e-2);
|
||||
% enforce phasor
|
||||
merged = merged ./ (abs(merged) + 1e-2);
|
||||
% apply amplitude
|
||||
merged = merged .* ((win .* corr .* utils.crop_pad(sinogram_abs,Npx_proj) + (1-win).* abs(stack_object)));
|
||||
|
||||
clear sinogram_phase sinogram_abs
|
||||
|
||||
if ~isempty(total_shift)
|
||||
% apply shift to match the original data
|
||||
merged = utils.imshift_fft(merged, -total_shift);
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,114 @@
|
||||
% PLOT_SAMPLE_STABILITY plot time evolution of the sample stability estimated from the
|
||||
% OMNY intererometers, useful to detect unexpected behaviour / setup vibrations
|
||||
%
|
||||
% poor_projections = plot_sample_stability(par, scanstomo,plot_stability, vibrations_threshold)
|
||||
%
|
||||
% Inputs:
|
||||
% ++scanstomo - number of the scans that will be checked
|
||||
% ++plot_stability - (bool, default = true)
|
||||
% ++vibrations_threshold - (default = pixel_size), acceptable level of vibrations in nanometers
|
||||
% *returns*
|
||||
% **poor_projections - (bool array), true if the projection stability is worse than vibrations_threshold
|
||||
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| Except where otherwise noted, this work is licensed under a |
|
||||
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||
%| International (CC BY-NC-SA 4.0) license. |
|
||||
%| |
|
||||
%| Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||
%| |
|
||||
%| Author: CXS group, PSI |
|
||||
%*-----------------------------------------------------------------------*
|
||||
% You may use this code with the following provisions:
|
||||
%
|
||||
% If the code is fully or partially redistributed, or rewritten in another
|
||||
% computing language this notice should be included in the redistribution.
|
||||
%
|
||||
% If this code, or subfunctions or parts of it, is used for research in a
|
||||
% publication or if it is fully or partially rewritten for another
|
||||
% computing language the authors and institution should be acknowledged
|
||||
% in written form in the publication: “Data processing was carried out
|
||||
% using the “cSAXS matlab package” developed by the CXS group,
|
||||
% Paul Scherrer Institut, Switzerland.”
|
||||
% Variations on the latter text can be incorporated upon discussion with
|
||||
% the CXS group if needed to more specifically reflect the use of the package
|
||||
% for the published work.
|
||||
%
|
||||
% A publication that focuses on describing features, or parameters, that
|
||||
% are already existing in the code should be first discussed with the
|
||||
% authors.
|
||||
%
|
||||
% This code and subroutines are part of a continuous development, they
|
||||
% are provided “as they are” without guarantees or liability on part
|
||||
% of PSI or the authors. It is the user responsibility to ensure its
|
||||
% proper use and the correctness of the results.
|
||||
|
||||
|
||||
|
||||
function poor_projections = plot_sample_stability(par, scanstomo, plot_stability, vibrations_threshold)
|
||||
|
||||
if nargin < 3
|
||||
plot_stability = true;
|
||||
end
|
||||
if nargin < 4
|
||||
vibrations_threshold = par.pixel_scale;
|
||||
end
|
||||
|
||||
num_proj = length(scanstomo);
|
||||
if num_proj == 0
|
||||
poor_projections = [];
|
||||
return
|
||||
end
|
||||
|
||||
for ii = 1:num_proj
|
||||
utils.progressbar(ii,num_proj)
|
||||
out = beamline.read_omny_pos(sprintf(par.omnyposfile, scanstomo(ii)));
|
||||
std_err(ii,1) = quantile(out.Stdev_x_st_fzp,0.8);
|
||||
std_err(ii,2) = quantile(out.Stdev_y_st_fzp,0.8);
|
||||
d = dir(sprintf(par.omnyposfile, scanstomo(ii)));
|
||||
scan_time(ii) = d.datenum;
|
||||
end
|
||||
|
||||
if plot_stability
|
||||
plotting.smart_figure(5457)
|
||||
|
||||
% Create the first axes
|
||||
hax1 = axes();
|
||||
|
||||
% Plot something here
|
||||
line(scan_time,std_err*1e3,'color', 'white');
|
||||
datetick('x','HH:MM')
|
||||
xlim([min(scan_time), max(scan_time)])
|
||||
grid on
|
||||
ylabel('Average vibrations [nm]')
|
||||
xlabel('Scan time')
|
||||
|
||||
% Create a transparent axes on top of the first one with it's xaxis on top
|
||||
% and no ytick marks (or labels)
|
||||
hax2 = axes('Position', get(hax1, 'Position'), ... % Copy position
|
||||
'XAxisLocation', 'top', ... % Put the x axis on top
|
||||
'YAxisLocation', 'right', ... % Doesn't really matter
|
||||
'xlim', [scanstomo(1),scanstomo(end)], ... % Set XLims to fit our data
|
||||
'Color', 'none', ... % Make it transparent
|
||||
'YTick', []); % Don't show markers on y axis
|
||||
% Plot data with a different x-range here
|
||||
|
||||
hplot2 = line(scanstomo,std_err*1e3, 'Parent', hax2);
|
||||
legend({'Horizontal','Vertical'}, 'Location', 'Best')
|
||||
xlabel(hax2, 'Scan number')
|
||||
|
||||
% Link the y limits and position together
|
||||
linkprop([hax1, hax2], {'ylim', 'Position'});
|
||||
|
||||
plotting.hline(vibrations_threshold)
|
||||
|
||||
end
|
||||
|
||||
% estimate poor projections
|
||||
|
||||
poor_projections = any(std_err > 1e6*vibrations_threshold,2);
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,22 @@
|
||||
% Normally the tomography angles can be read from an angles file from OMNY,
|
||||
% flOMNI, or LaMNI. However in one case this did not work and we had to
|
||||
% extract the angle from the header of the ptycho positions file. This is a
|
||||
% script that allows just that.
|
||||
% Usage example:
|
||||
% strpatt = '~/Data10/specES1/scan_positions/scan_%05d.dat';
|
||||
% scannums = [271:277];
|
||||
% angles = prepare.read_angles_from_position_files(strpatt,scannums)
|
||||
|
||||
function angles = read_angles_from_position_files(strpatt,scannums)
|
||||
|
||||
filenames = cell(numel(scannums),1);
|
||||
angles = nan(numel(scannums),1);
|
||||
for ii = 1:numel(scannums)
|
||||
filenames{ii} = sprintf(strpatt,scannums(ii));
|
||||
try
|
||||
aux = beamline.read_omny_pos(filenames{ii});
|
||||
angles(ii) = aux.lsamrot_encoder;
|
||||
catch
|
||||
fprintf('Scan %i is missing \n', scannums(ii))
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,137 @@
|
||||
% SAVE_MERGED_PROJECTIONS save projections generated from tomography to be loaded as initial guess in
|
||||
% ptychography , projections are saved to the same path from where they were loaded
|
||||
% just with a differenent suffix
|
||||
%
|
||||
% save_merged_projections(par,stack_object, volData_c, theta, total_shift, name_sufix)
|
||||
%
|
||||
% Inputs:
|
||||
% **par - tomography parameters structure
|
||||
% **stack_object - array of complex valued projections
|
||||
% **volData_c - complex valued sample reconstruction
|
||||
% **theta - measured angles
|
||||
% **total_shift - reconstructed shift of the projections
|
||||
% **name_sufix - extra sufix added to the saved projections
|
||||
% *returns*
|
||||
% ++prepared_objects - prepared lsit of structures for 3D ptychotomo
|
||||
|
||||
%*-----------------------------------------------------------------------*
|
||||
%| |
|
||||
%| Except where otherwise noted, this work is licensed under a |
|
||||
%| Creative Commons Attribution-NonCommercial-ShareAlike 4.0 |
|
||||
%| International (CC BY-NC-SA 4.0) license. |
|
||||
%| |
|
||||
%| Copyright (c) 2018 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||
%| |
|
||||
%| Author: CXS group, PSI |
|
||||
%*-----------------------------------------------------------------------*
|
||||
% You may use this code with the following provisions:
|
||||
%
|
||||
% If the code is fully or partially redistributed, or rewritten in another
|
||||
% computing language this notice should be included in the redistribution.
|
||||
%
|
||||
% If this code, or subfunctions or parts of it, is used for research in a
|
||||
% publication or if it is fully or partially rewritten for another
|
||||
% computing language the authors and institution should be acknowledged
|
||||
% in written form in the publication: “Data processing was carried out
|
||||
% using the “cSAXS matlab package” developed by the CXS group,
|
||||
% Paul Scherrer Institut, Switzerland.”
|
||||
% Variations on the latter text can be incorporated upon discussion with
|
||||
% the CXS group if needed to more specifically reflect the use of the package
|
||||
% for the published work.
|
||||
%
|
||||
% A publication that focuses on describing features, or parameters, that
|
||||
% are already existing in the code should be first discussed with the
|
||||
% authors.
|
||||
%
|
||||
% This code and subroutines are part of a continuous development, they
|
||||
% are provided “as they are” without guarantees or liability on part
|
||||
% of PSI or the authors. It is the user responsibility to ensure its
|
||||
% proper use and the correctness of the results.
|
||||
|
||||
|
||||
|
||||
function prepared_objects = save_merged_projections(par,stack_object, theta, total_shift, name_sufix)
|
||||
|
||||
import ptycho.*
|
||||
import utils.*
|
||||
import io.*
|
||||
import plotting.imagesc3D
|
||||
|
||||
|
||||
scanstomo = par.scanstomo;
|
||||
num_proj = length(scanstomo);
|
||||
|
||||
verbose(0,'Checking available files')
|
||||
verbose(0); % make it quiet
|
||||
missing_projections = [];
|
||||
proj_file_names = cell(length(scanstomo),1);
|
||||
for num = 1:length(scanstomo)
|
||||
progressbar(num, length(scanstomo))
|
||||
path = find_projection_files_names(par, scanstomo(num));
|
||||
if isempty(path)
|
||||
missing_projections(end+1) = num;
|
||||
continue
|
||||
end
|
||||
% take the last file fitting the constraints
|
||||
proj_file_names{num} = path;
|
||||
end
|
||||
|
||||
verbose(par.verbose_level); % return to original settings
|
||||
if ~isempty(missing_projections)
|
||||
verbose(1,['Did not find following scans:', num2str(missing_projections)])
|
||||
end
|
||||
|
||||
[Nx,Ny,~] = size(stack_object);
|
||||
verbose(1,'Preparing projections')
|
||||
for num = 1:num_proj
|
||||
progressbar(num, num_proj)
|
||||
|
||||
[filepath,name, ext] = fileparts(proj_file_names{num});
|
||||
|
||||
out_name = [name,'_',name_sufix];
|
||||
fullpath = [filepath, '/', out_name,'.mat'];
|
||||
|
||||
% load original data
|
||||
d = io.load_ptycho_recons(proj_file_names{num}, 'recon');
|
||||
|
||||
|
||||
positions = h5read(proj_file_names{num}, '/reconstruction/p/positions')';
|
||||
|
||||
obj_size = size(d.object);
|
||||
object = zeros(obj_size,'like',stack_object);
|
||||
object(1:min(end,Nx),1:min(end,Ny)) = ...
|
||||
stack_object(1:min(end,obj_size(1)),1:min(end,obj_size(2)),num);
|
||||
|
||||
% load the complex projections from fp16 precision if used
|
||||
object = fp16.get(object);
|
||||
|
||||
|
||||
%% prepare structure for ptychtomo solver
|
||||
|
||||
prepared_objects{num}.object = object;
|
||||
prepared_objects{num}.positions = positions;
|
||||
prepared_objects{num}.illum_sum = [];
|
||||
prepared_objects{num}.weight = [];
|
||||
prepared_objects{num}.angle = theta(num);
|
||||
prepared_objects{num}.position_offset = round(total_shift(num,:));
|
||||
% testme
|
||||
prepared_objects{num}.probe = utils.imshift_fft(d.probe, total_shift(num,:) -round(total_shift(num,:))) ;
|
||||
prepared_objects{num}.scan_id = scanstomo(num);
|
||||
prepared_objects{num}.proj_id = num;
|
||||
|
||||
% phase removal in probe
|
||||
[~,~, gamma_x, gamma_y] = utils.stabilize_phase(d.object,object, 'binning', 8);
|
||||
|
||||
% remove ramp from probe as well
|
||||
xramp = pi*(linspace(-1,1,par.asize(1)))';
|
||||
yramp = pi*(linspace(-1,1,par.asize(2)));
|
||||
c_offset = xramp.*gamma_x*par.asize(1) + yramp.*gamma_y*par.asize(2);
|
||||
prepared_objects{num}.probe = prepared_objects{num}.probe .* exp(1i*c_offset);
|
||||
|
||||
% plotting.imagesc3D( angle(d.object .* conj(object(1:4:end,1:4:end)) ))
|
||||
%drawnow
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
Reference in New Issue
Block a user