initial commit

This commit is contained in:
2026-08-07 15:56:42 +09:00
commit 91ad25aca9
1012 changed files with 159314 additions and 0 deletions
+168
View File
@@ -0,0 +1,168 @@
% TESTING SCRIPT for ASTRA wrappers
% This script will run some basic features in the ASTRA wrapper code
% ie reconstruciton , splitting on GPU, splitting between multiple workers
% compare results with expected values to detect inconsistencies
% recompile commands
% (Linux, GCC 4.8.5) mexcuda -outdir private ASTRA_GPU_wrapper/ASTRA_GPU_wrapper.cu ASTRA_GPU_wrapper/util3d.cu ASTRA_GPU_wrapper/par3d_fp.cu ASTRA_GPU_wrapper/par3d_bp.cu
% (Windows) mexcuda -outdir private ASTRA_GPU_wrapper\ASTRA_GPU_wrapper.cu ASTRA_GPU_wrapper\util3d.cu ASTRA_GPU_wrapper\par3d_fp.cu ASTRA_GPU_wrapper\par3d_bp.cu
cd(fullfile( fileparts(mfilename('fullpath')), '..'))
addpath('tests')
addpath('utils')
addpath('./')
addpath(find_base_package)
utils.verbose(0)
utils.verbose(0,'Creating data for ASTRA wrapper tests')
if ~exist('GPU_id', 'var'); GPU_id = [1]; end
gpuDevice(GPU_id);
% volume settings
Npix_vol = [300, 300, 200] ;
Nangles = 400;
Npix_proj = [400, 400];
% create "data"
angles = linspace(0, 180, Nangles);
lamino_angle = 60; % 90 deg is normal tomo
tilt_angle = 10; % rotation in plane of the projection
CoR_offset = [20,10]; % offset of the center of rotation
pixel_scale = [1,1] ; % relative scale of the pixels
volData = ones(Npix_vol, 'single');
% generate geometry
[cfg, vectors] = astra.ASTRA_initialize(Npix_vol, Npix_proj, angles, lamino_angle, tilt_angle, pixel_scale,Npix_proj/2+CoR_offset);
% find optimal split, for small volumes below 600^3 no split is needed
split = astra.ASTRA_find_optimal_split(cfg);
% generate projections
projData = astra.Ax_partial(volData, cfg, vectors, split);
% plot the projections
figure
plotting.imagesc3D(projData, 'init_frame', 50); axis off image; colormap bone
title('Volume projection')
drawnow
% do backprojection projections !!! not FBP !!!
backprojData = astra.Atx_partial(projData, cfg, vectors, split);
utils.verbose(0,'Simple ASTRA wrapper tested')
%% =============== tests simple "on GPU" splitting ============
split = [2,2,2,2];
% generate projections
projData_split = astra.Ax_partial(volData, cfg, vectors, split);
err = norm(projData(:) - projData_split(:)) / norm(projData(:));
% plotting.imagesc3D(projData - projData_split); colorbar; axis off image; colormap bone
assert(err < 1e-5, "Splitted projections solver is not fully consistent with the unsplitted one")
% do backprojection projections !!! not FBP !!!
backprojData_split = astra.Atx_partial(projData, cfg, vectors, split);
err = norm(backprojData(:) - backprojData_split(:)) / norm(backprojData(:));
assert(err < 1e-6, "Splitted backprojections solver is not fully consistent with the unsplitted one")
utils.verbose(0,'On GPU splitting tested')
%% =============== tests additional splitting for tomography ============
split = [2,2,2,1];
projData_split = tomo.Ax_sup_partial(volData, cfg, vectors, split);
err = norm(projData(:) - projData_split(:)) / norm(projData(:));
if err > 1e-5
figure
plotting.imagesc3D(projData - projData_split); colorbar; axis off image; colormap bone
title('Projection data difference')
drawnow
end
if err > 1e-3
error("Sup-splitted projections solver is not fully consistent with the unsplitted one")
elseif err > 1e-5
warning("Sup-splitted projections solver is not fully consistent with the unsplitted one, most likely only subpixel errors are present")
end
backprojData_split = tomo.Atx_sup_partial(projData, cfg, vectors, split);
err = norm(backprojData(:) - backprojData_split(:)) / norm(backprojData(:));
if err > 1e-5
figure
plotting.imagesc_tomo(backprojData - backprojData_split); colorbar; axis off image; colormap bone
title('Backprojection data difference')
drawnow
end
if err > 1e-3
error("Sup-splitted backprojections solver is not fully consistent with the unsplitted one")
elseif err > 1e-5
warning("Sup-splitted backprojections solver is not fully consistent with the unsplitted one, most likely only subpixel errors are present")
end
utils.verbose(0,'Extra splitting tested')
%% =============== tests multiGPU solvers ============
utils.verbose(0,'Testing multiGPU solver')
c = parcluster('local');
if exist('local_cluster_jobs', 'dir')
rmdir('local_cluster_jobs', 's') % delete folder with jobs (prevent accumulation )
end
mkdir('local_cluster_jobs') % recreate the folder
c.JobStorageLocation = ['local_cluster_jobs'];
GPU = [1:gpuDeviceCount];
split = [2,2,2,2];
projData_split = tomo.Ax_sup_partial(volData, cfg, vectors, split, 'GPU', GPU);
err = norm(projData(:) - projData_split(:)) / norm(projData(:));
% plotting.imagesc3D(projData - projData_split); colorbar; axis off image; colormap bone
assert(err < 1e-5, "Sup-splitted projections solver is not fully consistent with the unsplitted one")
backprojData_split = tomo.Atx_sup_partial(projData, cfg, vectors, split, 'GPU', GPU);
err = norm(backprojData(:) - backprojData_split(:)) / norm(backprojData(:));
assert(err < 1e-6, "Sup-splitted backprojections solver is not fully consistent with the unsplitted one")
utils.verbose(0,'Multi GPU solver tested')
rmdir('local_cluster_jobs', 's') % delete folder with jobs (prevent accumulation )
utils.verbose(0,'==== All ASTRA wrapper tests passed ===== ')
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  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.
+65
View File
@@ -0,0 +1,65 @@
% DEBUG returns current debug level, if nothing was set, returns 0
%
% out = debug(varargin)
% Inputs:
% **debug_level - debugging level, if nothing was set, returns 0
% returns:
% ++debug_level - last set debug level
%
% USE:
% set debug level :
% debug(debug_level)
% get debug level :
% level = debug()
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  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 out = debug(varargin)
persistent debug_level
if nargin > 0
debug_level = varargin{1};
end
if isempty(debug_level)
debug_level = 0; % no debugging
end
if nargout > 0
out = debug_level;
end
end
+53
View File
@@ -0,0 +1,53 @@
clear; close all; clc
addpath('utils')
addpath(find_base_package())
utils.verbose(struct('prefix', 'run_tests'))
%% SELECTED TESTS TO BE RUN
test_astra = true; % run tests of ASTRA projectiors in +astra and multiGPU astra wrappers in +tomo, check that they all provide consistent results
test_mex_function = true; % test MEX functions used by tomo.block_fun, tomo.Ax_sup_partial, tomo.Axt_sup_partial
test_simulated_data = true; % test uses synthetic data to run all templates under well controlled conditions
test_real_data = true; % test uses real data to run all templates under real experimental conditions
%% SELECT BASIC PARAMETERS
GPU_id = 1;
base_path = './'; % path to store temporal data
gpuDevice(GPU_id);
utils.report_GPU_usage
pause(1)
%% TEST ASTRA WRAPPER
% This script will run some basic features in the +astra/ ASTRA wrapper code
% ie reconstruciton , splitting on GPU, splitting between multiple workers
% compare results with expected values to detect inconsistencies
if test_astra
utils.verbose(struct('prefix', 'Test ASTRA'))
run('tests/astra_wrappers_tests.m')
end
%% TEST MEX FUNCTION
% the MEX functions in +utils/private use OpenMP to accelerate memory transfer from
% large array into small sub array and back
if test_mex_function
utils.verbose(struct('prefix', 'Test MEX'))
run('tests/test_MEX_functions.m')
end
clearvars -except GPU_id base_path test_real_data test_simulated_data
%% TEMPLATE FOR AUTOMATIC TOMOGRAPHY CODE TESTS
% test uses synthetic data to run all templates under well controlled
% conditions, use setting if you want to add noise or other difficulties to
% be tested during alignment
if test_simulated_data
utils.verbose(struct('prefix', 'Test simulated data'))
run('tests/test_tomo_simulated_data.m')
end
clearvars -except GPU_id base_path test_real_data
if test_real_data
utils.verbose(struct('prefix', 'Test real data'))
run('tests/test_tomo_real_data.m')
end
+132
View File
@@ -0,0 +1,132 @@
%% simple script to test performace of the MEX accelerated functions
% utils.get_from_3D_projection and utils.add_to_3D_projection
% the MEX functions use OpenMP to accelerate memory transfer from
% large array into small sub array and back
%
% Matlab equivalent is :
% small_array = full_array(1:Npix_small(1),1:Npix_small(2),1:Npix_small(3));
% full_array(1:Npix_small(1),1:Npix_small(2),1:Npix_small(3)) = full_array(1:Npix_small(1),1:Npix_small(2),1:Npix_small(3)) + small_array;
cd(fullfile( fileparts(mfilename('fullpath')), '..'))
addpath('tests')
addpath('utils')
addpath('./')
addpath(find_base_package)
utils.verbose(0)
%% if needed, recompile the mex functions manually
% cd cSAXS_matlab_base/+utils/private
% if verLessThan('matlab', '9.4')
% mex -largeArrayDims 'CFLAGS="\$CFLAGS -fopenmp"' LDFLAGS="\$LDFLAGS -fopenmp" get_from_3D_projection.cpp
% mex -largeArrayDims 'CFLAGS="\$CFLAGS -fopenmp"' LDFLAGS="\$LDFLAGS -fopenmp" add_to_3D_projection.cpp
% else
% mex -R2018a 'CFLAGS="\$CFLAGS -fopenmp"' LDFLAGS="\$LDFLAGS -fopenmp" get_from_3D_projection_mex.cpp
% mex -R2018a 'CFLAGS="\$CFLAGS -fopenmp"' LDFLAGS="\$LDFLAGS -fopenmp" add_to_3D_projection_mex.cpp
% end
Npix_full = [600,600,600];
Npix_small = [400,400,400];
utils.verbose(0,'--- get_from_3D_projection')
full_array = randn(Npix_full, 'single')+1i;
small_array = ones(Npix_small, 'like', single(1i));
positions = (10*rand(Npix_small(3),2));
indices = ([1:Npix_small(3)]); % indices start from 1
%% get 3D stack array "small_array" from 3D stack array "full_array" given the offsets "positions" and layers "indices"
utils.verbose(0,'Speed test MEX')
for ii = 1:3
tic; utils.get_from_3D_projection(small_array,full_array,positions,indices); toc
end
assert(norm(small_array(:)-reshape(utils.get_from_3D_projection(small_array,full_array,positions,indices, false),[],1))==0, 'get_from_3D_projection MEX function does not provide exact results')
utils.verbose(0,'Speed test Matlab')
for ii = 1:3
tic; small_array = full_array(1:Npix_small(1),1:Npix_small(2),1:Npix_small(3)); toc
end
%% add 3D stack array "small_array" into 3D stack array "full_array" given the offsets "positions" and layers "indices"
utils.verbose(0,'--- add_to_3D_projection')
full_array = zeros(Npix_full, 'like', single(1i));
small_array = ones(Npix_small, 'like', single(1i));
positions = (10*rand(Npix_small(3),2));
indices = ([1:Npix_small(3)]); % indices are starting from 1 !!
add_values = true;
utils.verbose(0,'=== add values atomic')
utils.verbose(0,'Speed test MEX')
for ii = 1:3
tic; utils.add_to_3D_projection(small_array,full_array,positions, indices,add_values, true);toc
end
assert(norm(full_array(:)-reshape(utils.add_to_3D_projection(3*small_array,zeros(Npix_full, 'like', single(1i)),positions, indices,add_values,true,false),[],1))==0, 'add_to_3D_projection MEX function does not provide exact results')
utils.verbose(0,'Speed test Matlab')
tic; full_array(1:Npix_small(1),1:Npix_small(2),1:Npix_small(3)) = full_array(1:Npix_small(1),1:Npix_small(2),1:Npix_small(3)) + small_array; toc
%% set 3D stack array "small_array" into 3D stack array "full_array" given the offsets "positions" and layers "indices"
utils.verbose(0,'=== add values nonatomic')
add_values = true;
utils.verbose(0,'Speed test MEX')
full_array = zeros(Npix_full, 'like', single(1i));
for ii = 1:3
tic; utils.add_to_3D_projection(small_array,full_array,positions, indices,add_values, false);toc
end
assert(norm(full_array(:)-reshape(utils.add_to_3D_projection(3*small_array,zeros(Npix_full, 'like', single(1i)),positions, indices,add_values,false,false),[],1))==0, 'add_to_3D_projection MEX function does not provide exact results')
utils.verbose(0,'Speed test Matlab')
tic; full_array(1:Npix_small(1),1:Npix_small(2),1:Npix_small(3)) = full_array(1:Npix_small(1),1:Npix_small(2),1:Npix_small(3)) + small_array; toc
%% set 3D stack array "small_array" into 3D stack array "full_array" given the offsets "positions" and layers "indices"
utils.verbose(0,'=== set values')
add_values = false;
utils.verbose(0,'Speed test MEX')
full_array = zeros(Npix_full, 'like', single(1i));
for ii = 1:3
tic; utils.add_to_3D_projection(small_array,full_array,positions, indices,add_values);toc
end
assert(norm(full_array(:)-reshape(utils.add_to_3D_projection(small_array,zeros(Npix_full, 'like', single(1i)),positions, indices,add_values,false,false),[],1))==0, 'add_to_3D_projection MEX function does not provide exact results')
utils.verbose(0,'Speed test Matlab')
tic; full_array(1:Npix_small(1),1:Npix_small(2),1:Npix_small(3)) = small_array; toc
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  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.
+214
View File
@@ -0,0 +1,214 @@
%% TEMPLATE FOR AUTOMATIC TOMOGRAPHY CODE TESTS
% perform tests on measured dataset stored in /das/work/p16/p16812/
cd(fullfile( fileparts(mfilename('fullpath')), '..'))
addpath('tests')
addpath('utils')
addpath('./')
addpath(find_base_package)
clearvars -except par0 tested_templates scratch_path GPU_id base_path test_simulated_data test_real_data base_path
%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Edit this section %%%
%%%%%%%%%%%%%%%%%%%%%%%%%
datasets = 1:5; % 1-nature chip, 2-FFC particle, 3-retina, 4-local tomo, 5-lamni chip
verbose_level = -1; % -1 = keep very quiet the reconstructions
scratch_path = '/das/work/p16/p16812/'; % path to the cSAXS scratch p-folder where are saved the test datasets
if ~exist('GPU_id', 'var'); GPU_id = [1]; end
if ~exist('base_path', 'var'); base_path = '../'; end
%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%
utils.verbose(verbose_level)
setenv('TMP',[base_path,'/tmp']) % TEMP for matlab scripts
utils.verbose(-1, '=== Searching for data in %s ====', scratch_path)
for dataset = datasets
par0 = struct();
par0.GPU_list = GPU_id;
switch dataset
case 1
%% Nature chip 2016
% test: large projections, phase residua/errors from sharp transitions
tested_templates ={'template_tomo_recons'} ;
par0.tomo_id = [];
par0.scanstomo = [2718:3925];
par0.fileprefix='online_'; % string at the beginning of the filename, related to reconstruction name
par0.filesuffix = '_600x600_wrap_1_c'; % string searched at the end of the data filenames, No need to add _c or _recons, it will look for it
par0.file_extension = 'mat';
par0.analysis_path = fullfile(scratch_path, 'data/e16622_tomo_nature_chip_2016/analysis/');
par0.surface_calib_file = [];
par0.omnyposfile = fullfile(scratch_path, 'data/e16622_tomo_nature_chip_2016/specES1/scan_positions/scan_%05d.dat'); %Filename pattern for Orchestra interferometer position files
par0.OMNY_angle_file = fullfile(scratch_path, 'data/e16622_tomo_nature_chip_2016/specES1/dat-files/tomography_scannumbers.txt'); % Filename with angles
par0.max_residua_limit = inf; % limit used to determine which projection have failed
case 2
%% johanness FCC catalyst
% test: large projections, low freq. errors, periodic artefacts, vertically asymmetric sample
tested_templates ={'template_tomo_recons'} ;
par0.tomo_id = [];
par0.scanstomo = [500:1349];
par0.fileprefix='offline_'; % string at the beginning of the filename, related to reconstruction name
par0.filesuffix = '500x500_run_1_recons'; % string searched at the end of the data filenames, No need to add _c or _recons, it will look for it
par0.file_extension = 'mat';
par0.analysis_path = fullfile(scratch_path, 'data/e16410_tomo_FCC_particle/analysis/');
par0.surface_calib_file = [];
par0.omnyposfile = fullfile(scratch_path, 'data/e16410_tomo_FCC_particle/specES1/scan_positions/scan_%05d.dat'); %Filename pattern for Orchestra interferometer position files
par0.OMNY_angle_file = fullfile(scratch_path, 'data/e16410_tomo_FCC_particle/specES1/dat-files/tomography_scannumbers.txt'); % Filename with angles
% solve in lower resolution
par0.downsample_projections = 1;
case 3
%% retina from OMNY
% test: large projections, low freq. errors, huge phase jumps
tested_templates ={'template_tomo_recons'} ;
par0.tomo_id = [];
par0.scanstomo = [1925:2384];
par0.fileprefix='online_wrap_'; % string at the beginning of the filename, related to reconstruction name
par0.filesuffix = '_452x452_run_1_c'; % string searched at the end of the data filenames, No need to add _c or _recons, it will look for it
par0.file_extension = 'mat';
par0.analysis_path = fullfile(scratch_path, 'data/e15634_retina_2015_OMNY/analysis/');
par0.surface_calib_file = [];
par0.omnyposfile = fullfile(scratch_path, 'data/e15634_retina_2015_OMNY/specES1/omny_recontruct/scan_%05d.dat'); %Filename pattern for Orchestra interferometer position files
par0.OMNY_angle_file = fullfile(scratch_path, 'data/e15634_retina_2015_OMNY/specES1/dat-files/omny_scannumbers.txt'); % Filename with angles
par0.downsample_projections = 1; % downsample projections by factor of 2^x, set 0 to do nothing and 1,2,.. for different levels of projection binning
par0.auto_alignment = false;
par0.get_auto_calibration = false;
case 4
%% local tomo dataset !! THIS TEST TAKES ~1 HOUR and requires 200GB of RAM !!
tested_templates ={'template_tomo_interior'} ;
par0.tomo_id = []; % [68:74]; % Either scan numbers or tomo_id can be given, but not both, if not provided leave tomo_id=[]
par0.scanstomo = 1700:7690;
par0.lowres_tomo_path =fullfile(scratch_path, 'data/e17312_localtomo_FCC_particle/tomogram_delta_S00089_to_S01525_ram-lak_freqscl_1.00.mat');
% IO loading
par0.fileprefix=''; % string at the beginning of the filename, related to reconstruction name
par0.filesuffix = '_recons'; % string searched at the end of the data filenames, No need to add _c or _recons, it will look for it
par0.file_extension = 'h5';
par0.downsample_projections = 0; % downsample projections by factor of 2^x, set 0 to do nothing and 1,2,.. for different levels of projection binning
par0.analysis_path = fullfile(scratch_path, 'data/e17312_localtomo_FCC_particle/analysis/');
par0.clip_amplitude_quantile = 0.95; % clip amplitudes in the loaded projections that are exceeding given quantile, if par0.clip_amplitude_quantile == 1, do nothing
par0.max_residua_limit = 100; % limit used to determine which projection have failed
par0.surface_calib_file = [];
par0.omnyposfile = fullfile(scratch_path, 'data/e17312_localtomo_FCC_particle/specES1/scan_positions/scan_%05d.dat'); %Filename pattern for Orchestra interferometer position files
par0.OMNY_angle_file = fullfile(scratch_path, 'data/e17312_localtomo_FCC_particle/specES1/dat-files/tomography_scannumbers.txt'); % Filename with angles
% Other
par0.save_memory = false; % try to limit use of RAM
par0.inplace_processing = par0.save_memory; % process object_stack using inplace operations to save memory
par0.fp16_precision = true; % use 16-bit precision to store the complex-valued projections
par0.cache_stack_object = par0.save_memory; % store stack_object to disk when no needed
case 5
%% lamni chip dataset !! THIS TEST TAKES SEVERAL HOURS and requires full RAM !!
tested_templates ={'template_tomo_recons_lamino'} ;
% par0.scanstomo = [984:1850]; %2326]; % smaller angular range
par0.scanstomo = [984:3717]; % full angular range
par0.tomo_id = []; % Either scan numbers or tomo_id can be given, but not both, if not provided leave tomo_id=[]
% IO loading
par0.fileprefix=''; % string at the beginning of the filename, related to reconstruction name
par0.filesuffix = 'test_1'; %% string searched at the end of the data filenames, No need to add _c or _recons, it will look for it
par0.file_extension = 'h5';
par0.downsample_projections = 0; % downsample projections by factor of 2^x, set 0 to do nothing and 1,2,.. for different levels of projection binning
par0.analysis_path = fullfile(scratch_path, 'data/e17299_lamni_chip_dataset_2018/analysis/');
par0.clip_amplitude_quantile = 0.95; % clip amplitudes in the loaded projections that are exceeding given quantile, if par0.clip_amplitude_quantile == 1, do nothing
par0.max_residua_limit = 100; % limit used to determine which projection have failed
par0.surface_calib_file = [];
par0.omnyposfile = fullfile(scratch_path, 'data/e17299_lamni_chip_dataset_2018/specES1/scan_positions/scan_%05d.dat'); %Filename pattern for Orchestra interferometer position files
par0.OMNY_angle_file = fullfile(scratch_path, 'data/e17299_lamni_chip_dataset_2018/specES1/dat-files/tomography_scannumbers.txt'); % Filename with angles
% Other
par0.save_memory = true; % try to limit use of RAM
par0.inplace_processing = par0.save_memory; % process object_stack using inplace operations to save memory
par0.fp16_precision = par0.save_memory; % use 16-bit precision to store the complex-valued projections
par0.cache_stack_object = par0.save_memory; % store stack_object to disk when no needed
otherwise
error('Missing dataset')
end
for tested_template = tested_templates
clearvars -except par0 tested_template tested_templates scratch_path GPU_id base_path test_simulated_data test_real_data base_path
utils.verbose(struct('prefix', 'init'))
%% test stage 0: load basic configuration parameters
utils.verbose(-1,'====================================================')
utils.verbose(-1,'===== Testing template "%s" ============', tested_template{1})
utils.verbose(-1,'====================================================')
% set debugging info level and marks
debug(1)
warning('off', 'MATLAB:mpath:nameNonexistentOrNotADirectory')
warning('off', 'MATLAB:dispatcher:pathWarning')
run(tested_template{1})
for item = fieldnames(par0)'
par.(item{1}) = par0.(item{1});
end
%% test stage 1: load test data and continue with the remplate
utils.verbose(-1,'Running template')
debug(3)
utils.verbose(struct('prefix', 'template'))
run(tested_template{1})
end
end
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  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.
+217
View File
@@ -0,0 +1,217 @@
%% TEMPLATE FOR AUTOMATIC TOMOGRAPHY CODE TESTS
% test uses synthetic data to run all templates under well controlled
% conditions, use setting if you want to add noise or other difficulties to
% be tested during alignment
cd(fullfile( fileparts(mfilename('fullpath')), '..'))
addpath('tests')
addpath('utils')
addpath('./')
addpath(find_base_package)
%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Edit this section %%%
%%%%%%%%%%%%%%%%%%%%%%%%%
tested_templates = 1:3; % IDs of the tested templates
templates_list ={ 'template_tomo_recons', ...
'template_tomo_recons_lamino', ...
'template_tomo_nonrigid', ...
'template_tomo_recons_deprecated'...
};
verbose_level = -1; % -1 = keep very quiet the reconstructions
% artificial data settings
Npix_vol = [200,200,200] ;
undersampling = 1; % level of undersampling compared to Crowther criterion
noise_level = 0; % relative noise level with respect to the maximal phase value in the projections
N_subtomos = 4;
add_residual_layer = false; % add a thin metal-like layer to test behaviour with residua
Nangles = ceil(pi/2*Npix_vol(1)) / undersampling;
Nangles = ceil(Nangles/N_subtomos)*N_subtomos; % make splitable for 4 subtomos
asize = ceil(Npix_vol(1:2) / 10); % size of the simulated probe
if ~exist('GPU_id', 'var'); GPU_id = [1]; end
if ~exist('base_path', 'var'); base_path = '../'; end
%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%
assert(all(GPU_id <= gpuDeviceCount), 'Select valid GPU id in GPU_id')
utils.verbose(verbose_level)
setenv('TMP',[base_path,'/tmp']) % TEMP for matlab scripts
%% MAKE A PHANTOM
utils.verbose(-1,'Creating phantom')
rng default
volData = randn(Npix_vol - asize(1), 'single');
volData = (0.5+0.5*(utils.imgaussfilt3_fft(volData, 3) > 0)) .* ...
(utils.imgaussfilt3_fft(volData, 10) > 0);
volData = utils.imgaussfilt3_conv(volData, 0.6); % prevent too sharp edges
if add_residual_layer
% add kind of metalic layer to test robustness of the codes
[X,Y,Z] = meshgrid(-Npix_vol(1)/2:Npix_vol(1)/2-1,-Npix_vol(2)/2:Npix_vol(2)/2-1,-Npix_vol(3)/2:Npix_vol(3)/2-1);
layer = abs(0.1*X + 0.5*Y+0.2*Z + 50*utils.imgaussfilt3_fft(randn(Npix_vol, 'single'),10) )<0.5;
volData = volData + 10*utils.crop_pad_3D(layer, size(volData));
end
volData = utils.apply_3D_apodization(volData, 0, Npix_vol(1)/5, 1);
volData = utils.crop_pad_3D(volData, Npix_vol);
for tested_template = templates_list(tested_templates)
utils.verbose(struct('prefix', 'init'))
%% test stage 0: load basic configuration parameters
utils.verbose(-1,'Loading template "%s"', tested_template{1})
if strcmpi(tested_template{1}, 'template_tomo_nonrigid')
%nonrigid tomo has data generation already included in the template
debug(1)
run(tested_template{1})
else
par = struct();
par.lamino_angle = 90; % default setting
% set debugging info level and marks
debug(1)
warning('off', 'MATLAB:mpath:nameNonexistentOrNotADirectory')
warning('off', 'MATLAB:dispatcher:pathWarning')
run(tested_template{1})
utils.verbose(-1,'Creating data')
% create "data"
if ~par.is_laminography
theta = pi+linspace(0, 180*(1-1/Nangles), Nangles);
else
Nangles = Nangles * 2;
theta = pi+linspace(0, 360*(1-1/Nangles), Nangles);
end
% create "N_subtomos" subtomos
theta = reshape(reshape(theta, N_subtomos,[])',1,[]);
par.subtomos = reshape(ones(Nangles/N_subtomos,N_subtomos).*[1:N_subtomos],1,[]);
% Add noise and offsets to the measured positions to make the
% alignment more difficult
position_errors = (0.1*randn(Nangles,2) + 0.1*sind(3*theta')) * Npix_vol(3);
asize = asize + ceil(max(asize, max(abs(position_errors)))/32)*32; % avoid the sample going out of FOV
par.asize = asize;
if par.lamino_angle == 90
Npix_proj = [Npix_vol(3), ceil(sqrt(2)*Npix_vol(1))]+asize;
max_sample_height = inf;
else
Npix_proj = ceil(sqrt(2)*Npix_vol([3,1]) .* [cosd(par.lamino_angle), 1] )+asize;
max_sample_height = 5e-6 ;
end
% provide other parameters required by the template
par.factor = 1;
par.factor_edensity = 1;
par.pixel_size = 50e-9;
par.scans_string = '';
par.output_folder = '???'; % some nonexistent folder, in default the template should not write any data during debug mode
obj_interf_pos_x = 0;
obj_interf_pos_y = 0;
delta_stack_prealign = [] ;
par.tilt_angle = 0;
par.skewness_angle = 0;
par.lambda = 0.2e-9;
par.scanstomo = 1:Nangles;
par.air_gap = [5,5];
par.GPU_list = GPU_id;
par.nresidua_per_frame = 0;
% generate geometry
Npix_vol(3) = min(Npix_vol(3),ceil(max_sample_height / par.pixel_size)-1);
CoR = Npix_proj/2 + position_errors;
[cfg, vectors] = astra.ASTRA_initialize(Npix_vol, Npix_proj, theta, par.lamino_angle, 'rotation_center', CoR);
% find optimal split, for small volumes below 600^3 no split is needed
split = astra.ASTRA_find_optimal_split(cfg);
par.illum_sum = ones(Npix_proj);
% generate complex projections
stack_object = tomo.Ax_sup_partial(utils.crop_pad_3D(volData, Npix_vol), cfg, vectors, split);
stack_object = stack_object / math.sp_quantile(stack_object, 0.99, 10);
if noise_level>0; stack_object = stack_object + noise_level * randn(size(stack_object)); end
stack_object = exp(-0.1*stack_object - 4i*stack_object);
object = stack_object(:,:,1);
if strcmpi(tested_template, 'template_tomo_recons_lamino')
% create errors in global geometry -> test automatic refinement
par.tilt_angle = -0.5;
par.skewness_angle = 0.5;
else
par.tilt_angle = 0;
par.skewness_angle = 0;
end
%% test stage 1: load test data and continue with the remplate
utils.verbose(-1,'Loading template "%s"', tested_template{1})
debug(2)
utils.verbose(struct('prefix', 'template'))
run(tested_template{1})
% check results of the geometry refinement provided by tests
if strcmpi(tested_template, 'template_tomo_recons_lamino')
assert(abs(par.tilt_angle) < 0.1 && abs(par.skewness_angle) < 0.1, 'Geometry refinement in laminography did not work well')
end
end
clearvars -except par tested_templates Nangles volData Npix_vol asize N_subtomos GPU_id noise_level test_astra test_mex_function test_simulated_data test_real_data base_path
end
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  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.