added ptychography scripts

This commit is contained in:
2026-08-07 16:31:16 +09:00
parent 3700c783e4
commit 5945346784
19 changed files with 5599 additions and 0 deletions
+24
View File
@@ -0,0 +1,24 @@
function par = parameter_builder(parfile)
par = struct;
fileID = fopen(parfile, 'r');
tline = fgetl(fileID);
while ischar(tline)
tline = fgetl(fileID);
if tline == -1
break;
end
% disp(tline);
temp = split(tline);
if size(temp, 1) == 1 || temp{1,1}(1) == '#'
continue
end
if ~isnan(str2double(temp{2,1}))
par.(temp{1,1}) = str2double(temp{2,1});
else
par.(temp{1,1}) = temp{2,1};
end
end
% fclose(fileID);
% save( parfile, "par");
end
+67
View File
@@ -0,0 +1,67 @@
% This script prepares experimental electron ptycho. data for PtychoShelves
function prepare_data(parfile)
%% Step 1: download sample data (rawdata_1x_crop.mat) from the link provided in
% https://www.nature.com/articles/s41467-020-16688-6
% Note: it's a good practice to store data (and reconstructions) in a
% different folder from fold_slice
%% Step 2: load data
par = parameter_builder(parfile); % load the struct with parameters
load(par.raw_data);
%% Step 3: go back to .../fold_slice/ptycho and pre-process data
% load the parameters in case it is not saved in the raw data
df = par.defocus;
voltage = par.voltage;
rbf = par.rbf;
ADU = par.ADU;
alpha0 = par.alpha_max;
addpath(strcat(pwd,'/utils_electron/'))
Np_p = [par.CBED_size, par.CBED_size]; % size of diffraction patterns used during reconstruction. can also pad to 256
% pad cbed
[ndpy,ndpx,npy,npx]=size(cbed);
if ndpy < Np_p(1) % pad zeros
dp=padarray(cbed,[(Np_p(1)-ndpy)/2,(Np_p(2)-ndpx)/2,0,0],0,'both');
else
dp=crop_pad(cbed,Np_p);
end
dp = dp / ADU; % convert to electron count
dp=reshape(dp,Np_p(1),Np_p(2),[]);
Itot=mean(squeeze(sum(sum(dp,1),2))); %need this for normalizting initial probe
% calculate pxiel size (1/A) in diffraction plane
[~,lambda]=electronwavelength(voltage);
dk=alpha0/1e3/rbf/lambda; %%% PtychoShelves script needs this %%%
%% Step 4: save CBED in a .hdf5 file (needed by Ptychoshelves)
scan_number = par.scan_number; %Ptychoshelves needs
save_dir = strcat(par.result_dir,num2str(scan_number),'/');
disp(save_dir);
mkdir(save_dir)
roi_label = par.roi_label;
saveName = strcat('data_roi',roi_label,'_dp.hdf5');
h5create(strcat(save_dir,saveName), '/dp', size(dp),'ChunkSize',[size(dp,1), size(dp,2), 1],'Deflate',4)
h5write(strcat(save_dir,saveName), '/dp', dp)
%% Step 5: prepare initial probe
dx=1/Np_p(1)/dk; %% pixel size in real space (angstrom)
par_probe = {};
par_probe.df = df;
par_probe.voltage = voltage;
par_probe.alpha_max = alpha0;
par_probe.plotting = true;
probe = make_tem_probe(dx, Np_p(1), par_probe);
probe=probe/sqrt(sum(sum(abs(probe.^2))))*sqrt(Itot)/sqrt(Np_p(1)*Np_p(2));
probe=single(probe);
% add parameters for PtychoShelves
p = {};
p.binning = false;
p.detector.binning = false;
%% Step 6: save initial probe
save(strcat(save_dir,'/init_probe.mat'),'probe','p')
end
+69
View File
@@ -0,0 +1,69 @@
% This script prepares experimental electron ptycho. data for PtychoShelves
%% Step 1: download sample data (rawdata_1x_crop.mat) from the link provided in
% https://www.nature.com/articles/s41467-020-16688-6
% Note: it's a good practice to store data (and reconstructions) in a
% different folder from fold_slice
%% Step 2: load data
load("parameter.mat"); % load the struct with parameters
% data_dir = 'BO_tests/'; %change this
data_dir = par.data_dir;
% load(strcat(data_dir,'rawdata_1x_crop.mat'))
load(strcat(data_dir, par.file_name));
%% Step 3: go back to .../fold_slice/ptycho and pre-process data
% load the parameters in case it is not saved in the raw data
df = par.defocus;
voltage = par.voltage;
rbf = par.rbf;
ADU = par.ADU;
alpha0 = par.alpha_max;
addpath(strcat(pwd,'/utils_electron/'))
Np_p = [128,128]; % size of diffraction patterns used during reconstruction. can also pad to 256
% pad cbed
[ndpy,ndpx,npy,npx]=size(cbed);
if ndpy < Np_p(1) % pad zeros
dp=padarray(cbed,[(Np_p(1)-ndpy)/2,(Np_p(2)-ndpx)/2,0,0],0,'both');
else
dp=crop_pad(cbed,Np_p);
end
dp = dp / ADU; % convert to electron count
dp=reshape(dp,Np_p(1),Np_p(2),[]);
Itot=mean(squeeze(sum(sum(dp,1),2))); %need this for normalizting initial probe
% calculate pxiel size (1/A) in diffraction plane
[~,lambda]=electronwavelength(voltage);
dk=alpha0/1e3/rbf/lambda; %%% PtychoShelves script needs this %%%
%% Step 4: save CBED in a .hdf5 file (needed by Ptychoshelves)
scan_number = 1; %Ptychoshelves needs
save_dir = strcat(data_dir,num2str(scan_number),'/');
mkdir(save_dir)
% roi_label = '0_Ndp128';
roi_label = par.roi_label;
saveName = strcat('data_roi',roi_label,'_dp.hdf5');
h5create(strcat(save_dir,saveName), '/dp', size(dp),'ChunkSize',[size(dp,1), size(dp,2), 1],'Deflate',4)
h5write(strcat(save_dir,saveName), '/dp', dp)
%% Step 5: prepare initial probe
dx=1/Np_p(1)/dk; %% pixel size in real space (angstrom)
par_probe = {};
par_probe.df = df;
par_probe.voltage = voltage;
par_probe.alpha_max = alpha0;
par_probe.plotting = true;
probe = make_tem_probe(dx, Np_p(1), par_probe);
probe=probe/sqrt(sum(sum(abs(probe.^2))))*sqrt(Itot)/sqrt(Np_p(1)*Np_p(2));
probe=single(probe);
% add parameters for PtychoShelves
p = {};
p.binning = false;
p.detector.binning = false;
%% Step 6: save initial probe
save(strcat(save_dir,'/init_probe.mat'),'probe','p')
+60
View File
@@ -0,0 +1,60 @@
% This script prepares experimental electron ptycho. data for PtychoShelves
%% Step 1: download the sample data from the PARADIM website:
% https://data.paradim.org/doi/ssmm-2j11/
% Note: it's a good practice to store data (and reconstructions) in a
% different folder from fold_slice
%% Step 2: load data
data_dir = 'BO_tests/'; %change this
load(strcat(data_dir,'sample_data_PrScO3.mat'))
%% Step 3: go back to .../fold_slice/ptycho and pre-process data
addpath(strcat(pwd,'/utils_electron/'))
Np_p = [256,256]; % size of diffraction patterns used during reconstruction. can also pad to 256
% pad cbed
[ndpy,ndpx,npy,npx]=size(dp);
if ndpy < Np_p(1) % pad zeros
dp=padarray(dp,[(Np_p(1)-ndpy)/2,(Np_p(2)-ndpx)/2,0,0],0,'both');
else
dp=crop_pad(dp,Np_p);
end
dp = dp / ADU; % convert to electron count
dp=reshape(dp,Np_p(1),Np_p(2),[]);
Itot=mean(squeeze(sum(sum(dp,1),2))); %need this for normalizting initial probe
% calculate pxiel size (1/A) in diffraction plane
[~,lambda]=electronwavelength(voltage);
rbf=26; % radius of center disk in pixels
dk=alpha/1e3/rbf/lambda; %%% PtychoShelves script needs this %%%
%% Step 4: save CBED in a .hdf5 file (needed by Ptychoshelves)
scan_number = 1; %Ptychoshelves needs
save_dir = strcat(data_dir,num2str(scan_number),'/');
mkdir(save_dir)
roi_label = '0_Ndp256';
saveName = strcat('data_roi',roi_label,'_dp.hdf5');
h5create(strcat(save_dir,saveName), '/dp', size(dp),'ChunkSize',[size(dp,1), size(dp,2), 1],'Deflate',4)
h5write(strcat(save_dir,saveName), '/dp', dp)
%% Step 5: prepare initial probe
dx=1/Np_p(1)/dk; %% pixel size in real space (angstrom)
par_probe = {};
par_probe.df = defocus;
par_probe.voltage = voltage;
par_probe.alpha_max = alpha;
par_probe.plotting = true;
probe = make_tem_probe(dx, Np_p(1), par_probe);
probe=probe/sqrt(sum(sum(abs(probe.^2))))*sqrt(Itot)/sqrt(Np_p(1)*Np_p(2));
probe=single(probe);
% add parameters for PtychoShelves
p = {};
p.binning = false;
p.detector.binning = false;
%% Step 6: save initial probe
save(strcat(save_dir,'/init_probe.mat'),'probe','p')
+328
View File
@@ -0,0 +1,328 @@
clear variables
addpath(strcat(pwd,'/utils/'))
addpath('/home/chenyu/Desktop/git/fold_slice/')
load("parameter.mat");
addpath(core.find_base_package)
%%%%%%%%%%%%%%%%%%%% data parameters %%%%%%%%%%%%%%%%%%%%
% base_path = 'BO_tests/';
base_path = par.data_dir;
roi_label = par.roi_label;
% roi_label = '0_Ndp128';
scan_number = 1;
scan_string_format = '%01d';
Ndpx = 128; % size of cbed
alpha0 = par.alpha_max;
% alpha0 = 21.4; % semi-convergence angle (mrad)
rbf = par.rbf;
% rbf = 26; % radius of the BF disk in cbed. Can be used to calculate dk
%dk = 0.0197; % pixel size in cbed (1/A). Should be calibrated as accurate as possible
voltage = par.voltage;
% voltage = 80;
rot_ang = par.rot_ang;
% rot_ang = 30; %angle between cbed and scan coord.
scan_step_size = par.scan_step_size;
% scan_step_size = 0.85; %angstrom
N_scan_y = par.N_scan_y;
N_scan_x = par.N_scan_x;
% N_scan_y = 60; %number of scan points
% N_scan_x = 60;
%%%%%%%%%%%%%%%%%%%% reconstruction parameters %%%%%%%%%%%%%%%%%%%%
gpu_id = 1;
Niter = par.Niter;
% Niter = 1000;
Niter_save_results = par.Niter_save_results;
% Niter_save_results = 100;
Niter_plot_results = 50;
Nprobe = par.Nprobe;
% Nprobe = 5; % # of probe modes
variable_probe_modes = 0; % # of modes for variable probe correction
grouping = 120; % group size. small -> better convergence but longer time/iteration
N_pos_corr = 0; % iteration number to start position correction. inf means no position correction
%initial_probe_file = 'D:\\Ptychography\\Data\\MoS2_NatComm\\1\\init_probe.mat';
initial_probe_file = strcat(par.data_dir, '1/init_probe.mat');
% initial_probe_file = 'BO_tests/1/init_probe.mat';
%% %%%%%%%%%%%%%%%%%% initialize data parameters %%%%%%%%%%%%%%%%%%%%
p = struct();
p. verbose_level = 2; % verbosity for standard output (0-1 for loops, 2-3 for testing and adjustments, >= 4 for debugging)
p. use_display = Niter_plot_results< Niter; % global switch for display, if [] then true for verbose > 1
p. scan_number = scan_number; % Multiple scan numbers for shared scans
% Geometry
p. z = 1; % Distance from object to detector. Always 1 for electron ptycho
p. asize = [Ndpx,Ndpx]; % Diffr. patt. array size
p. ctr = [fix(Ndpx/2)+1, fix(Ndpx/2)+1]; % Diffr. patt. center coordinates (y,x) (empty means middle of the array); e.g. [100 207;100+20 207+10];
p. beam_source = 'electron'; % Added by YJ for electron pty. Use relativistic corrected formula for wavelength. Also change the units on figures
%p. dk = dk; % Added by YJ. dk is the pixel size in cbed (1/A). This is used to determine pixel size in electron ptycho
p. d_alpha = alpha0/rbf; % Added by YJ. d_alpha is the pixel size in cbed (mrad). This is used to determine pixel size in electron ptycho
p. prop_regime = 'farfield'; % propagation regime: nearfield, farfield (default), !! nearfield is supported only by GPU engines
p. focus_to_sample_distance = []; % sample to focus distance, parameter to be set for nearfield ptychography, otherwise it is ignored
p. energy = voltage; % Energy (in keV), leave empty to use spec entry mokev
%p. affine_angle = 0; % Not used by ptycho_recons at all. This allows you to define a variable for the affine matrix below and keep it in p for future record. This is used later by the affine_matrix_search.m script
%p. affine_matrix = [1 , 0; 0, 1] ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
affine_mat = compose_affine_matrix(1, 0, rot_ang, 0);
p. affine_matrix = affine_mat ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
% Scan meta data
p. src_metadata = 'none'; % source of the meta data, following options are supported: 'spec', 'none' , 'artificial' - or add new to +scan/+meta/
p. queue.lockfile = false; % If true writes a lock file, if lock file exists skips recontruction
% Data preparation
p. detector.name = 'empad'; % see +detectors/ folder
p. detector.check_2_detpos = []; % = []; (ignores) = 270; compares to dettrx to see if p.ctr should be reversed (for OMNY shared scans 1221122), make equal to the middle point of dettrx between the 2 detector positions
p. detector.data_prefix = ''; % Default using current eaccount e.g. e14169_1_
p. detector.binning = false; % = true to perform 2x2 binning of detector pixels, for binning = N do 2^Nx2^N binning
p. detector.upsampling = false; % upsample the measured data by 2^data_upsampling, (transposed operator to the binning), it can be used for superresolution in nearfield ptychography or to account for undersampling in a far-field dataset
p. detector.burst_frames = 1; % number of frames collected per scan position
p. prepare.data_preparator = 'matlab_aps'; % data preparator; 'python' or 'matlab' or 'matlab_aps'
p. prepare.auto_prepare_data = true; % if true: prepare dataset from raw measurements if the prepared data does not exist
p. prepare.force_preparation_data = true; % Prepare dataset even if it exists, it will overwrite the file % Default: @prepare_data_2d
p. prepare.store_prepared_data = false; % store the loaded data to h5 even for non-external engines (i.e. other than c_solver)
p. prepare.prepare_data_function = ''; % (used only if data should be prepared) custom data preparation function handle;
p. prepare.auto_center_data = false; % if matlab data preparator is used, try to automatically center the diffraction pattern to keep center of mass in center of diffraction
% Scan positions
p. src_positions = 'matlab_pos'; % 'spec', 'orchestra', 'load_from_file', 'matlab_pos' (scan params are defined below) or add new position loaders to +scan/+positions/
p. positions_file = ''; %Filename pattern for position files, Example: ['../../specES1/scan_positions/scan_%05d.dat']; (the scan number will be automatically filled in)
% scan parameters for option src_positions = 'matlab_pos';
p. scan.type = 'raster'; % {'round', 'raster', 'round_roi', 'custom'}
p. scan.roi_label = roi_label; % For APS data
p. scan.format = scan_string_format; % For APS data format for scan directory generation
p. scan.radius_in = 0; % round scan: interior radius of the round scan
p. scan.radius_out = 5e-6; % round scan: exterior radius of the round scan
p. scan.nr = 10; % round scan: number of intervals (# of shells - 1)
p. scan.nth = 3; % round scan: number of points in the first shell
p. scan.lx = 20e-6; % round_roi scan: width of the roi
p. scan.ly = 20e-6; % round_roi scan: height of the roi
p. scan.dr = 1.5e-6; % round_roi scan: shell step size
p. scan.nx = N_scan_x; %size(dp,3) % raster scan: number of steps in x
p. scan.ny = N_scan_y; % raster scan: number of steps in y
p. scan.step_size_x = scan_step_size; % raster scan: step size (grid spacing)
p. scan.step_size_y = scan_step_size; % raster scan: step size (grid spacing)
p. scan.custom_flip = [1,1,1]; % raster scan: apply custom flip [fliplr, flipud, transpose] to positions- similar to eng.custom_data_flip in GPU engines. Added by ZC.
p. scan.step_randn_offset = 0; % raster scan: relative random offset from the ideal periodic grid to avoid the raster grid pathology
p. scan.b = 0; % fermat: angular offset
p. scan.n_max = 1e4; % fermat: maximal number of points generated
p. scan.step = 0.5e-6; % fermat: step size
p. scan.cenxy = [0,0]; % fermat: position of center offset
p. scan.roi = []; % Region of interest in the object [xmin xmax ymin ymax] in meters. Points outside this region are not used for reconstruction.
% (relative to upper corner for raster scans and to center for round scans)
% custom: a string name of a function that defines the positions; also accepts mat file with entry 'pos', see +scans/+positions/+mat_pos.m
p. scan.custom_positions_source = '';
p. scan.custom_params = []; % custom: the parameters to feed to the custom position function.
% I/O
p. prefix = ''; % For automatic output filenames. If empty: scan number
p. suffix = strcat('ML_recon'); % Optional suffix for reconstruction
p. scan_string_format = scan_string_format; % format for scan string generation, it is used e.g for plotting and data saving
%%%p. base_path = '../../'; % base path : used for automatic generation of other paths
p. base_path = base_path; % base path : used for automatic generation of other paths
p. specfile = ''; % Name of spec file to get motor positions and check end of scan, defaut is p.spec_file == p.base_path;
p. ptycho_matlab_path = ''; % cSAXS ptycho package path
p. cSAXS_matlab_path = ''; % cSAXS base package path
p. raw_data_path{1} = ''; % Default using compile_x12sa_filename, used only if data should be prepared automatically
p. prepare_data_path = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. prepare_data_filename = []; % Leave empty for default file name generation, otherwise use [sprintf('S%05d_data_%03dx%03d',p.scan_number(1), p.asize(1), p.asize(2)) p.prep_data_suffix '.h5'] as default
p. save_path{1} = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. io.default_mask_file = ''; % load detector mask defined in this file instead of the mask in the detector packages, (used only if data should be prepared)
p. io.default_mask_type = 'binary'; % (used only if data should be prepared) ['binary', 'indices']. Default: 'binary'
p. io.file_compression = 0; % reconstruction file compression for HDF5 files; 0 for no compression
p. io.data_compression = 3; % prepared data file compression for HDF5 files; 0 for no compression
p. io.load_prep_pos = false; % load positions from prepared data file and ignore positions provided by metadata
p. io.data_descriptor = 'MoS2'; %added by YJ. A short string that describe data when sending notifications
p. io.phone_number = ''; % phone number for sending messages
p. io.send_failed_scans_SMS = false; % send message if p.queue_max_attempts is exceeded
p. io.send_finished_recon_SMS = false; % send message after the reconstruction is completed
p. io.send_crashed_recon_SMS = false; % send message if the reconstruction crashes
p. io.SMS_sleep = 1800; % max 1 message per SMS_sleep seconds
p. io.script_name = mfilename; % added by YJ. store matlab script name
p. artificial_data_file = 'template_artificial_data'; % artificial data parameters, set p.src_metadata = 'artificial' to use this template
%% Reconstruction
% Initial iterate object
p. model_object = true; % Use model object, if false load it from file
p. model.object_type = 'rand'; % specify how the object shall be created; use 'rand' for a random initial guess; use 'amplitude' for an initial guess based on the prepared data
p. initial_iterate_object_file{1} = ''; % use this mat-file as initial guess of object, it is possible to use wild characters and pattern filling, example: '../analysis/S%05i/wrap_*_1024x1024_1_recons*'
% Initial iterate probe
p. model_probe = false; % Use model probe, if false load it from file
p. model.probe_alpha_max = par.alpha_max;
% p. model.probe_alpha_max = 21.4; % Modal STEM probe's aperture size
p. model.probe_df = par.defocus;
% p. model.probe_df = -500; % Modal STEM probe's defocus
p. model.probe_c3 = 0; % Modal STEM probe's third-order spherical aberration in angstrom (optional)
p. model.probe_c5 = 0; % Modal STEM probe's fifth-order spherical aberration in angstrom (optional)
p. model.probe_c7 = 0; % Modal STEM probe's seventh-order spherical aberration in angstrom (optional)
p. model.probe_f_a2 = 0; % Modal STEM probe's twofold astigmatism in angstrom (optional)
p. model.probe_theta_a2 = 0; % Modal STEM probe's twofold azimuthal orientation in radian (optional)
p. model.probe_f_a3 = 0; % Modal STEM probe's threefold astigmatism in angstrom (optional)
p. model.probe_theta_a3 = 0; % Modal STEM probe's threefold azimuthal orientation in radian (optional)
p. model.probe_f_c3 = 0; % Modal STEM probe's coma in angstrom (optional)
p. model.probe_theta_c3 = 0; % Modal STEM probe's coma azimuthal orientation in radian (optional)
%Use probe from this mat-file (not used if model_probe is true)
p. initial_probe_file = initial_probe_file;
p. probe_file_propagation = 0.0e-3; % Distance for propagating the probe from file in meters, = 0 to ignore
p. normalize_init_probe = false; % Added by YJ. Can be used to disable normalization of initial probes
% Shared scans - Currently working only for sharing probe and object
p. share_probe = 0; % Share probe between scans. Can be either a number/boolean or a list of numbers, specifying the probe index; e.g. [1 2 2] to share the probes between the second and third scan.
p. share_object = 0; % Share object between scans. Can be either a number/boolean or a list of numbers, specifying the object index; e.g. [1 2 2] to share the objects between the second and third scan.
% Modes
p. probe_modes = Nprobe; % Number of coherent modes for probe
p. object_modes = 1; % Number of coherent modes for object
% Mode starting guess
p. mode_start_pow = 0.02; % Normalized intensity on probe modes > 1. Can be a number (all higher modes equal) or a vector
p. mode_start = 'herm'; % (for probe) = 'rand', = 'herm' (Hermitian-like base), = 'hermver' (vertical modes only), = 'hermhor' (horizontal modes only)
p. ortho_probes = true; % orthogonalize probes after each engine
%% Plot, save and analyze
p. plot.prepared_data = false; % plot prepared data
p. plot.interval = []; % plot each interval-th iteration, does not work for c_solver code
p. plot.log_scale = [0 0]; % Plot on log scale for x and y
p. plot.realaxes = true; % Plots show scale in microns
p. plot.remove_phase_ramp = false; % Remove phase ramp from the plotted / saved phase figures
p. plot.fov_box = false; % Plot the scanning FOV box on the object (both phase and amplitude)
p. plot.fov_box_color = 'r'; % Color of the scanning FOV box
p. plot.positions = true; % Plot the scanning positions
p. plot.mask_bool = true; % Mask the noisy contour of the reconstructed object in plots
p. plot.windowautopos = true; % First plotting will auto position windows
p. plot.obj_apod = false; % Apply apodization to the reconstructed object;
p. plot.prop_obj = 0; % Distance to propagate reconstructed object before plotting [m]
p. plot.show_layers = true; % show each layer in multilayer reconstruction
p. plot.show_layers_stack = false; % show each layer in multilayer reconstruction by imagesc3D
p. plot.object_spectrum = []; % Plot propagated object (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.probe_spectrum = []; % Plot propagated probe (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.conjugate = false; % plot complex conjugate of the reconstruction
p. plot.horz_fact = 2.5; % Scales the space that the ptycho figures take horizontally
p. plot.FP_maskdim = 180e-6; % Filter the backpropagation (Fourier Ptychography)
p. plot.calc_FSC = false; % Calculate the Fourier Shell correlation for 2 scans or compare with model in case of artificial data tests
p. plot.show_FSC = false; % Show the FSC plots, including the cropped FOV
p. plot.residua = false; % highlight phase-residua in the image of the reconstructed phase
p. save.external = true; % Use a new Matlab session to run save final figures (saves ~6s per reconstruction). Please be aware that this might lead to an accumulation of Matlab sessions if your single reconstruction is very fast.
p. save.store_images = false; % Write preview images containing the final reconstructions in [p.base_path,'analysis/online/ptycho/'] if p.use_display = 0 then the figures are opened invisible in order to create the nice layout. It writes images in analysis/online/ptycho
p. save.store_images_intermediate = false; % save images to disk after each engine
p. save.store_images_ids = 1:4; % identifiers of the figure to be stored, 1=obj. amplitude, 2=obj. phase, 3=probes, 4=errors, 5=probes spectrum, 6=object spectrum
p. save.store_images_format = 'png'; % data type of the stored images jpg or png
p. save.store_images_dpi = 150; % DPI of the stored bitmap images
p. save.exclude = {'fmag', 'fmask', 'illum_sum'}; % exclude variables to reduce the file size on disk
p. save.save_reconstructions_intermediate = false; % save final object and probes after each engine
p. save.save_reconstructions = false; % save reconstructed object and probe when full reconstruction is finished
p. save.output_file = 'h5'; % data type of reconstruction file; 'h5' or 'mat'
%% %%%%%%%%%%%%%%%%%% initialize reconstruction parameters %%%%%%%%%%%%%%%%%%%%
% --------- GPU engines ------------- See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng = struct(); % reset settings for this engine
eng. name = 'GPU';
eng. use_gpu = true; % if false, run CPU code, but it will get very slow
eng. keep_on_gpu = true; % keep data + projections on GPU, false is useful for large data if DM is used
eng. compress_data = false; % use automatic online memory compression to limit need of GPU memory
eng. gpu_id = gpu_id; % default GPU id, [] means choosen by matlab
eng. check_gpu_load = true; % check available GPU memory before starting GPU engines
% general
eng. number_iterations = Niter; % number of iterations for selected method
eng. asize_presolve = []; % crop data to "asize_presolve" size to get low resolution estimate that can be used in the next engine as a good initial guess
eng. align_shared_objects = false; % before merging multiple unshared objects into one shared, the object will be aligned and the probes shifted by the same distance -> use for alignement and shared reconstruction of drifting scans
eng. method = 'MLs'; % choose GPU solver: DM, ePIE, hPIE, MLc, Mls, -- recommended are MLc and MLs
eng. opt_errmetric = 'L1'; % optimization likelihood - poisson, L1
eng. grouping = grouping; % size of processed blocks, larger blocks need more memory but they use GPU more effeciently, !!! grouping == inf means use as large as possible to fit into memory
% * for hPIE, ePIE, MLs methods smaller blocks lead to faster convergence,
% * for MLc the convergence is similar
% * for DM is has no effect on convergence
eng. probe_modes = p.probe_modes; % Number of coherent modes for probe
eng. object_change_start = 1; % Start updating object at this iteration number
eng. probe_change_start = 1; % Start updating probe at this iteration number
% regularizations
eng. reg_mu = 0; % Regularization (smooting) constant ( reg_mu = 0 for no regularization)
eng. delta = 0; % press values to zero out of the illumination area in th object, usually 1e-2 is enough
eng. positivity_constraint_object = 0; % enforce weak (relaxed) positivity in object, ie O = O*(1-a)+a*|O|, usually a=1e-2 is already enough. Useful in conbination with OPRP or probe_fourier_shift_search
eng. apply_multimodal_update = true; % apply all incoherent modes to object, it can cause isses if the modes collect some crap
eng. probe_backpropagate = 0; % backpropagation distance the probe mask, 0 == apply in the object plane. Useful for pinhole imaging where the support can be applied at the pinhole plane
eng. probe_support_radius = []; % Normalized radius of circular support, = 1 for radius touching the window
eng. probe_support_fft = false; % assume that there is not illumination intensity out of the central FZP cone and enforce this contraint. Useful for imaging with focusing optics. Helps to remove issues from the gaps between detector modules.
% basic recontruction parameters
% PIE / ML methods % See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. beta_object = 1; % object step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. beta_probe = 1; % probe step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. delta_p = 0.1; % LSQ dumping constant, 0 == no preconditioner, 0.1 is usually safe, Preconditioner accelerates convergence and ML methods become approximations of the second order solvers
eng. momentum = 0; % add momentum acceleration term to the MLc method, useful if the probe guess is very poor or for acceleration of multilayer solver, but it is quite computationally expensive to be used in conventional ptycho without any refinement.
% The momentum method works usually well even with the accelerated_gradients option. eng.momentum = multiplication gain for velocity, eng.momentum == 0 -> no acceleration, eng.momentum == 0.5 is a good value
% momentum is enabled only when par.Niter < par.accelerated_gradients_start;
eng. accelerated_gradients_start = inf; % iteration number from which the Nesterov gradient acceleration should be applied, this option is supported only for MLc method. It is very computationally cheap way of convergence acceleration.
% DM
eng. pfft_relaxation = 0.05; % Relaxation in the Fourier domain projection, = 0 for full projection
eng. probe_regularization = 0.1; % Weight factor for the probe update (inertia)
% ADVANCED OPTIONS See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
% position refinement
eng. apply_subpix_shift = true; % apply FFT-based subpixel shift, it is automatically allowed for position refinement
eng. probe_position_search = N_pos_corr; % iteration number from which the engine will reconstruct probe positions, from iteration == probe_position_search, assume they have to match geometry model with error less than probe_position_error_max
eng. probe_geometry_model = {'scale', 'asymmetry', 'rotation', 'shear'}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
%eng. probe_geometry_model = {}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_position_error_max = inf; % maximal expected random position errors, probe prositions are confined in a circle with radius defined by probe_position_error_max and with center defined by original positions scaled by probe_geometry_model
eng. apply_relaxed_position_constraint = true; % added by YJ. Apply a relaxed constraint to probe positions. default = true. Set to false if there are big jumps in positions.
eng. update_pos_weight_every = 100; % added by YJ. Allow position weight to be updated multiple times. default = inf: only update once.
% multilayer extension
eng. delta_z = []; % if not empty, use multilayer ptycho extension , see ML_MS code for example of use, [] == common single layer ptychography , note that delta_z provides only relative propagation distance from the previous layer, ie delta_z can be either positive or negative. If preshift_ML_probe == false, the first layer is defined by position of initial probe plane. It is useful to use eng.momentum for convergence acceleration
eng. regularize_layers = 0; % multilayer extension: 0<R<<1 -> apply regularization on the reconstructed object layers, 0 == no regularization, 0.01 == weak regularization that will slowly symmetrize information content between layers
eng. preshift_ML_probe = true; % multilayer extension: if true, assume that the provided probe is reconstructed in center of the sample and the layers are centered around this position
% other extensions
eng. background = 0; % average background scattering level, for OMNI values around 0.3 for 100ms, for flOMNI <0.1 per 100ms exposure, see for more details: Odstrcil, M., et al., Optics letters 40.23 (2015): 5574-5577.
eng. background_width = inf; % width of the background function in pixels, inf == flat background, background function is then convolved with the average diffraction pattern in order to account for beam diversion
eng. clean_residua = false; % remove phase residua from reconstruction by iterative unwrapping, it will result in low spatial freq. artefacts -> object can be used as an residua-free initial guess for netx engine
% wavefront & camera geometry refinement See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. probe_fourier_shift_search = inf; % iteration number from which the engine will: refine farfield position of the beam (ie angle) from iteration == probe_fourier_shift_search
eng. estimate_NF_distance = inf; % iteration number from which the engine will: try to estimate the nearfield propagation distance using gradient descent optimization
eng. detector_rotation_search = inf; % iteration number from which the engine will: search for optimal detector rotation, preferably use with option mirror_scan = true , rotation of the detector axis with respect to the sample axis, similar as rotation option in the position refinement geometry model but works also for 0/180deg rotation shared scans
eng. detector_scale_search = inf; % iteration number from which the engine will: refine pixel scale of the detector, can be used to refine propagation distance in ptycho
eng. variable_probe = variable_probe_modes>0; % Use SVD to account for variable illumination during a single (coupled) scan, see for more details: Odstrcil, M. et al. Optics express 24.8 (2016): 8360-8369.
eng. variable_probe_modes = variable_probe_modes; % OPRP settings , number of SVD modes using to describe the probe evolution.
eng. variable_probe_smooth = 0; % OPRP settings , enforce of smooth evolution of the OPRP modes -> N is order of polynomial fit used for smoothing, 0 == do not apply any smoothing. Smoothing is useful if only a smooth drift is assumed during the ptycho acquisition
eng. variable_intensity = variable_probe_modes>0; % account to changes in probe intensity
% extra analysis
eng. get_fsc_score = false; % measure evolution of the Fourier ring correlation during convergence
eng. mirror_objects = false; % mirror objects, useful for 0/180deg scan sharing -> geometry refinement for tomography, works only if 2 scans are provided
% custom data adjustments, useful for offaxis ptychography
eng.auto_center_data = false; % autoestimate the center of mass from data and shift the diffraction patterns so that the average center of mass corresponds to center of mass of the provided probe
eng.auto_center_probe = false; % center the probe position in real space before reconstruction is started
eng.custom_data_flip = [0,0,0]; % apply custom flip of the data [fliplr, flipud, transpose] - can be used for quick testing of reconstruction with various flips or for reflection ptychography
eng.apply_tilted_plane_correction = ''; % if any(p.sample_rotation_angles([1,2]) ~= 0), this option will apply tilted plane correction. (a) 'diffraction' apply correction into the data, note that it is valid only for "low NA" illumination Gardner, D. et al., Optics express 20.17 (2012): 19050-19059. (b) 'propagation' - use tilted plane propagation, (c) '' - will not apply any correction
% I/O
eng.plot_results_every = Niter_plot_results;
eng.save_results_every = Niter_save_results;
eng.save_images ={'obj_ph','probe_mag','probe'};
eng.extraPrintInfo = par.extra_print_info;
% eng.extraPrintInfo = strcat('MoS2');
resultDir = strcat(p.base_path,sprintf(p.scan.format, p.scan_number),'/roi',p.scan.roi_label,'/');
[eng.fout, p.suffix] = generateResultDir(eng, resultDir);
%add engine
[p, ~] = core.append_engine(p, eng); % Adds this engine to the reconstruction process
%% Run the reconstruction
tic
out = core.ptycho_recons(p);
toc
+335
View File
@@ -0,0 +1,335 @@
clear variables
addpath(strcat(pwd,'/utils/'))
addpath(core.find_base_package)
%%%%%%%%%%%%%%%%%%%% data parameters %%%%%%%%%%%%%%%%%%%%
base_path = 'BO_tests/';
roi_label = '0_Ndp256';
scan_number = 1;
scan_string_format = '%01d';
Ndpx = 256; % size of cbed
alpha0 = 21.4; % semi-convergence angle (mrad)
rbf = 26; % radius of the BF disk in cbed. Can be used to calculate dk
voltage = 300;
rot_ang = 0; %angle between cbed and scan coord.
scan_step_size = 0.41; %angstrom
N_scan_y = 64; %number of scan points
N_scan_x = 64;
%%%%%%%%%%%%%%%%%%%% reconstruction parameters %%%%%%%%%%%%%%%%%%%%
gpu_id = 1;
Niter_save_results = 50;
Niter_plot_results = inf;
Nprobe = 8; % # of probe modes
thickness = 210; % sample thickness in angstrom
Nlayers = 21; % # of slices for multi-slice, 1 for single-slice
delta_z = thickness / Nlayers;
initial_probe_file = fullfile(base_path,'/1/init_probe.mat');
%% %%%%%%%%%%%%%%%%%% initialize data parameters %%%%%%%%%%%%%%%%%%%%
p = struct();
p. verbose_level = 2; % verbosity for standard output (0-1 for loops, 2-3 for testing and adjustments, >= 4 for debugging)
p. use_display = false; % global switch for display, if [] then true for verbose > 1
p. scan_number = scan_number; % Multiple scan numbers for shared scans
% Geometry
p. z = 1; % Distance from object to detector. Always 1 for electron ptycho
p. asize = [Ndpx,Ndpx]; % Diffr. patt. array size
p. ctr = [fix(Ndpx/2)+1, fix(Ndpx/2)+1]; % Diffr. patt. center coordinates (y,x) (empty means middle of the array); e.g. [100 207;100+20 207+10];
p. beam_source = 'electron'; % Added by YJ for electron pty. Use relativistic corrected formula for wavelength. Also change the units on figures
%p. dk = dk; % Added by YJ. dk is the pixel size in cbed (1/A). This is used to determine pixel size in electron ptycho
p. d_alpha = alpha0/rbf; % Added by YJ. d_alpha is the pixel size in cbed (mrad). This is used to determine pixel size in electron ptycho
p. prop_regime = 'farfield'; % propagation regime: nearfield, farfield (default), !! nearfield is supported only by GPU engines
p. focus_to_sample_distance = []; % sample to focus distance, parameter to be set for nearfield ptychography, otherwise it is ignored
p. energy = voltage; % Energy (in keV), leave empty to use spec entry mokev
%p. affine_angle = 0; % Not used by ptycho_recons at all. This allows you to define a variable for the affine matrix below and keep it in p for future record. This is used later by the affine_matrix_search.m script
%p. affine_matrix = [1 , 0; 0, 1] ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
affine_mat = compose_affine_matrix(1, 0, rot_ang, 0);
p. affine_matrix = affine_mat ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
% Scan meta data
p. src_metadata = 'none'; % source of the meta data, following options are supported: 'spec', 'none' , 'artificial' - or add new to +scan/+meta/
p. queue.lockfile = false; % If true writes a lock file, if lock file exists skips recontruction
% Data preparation
p. detector.name = 'empad'; % see +detectors/ folder
p. detector.check_2_detpos = []; % = []; (ignores) = 270; compares to dettrx to see if p.ctr should be reversed (for OMNY shared scans 1221122), make equal to the middle point of dettrx between the 2 detector positions
p. detector.data_prefix = ''; % Default using current eaccount e.g. e14169_1_
p. detector.binning = false; % = true to perform 2x2 binning of detector pixels, for binning = N do 2^Nx2^N binning
p. detector.upsampling = false; % upsample the measured data by 2^data_upsampling, (transposed operator to the binning), it can be used for superresolution in nearfield ptychography or to account for undersampling in a far-field dataset
p. detector.burst_frames = 1; % number of frames collected per scan position
p. prepare.data_preparator = 'matlab_aps'; % data preparator; 'python' or 'matlab' or 'matlab_aps'
p. prepare.auto_prepare_data = true; % if true: prepare dataset from raw measurements if the prepared data does not exist
p. prepare.force_preparation_data = true; % Prepare dataset even if it exists, it will overwrite the file % Default: @prepare_data_2d
p. prepare.store_prepared_data = false; % store the loaded data to h5 even for non-external engines (i.e. other than c_solver)
p. prepare.prepare_data_function = ''; % (used only if data should be prepared) custom data preparation function handle;
p. prepare.auto_center_data = false; % if matlab data preparator is used, try to automatically center the diffraction pattern to keep center of mass in center of diffraction
% Scan positions
p. src_positions = 'matlab_pos'; % 'spec', 'orchestra', 'load_from_file', 'matlab_pos' (scan params are defined below) or add new position loaders to +scan/+positions/
p. positions_file = ''; %Filename pattern for position files, Example: ['../../specES1/scan_positions/scan_%05d.dat']; (the scan number will be automatically filled in)
% scan parameters for option src_positions = 'matlab_pos';
p. scan.type = 'raster'; % {'round', 'raster', 'round_roi', 'custom'}
p. scan.roi_label = roi_label; % For APS data
p. scan.format = scan_string_format; % For APS data format for scan directory generation
p. scan.radius_in = 0; % round scan: interior radius of the round scan
p. scan.radius_out = 5e-6; % round scan: exterior radius of the round scan
p. scan.nr = 10; % round scan: number of intervals (# of shells - 1)
p. scan.nth = 3; % round scan: number of points in the first shell
p. scan.lx = 20e-6; % round_roi scan: width of the roi
p. scan.ly = 20e-6; % round_roi scan: height of the roi
p. scan.dr = 1.5e-6; % round_roi scan: shell step size
p. scan.nx = N_scan_x; %size(dp,3) % raster scan: number of steps in x
p. scan.ny = N_scan_y; % raster scan: number of steps in y
p. scan.step_size_x = scan_step_size; % raster scan: step size (grid spacing)
p. scan.step_size_y = scan_step_size; % raster scan: step size (grid spacing)
p. scan.custom_flip = [1,1,1]; % raster scan: apply custom flip [fliplr, flipud, transpose] to positions- similar to eng.custom_data_flip in GPU engines. Added by ZC.
p. scan.step_randn_offset = 0; % raster scan: relative random offset from the ideal periodic grid to avoid the raster grid pathology
p. scan.b = 0; % fermat: angular offset
p. scan.n_max = 1e4; % fermat: maximal number of points generated
p. scan.step = 0.5e-6; % fermat: step size
p. scan.cenxy = [0,0]; % fermat: position of center offset
p. scan.roi = []; % Region of interest in the object [xmin xmax ymin ymax] in meters. Points outside this region are not used for reconstruction.
% (relative to upper corner for raster scans and to center for round scans)
% custom: a string name of a function that defines the positions; also accepts mat file with entry 'pos', see +scans/+positions/+mat_pos.m
p. scan.custom_positions_source = '';
p. scan.custom_params = []; % custom: the parameters to feed to the custom position function.
% I/O
p. prefix = ''; % For automatic output filenames. If empty: scan number
p. suffix = strcat('ML_recon'); % Optional suffix for reconstruction
p. scan_string_format = scan_string_format; % format for scan string generation, it is used e.g for plotting and data saving
%%%p. base_path = '../../'; % base path : used for automatic generation of other paths
p. base_path = base_path; % base path : used for automatic generation of other paths
p. specfile = ''; % Name of spec file to get motor positions and check end of scan, defaut is p.spec_file == p.base_path;
p. ptycho_matlab_path = ''; % cSAXS ptycho package path
p. cSAXS_matlab_path = ''; % cSAXS base package path
p. raw_data_path{1} = ''; % Default using compile_x12sa_filename, used only if data should be prepared automatically
p. prepare_data_path = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. prepare_data_filename = []; % Leave empty for default file name generation, otherwise use [sprintf('S%05d_data_%03dx%03d',p.scan_number(1), p.asize(1), p.asize(2)) p.prep_data_suffix '.h5'] as default
p. save_path{1} = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. io.default_mask_file = ''; % load detector mask defined in this file instead of the mask in the detector packages, (used only if data should be prepared)
p. io.default_mask_type = 'binary'; % (used only if data should be prepared) ['binary', 'indices']. Default: 'binary'
p. io.file_compression = 0; % reconstruction file compression for HDF5 files; 0 for no compression
p. io.data_compression = 3; % prepared data file compression for HDF5 files; 0 for no compression
p. io.load_prep_pos = false; % load positions from prepared data file and ignore positions provided by metadata
p. io.data_descriptor = 'PSO multislice'; %added by YJ. A short string that describe data when sending notifications
p. io.phone_number = ''; % phone number for sending messages
p. io.send_failed_scans_SMS = false; % send message if p.queue_max_attempts is exceeded
p. io.send_finished_recon_SMS = false; % send message after the reconstruction is completed
p. io.send_crashed_recon_SMS = false; % send message if the reconstruction crashes
p. io.SMS_sleep = 1800; % max 1 message per SMS_sleep seconds
p. io.script_name = mfilename; % added by YJ. store matlab script name
p. artificial_data_file = 'template_artificial_data'; % artificial data parameters, set p.src_metadata = 'artificial' to use this template
%% Reconstruction
% Initial iterate object
p. model_object = true; % Use model object, if false load it from file
p. model.object_type = 'rand'; % specify how the object shall be created; use 'rand' for a random initial guess; use 'amplitude' for an initial guess based on the prepared data
p. initial_iterate_object_file{1} = ''; % use this mat-file as initial guess of object, it is possible to use wild characters and pattern filling, example: '../analysis/S%05i/wrap_*_1024x1024_1_recons*'
% Initial iterate probe
p. model_probe = false; % Use model probe, if false load it from file
p. model.probe_alpha_max = 21.4; % Modal STEM probe's aperture size
p. model.probe_df = -200; % Modal STEM probe's defocus
p. model.probe_c3 = 0; % Modal STEM probe's third-order spherical aberration in angstrom (optional)
p. model.probe_c5 = 0; % Modal STEM probe's fifth-order spherical aberration in angstrom (optional)
p. model.probe_c7 = 0; % Modal STEM probe's seventh-order spherical aberration in angstrom (optional)
p. model.probe_f_a2 = 0; % Modal STEM probe's twofold astigmatism in angstrom (optional)
p. model.probe_theta_a2 = 0; % Modal STEM probe's twofold azimuthal orientation in radian (optional)
p. model.probe_f_a3 = 0; % Modal STEM probe's threefold astigmatism in angstrom (optional)
p. model.probe_theta_a3 = 0; % Modal STEM probe's threefold azimuthal orientation in radian (optional)
p. model.probe_f_c3 = 0; % Modal STEM probe's coma in angstrom (optional)
p. model.probe_theta_c3 = 0; % Modal STEM probe's coma azimuthal orientation in radian (optional)
%Use probe from this mat-file (not used if model_probe is true)
p. initial_probe_file = initial_probe_file;
p. probe_file_propagation = 0.0e-3; % Distance for propagating the probe from file in meters, = 0 to ignore
p. normalize_init_probe = true; % Added by YJ. Can be used to disable normalization of initial probes
% Shared scans - Currently working only for sharing probe and object
p. share_probe = 0; % Share probe between scans. Can be either a number/boolean or a list of numbers, specifying the probe index; e.g. [1 2 2] to share the probes between the second and third scan.
p. share_object = 0; % Share object between scans. Can be either a number/boolean or a list of numbers, specifying the object index; e.g. [1 2 2] to share the objects between the second and third scan.
% Modes
p. probe_modes = Nprobe; % Number of coherent modes for probe
p. object_modes = 1; % Number of coherent modes for object
% Mode starting guess
p. mode_start_pow = 0.02; % Normalized intensity on probe modes > 1. Can be a number (all higher modes equal) or a vector
p. mode_start = 'herm'; % (for probe) = 'rand', = 'herm' (Hermitian-like base), = 'hermver' (vertical modes only), = 'hermhor' (horizontal modes only)
p. ortho_probes = true; % orthogonalize probes after each engine
%% Plot, save and analyze
p. plot.prepared_data = false; % plot prepared data
p. plot.interval = []; % plot each interval-th iteration, does not work for c_solver code
p. plot.log_scale = [0 0]; % Plot on log scale for x and y
p. plot.realaxes = true; % Plots show scale in microns
p. plot.remove_phase_ramp = false; % Remove phase ramp from the plotted / saved phase figures
p. plot.fov_box = false; % Plot the scanning FOV box on the object (both phase and amplitude)
p. plot.fov_box_color = 'r'; % Color of the scanning FOV box
p. plot.positions = true; % Plot the scanning positions
p. plot.mask_bool = true; % Mask the noisy contour of the reconstructed object in plots
p. plot.windowautopos = true; % First plotting will auto position windows
p. plot.obj_apod = false; % Apply apodization to the reconstructed object;
p. plot.prop_obj = 0; % Distance to propagate reconstructed object before plotting [m]
p. plot.show_layers = true; % show each layer in multilayer reconstruction
p. plot.show_layers_stack = false; % show each layer in multilayer reconstruction by imagesc3D
p. plot.object_spectrum = []; % Plot propagated object (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.probe_spectrum = []; % Plot propagated probe (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.conjugate = false; % plot complex conjugate of the reconstruction
p. plot.horz_fact = 2.5; % Scales the space that the ptycho figures take horizontally
p. plot.FP_maskdim = 180e-6; % Filter the backpropagation (Fourier Ptychography)
p. plot.calc_FSC = false; % Calculate the Fourier Shell correlation for 2 scans or compare with model in case of artificial data tests
p. plot.show_FSC = false; % Show the FSC plots, including the cropped FOV
p. plot.residua = false; % highlight phase-residua in the image of the reconstructed phase
p. save.external = true; % Use a new Matlab session to run save final figures (saves ~6s per reconstruction). Please be aware that this might lead to an accumulation of Matlab sessions if your single reconstruction is very fast.
p. save.store_images = false; % Write preview images containing the final reconstructions in [p.base_path,'analysis/online/ptycho/'] if p.use_display = 0 then the figures are opened invisible in order to create the nice layout. It writes images in analysis/online/ptycho
p. save.store_images_intermediate = false; % save images to disk after each engine
p. save.store_images_ids = 1:4; % identifiers of the figure to be stored, 1=obj. amplitude, 2=obj. phase, 3=probes, 4=errors, 5=probes spectrum, 6=object spectrum
p. save.store_images_format = 'png'; % data type of the stored images jpg or png
p. save.store_images_dpi = 150; % DPI of the stored bitmap images
p. save.exclude = {'fmag', 'fmask', 'illum_sum'}; % exclude variables to reduce the file size on disk
p. save.save_reconstructions_intermediate = false; % save final object and probes after each engine
p. save.save_reconstructions = false; % save reconstructed object and probe when full reconstruction is finished
p. save.output_file = 'h5'; % data type of reconstruction file; 'h5' or 'mat'
%% %%%%%%%%%%%%%%%%%% initialize reconstruction parameters %%%%%%%%%%%%%%%%%%%%
% --------- GPU engines ------------- See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng = struct(); % reset settings for this engine
eng. name = 'GPU_MS';
eng. use_gpu = true; % if false, run CPU code, but it will get very slow
eng. keep_on_gpu = true; % keep data + projections on GPU, false is useful for large data if DM is used
eng. compress_data = false; % use automatic online memory compression to limit need of GPU memory
eng. gpu_id = gpu_id; % default GPU id, [] means choosen by matlab
eng. check_gpu_load = true; % check available GPU memory before starting GPU engines
% general
eng. number_iterations = 200; % number of iterations for selected method
eng. asize_presolve = [128, 128]; % crop data to "asize_presolve" size to get low resolution estimate that can be used in the next engine as a good initial guess
eng. align_shared_objects = false; % before merging multiple unshared objects into one shared, the object will be aligned and the probes shifted by the same distance -> use for alignement and shared reconstruction of drifting scans
eng. method = 'MLs'; % choose GPU solver: DM, ePIE, hPIE, MLc, Mls, -- recommended are MLc and MLs
eng. opt_errmetric = 'L1'; % optimization likelihood - poisson, L1
eng. grouping = 64; % size of processed blocks, larger blocks need more memory but they use GPU more effeciently, !!! grouping == inf means use as large as possible to fit into memory
% * for hPIE, ePIE, MLs methods smaller blocks lead to faster convergence,
% * for MLc the convergence is similar
% * for DM is has no effect on convergence
eng. probe_modes = p.probe_modes; % Number of coherent modes for probe
eng. object_change_start = 1; % Start updating object at this iteration number
eng. probe_change_start = 20; % Start updating probe at this iteration number
% regularizations
eng. reg_mu = 0; % Regularization (smooting) constant ( reg_mu = 0 for no regularization)
eng. delta = 0; % press values to zero out of the illumination area in th object, usually 1e-2 is enough
eng. positivity_constraint_object = 0; % enforce weak (relaxed) positivity in object, ie O = O*(1-a)+a*|O|, usually a=1e-2 is already enough. Useful in conbination with OPRP or probe_fourier_shift_search
eng. apply_multimodal_update = false; % apply all incoherent modes to object, it can cause isses if the modes collect some crap
eng. probe_backpropagate = 0; % backpropagation distance the probe mask, 0 == apply in the object plane. Useful for pinhole imaging where the support can be applied at the pinhole plane
eng. probe_support_radius = []; % Normalized radius of circular support, = 1 for radius touching the window
eng. probe_support_fft = false; % assume that there is not illumination intensity out of the central FZP cone and enforce this contraint. Useful for imaging with focusing optics. Helps to remove issues from the gaps between detector modules.
% basic recontruction parameters
% PIE / ML methods % See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. beta_object = 1; % object step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. beta_probe = 1; % probe step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. delta_p = 0.1; % LSQ dumping constant, 0 == no preconditioner, 0.1 is usually safe, Preconditioner accelerates convergence and ML methods become approximations of the second order solvers
eng. momentum = 0; % add momentum acceleration term to the MLc method, useful if the probe guess is very poor or for acceleration of multilayer solver, but it is quite computationally expensive to be used in conventional ptycho without any refinement.
% The momentum method works usually well even with the accelerated_gradients option. eng.momentum = multiplication gain for velocity, eng.momentum == 0 -> no acceleration, eng.momentum == 0.5 is a good value
% momentum is enabled only when par.Niter < par.accelerated_gradients_start;
eng. accelerated_gradients_start = inf; % iteration number from which the Nesterov gradient acceleration should be applied, this option is supported only for MLc method. It is very computationally cheap way of convergence acceleration.
% DM
eng. pfft_relaxation = 0.05; % Relaxation in the Fourier domain projection, = 0 for full projection
eng. probe_regularization = 0.1; % Weight factor for the probe update (inertia)
% ADVANCED OPTIONS See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
% position refinement
eng. apply_subpix_shift = true; % apply FFT-based subpixel shift, it is automatically allowed for position refinement
eng. probe_position_search = 50; % iteration number from which the engine will reconstruct probe positions, from iteration == probe_position_search, assume they have to match geometry model with error less than probe_position_error_max
%eng. probe_geometry_model = {'scale', 'asymmetry', 'rotation', 'shear'}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_geometry_model = {}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_position_error_max = inf; % maximal expected random position errors, probe prositions are confined in a circle with radius defined by probe_position_error_max and with center defined by original positions scaled by probe_geometry_model
eng. apply_relaxed_position_constraint = false; % added by YJ. Apply a relaxed constraint to probe positions. default = true. Set to false if there are big jumps in positions.
eng. update_pos_weight_every = inf; % added by YJ. Allow position weight to be updated multiple times. default = inf: only update once.
% multilayer extension
eng. delta_z = delta_z*ones(Nlayers,1); % if not empty, use multilayer ptycho extension , see ML_MS code for example of use, [] == common single layer ptychography , note that delta_z provides only relative propagation distance from the previous layer, ie delta_z can be either positive or negative. If preshift_ML_probe == false, the first layer is defined by position of initial probe plane. It is useful to use eng.momentum for convergence acceleration
eng. regularize_layers = 1; % multilayer extension: 0<R<<1 -> apply regularization on the reconstructed object layers, 0 == no regularization, 0.01 == weak regularization that will slowly symmetrize information content between layers
eng. preshift_ML_probe = false; % multilayer extension: if true, assume that the provided probe is reconstructed in center of the sample and the layers are centered around this position
eng. layer4pos = []; % Added by ZC. speficy which layer is used for position correction ; if empty, then default, ceil(Nlayers/2)
eng. init_layer_select = []; % Added by YJ. Select layers in the initial object for pre-processing. If empty (default): use all layers.
eng. init_layer_preprocess = ''; % Added by YJ. Specify how to pre-process initial layers
% '' or 'all' (default): use all layers (do nothing)
% 'avg': average all layers
% 'interp': interpolate layers using spline method. Need to specify desired depths in init_layer_interp
eng. init_layer_interp = []; % Specify desired depths for interpolation. The depths of initial are [1:Nlayer_init]. If empty (default), no interpolation
eng. init_layer_append_mode = ''; % Added by YJ. Specify how to initialize extra layers
% '' or 'vac' (default): add vacuum layers
% 'edge': append 1st or last layers
% 'avg': append averaged layer
eng. init_layer_scaling_factor = 1; % Added by YJ. Scale all layers. Default: 1 (no scaling). Useful when delta_z is changed
% other extensions
eng. background = 0; % average background scattering level, for OMNI values around 0.3 for 100ms, for flOMNI <0.1 per 100ms exposure, see for more details: Odstrcil, M., et al., Optics letters 40.23 (2015): 5574-5577.
eng. background_width = inf; % width of the background function in pixels, inf == flat background, background function is then convolved with the average diffraction pattern in order to account for beam diversion
eng. clean_residua = false; % remove phase residua from reconstruction by iterative unwrapping, it will result in low spatial freq. artefacts -> object can be used as an residua-free initial guess for netx engine
% wavefront & camera geometry refinement See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. probe_fourier_shift_search = inf; % iteration number from which the engine will: refine farfield position of the beam (ie angle) from iteration == probe_fourier_shift_search
eng. estimate_NF_distance = inf; % iteration number from which the engine will: try to estimate the nearfield propagation distance using gradient descent optimization
eng. detector_rotation_search = inf; % iteration number from which the engine will: search for optimal detector rotation, preferably use with option mirror_scan = true , rotation of the detector axis with respect to the sample axis, similar as rotation option in the position refinement geometry model but works also for 0/180deg rotation shared scans
eng. detector_scale_search = inf; % iteration number from which the engine will: refine pixel scale of the detector, can be used to refine propagation distance in ptycho
eng. variable_probe = true; % Use SVD to account for variable illumination during a single (coupled) scan, see for more details: Odstrcil, M. et al. Optics express 24.8 (2016): 8360-8369.
eng. variable_probe_modes = 1; % OPRP settings , number of SVD modes using to describe the probe evolution.
eng. variable_probe_smooth = 0; % OPRP settings , enforce of smooth evolution of the OPRP modes -> N is order of polynomial fit used for smoothing, 0 == do not apply any smoothing. Smoothing is useful if only a smooth drift is assumed during the ptycho acquisition
eng. variable_intensity = false; % account to changes in probe intensity
% extra analysis
eng. get_fsc_score = false; % measure evolution of the Fourier ring correlation during convergence
eng. mirror_objects = false; % mirror objects, useful for 0/180deg scan sharing -> geometry refinement for tomography, works only if 2 scans are provided
% custom data adjustments, useful for offaxis ptychography
eng.auto_center_data = false; % autoestimate the center of mass from data and shift the diffraction patterns so that the average center of mass corresponds to center of mass of the provided probe
eng.auto_center_probe = false; % center the probe position in real space before reconstruction is started
eng.custom_data_flip = [0,0,0]; % apply custom flip of the data [fliplr, flipud, transpose] - can be used for quick testing of reconstruction with various flips or for reflection ptychography
eng.apply_tilted_plane_correction = ''; % if any(p.sample_rotation_angles([1,2]) ~= 0), this option will apply tilted plane correction. (a) 'diffraction' apply correction into the data, note that it is valid only for "low NA" illumination Gardner, D. et al., Optics express 20.17 (2012): 19050-19059. (b) 'propagation' - use tilted plane propagation, (c) '' - will not apply any correction
% I/O
eng.plot_results_every = Niter_plot_results;
eng.save_results_every = Niter_save_results;
eng.save_images ={'obj_ph_stack','obj_ph_sum','probe'};
eng.extraPrintInfo = strcat('PSO');
resultDir = strcat(p.base_path,sprintf(p.scan.format, p.scan_number),'/roi',p.scan.roi_label,'/');
[eng.fout, p.suffix] = generateResultDir(eng, resultDir);
%add engine
[p, ~] = core.append_engine(p, eng); % Adds this engine to the reconstruction process
%% refined reconstruction at full resolution
eng. number_iterations = 200; % number of iterations for selected method
eng. asize_presolve = []; % crop data to "asize_presolve" size to get low resolution estimate that can be used in the next engine as a good initial guess
eng. grouping = 32; % size of processed blocks, larger blocks need more memory but they use GPU more effeciently, !!! grouping == inf means use as large as possible to fit into memory
% * for hPIE, ePIE, MLs methods smaller blocks lead to faster convergence,
% * for MLc the convergence is similar
% * for DM is has no effect on convergence
eng. probe_change_start = 10; % Start updating probe at this iteration number
eng. probe_position_search = 50; % iteration number from which the engine will reconstruct probe positions, from iteration == probe_position_search, assume they have to match geometry model with error less than probe_position_error_max
[eng.fout, p.suffix] = generateResultDir(eng, resultDir);
%add engine
[p, ~] = core.append_engine(p, eng); % Adds this engine to the reconstruction process
%% Run the reconstruction
tic
out = core.ptycho_recons(p);
toc
@@ -0,0 +1,437 @@
% initialize reconstruction parameters for simulated ptycho data
addpath(fullfile(pwd,'/utils/'))
addpath(core.find_base_package)
testmode = false; % In test mode, lock files are not written and plots are generated every iteration
%% %%%%%%%%%%%%%%%%%% load data parameters %%%%%%%%%%%%%%%%%%%%
initial_probe_file = strcat(base_path_ptycho,'/init_probe.mat');
load(initial_probe_file)
energy = par_probe.voltage;
dk = p.dk;
scan_string_format = 'data%d';
roi_label = '0';
%% %%%%%%%%%%%%%%%%%% recon parameters %%%%%%%%%%%%%%%%%%%%
gpu_id = 1;
Niter = 200;
Nprobe = 3;
var_probe_modes = 0;
%grouping = 20;
Ndp = 128; %size of diffraction patterns
cen_dp = floor(Ndp/2)+1;
Niter_refined = 0; % more refined reconstruction
get_fsc_score = true;
Niter_save_results = 100;
Niter_plot_results = 20; % set to inf if you don't want any plots
%% General
p = struct();
p. verbose_level = 2; % verbosity for standard output (0-1 for loops, 2-3 for testing and adjustments, >= 4 for debugging)
p. use_display = Niter_plot_results<Niter; % global switch for display, if [] then true for verbose > 1
p. scan_number = [1,2]; % Multiple scan numbers for shared scans
% Geometry
p. z = 1; % Distance from object to detector
p. asize = [Ndp, Ndp]; % Diffr. patt. array size
p. ctr = [cen_dp, cen_dp]; % Diffr. patt. center coordinates (y,x) (empty means middle of the array); e.g. [100 207;100+20 207+10];
p. beam_source = 'electron'; % Added by YJ for electron pty. Use relativistic corrected formula for wavelength
p. dk = dk; % Added by YJ. For determinting pixel size in electron pty.
p. prop_regime = 'farfield'; % propagation regime: nearfield, farfield (default), !! nearfield is supported only by GPU engines
p. focus_to_sample_distance = []; % sample to focus distance, parameter to be set for nearfield ptychography, otherwise it is ignored
p. FP_focal_distance = []; % if nonempty -> assume Fourier ptychography configuration, FP_focal_distance = focal length of objective lens for Fourier Ptychography only,
p. angular_correction_setup = 'none'; % if src_positions=='orchestra', choose angular correction for specific cSAXS experiment: 'flomni', 'omny', 'lamni', 'none',
p. energy = energy; % Energy (in keV), leave empty to use spec entry mokev
p. sample_rotation_angles = [0,0,0]; % Offaxis ptychography correction , 3x1 vector rotation around [X,Y,beam] axes in degrees , apply a correction accounting for tilted plane oR the sample and ewald sphere curvature (high NA correction)
%p. affine_angle = 0; % Not used by ptycho_recons at all. This allows you to define a variable for the affine matrix below and keep it in p for future record. This is used later by the affine_matrix_search.m script
p. affine_matrix = [1 , 0; 0, 1] ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x]. For flOMNI we found in June 2019: = [1 , 0.0003583 ; 5.811e-05 , 1 ]; for OMNY we found in October 2018: = [1 0;tan(0.4*pi/180) 1]; laMNI in June 2018 [1,0.0154;-0.0017,1.01]; laMNI in August [1.01 0.0031; -0.0018 1.00]
% Scan meta data
p. src_metadata = 'none'; % source of the meta data, following options are supported: 'spec', 'none' , 'artificial' - or add new to +scan/+meta/
% Scan queue
p. queue.name = ''; % specify file queue; currently only 'filelist' is supported
p. queue.path=['']; % Folder where the queue of files is defined, note the content of files can overwrite some parameters in p-structure
p. queue.max_attempts = 5; % Max number of attempts to reconstruct a scan.
p. queue.file_queue_timeout = 10; % Time to wait when queue is empty before checking it again
p. queue.remote_recons = false; % divide the reconstruction into primary/replica processes to reconstruction on a remote server
p. queue.recon_latest_first = 1; % When using 'p.queue_path', (1) reconstruct the latest measurement first or (0) reconstruct in lexicographical order
p. queue.remote_path = ''; % Queue list for remote reconstructions. Needs to be accessible for primary and replica processes
p. queue.tmp_dir_remote = ''; % shared directory for storing the remote reconstruction
p. queue.lockfile = false; % If true writes a lock file, if lock file exists skips recontruction
p. spec.waitforscanfinish = true; % Checks spec file for the scan end flag 'X#'
p. spec.check_nextscan_started = true; % Waits until the next scan starts to begin reconstructing this one. It is important for OMNY scans with orchestra
p. spec.isptycho = {}; % Use only when SPEC is used: = {'round_roi','cont_line','ura_mesh'} ( = {} to skip) List of ptycho spec commands for valid ptycho scans
% Data preparation
p. detector.name = 'empad'; % see +detectors/ folder
p. detector.check_2_detpos = []; % = []; (ignores) = 270; compares to dettrx to see if p.ctr should be reversed (for OMNY shared scans 1221122), make equal to the middle point of dettrx between the 2 detector positions
p. detector.data_prefix = ''; % Default using current eaccount e.g. e14169_1_
p. detector.binning = false; % = true to perform 2x2 binning of detector pixels, for binning = N do 2^Nx2^N binning
p. detector.upsampling = false; % upsample the measured data by 2^data_upsampling, (transposed operator to the binning), it can be used for superresolution in nearfield ptychography or to account for undersampling in a far-field dataset
p. detector.burst_frames = 1; % number of frames collected per scan position
p. prepare.data_preparator = 'matlab_aps'; % data preparator; 'python' or 'matlab' or 'matlab_aps'
p. prepare.auto_prepare_data = true; % if true: prepare dataset from raw measurements if the prepared data does not exist
p. prepare.force_preparation_data = true; % Prepare dataset even if it exists, it will overwrite the file % Default: @prepare_data_2d
p. prepare.store_prepared_data = false; % store the loaded data to h5 even for non-external engines (i.e. other than c_solver)
p. prepare.prepare_data_function = ''; % (used only if data should be prepared) custom data preparation function handle;
p. prepare.auto_center_data = false; % if matlab data preparator is used, try to automatically center the diffraction pattern to keep center of mass in center of diffraction
% Scan positions
p. src_positions = 'hdf5_pos'; % 'spec', 'orchestra', 'load_from_file', 'matlab_pos' (scan params are defined below) or add new position loaders to +scan/+positions/
p. positions_file = ['']; %Filename pattern for position files, Example: ['../../specES1/scan_positions/scan_%05d.dat']; (the scan number will be automatically filled in)
p. spec.motor.fine_motors = {}; % Y and X motor name for positions, leave empty for defaults
p. spec.motor.fine_motors_scale = []; % ptycho expects real positions in m;
p. spec.motor.coarse_motors = {}; % Coarse sample position for shared object, use {X-motor, Y-motor}
p. spec.motor.coarse_motors_scale = []; % Scale of the coarse motors (to scale the provided values to meters)
% scan parameters for option src_positions = 'matlab_pos' or 'hdf5_pos';
p. scan.type = 'default'; % {'round', 'raster', 'round_roi', 'custom'}
p. scan.roi_label = roi_label; % For APS data
p. scan.format = scan_string_format; % For APS data format for scan directory generation
%%% PSI %%%
p. scan.radius_in = 0; % round scan: interior radius of the round scan
p. scan.radius_out = 5e-6; % round scan: exterior radius of the round scan
p. scan.nr = 10; % round scan: number of intervals (# of shells - 1)
p. scan.nth = 3; % round scan: number of points in the first shell
p. scan.lx = 20e-6; % round_roi scan: width of the roi
p. scan.ly = 20e-6; % round_roi scan: height of the roi
p. scan.dr = 1.5e-6; % round_roi scan: shell step size
p. scan.nx = 10; % raster scan: number of steps in x
p. scan.ny = 10; % raster scan: number of steps in y
p. scan.step_size_x = 1e-6; % raster scan: step size (grid spacing)
p. scan.step_size_y = 1e-6; % raster scan: step size (grid spacing)
p. scan.step_randn_offset = 0; % raster scan: relative random offset from the ideal periodic grid to avoid the raster grid pathology
p. scan.b = 0; % fermat: angular offset
p. scan.n_max = 1e4; % fermat: maximal number of points generated
p. scan.step = 0.5e-6; % fermat: step size
p. scan.cenxy = [0,0]; % fermat: position of center offset
p. scan.roi = []; % Region of interest in the object [xmin xmax ymin ymax] in meters. Points outside this region are not used for reconstruction.
% (relative to upper corner for raster scans and to center for round scans)
p. scan.custom_positions_source = ''; % custom: a string name of a function that defines the positions; also accepts mat file with entry 'pos', see +scans/+positions/+mat_pos.m
p. scan.custom_params = []; % custom: the parameters to feed to the custom position function.
% I/O1
p. prefix = ''; % For automatic output filenames. If empty: scan number
p. suffix = ''; % Optional suffix for reconstruction
p. scan_string_format = scan_string_format; % format for scan string generation, it is used e.g for plotting and data saving
%%%p. base_path = '../../'; % base path : used for automatic generation of other paths
p. base_path = base_path_ptycho; % base path : used for automatic generation of other paths
p. specfile = ''; % Name of spec file to get motor positions and check end of scan, defaut is p.spec_file == p.base_path;
p. ptycho_matlab_path = ''; % cSAXS ptycho package path
p. cSAXS_matlab_path = ''; % cSAXS base package path
p. raw_data_path{1} = ''; % Default using compile_x12sa_filename, used only if data should be prepared automatically
p. prepare_data_path = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. prepare_data_filename = []; % Leave empty for default file name generation, otherwise use [sprintf('S%05d_data_%03dx%03d',p.scan_number(1), p.asize(1), p.asize(2)) p.prep_data_suffix '.h5'] as default
p. save_path{1} = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. io.default_mask_file = ''; % load detector mask defined in this file instead of the mask in the detector packages, (used only if data should be prepared)
p. io.default_mask_type = 'binary'; % (used only if data should be prepared) ['binary', 'indices']. Default: 'binary'
p. io.file_compression = 0; % reconstruction file compression for HDF5 files; 0 for no compression
p. io.data_compression = 3; % prepared data file compression for HDF5 files; 0 for no compression
p. io.load_prep_pos = false; % load positions from prepared data file and ignore positions provided by metadata
p. io.data_descriptor = 'simulation'; %added by YJ. A short string that describe data when sending notifications
p. io.phone_number = ['2178192766']; % phone number for sending messages
p. io.send_failed_scans_SMS = false; % send message if p.queue_max_attempts is exceeded
p. io.send_finished_recon_SMS = false; % send message after the reconstruction is completed
p. io.send_crashed_recon_SMS = false; % send message if the reconstruction crashes
p. io.SMS_sleep = 1800; % max 1 message per SMS_sleep seconds
p. io.script_name = mfilename; % added by YJ. store matlab script name
p. artificial_data_file = 'template_artificial_data'; % artificial data parameters, set p.src_metadata = 'artificial' to use this template
%% Reconstruction
% Initial iterate object
p. model_object = true; % Use model object, if false load it from file
p. model.object_type = 'rand'; % specify how the object shall be created; use 'rand' for a random initial guess; use 'amplitude' for an initial guess based on the prepared data
%p. initial_iterate_object_file{1} = '/mnt/micdata2/velociprobe/2019-2/RAVEN_Pillar/results/Pillar_ML_recon/analysis/S00000-00999/S00239/S00239_128x128_b0__recons.mat'; % use this mat-file as initial guess of object, it is possible to use wild characters and pattern filling, example: '../analysis/S%05i/wrap_*_1024x1024_1_recons*'
%p. initial_iterate_object_file{1} = '/home/beams0/YJIANG/research/algorithm/ptychography/simulation/sim100/scalingFactor1_stepSizeFactor1/MLs_poisson_p2_g40_pc10_vp1_Niter20/Niter20.mat'; % use this mat-file as initial guess of object, it is possible to use wild characters and pattern filling, example: '../analysis/S%05i/wrap_*_1024x1024_1_recons*'
p. initial_iterate_object_file{1} = ''; % use this mat-file as initial guess of object, it is possible to use wild characters and pattern filling, example: '../analysis/S%05i/wrap_*_1024x1024_1_recons*'
% Initial iterate probe
p. model_probe = false; % Use model probe, if false load it from file
p. model.probe_is_focused = true; % Model probe is focused (false: just a pinhole)
p. model.probe_central_stop = true; % Model central stop
p. model.probe_diameter = 170e-6; % Model probe pupil diameter
p. model.probe_central_stop_diameter = 60e-6; % Model central stop diameter
p. model.probe_zone_plate_diameter = 180e-6; % Model probe zone plate diameter
p. model.probe_outer_zone_width = []; % Model probe zone plate outermost zone width (not used if not a focused probe)
p. model.probe_propagation_dist = 3e-3; % Model probe propagation distance (pinhole <-> sample for unfocused, focal-plane <-> sample for focused)
p. model.probe_focal_length = 51e-3; % Model probe focal length (used only if model_is_focused is true
% AND model_outer_zone_width is empty)
p. model.probe_upsample = 10; % Model probe upsample factor (for focused probes)
%Use probe from this mat-file (not used if model_probe is true)
p. initial_probe_file = initial_probe_file;
p. probe_file_propagation = 0.0e-3; % Distance for propagating the probe from file in meters, = 0 to ignore
% Shared scans - Currently working only for sharing probe and object
p. share_probe = 0; % Share probe between scans. Can be either a number/boolean or a list of numbers, specifying the probe index; e.g. [1 2 2] to share the probes between the second and third scan.
p. share_object = 0; % Share object between scans. Can be either a number/boolean or a list of numbers, specifying the object index; e.g. [1 2 2] to share the objects between the second and third scan.
% Modes
p. probe_modes = Nprobe; % Number of coherent modes for probe
p. object_modes = 1; % Number of coherent modes for object
% Mode starting guess
p. mode_start_pow = [0.02]; % Normalized intensity on probe modes > 1. Can be a number (all higher modes equal) or a vector
p. mode_start = 'herm'; % (for probe) = 'rand', = 'herm' (Hermitian-like base), = 'hermver' (vertical modes only), = 'hermhor' (horizontal modes only)
p. ortho_probes = true; % orthogonalize probes after each engine
%% Plot, save and analyze
p. plot.prepared_data = false; % plot prepared data
p. plot.interval = []; % plot each interval-th iteration, does not work for c_solver code
p. plot.log_scale = [0 0]; % Plot on log scale for x and y
p. plot.realaxes = true; % Plots show scale in microns
p. plot.remove_phase_ramp = false; % Remove phase ramp from the plotted / saved phase figures
p. plot.fov_box = false; % Plot the scanning FOV box on the object (both phase and amplitude)
p. plot.fov_box_color = 'r'; % Color of the scanning FOV box
p. plot.positions = true; % Plot the scanning positions
p. plot.mask_bool = true; % Mask the noisy contour of the reconstructed object in plots
p. plot.windowautopos = true; % First plotting will auto position windows
p. plot.obj_apod = false; % Apply apodization to the reconstructed object;
p. plot.prop_obj = 0; % Distance to propagate reconstructed object before plotting [m]
p. plot.show_layers = true; % show each layer in multilayer reconstruction
p. plot.show_layers_stack = false; % show each layer in multilayer reconstruction by imagesc3D
p. plot.object_spectrum = []; % Plot propagated object (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.probe_spectrum = []; % Plot propagated probe (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.conjugate = false; % plot complex conjugate of the reconstruction
p. plot.horz_fact = 2.5; % Scales the space that the ptycho figures take horizontally
p. plot.FP_maskdim = 180e-6; % Filter the backpropagation (Fourier Ptychography)
p. plot.calc_FSC = false; % Calculate the Fourier Shell correlation for 2 scans or compare with model in case of artificial data tests
p. plot.show_FSC = false; % Show the FSC plots, including the cropped FOV
p. plot.residua = false; % highlight phase-residua in the image of the reconstructed phase
p. save.external = ~testmode; % Use a new Matlab session to run save final figures (saves ~6s per reconstruction). Please be aware that this might lead to an accumulation of Matlab sessions if your single reconstruction is very fast.
p. save.store_images = false; % Write preview images containing the final reconstructions in [p.base_path,'analysis/online/ptycho/'] if p.use_display = 0 then the figures are opened invisible in order to create the nice layout. It writes images in analysis/online/ptycho
p. save.store_images_intermediate = false; % save images to disk after each engine
p. save.store_images_ids = 1:4; % identifiers of the figure to be stored, 1=obj. amplitude, 2=obj. phase, 3=probes, 4=errors, 5=probes spectrum, 6=object spectrum
p. save.store_images_format = 'png'; % data type of the stored images jpg or png
p. save.store_images_dpi = 150; % DPI of the stored bitmap images
p. save.exclude = {'fmag', 'fmask', 'illum_sum'}; % exclude variables to reduce the file size on disk
p. save.save_reconstructions_intermediate = false; % save final object and probes after each engine
p. save.save_reconstructions = false; % save reconstructed object and probe when full reconstruction is finished
p. save.output_file = 'mat'; % data type of reconstruction file; 'h5' or 'mat'
%% ENGINES
% --------- GPU engines ------------- See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng = struct(); % reset settings for this engine
eng. name = 'GPU';
eng. use_gpu = true; % if false, run CPU code, but it will get very slow
eng. keep_on_gpu = true; % keep data + projections on GPU, false is useful for large data if DM is used
eng. compress_data = false; % use automatic online memory compression to limit need of GPU memory
eng. gpu_id = gpu_id; % default GPU id, [] means choosen by matlab
eng. check_gpu_load = true; % check available GPU memory before starting GPU engines
% general
eng. number_iterations = Niter; % number of iterations for selected method
eng. asize_presolve = []; % crop data to "asize_presolve" size to get low resolution estimate that can be used in the next engine as a good initial guess
%eng. share_probe = 1; % Share probe between scans. Can be either a number/boolean or a list of numbers, specifying the probe index; e.g. [1 2 2] to share the probes between the second and third scan.
%eng. share_object = 0; % Share object between scans. Can be either a number/boolean or a list of numbers, specifying the object index; e.g. [1 2 2] to share the objects between the second and third scan.
eng. align_shared_objects = false; % before merging multiple unshared objects into one shared, the object will be aligned and the probes shifted by the same distance -> use for alignement and shared reconstruction of drifting scans
eng. method = 'MLc'; % choose GPU solver: DM, ePIE, hPIE, MLc, Mls, -- recommended are MLc and MLs
eng. opt_errmetric = 'L1' ; % optimization likelihood - poisson, L1
eng. grouping = grouping; % size of processed blocks, larger blocks need more memory but they use GPU more effeciently, !!! grouping == inf means use as large as possible to fit into memory
% * for hPIE, ePIE, MLs methods smaller blocks lead to faster convergence,
% * for MLc the convergence is similar
% * for DM is has no effect on convergence
eng. probe_modes = p.probe_modes; % Number of coherent modes for probe
eng. object_change_start = 1; % Start updating object at this iteration number
eng. probe_change_start = 1; % Start updating probe at this iteration number
% regularizations
eng. reg_mu = 0; % Regularization (smooting) constant ( reg_mu = 0 for no regularization)
eng. delta = 0; % press values to zero out of the illumination area in th object, usually 1e-2 is enough
eng. positivity_constraint_object = 0; % enforce weak (relaxed) positivity in object, ie O = O*(1-a)+a*|O|, usually a=1e-2 is already enough. Useful in conbination with OPRP or probe_fourier_shift_search
eng. apply_multimodal_update = true; % apply all incoherent modes to object, it can cause isses if the modes collect some crap
eng. probe_backpropagate = 0; % backpropagation distance the probe mask, 0 == apply in the object plane. Useful for pinhole imaging where the support can be applied at the pinhole plane
eng. probe_support_radius = []; % Normalized radius of circular support, = 1 for radius touching the window
eng. probe_support_fft = false; % assume that there is not illumination intensity out of the central FZP cone and enforce this contraint. Useful for imaging with focusing optics. Helps to remove issues from the gaps between detector modules.
% basic recontruction parameters
% PIE / ML methods % See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. beta_object = 1; % object step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. beta_probe = 1; % probe step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. delta_p = 0.1; % LSQ dumping constant, 0 == no preconditioner, 0.1 is usually safe, Preconditioner accelerates convergence and ML methods become approximations of the second order solvers
eng. momentum = 0; % add momentum acceleration term to the MLc method, useful if the probe guess is very poor or for acceleration of multilayer solver, but it is quite computationally expensive to be used in conventional ptycho without any refinement.
% The momentum method works usually well even with the accelerated_gradients option. eng.momentum = multiplication gain for velocity, eng.momentum == 0 -> no acceleration, eng.momentum == 0.5 is a good value
% momentum is enabled only when par.Niter < par.accelerated_gradients_start;
eng. accelerated_gradients_start = inf; % iteration number from which the Nesterov gradient acceleration should be applied, this option is supported only for MLc method. It is very computationally cheap way of convergence acceleration.
% DM
eng. pfft_relaxation = 0.05; % Relaxation in the Fourier domain projection, = 0 for full projection
eng. probe_regularization = 0.1; % Weight factor for the probe update (inertia)
% ADVANCED OPTIONS See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
% position refinement
eng. apply_subpix_shift = true; % apply FFT-based subpixel shift, it is automatically allowed for position refinement
eng. probe_position_search = inf; % iteration number from which the engine will reconstruct probe positions, from iteration == probe_position_search, assume they have to match geometry model with error less than probe_position_error_max
%eng. probe_geometry_model = {'rotation','scale','shear','asymmetry'}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_geometry_model = {}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_position_error_max = inf; % maximal expected random position errors, probe prositions are confined in a circle with radius defined by probe_position_error_max and with center defined by original positions scaled by probe_geometry_model
eng.apply_relaxed_position_constraint = false; % added by YJ. Apply a relaxed constraint to probe positions. default = true. Set to false if there are big jumps in positions.
eng.update_pos_weight_every = inf; % added by YJ. Allow position weight to be updated multiple times. default = true: only update once.
% multilayer extension
eng. delta_z = []; % if not empty, use multilayer ptycho extension , see ML_MS code for example of use, [] == common single layer ptychography , note that delta_z provides only relative propagation distance from the previous layer, ie delta_z can be either positive or negative. If preshift_ML_probe == false, the first layer is defined by position of initial probe plane. It is useful to use eng.momentum for convergence acceleration
eng. regularize_layers = 0; % multilayer extension: 0<R<<1 -> apply regularization on the reconstructed object layers, 0 == no regularization, 0.01 == weak regularization that will slowly symmetrize information content between layers
eng. preshift_ML_probe = true; % multilayer extension: if true, assume that the provided probe is reconstructed in center of the sample and the layers are centered around this position
% other extensions
eng. background = 0; % average background scattering level, for OMNI values around 0.3 for 100ms, for flOMNI <0.1 per 100ms exposure, see for more details: Odstrcil, M., et al., Optics letters 40.23 (2015): 5574-5577.
eng. background_width = inf; % width of the background function in pixels, inf == flat background, background function is then convolved with the average diffraction pattern in order to account for beam diversion
eng. clean_residua = false; % remove phase residua from reconstruction by iterative unwrapping, it will result in low spatial freq. artefacts -> object can be used as an residua-free initial guess for netx engine
% wavefront & camera geometry refinement See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. probe_fourier_shift_search = inf; % iteration number from which the engine will: refine farfield position of the beam (ie angle) from iteration == probe_fourier_shift_search
eng. estimate_NF_distance = inf; % iteration number from which the engine will: try to estimate the nearfield propagation distance using gradient descent optimization
eng. detector_rotation_search = inf; % iteration number from which the engine will: search for optimal detector rotation, preferably use with option mirror_scan = true , rotation of the detector axis with respect to the sample axis, similar as rotation option in the position refinement geometry model but works also for 0/180deg rotation shared scans
eng. detector_scale_search = inf; % iteration number from which the engine will: refine pixel scale of the detector, can be used to refine propagation distance in ptycho
eng. variable_probe = var_probe_modes>0; % Use SVD to account for variable illumination during a single (coupled) scan, see for more details: Odstrcil, M. et al. Optics express 24.8 (2016): 8360-8369.
eng. variable_probe_modes = var_probe_modes; % OPRP settings , number of SVD modes using to describe the probe evolution.
eng. variable_probe_smooth = 0; % OPRP settings , enforce of smooth evolution of the OPRP modes -> N is order of polynomial fit used for smoothing, 0 == do not apply any smoothing. Smoothing is useful if only a smooth drift is assumed during the ptycho acquisition
eng. variable_intensity = true; % account to changes in probe intensity
% extra analysis
eng. get_fsc_score = get_fsc_score; % measure evolution of the Fourier ring correlation during convergence
eng. mirror_objects = false; % mirror objects, useful for 0/180deg scan sharing -> geometry refinement for tomography, works only if 2 scans are provided
% custom data adjustments, useful for offaxis ptychography
eng.auto_center_data = false; % autoestimate the center of mass from data and shift the diffraction patterns so that the average center of mass corresponds to center of mass of the provided probe
eng.auto_center_probe = false; % center the probe position in real space before reconstruction is started
eng.custom_data_flip = [0,0,0]; % apply custom flip of the data [fliplr, flipud, transpose] - can be used for quick testing of reconstruction with various flips or for reflection ptychography
eng.apply_tilted_plane_correction = ''; % if any(p.sample_rotation_angles([1,2]) ~= 0), this option will apply tilted plane correction. (a) 'diffraction' apply correction into the data, note that it is valid only for "low NA" illumination Gardner, D. et al., Optics express 20.17 (2012): 19050-19059. (b) 'propagation' - use tilted plane propagation, (c) '' - will not apply any correction
%% added by YJ
eng.plot_results_every = Niter_plot_results;
eng.save_results_every = Niter_save_results;
eng.save_images = {'obj_ph','probe'};
eng.avg_photon_threshold = 0; %Added by YJ. Check averaged photon count per pixel during pre-processing. Stop if smaller than the threshold (default = 0.01);
resultDir = p.base_path;
eng.fout = generateResultDir(eng, resultDir);
[eng.fout, p.suffix] = generateResultDir(eng, resultDir);
fout_old = eng.fout;
% add engine
[p, ~] = core.append_engine(p, eng); % Adds this engine to the reconstruction process
if Niter_refined>0
%%%%%%%%%%%%%%%%%%%%%% refined recon %%%%%%%%%%%%%%%%%%%%%%
%eng = struct(); % reset settings for this engine
eng. name = 'GPU';
eng. use_gpu = true; % if false, run CPU code, but it will get very slow
eng. keep_on_gpu = true; % keep data + projections on GPU, false is useful for large data if DM is used
eng. compress_data = true; % use automatic online memory compression to limit need of GPU memory
eng. gpu_id = gpu_id; % default GPU id, [] means choosen by matlab
eng. check_gpu_load = true; % check available GPU memory before starting GPU engines
% general
eng. number_iterations = Niter_refined; % number of iterations for selected method
eng. asize_presolve = []; % crop data to "asize_presolve" size to get low resolution estimate that can be used in the next engine as a good initial guess
eng. share_probe = p.share_probe; % Share probe between scans. Can be either a number/boolean or a list of numbers, specifying the probe index; e.g. [1 2 2] to share the probes between the second and third scan.
eng. share_object = p.share_object; % Share object between scans. Can be either a number/boolean or a list of numbers, specifying the object index; e.g. [1 2 2] to share the objects between the second and third scan.
eng. align_shared_objects = false; % before merging multiple unshared objects into one shared, the object will be aligned and the probes shifted by the same distance -> use for alignement and shared reconstruction of drifting scans
eng. method = 'MLc'; % choose GPU solver: DM, ePIE, hPIE, MLc, Mls, -- recommended are MLc and MLs
eng. opt_errmetric = 'poisson' ; % optimization likelihood - poisson, L1
eng. grouping = grouping; % size of processed blocks, larger blocks need more memory but they use GPU more effeciently, !!! grouping == inf means use as large as possible to fit into memory
% * for hPIE, ePIE, MLs methods smaller blocks lead to faster convergence,
% * for MLc the convergence is similar
% * for DM is has no effect on convergence
%eng. probe_modes = 1; % Number of coherent modes for probe
eng. object_change_start = 1; % Start updating object at this iteration number
eng. probe_change_start = 1; % Start updating probe at this iteration number
eng. probe_modes = p.probe_modes; % Number of coherent modes for probe
% regularizations
eng. reg_mu = 0; % Regularization (smooting) constant ( reg_mu = 0 for no regularization)
eng. delta = 0; % press values to zero out of the illumination area in th object, usually 1e-2 is enough
eng. positivity_constraint_object = 0; % enforce weak (relaxed) positivity in object, ie O = O*(1-a)+a*|O|, usually a=1e-2 is already enough. Useful in conbination with OPRP or probe_fourier_shift_search
eng. apply_multimodal_update = true; % apply all incoherent modes to object, it can cause isses if the modes collect some crap
eng. probe_backpropagate = 0; % backpropagation distance the probe mask, 0 == apply in the object plane. Useful for pinhole imaging where the support can be applied at the pinhole plane
eng. probe_support_radius = []; % Normalized radius of circular support, = 1 for radius touching the window
eng. probe_support_fft = false; % assume that there is not illumination intensity out of the central FZP cone and enforce this contraint. Useful for imaging with focusing optics. Helps to remove issues from the gaps between detector modules.
% basic recontruction parameters
% PIE / ML methods % See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. beta_object = 1; % object step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. beta_probe = 1; % probe step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. delta_p = 0.1; % LSQ dumping constant, 0 == no preconditioner, 0.1 is usually safe, Preconditioner accelerates convergence and ML methods become approximations of the second order solvers
eng. momentum = 0; % add momentum acceleration term to the MLc method, useful if the probe guess is very poor or for acceleration of multilayer solver, but it is quite computationally expensive to be used in conventional ptycho without any refinement. The momentum method works usually well even with the accelerated_gradients option. eng.momentum = multiplication gain for velocity, eng.momentum == 0 -> no acceleration, eng.momentum == 0.5 is a good value
eng. accelerated_gradients_start = inf; % iteration number from which the Nesterov gradient acceleration should be applied, this option is supported only for MLc method. It is very computationally cheap way of convergence acceleration.
% DM
eng. pfft_relaxation = 0.05; % Relaxation in the Fourier domain projection, = 0 for full projection
eng. probe_regularization = 0.1; % Weight factor for the probe update (inertia)
% ADVANCED OPTIONS See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
% position refinement
eng. apply_subpix_shift = true; % apply FFT-based subpixel shift, it is automatically allowed for position refinement
eng. probe_position_search = inf; % iteration number from which the engine will reconstruct probe positions, from iteration == probe_position_search, assume they have to match geometry model with error less than probe_position_error_max
%eng. probe_geometry_model = {'scale', 'asymmetry', 'rotation', 'shear'}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_geometry_model = {}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_position_error_max = inf; % maximal expected random position errors, probe prositions are confined in a circle with radius defined by probe_position_error_max and with center defined by original positions scaled by probe_geometry_model
eng. apply_relaxed_position_constraint = false; % added by YJ. Apply a relaxed constraint to probe positions. default = true. Set to false if there are big jumps in positions.
eng. update_pos_weight_every = inf; % added by YJ. Allow position weight to be updated multiple times. default = inf: only update once.
% multilayer extension
eng. delta_z = []; % if not empty, use multilayer ptycho extension , see ML_MS code for example of use, [] == common single layer ptychography , note that delta_z provides only relative propagation distance from the previous layer, ie delta_z can be either positive or negative. If preshift_ML_probe == false, the first layer is defined by position of initial probe plane. It is useful to use eng.momentum for convergence acceleration
eng. regularize_layers = 0; % multilayer extension: 0<R<<1 -> apply regularization on the reconstructed object layers, 0 == no regularization, 0.01 == weak regularization that will slowly symmetrize information content between layers
eng. preshift_ML_probe = true; % multilayer extension: if true, assume that the provided probe is reconstructed in center of the sample and the layers are centered around this position
% other extensions
eng. background = 0; % average background scattering level, for OMNI values around 0.3 for 100ms, for flOMNI <0.1 per 100ms exposure, see for more details: Odstrcil, M., et al., Optics letters 40.23 (2015): 5574-5577.
eng. background_width = inf; % width of the background function in pixels, inf == flat background, background function is then convolved with the average diffraction pattern in order to account for beam diversion
eng. clean_residua = false; % remove phase residua from reconstruction by iterative unwrapping, it will result in low spatial freq. artefacts -> object can be used as an residua-free initial guess for netx engine
% wavefront & camera geometry refinement See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. probe_fourier_shift_search = inf; % iteration number from which the engine will: refine farfield position of the beam (ie angle) from iteration == probe_fourier_shift_search
eng. estimate_NF_distance = inf; % iteration number from which the engine will: try to estimate the nearfield propagation distance using gradient descent optimization
eng. detector_rotation_search = inf; % iteration number from which the engine will: search for optimal detector rotation, preferably use with option mirror_scan = true , rotation of the detector axis with respect to the sample axis, similar as rotation option in the position refinement geometry model but works also for 0/180deg rotation shared scans
eng. detector_scale_search = inf; % iteration number from which the engine will: refine pixel scale of the detector, can be used to refine propagation distance in ptycho
eng. variable_probe = var_probe_modes>0; % Use SVD to account for variable illumination during a single (coupled) scan, see for more details: Odstrcil, M. et al. Optics express 24.8 (2016): 8360-8369.
eng. variable_probe_modes = var_probe_modes; % OPRP settings , number of SVD modes using to describe the probe evolution.
eng. variable_probe_smooth = 0; % OPRP settings , enforce of smooth evolution of the OPRP modes -> N is order of polynomial fit used for smoothing, 0 == do not apply any smoothing. Smoothing is useful if only a smooth drift is assumed during the ptycho acquisition
eng. variable_intensity = var_probe_modes; % account to changes in probe intensity
% extra analysis
eng. get_fsc_score = get_fsc_score; % measure evolution of the Fourier ring correlation during convergence
eng. mirror_objects = false; % mirror objects, useful for 0/180deg scan sharing -> geometry refinement for tomography, works only if 2 scans are provided
% custom data adjustments, useful for offaxis ptychography
eng.auto_center_data = false; % autoestimate the center of mass from data and shift the diffraction patterns so that the average center of mass corresponds to center of mass of the provided probe
eng.auto_center_probe = false; % center the probe position in real space before reconstruction is started
eng.custom_data_flip = [0,0,0]; % apply custom flip of the data [fliplr, flipud, transpose] - can be used for quick testing of reconstruction with various flips or for reflection ptychography
eng.apply_tilted_plane_correction = ''; % if any(p.sample_rotation_angles([1,2]) ~= 0), this option will apply tilted plane correction. (a) 'diffraction' apply correction into the data, note that it is valid only for "low NA" illumination Gardner, D. et al., Optics express 20.17 (2012): 19050-19059. (b) 'propagation' - use tilted plane propagation, (c) '' - will not apply any correction
%added by YJ
eng.plot_results_every = Niter_plot_results;
eng.save_results_every = Niter_save_results;
[eng.fout, p.suffix] = generateResultDir(eng, fout_old);
fout_old = eng.fout;
eng.extraPrintInfo = strcat('simulation-',num2str(p.scan_number));
[p, ~] = core.append_engine(p, eng); % Adds this engine to the reconstruction process
end
%% Run the reconstruction
caller = dbstack;
if length(caller)==1
tic
out = core.ptycho_recons(p);
toc
end
+324
View File
@@ -0,0 +1,324 @@
function run_mixed_states(parfile)
% clear variables
par = parameter_builder(parfile);
addpath(strcat(pwd,'/utils/'));
addpath('../');
addpath(core.find_base_package);
%%%%%%%%%%%%%%%%%%%% data parameters %%%%%%%%%%%%%%%%%%%%
base_path = par.result_dir;
roi_label = par.roi_label;
scan_number = par.scan_number;
scan_string_format = '%01d';
Ndpx = par.CBED_size; % size of cbed
alpha0 = par.alpha_max; % semi-convergence angle (mrad)
rbf = par.rbf; % radius of the BF disk in cbed. Can be used to calculate dk
%dk = 0.0197; % pixel size in cbed (1/A). Should be calibrated as accurate as possible
voltage = par.voltage;
rot_ang = par.rot_ang; %angle between cbed and scan coord.
scan_step_size = par.scan_step_size; %angstrom
N_scan_y = par.N_scan_y;
N_scan_x = par.N_scan_x; %number of scan points
%%%%%%%%%%%%%%%%%%%% reconstruction parameters %%%%%%%%%%%%%%%%%%%%
gpu_id = par.gpu_id;
Niter = par.Niter;
Niter_save_results = par.Niter_save_results;
Niter_plot_results = 50;
Nprobe = par.Nprobe; % # of probe modes
variable_probe_modes = 0; % # of modes for variable probe correction
grouping = 120; % group size. small -> better convergence but longer time/iteration
if isfield(par, 'probe_position_search')
N_pos_corr = par.probe_position_search;
else
N_pos_corr = 0; % iteration number from which the engine will reconstruct probe positions, from iteration == probe_position_search, assume they have to match geometry model with error less than probe_position_error_max
end
% N_pos_corr = 0; % iteration number to start position correction. inf means no position correction
initial_probe_file = strcat(par.result_dir, num2str(scan_number), '/init_probe.mat');
%% %%%%%%%%%%%%%%%%%% initialize data parameters %%%%%%%%%%%%%%%%%%%%
p = struct();
p. verbose_level = 2; % verbosity for standard output (0-1 for loops, 2-3 for testing and adjustments, >= 4 for debugging)
p. use_display = Niter_plot_results< Niter; % global switch for display, if [] then true for verbose > 1
p. scan_number = scan_number; % Multiple scan numbers for shared scans
% Geometry
p. z = 1; % Distance from object to detector. Always 1 for electron ptycho
p. asize = [Ndpx,Ndpx]; % Diffr. patt. array size
p. ctr = [fix(Ndpx/2)+1, fix(Ndpx/2)+1]; % Diffr. patt. center coordinates (y,x) (empty means middle of the array); e.g. [100 207;100+20 207+10];
p. beam_source = 'electron'; % Added by YJ for electron pty. Use relativistic corrected formula for wavelength. Also change the units on figures
%p. dk = dk; % Added by YJ. dk is the pixel size in cbed (1/A). This is used to determine pixel size in electron ptycho
p. d_alpha = alpha0/rbf; % Added by YJ. d_alpha is the pixel size in cbed (mrad). This is used to determine pixel size in electron ptycho
p. prop_regime = 'farfield'; % propagation regime: nearfield, farfield (default), !! nearfield is supported only by GPU engines
p. focus_to_sample_distance = []; % sample to focus distance, parameter to be set for nearfield ptychography, otherwise it is ignored
p. energy = voltage; % Energy (in keV), leave empty to use spec entry mokev
%p. affine_angle = 0; % Not used by ptycho_recons at all. This allows you to define a variable for the affine matrix below and keep it in p for future record. This is used later by the affine_matrix_search.m script
%p. affine_matrix = [1 , 0; 0, 1] ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
affine_mat = compose_affine_matrix(1, 0, rot_ang, 0);
p. affine_matrix = affine_mat ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
% Scan meta data
p. src_metadata = 'none'; % source of the meta data, following options are supported: 'spec', 'none' , 'artificial' - or add new to +scan/+meta/
p. queue.lockfile = false; % If true writes a lock file, if lock file exists skips recontruction
% Data preparation
p. detector.name = 'empad'; % see +detectors/ folder
p. detector.check_2_detpos = []; % = []; (ignores) = 270; compares to dettrx to see if p.ctr should be reversed (for OMNY shared scans 1221122), make equal to the middle point of dettrx between the 2 detector positions
p. detector.data_prefix = ''; % Default using current eaccount e.g. e14169_1_
p. detector.binning = false; % = true to perform 2x2 binning of detector pixels, for binning = N do 2^Nx2^N binning
p. detector.upsampling = false; % upsample the measured data by 2^data_upsampling, (transposed operator to the binning), it can be used for superresolution in nearfield ptychography or to account for undersampling in a far-field dataset
p. detector.burst_frames = 1; % number of frames collected per scan position
p. prepare.data_preparator = 'matlab_aps'; % data preparator; 'python' or 'matlab' or 'matlab_aps'
p. prepare.auto_prepare_data = true; % if true: prepare dataset from raw measurements if the prepared data does not exist
p. prepare.force_preparation_data = true; % Prepare dataset even if it exists, it will overwrite the file % Default: @prepare_data_2d
p. prepare.store_prepared_data = false; % store the loaded data to h5 even for non-external engines (i.e. other than c_solver)
p. prepare.prepare_data_function = ''; % (used only if data should be prepared) custom data preparation function handle;
p. prepare.auto_center_data = false; % if matlab data preparator is used, try to automatically center the diffraction pattern to keep center of mass in center of diffraction
% Scan positions
p. src_positions = 'matlab_pos'; % 'spec', 'orchestra', 'load_from_file', 'matlab_pos' (scan params are defined below) or add new position loaders to +scan/+positions/
p. positions_file = ''; %Filename pattern for position files, Example: ['../../specES1/scan_positions/scan_%05d.dat']; (the scan number will be automatically filled in)
% scan parameters for option src_positions = 'matlab_pos';
p. scan.type = 'raster'; % {'round', 'raster', 'round_roi', 'custom'}
p. scan.roi_label = roi_label; % For APS data
p. scan.format = scan_string_format; % For APS data format for scan directory generation
p. scan.radius_in = 0; % round scan: interior radius of the round scan
p. scan.radius_out = 5e-6; % round scan: exterior radius of the round scan
p. scan.nr = 10; % round scan: number of intervals (# of shells - 1)
p. scan.nth = 3; % round scan: number of points in the first shell
p. scan.lx = 20e-6; % round_roi scan: width of the roi
p. scan.ly = 20e-6; % round_roi scan: height of the roi
p. scan.dr = 1.5e-6; % round_roi scan: shell step size
p. scan.nx = N_scan_x; %size(dp,3) % raster scan: number of steps in x
p. scan.ny = N_scan_y; % raster scan: number of steps in y
p. scan.step_size_x = scan_step_size; % raster scan: step size (grid spacing)
p. scan.step_size_y = scan_step_size; % raster scan: step size (grid spacing)
p. scan.custom_flip = [1,1,1]; % raster scan: apply custom flip [fliplr, flipud, transpose] to positions- similar to eng.custom_data_flip in GPU engines. Added by ZC.
p. scan.step_randn_offset = 0; % raster scan: relative random offset from the ideal periodic grid to avoid the raster grid pathology
p. scan.b = 0; % fermat: angular offset
p. scan.n_max = 1e4; % fermat: maximal number of points generated
p. scan.step = 0.5e-6; % fermat: step size
p. scan.cenxy = [0,0]; % fermat: position of center offset
p. scan.roi = []; % Region of interest in the object [xmin xmax ymin ymax] in meters. Points outside this region are not used for reconstruction.
% (relative to upper corner for raster scans and to center for round scans)
% custom: a string name of a function that defines the positions; also accepts mat file with entry 'pos', see +scans/+positions/+mat_pos.m
p. scan.custom_positions_source = '';
p. scan.custom_params = []; % custom: the parameters to feed to the custom position function.
% I/O
p. prefix = ''; % For automatic output filenames. If empty: scan number
p. suffix = strcat('ML_recon'); % Optional suffix for reconstruction
p. scan_string_format = scan_string_format; % format for scan string generation, it is used e.g for plotting and data saving
%%%p. base_path = '../../'; % base path : used for automatic generation of other paths
p. base_path = base_path; % base path : used for automatic generation of other paths
p. specfile = ''; % Name of spec file to get motor positions and check end of scan, defaut is p.spec_file == p.base_path;
p. ptycho_matlab_path = ''; % cSAXS ptycho package path
p. cSAXS_matlab_path = ''; % cSAXS base package path
p. raw_data_path{1} = ''; % Default using compile_x12sa_filename, used only if data should be prepared automatically
p. prepare_data_path = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. prepare_data_filename = []; % Leave empty for default file name generation, otherwise use [sprintf('S%05d_data_%03dx%03d',p.scan_number(1), p.asize(1), p.asize(2)) p.prep_data_suffix '.h5'] as default
p. save_path{1} = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. io.default_mask_file = ''; % load detector mask defined in this file instead of the mask in the detector packages, (used only if data should be prepared)
p. io.default_mask_type = 'binary'; % (used only if data should be prepared) ['binary', 'indices']. Default: 'binary'
p. io.file_compression = 0; % reconstruction file compression for HDF5 files; 0 for no compression
p. io.data_compression = 3; % prepared data file compression for HDF5 files; 0 for no compression
p. io.load_prep_pos = false; % load positions from prepared data file and ignore positions provided by metadata
p. io.data_descriptor = par.extra_print_info; %added by YJ. A short string that describe data when sending notifications
p. io.phone_number = ''; % phone number for sending messages
p. io.send_failed_scans_SMS = false; % send message if p.queue_max_attempts is exceeded
p. io.send_finished_recon_SMS = false; % send message after the reconstruction is completed
p. io.send_crashed_recon_SMS = false; % send message if the reconstruction crashes
p. io.SMS_sleep = 1800; % max 1 message per SMS_sleep seconds
p. io.script_name = mfilename; % added by YJ. store matlab script name
p. artificial_data_file = 'template_artificial_data'; % artificial data parameters, set p.src_metadata = 'artificial' to use this template
%% Reconstruction
% Initial iterate object
p. model_object = true; % Use model object, if false load it from file
p. model.object_type = 'rand'; % specify how the object shall be created; use 'rand' for a random initial guess; use 'amplitude' for an initial guess based on the prepared data
p. initial_iterate_object_file{1} = ''; % use this mat-file as initial guess of object, it is possible to use wild characters and pattern filling, example: '../analysis/S%05i/wrap_*_1024x1024_1_recons*'
% Initial iterate probe
p. model_probe = false; % Use model probe, if false load it from file
p. model.probe_alpha_max = par.alpha_max; % Modal STEM probe's aperture size
p. model.probe_df = par.defocus; % Modal STEM probe's defocus
p. model.probe_c3 = 0; % Modal STEM probe's third-order spherical aberration in angstrom (optional)
p. model.probe_c5 = 0; % Modal STEM probe's fifth-order spherical aberration in angstrom (optional)
p. model.probe_c7 = 0; % Modal STEM probe's seventh-order spherical aberration in angstrom (optional)
p. model.probe_f_a2 = 0; % Modal STEM probe's twofold astigmatism in angstrom (optional)
p. model.probe_theta_a2 = 0; % Modal STEM probe's twofold azimuthal orientation in radian (optional)
p. model.probe_f_a3 = 0; % Modal STEM probe's threefold astigmatism in angstrom (optional)
p. model.probe_theta_a3 = 0; % Modal STEM probe's threefold azimuthal orientation in radian (optional)
p. model.probe_f_c3 = 0; % Modal STEM probe's coma in angstrom (optional)
p. model.probe_theta_c3 = 0; % Modal STEM probe's coma azimuthal orientation in radian (optional)
%Use probe from this mat-file (not used if model_probe is true)
p. initial_probe_file = initial_probe_file;
p. probe_file_propagation = 0.0e-3; % Distance for propagating the probe from file in meters, = 0 to ignore
p. normalize_init_probe = false; % Added by YJ. Can be used to disable normalization of initial probes
% Shared scans - Currently working only for sharing probe and object
p. share_probe = 0; % Share probe between scans. Can be either a number/boolean or a list of numbers, specifying the probe index; e.g. [1 2 2] to share the probes between the second and third scan.
p. share_object = 0; % Share object between scans. Can be either a number/boolean or a list of numbers, specifying the object index; e.g. [1 2 2] to share the objects between the second and third scan.
% Modes
p. probe_modes = Nprobe; % Number of coherent modes for probe
p. object_modes = 1; % Number of coherent modes for object
% Mode starting guess
p. mode_start_pow = 0.02; % Normalized intensity on probe modes > 1. Can be a number (all higher modes equal) or a vector
p. mode_start = 'herm'; % (for probe) = 'rand', = 'herm' (Hermitian-like base), = 'hermver' (vertical modes only), = 'hermhor' (horizontal modes only)
p. ortho_probes = true; % orthogonalize probes after each engine
%% Plot, save and analyze
p. plot.prepared_data = false; % plot prepared data
p. plot.interval = []; % plot each interval-th iteration, does not work for c_solver code
p. plot.log_scale = [0 0]; % Plot on log scale for x and y
p. plot.realaxes = true; % Plots show scale in microns
p. plot.remove_phase_ramp = false; % Remove phase ramp from the plotted / saved phase figures
p. plot.fov_box = false; % Plot the scanning FOV box on the object (both phase and amplitude)
p. plot.fov_box_color = 'r'; % Color of the scanning FOV box
p. plot.positions = true; % Plot the scanning positions
p. plot.mask_bool = true; % Mask the noisy contour of the reconstructed object in plots
p. plot.windowautopos = true; % First plotting will auto position windows
p. plot.obj_apod = false; % Apply apodization to the reconstructed object;
p. plot.prop_obj = 0; % Distance to propagate reconstructed object before plotting [m]
p. plot.show_layers = true; % show each layer in multilayer reconstruction
p. plot.show_layers_stack = false; % show each layer in multilayer reconstruction by imagesc3D
p. plot.object_spectrum = []; % Plot propagated object (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.probe_spectrum = []; % Plot propagated probe (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.conjugate = false; % plot complex conjugate of the reconstruction
p. plot.horz_fact = 2.5; % Scales the space that the ptycho figures take horizontally
p. plot.FP_maskdim = 180e-6; % Filter the backpropagation (Fourier Ptychography)
p. plot.calc_FSC = false; % Calculate the Fourier Shell correlation for 2 scans or compare with model in case of artificial data tests
p. plot.show_FSC = false; % Show the FSC plots, including the cropped FOV
p. plot.residua = false; % highlight phase-residua in the image of the reconstructed phase
p. save.external = true; % Use a new Matlab session to run save final figures (saves ~6s per reconstruction). Please be aware that this might lead to an accumulation of Matlab sessions if your single reconstruction is very fast.
p. save.store_images = false; % Write preview images containing the final reconstructions in [p.base_path,'analysis/online/ptycho/'] if p.use_display = 0 then the figures are opened invisible in order to create the nice layout. It writes images in analysis/online/ptycho
p. save.store_images_intermediate = false; % save images to disk after each engine
p. save.store_images_ids = 1:4; % identifiers of the figure to be stored, 1=obj. amplitude, 2=obj. phase, 3=probes, 4=errors, 5=probes spectrum, 6=object spectrum
p. save.store_images_format = 'png'; % data type of the stored images jpg or png
p. save.store_images_dpi = 150; % DPI of the stored bitmap images
p. save.exclude = {'fmag', 'fmask', 'illum_sum'}; % exclude variables to reduce the file size on disk
p. save.save_reconstructions_intermediate = false; % save final object and probes after each engine
p. save.save_reconstructions = false; % save reconstructed object and probe when full reconstruction is finished
p. save.output_file = 'h5'; % data type of reconstruction file; 'h5' or 'mat'
%% %%%%%%%%%%%%%%%%%% initialize reconstruction parameters %%%%%%%%%%%%%%%%%%%%
% --------- GPU engines ------------- See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng = struct(); % reset settings for this engine
eng. name = 'GPU';
eng. use_gpu = true; % if false, run CPU code, but it will get very slow
eng. keep_on_gpu = true; % keep data + projections on GPU, false is useful for large data if DM is used
eng. compress_data = false; % use automatic online memory compression to limit need of GPU memory
eng. gpu_id = gpu_id; % default GPU id, [] means choosen by matlab
eng. check_gpu_load = true; % check available GPU memory before starting GPU engines
% general
eng. number_iterations = Niter; % number of iterations for selected method
eng. asize_presolve = []; % crop data to "asize_presolve" size to get low resolution estimate that can be used in the next engine as a good initial guess
eng. align_shared_objects = false; % before merging multiple unshared objects into one shared, the object will be aligned and the probes shifted by the same distance -> use for alignement and shared reconstruction of drifting scans
eng. method = 'MLs'; % choose GPU solver: DM, ePIE, hPIE, MLc, Mls, -- recommended are MLc and MLs
eng. opt_errmetric = 'L1'; % optimization likelihood - poisson, L1
eng. grouping = grouping; % size of processed blocks, larger blocks need more memory but they use GPU more effeciently, !!! grouping == inf means use as large as possible to fit into memory
% * for hPIE, ePIE, MLs methods smaller blocks lead to faster convergence,
% * for MLc the convergence is similar
% * for DM is has no effect on convergence
eng. probe_modes = p.probe_modes; % Number of coherent modes for probe
eng. object_change_start = 1; % Start updating object at this iteration number
if isfield(par, 'probe_change_start')
eng.probe_change_start = par.probe_change_start;
else
eng.probe_change_start = 1; % Start updating probe at this iteration number
end
% eng. probe_change_start = 1; % Start updating probe at this iteration number
% regularizations
eng. reg_mu = 0; % Regularization (smooting) constant ( reg_mu = 0 for no regularization)
eng. delta = 0; % press values to zero out of the illumination area in th object, usually 1e-2 is enough
eng. positivity_constraint_object = 0; % enforce weak (relaxed) positivity in object, ie O = O*(1-a)+a*|O|, usually a=1e-2 is already enough. Useful in conbination with OPRP or probe_fourier_shift_search
eng. apply_multimodal_update = true; % apply all incoherent modes to object, it can cause isses if the modes collect some crap
eng. probe_backpropagate = 0; % backpropagation distance the probe mask, 0 == apply in the object plane. Useful for pinhole imaging where the support can be applied at the pinhole plane
eng. probe_support_radius = []; % Normalized radius of circular support, = 1 for radius touching the window
eng. probe_support_fft = false; % assume that there is not illumination intensity out of the central FZP cone and enforce this contraint. Useful for imaging with focusing optics. Helps to remove issues from the gaps between detector modules.
% basic recontruction parameters
% PIE / ML methods % See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. beta_object = 1; % object step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. beta_probe = 1; % probe step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. delta_p = 0.1; % LSQ dumping constant, 0 == no preconditioner, 0.1 is usually safe, Preconditioner accelerates convergence and ML methods become approximations of the second order solvers
eng. momentum = 0; % add momentum acceleration term to the MLc method, useful if the probe guess is very poor or for acceleration of multilayer solver, but it is quite computationally expensive to be used in conventional ptycho without any refinement.
% The momentum method works usually well even with the accelerated_gradients option. eng.momentum = multiplication gain for velocity, eng.momentum == 0 -> no acceleration, eng.momentum == 0.5 is a good value
% momentum is enabled only when par.Niter < par.accelerated_gradients_start;
eng. accelerated_gradients_start = inf; % iteration number from which the Nesterov gradient acceleration should be applied, this option is supported only for MLc method. It is very computationally cheap way of convergence acceleration.
% DM
eng. pfft_relaxation = 0.05; % Relaxation in the Fourier domain projection, = 0 for full projection
eng. probe_regularization = 0.1; % Weight factor for the probe update (inertia)
% ADVANCED OPTIONS See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
% position refinement
eng. apply_subpix_shift = true; % apply FFT-based subpixel shift, it is automatically allowed for position refinement
eng. probe_position_search = N_pos_corr; % iteration number from which the engine will reconstruct probe positions, from iteration == probe_position_search, assume they have to match geometry model with error less than probe_position_error_max
eng. probe_geometry_model = {'scale', 'asymmetry', 'rotation', 'shear'}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
%eng. probe_geometry_model = {}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_position_error_max = inf; % maximal expected random position errors, probe prositions are confined in a circle with radius defined by probe_position_error_max and with center defined by original positions scaled by probe_geometry_model
eng. apply_relaxed_position_constraint = true; % added by YJ. Apply a relaxed constraint to probe positions. default = true. Set to false if there are big jumps in positions.
eng. update_pos_weight_every = 100; % added by YJ. Allow position weight to be updated multiple times. default = inf: only update once.
% multilayer extension
eng. delta_z = []; % if not empty, use multilayer ptycho extension , see ML_MS code for example of use, [] == common single layer ptychography , note that delta_z provides only relative propagation distance from the previous layer, ie delta_z can be either positive or negative. If preshift_ML_probe == false, the first layer is defined by position of initial probe plane. It is useful to use eng.momentum for convergence acceleration
eng. regularize_layers = 0; % multilayer extension: 0<R<<1 -> apply regularization on the reconstructed object layers, 0 == no regularization, 0.01 == weak regularization that will slowly symmetrize information content between layers
eng. preshift_ML_probe = true; % multilayer extension: if true, assume that the provided probe is reconstructed in center of the sample and the layers are centered around this position
% other extensions
eng. background = 0; % average background scattering level, for OMNI values around 0.3 for 100ms, for flOMNI <0.1 per 100ms exposure, see for more details: Odstrcil, M., et al., Optics letters 40.23 (2015): 5574-5577.
eng. background_width = inf; % width of the background function in pixels, inf == flat background, background function is then convolved with the average diffraction pattern in order to account for beam diversion
eng. clean_residua = false; % remove phase residua from reconstruction by iterative unwrapping, it will result in low spatial freq. artefacts -> object can be used as an residua-free initial guess for netx engine
% wavefront & camera geometry refinement See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. probe_fourier_shift_search = inf; % iteration number from which the engine will: refine farfield position of the beam (ie angle) from iteration == probe_fourier_shift_search
eng. estimate_NF_distance = inf; % iteration number from which the engine will: try to estimate the nearfield propagation distance using gradient descent optimization
eng. detector_rotation_search = inf; % iteration number from which the engine will: search for optimal detector rotation, preferably use with option mirror_scan = true , rotation of the detector axis with respect to the sample axis, similar as rotation option in the position refinement geometry model but works also for 0/180deg rotation shared scans
eng. detector_scale_search = inf; % iteration number from which the engine will: refine pixel scale of the detector, can be used to refine propagation distance in ptycho
eng. variable_probe = variable_probe_modes>0; % Use SVD to account for variable illumination during a single (coupled) scan, see for more details: Odstrcil, M. et al. Optics express 24.8 (2016): 8360-8369.
eng. variable_probe_modes = variable_probe_modes; % OPRP settings , number of SVD modes using to describe the probe evolution.
eng. variable_probe_smooth = 0; % OPRP settings , enforce of smooth evolution of the OPRP modes -> N is order of polynomial fit used for smoothing, 0 == do not apply any smoothing. Smoothing is useful if only a smooth drift is assumed during the ptycho acquisition
eng. variable_intensity = variable_probe_modes>0; % account to changes in probe intensity
% extra analysis
eng. get_fsc_score = false; % measure evolution of the Fourier ring correlation during convergence
eng. mirror_objects = false; % mirror objects, useful for 0/180deg scan sharing -> geometry refinement for tomography, works only if 2 scans are provided
% custom data adjustments, useful for offaxis ptychography
eng.auto_center_data = false; % autoestimate the center of mass from data and shift the diffraction patterns so that the average center of mass corresponds to center of mass of the provided probe
eng.auto_center_probe = false; % center the probe position in real space before reconstruction is started
eng.custom_data_flip = [0,0,0]; % apply custom flip of the data [fliplr, flipud, transpose] - can be used for quick testing of reconstruction with various flips or for reflection ptychography
eng.apply_tilted_plane_correction = ''; % if any(p.sample_rotation_angles([1,2]) ~= 0), this option will apply tilted plane correction. (a) 'diffraction' apply correction into the data, note that it is valid only for "low NA" illumination Gardner, D. et al., Optics express 20.17 (2012): 19050-19059. (b) 'propagation' - use tilted plane propagation, (c) '' - will not apply any correction
% I/O
eng.plot_results_every = Niter_plot_results;
eng.save_results_every = Niter_save_results;
eng.save_images ={'obj_ph','probe_mag','probe'};
eng.extraPrintInfo = par.extra_print_info;
% eng.extraPrintInfo = strcat('MoS2');
resultDir = strcat(par.result_dir,sprintf(p.scan.format, p.scan_number),'/roi',p.scan.roi_label,'/');
[eng.fout, p.suffix] = generateResultDir(eng, resultDir);
%add engine
[p, ~] = core.append_engine(p, eng); % Adds this engine to the reconstruction process
%% Run the reconstruction
tic
out = core.ptycho_recons(p);
toc
end
+337
View File
@@ -0,0 +1,337 @@
function run_mixed_states_bio(parfile)
% clear variables
par = parameter_builder(parfile);
addpath(strcat(pwd,'/utils/'));
addpath('../');
addpath(core.find_base_package);
%%%%%%%%%%%%%%%%%%%% data parameters %%%%%%%%%%%%%%%%%%%%
base_path = par.result_dir;
roi_label = par.roi_label;
scan_number = par.scan_number;
scan_string_format = '%01d';
Ndpx = par.CBED_size; % size of cbed
alpha0 = par.alpha_max; % semi-convergence angle (mrad)
rbf = par.rbf; % radius of the BF disk in cbed. Can be used to calculate dk
%dk = 0.0197; % pixel size in cbed (1/A). Should be calibrated as accurate as possible
voltage = par.voltage;
rot_ang = par.rot_ang; %angle between cbed and scan coord.
scan_step_size = par.scan_step_size; %angstrom
N_scan_y = par.N_scan_y;
N_scan_x = par.N_scan_x; %number of scan points
%%%%%%%%%%%%%%%%%%%% reconstruction parameters %%%%%%%%%%%%%%%%%%%%
gpu_id = par.gpu_id;
Niter = par.Niter;
Niter_save_results = par.Niter_save_results;
Niter_plot_results = 50;
Nprobe = par.Nprobe; % # of probe modes
variable_probe_modes = 0; % # of modes for variable probe correction
%grouping = 64; % group size. small -> better convergence but longer time/iteration
if isfield(par, 'probe_position_search')
N_pos_corr = par.probe_position_search;
else
N_pos_corr = 0; % iteration number from which the engine will reconstruct probe positions, from iteration == probe_position_search, assume they have to match geometry model with error less than probe_position_error_max
end
% N_pos_corr = 0; % iteration number to start position correction. inf means no position correction
initial_probe_file = strcat(par.result_dir, num2str(scan_number), '/init_probe.mat');
%% %%%%%%%%%%%%%%%%%% initialize data parameters %%%%%%%%%%%%%%%%%%%%
p = struct();
p. verbose_level = 2; % verbosity for standard output (0-1 for loops, 2-3 for testing and adjustments, >= 4 for debugging)
p. use_display = Niter_plot_results< Niter; % global switch for display, if [] then true for verbose > 1
p. scan_number = scan_number; % Multiple scan numbers for shared scans
% Geometry
p. z = 1; % Distance from object to detector. Always 1 for electron ptycho
p. asize = [Ndpx,Ndpx]; % Diffr. patt. array size
p. ctr = [fix(Ndpx/2)+1, fix(Ndpx/2)+1]; % Diffr. patt. center coordinates (y,x) (empty means middle of the array); e.g. [100 207;100+20 207+10];
p. beam_source = 'electron'; % Added by YJ for electron pty. Use relativistic corrected formula for wavelength. Also change the units on figures
%p. dk = dk; % Added by YJ. dk is the pixel size in cbed (1/A). This is used to determine pixel size in electron ptycho
p. d_alpha = alpha0/rbf; % Added by YJ. d_alpha is the pixel size in cbed (mrad). This is used to determine pixel size in electron ptycho
p. prop_regime = 'farfield'; % propagation regime: nearfield, farfield (default), !! nearfield is supported only by GPU engines
p. focus_to_sample_distance = []; % sample to focus distance, parameter to be set for nearfield ptychography, otherwise it is ignored
p. energy = voltage; % Energy (in keV), leave empty to use spec entry mokev
%p. affine_angle = 0; % Not used by ptycho_recons at all. This allows you to define a variable for the affine matrix below and keep it in p for future record. This is used later by the affine_matrix_search.m script
%p. affine_matrix = [1 , 0; 0, 1] ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
affine_mat = compose_affine_matrix(1, 0, rot_ang, 0);
p. affine_matrix = affine_mat ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
% Scan meta data
p. src_metadata = 'none'; % source of the meta data, following options are supported: 'spec', 'none' , 'artificial' - or add new to +scan/+meta/
p. queue.lockfile = false; % If true writes a lock file, if lock file exists skips recontruction
% Data preparation
p. detector.name = 'empad'; % see +detectors/ folder
p. detector.check_2_detpos = []; % = []; (ignores) = 270; compares to dettrx to see if p.ctr should be reversed (for OMNY shared scans 1221122), make equal to the middle point of dettrx between the 2 detector positions
p. detector.data_prefix = ''; % Default using current eaccount e.g. e14169_1_
p. detector.binning = false; % = true to perform 2x2 binning of detector pixels, for binning = N do 2^Nx2^N binning
p. detector.upsampling = false; % upsample the measured data by 2^data_upsampling, (transposed operator to the binning), it can be used for superresolution in nearfield ptychography or to account for undersampling in a far-field dataset
p. detector.burst_frames = 1; % number of frames collected per scan position
p. prepare.data_preparator = 'matlab_aps'; % data preparator; 'python' or 'matlab' or 'matlab_aps'
p. prepare.auto_prepare_data = true; % if true: prepare dataset from raw measurements if the prepared data does not exist
p. prepare.force_preparation_data = true; % Prepare dataset even if it exists, it will overwrite the file % Default: @prepare_data_2d
p. prepare.store_prepared_data = false; % store the loaded data to h5 even for non-external engines (i.e. other than c_solver)
p. prepare.prepare_data_function = ''; % (used only if data should be prepared) custom data preparation function handle;
p. prepare.auto_center_data = false; % if matlab data preparator is used, try to automatically center the diffraction pattern to keep center of mass in center of diffraction
% Scan positions
p. src_positions = 'matlab_pos'; % 'spec', 'orchestra', 'load_from_file', 'matlab_pos' (scan params are defined below) or add new position loaders to +scan/+positions/
p. positions_file = ''; %Filename pattern for position files, Example: ['../../specES1/scan_positions/scan_%05d.dat']; (the scan number will be automatically filled in)
% scan parameters for option src_positions = 'matlab_pos';
p. scan.type = 'raster'; % {'round', 'raster', 'round_roi', 'custom'}
p. scan.roi_label = roi_label; % For APS data
p. scan.format = scan_string_format; % For APS data format for scan directory generation
p. scan.radius_in = 0; % round scan: interior radius of the round scan
p. scan.radius_out = 5e-6; % round scan: exterior radius of the round scan
p. scan.nr = 10; % round scan: number of intervals (# of shells - 1)
p. scan.nth = 3; % round scan: number of points in the first shell
p. scan.lx = 20e-6; % round_roi scan: width of the roi
p. scan.ly = 20e-6; % round_roi scan: height of the roi
p. scan.dr = 1.5e-6; % round_roi scan: shell step size
p. scan.nx = N_scan_x; %size(dp,3) % raster scan: number of steps in x
p. scan.ny = N_scan_y; % raster scan: number of steps in y
p. scan.step_size_x = scan_step_size; % raster scan: step size (grid spacing)
p. scan.step_size_y = scan_step_size; % raster scan: step size (grid spacing)
p. scan.custom_flip = [1,1,1]; % raster scan: apply custom flip [fliplr, flipud, transpose] to positions- similar to eng.custom_data_flip in GPU engines. Added by ZC.
p. scan.step_randn_offset = 0; % raster scan: relative random offset from the ideal periodic grid to avoid the raster grid pathology
p. scan.b = 0; % fermat: angular offset
p. scan.n_max = 1e4; % fermat: maximal number of points generated
p. scan.step = 0.5e-6; % fermat: step size
p. scan.cenxy = [0,0]; % fermat: position of center offset
p. scan.roi = []; % Region of interest in the object [xmin xmax ymin ymax] in meters. Points outside this region are not used for reconstruction.
% (relative to upper corner for raster scans and to center for round scans)
% custom: a string name of a function that defines the positions; also accepts mat file with entry 'pos', see +scans/+positions/+mat_pos.m
p. scan.custom_positions_source = '';
p. scan.custom_params = []; % custom: the parameters to feed to the custom position function.
% I/O
p. prefix = ''; % For automatic output filenames. If empty: scan number
p. suffix = strcat('ML_recon'); % Optional suffix for reconstruction
p. scan_string_format = scan_string_format; % format for scan string generation, it is used e.g for plotting and data saving
%%%p. base_path = '../../'; % base path : used for automatic generation of other paths
p. base_path = base_path; % base path : used for automatic generation of other paths
p. specfile = ''; % Name of spec file to get motor positions and check end of scan, defaut is p.spec_file == p.base_path;
p. ptycho_matlab_path = ''; % cSAXS ptycho package path
p. cSAXS_matlab_path = ''; % cSAXS base package path
p. raw_data_path{1} = ''; % Default using compile_x12sa_filename, used only if data should be prepared automatically
p. prepare_data_path = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. prepare_data_filename = []; % Leave empty for default file name generation, otherwise use [sprintf('S%05d_data_%03dx%03d',p.scan_number(1), p.asize(1), p.asize(2)) p.prep_data_suffix '.h5'] as default
p. save_path{1} = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. io.default_mask_file = ''; % load detector mask defined in this file instead of the mask in the detector packages, (used only if data should be prepared)
p. io.default_mask_type = 'binary'; % (used only if data should be prepared) ['binary', 'indices']. Default: 'binary'
p. io.file_compression = 0; % reconstruction file compression for HDF5 files; 0 for no compression
p. io.data_compression = 3; % prepared data file compression for HDF5 files; 0 for no compression
p. io.load_prep_pos = false; % load positions from prepared data file and ignore positions provided by metadata
p. io.data_descriptor = par.extra_print_info; %added by YJ. A short string that describe data when sending notifications
p. io.phone_number = ''; % phone number for sending messages
p. io.send_failed_scans_SMS = false; % send message if p.queue_max_attempts is exceeded
p. io.send_finished_recon_SMS = false; % send message after the reconstruction is completed
p. io.send_crashed_recon_SMS = false; % send message if the reconstruction crashes
p. io.SMS_sleep = 1800; % max 1 message per SMS_sleep seconds
p. io.script_name = mfilename; % added by YJ. store matlab script name
p. artificial_data_file = 'template_artificial_data'; % artificial data parameters, set p.src_metadata = 'artificial' to use this template
%% Reconstruction
% Initial iterate object
p. model_object = true; % Use model object, if false load it from file
p. model.object_type = 'rand'; % specify how the object shall be created; use 'rand' for a random initial guess; use 'amplitude' for an initial guess based on the prepared data
p. initial_iterate_object_file{1} = ''; % use this mat-file as initial guess of object, it is possible to use wild characters and pattern filling, example: '../analysis/S%05i/wrap_*_1024x1024_1_recons*'
% Initial iterate probe
p. model_probe = false; % Use model probe, if false load it from file
p. model.probe_alpha_max = par.alpha_max; % Modal STEM probe's aperture size
p. model.probe_df = par.defocus; % Modal STEM probe's defocus
p. model.probe_c3 = 0; % Modal STEM probe's third-order spherical aberration in angstrom (optional)
p. model.probe_c5 = 0; % Modal STEM probe's fifth-order spherical aberration in angstrom (optional)
p. model.probe_c7 = 0; % Modal STEM probe's seventh-order spherical aberration in angstrom (optional)
p. model.probe_f_a2 = 0; % Modal STEM probe's twofold astigmatism in angstrom (optional)
p. model.probe_theta_a2 = 0; % Modal STEM probe's twofold azimuthal orientation in radian (optional)
p. model.probe_f_a3 = 0; % Modal STEM probe's threefold astigmatism in angstrom (optional)
p. model.probe_theta_a3 = 0; % Modal STEM probe's threefold azimuthal orientation in radian (optional)
p. model.probe_f_c3 = 0; % Modal STEM probe's coma in angstrom (optional)
p. model.probe_theta_c3 = 0; % Modal STEM probe's coma azimuthal orientation in radian (optional)
%Use probe from this mat-file (not used if model_probe is true)
p. initial_probe_file = initial_probe_file;
p. probe_file_propagation = 0.0e-3; % Distance for propagating the probe from file in meters, = 0 to ignore
p. normalize_init_probe = false; % Added by YJ. Can be used to disable normalization of initial probes
% Shared scans - Currently working only for sharing probe and object
p. share_probe = 0; % Share probe between scans. Can be either a number/boolean or a list of numbers, specifying the probe index; e.g. [1 2 2] to share the probes between the second and third scan.
p. share_object = 0; % Share object between scans. Can be either a number/boolean or a list of numbers, specifying the object index; e.g. [1 2 2] to share the objects between the second and third scan.
% Modes
p. probe_modes = Nprobe; % Number of coherent modes for probe
p. object_modes = 1; % Number of coherent modes for object
% Mode starting guess
p. mode_start_pow = 0.02; % Normalized intensity on probe modes > 1. Can be a number (all higher modes equal) or a vector
p. mode_start = 'herm'; % (for probe) = 'rand', = 'herm' (Hermitian-like base), = 'hermver' (vertical modes only), = 'hermhor' (horizontal modes only)
p. ortho_probes = true; % orthogonalize probes after each engine
%% Plot, save and analyze
p. plot.prepared_data = false; % plot prepared data
p. plot.interval = []; % plot each interval-th iteration, does not work for c_solver code
p. plot.log_scale = [0 0]; % Plot on log scale for x and y
p. plot.realaxes = true; % Plots show scale in microns
p. plot.remove_phase_ramp = false; % Remove phase ramp from the plotted / saved phase figures
p. plot.fov_box = false; % Plot the scanning FOV box on the object (both phase and amplitude)
p. plot.fov_box_color = 'r'; % Color of the scanning FOV box
p. plot.positions = true; % Plot the scanning positions
p. plot.mask_bool = true; % Mask the noisy contour of the reconstructed object in plots
p. plot.windowautopos = true; % First plotting will auto position windows
p. plot.obj_apod = false; % Apply apodization to the reconstructed object;
p. plot.prop_obj = 0; % Distance to propagate reconstructed object before plotting [m]
p. plot.show_layers = true; % show each layer in multilayer reconstruction
p. plot.show_layers_stack = false; % show each layer in multilayer reconstruction by imagesc3D
p. plot.object_spectrum = []; % Plot propagated object (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.probe_spectrum = []; % Plot propagated probe (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.conjugate = false; % plot complex conjugate of the reconstruction
p. plot.horz_fact = 2.5; % Scales the space that the ptycho figures take horizontally
p. plot.FP_maskdim = 180e-6; % Filter the backpropagation (Fourier Ptychography)
p. plot.calc_FSC = false; % Calculate the Fourier Shell correlation for 2 scans or compare with model in case of artificial data tests
p. plot.show_FSC = false; % Show the FSC plots, including the cropped FOV
p. plot.residua = false; % highlight phase-residua in the image of the reconstructed phase
p. save.external = true; % Use a new Matlab session to run save final figures (saves ~6s per reconstruction). Please be aware that this might lead to an accumulation of Matlab sessions if your single reconstruction is very fast.
p. save.store_images = false; % Write preview images containing the final reconstructions in [p.base_path,'analysis/online/ptycho/'] if p.use_display = 0 then the figures are opened invisible in order to create the nice layout. It writes images in analysis/online/ptycho
p. save.store_images_intermediate = false; % save images to disk after each engine
p. save.store_images_ids = 1:4; % identifiers of the figure to be stored, 1=obj. amplitude, 2=obj. phase, 3=probes, 4=errors, 5=probes spectrum, 6=object spectrum
p. save.store_images_format = 'png'; % data type of the stored images jpg or png
p. save.store_images_dpi = 150; % DPI of the stored bitmap images
p. save.exclude = {'fmag', 'fmask', 'illum_sum'}; % exclude variables to reduce the file size on disk
p. save.save_reconstructions_intermediate = false; % save final object and probes after each engine
p. save.save_reconstructions = false; % save reconstructed object and probe when full reconstruction is finished
p. save.output_file = 'h5'; % data type of reconstruction file; 'h5' or 'mat'
if isfield(par, 'diff_pattern_blur')
p. diff_pattern_blur = par.diff_pattern_blur;
end
%% %%%%%%%%%%%%%%%%%% initialize reconstruction parameters %%%%%%%%%%%%%%%%%%%%
% --------- GPU engines ------------- See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng = struct(); % reset settings for this engine
eng. name = 'GPU';
eng. use_gpu = true; % if false, run CPU code, but it will get very slow
eng. keep_on_gpu = true; % keep data + projections on GPU, false is useful for large data if DM is used
eng. compress_data = false; % use automatic online memory compression to limit need of GPU memory
eng. gpu_id = gpu_id; % default GPU id, [] means choosen by matlab
eng. check_gpu_load = true; % check available GPU memory before starting GPU engines
% general
eng. number_iterations = Niter; % number of iterations for selected method
eng. asize_presolve = []; % crop data to "asize_presolve" size to get low resolution estimate that can be used in the next engine as a good initial guess
eng. align_shared_objects = false; % before merging multiple unshared objects into one shared, the object will be aligned and the probes shifted by the same distance -> use for alignement and shared reconstruction of drifting scans
eng. method = 'MLs'; % choose GPU solver: DM, ePIE, hPIE, MLc, Mls, -- recommended are MLc and MLs
eng. opt_errmetric = 'L1'; % optimization likelihood - poisson, L1
%eng. grouping = grouping; % size of processed blocks, larger blocks need more memory but they use GPU more effeciently, !!! grouping == inf means use as large as possible to fit into memory
if isfield(par, 'grouping')
eng.grouping = par.grouping;
else
eng.grouping = 64;
end % * for hPIE, ePIE, MLs methods smaller blocks lead to faster convergence,
% * for MLc the convergence is similar
% * for DM is has no effect on convergence
eng. probe_modes = p.probe_modes; % Number of coherent modes for probe
% eng. object_change_start = 1; % Start updating object at this iteration number
if isfield(par, 'object_change_start')
eng. object_change_start = par.object_change_start;
else
eng. object_change_start = 1; % Start updating object at this iteration number
end
if isfield(par, 'probe_change_start')
eng.probe_change_start = par.probe_change_start;
else
eng.probe_change_start = 1; % Start updating probe at this iteration number
end
% eng. probe_change_start = 1; % Start updating probe at this iteration number
% regularizations
eng. reg_mu = 0; % Regularization (smooting) constant ( reg_mu = 0 for no regularization)
eng. delta = 0; % press values to zero out of the illumination area in th object, usually 1e-2 is enough
eng. positivity_constraint_object = 0; % enforce weak (relaxed) positivity in object, ie O = O*(1-a)+a*|O|, usually a=1e-2 is already enough. Useful in conbination with OPRP or probe_fourier_shift_search
eng. apply_multimodal_update = true; % apply all incoherent modes to object, it can cause isses if the modes collect some crap
eng. probe_backpropagate = 0; % backpropagation distance the probe mask, 0 == apply in the object plane. Useful for pinhole imaging where the support can be applied at the pinhole plane
eng. probe_support_radius = []; % Normalized radius of circular support, = 1 for radius touching the window
eng. probe_support_fft = false; % assume that there is not illumination intensity out of the central FZP cone and enforce this contraint. Useful for imaging with focusing optics. Helps to remove issues from the gaps between detector modules.
% basic recontruction parameters
% PIE / ML methods % See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. beta_object = 0.5; % object step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. beta_probe = 0.5; % probe step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. delta_p = 0.1; % LSQ dumping constant, 0 == no preconditioner, 0.1 is usually safe, Preconditioner accelerates convergence and ML methods become approximations of the second order solvers
eng. momentum = 0.5; % add momentum acceleration term to the MLc method, useful if the probe guess is very poor or for acceleration of multilayer solver, but it is quite computationally expensive to be used in conventional ptycho without any refinement.
% The momentum method works usually well even with the accelerated_gradients option. eng.momentum = multiplication gain for velocity, eng.momentum == 0 -> no acceleration, eng.momentum == 0.5 is a good value
% momentum is enabled only when par.Niter < par.accelerated_gradients_start;
eng. accelerated_gradients_start = inf; % iteration number from which the Nesterov gradient acceleration should be applied, this option is supported only for MLc method. It is very computationally cheap way of convergence acceleration.
% DM
eng. pfft_relaxation = 0.05; % Relaxation in the Fourier domain projection, = 0 for full projection
eng. probe_regularization = 0.1; % Weight factor for the probe update (inertia)
% ADVANCED OPTIONS See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
% position refinement
eng. apply_subpix_shift = true; % apply FFT-based subpixel shift, it is automatically allowed for position refinement
eng. probe_position_search = N_pos_corr; % iteration number from which the engine will reconstruct probe positions, from iteration == probe_position_search, assume they have to match geometry model with error less than probe_position_error_max
%eng. probe_geometry_model = {'scale', 'asymmetry', 'rotation', 'shear'}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_geometry_model = {}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_position_error_max = inf; % maximal expected random position errors, probe prositions are confined in a circle with radius defined by probe_position_error_max and with center defined by original positions scaled by probe_geometry_model
eng. apply_relaxed_position_constraint = true; % added by YJ. Apply a relaxed constraint to probe positions. default = true. Set to false if there are big jumps in positions.
eng. update_pos_weight_every = 100; % added by YJ. Allow position weight to be updated multiple times. default = inf: only update once.
% multilayer extension
eng. delta_z = []; % if not empty, use multilayer ptycho extension , see ML_MS code for example of use, [] == common single layer ptychography , note that delta_z provides only relative propagation distance from the previous layer, ie delta_z can be either positive or negative. If preshift_ML_probe == false, the first layer is defined by position of initial probe plane. It is useful to use eng.momentum for convergence acceleration
eng. regularize_layers = 0; % multilayer extension: 0<R<<1 -> apply regularization on the reconstructed object layers, 0 == no regularization, 0.01 == weak regularization that will slowly symmetrize information content between layers
eng. preshift_ML_probe = true; % multilayer extension: if true, assume that the provided probe is reconstructed in center of the sample and the layers are centered around this position
% other extensions
eng. background = 0; % average background scattering level, for OMNI values around 0.3 for 100ms, for flOMNI <0.1 per 100ms exposure, see for more details: Odstrcil, M., et al., Optics letters 40.23 (2015): 5574-5577.
eng. background_width = inf; % width of the background function in pixels, inf == flat background, background function is then convolved with the average diffraction pattern in order to account for beam diversion
eng. clean_residua = false; % remove phase residua from reconstruction by iterative unwrapping, it will result in low spatial freq. artefacts -> object can be used as an residua-free initial guess for netx engine
% wavefront & camera geometry refinement See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. probe_fourier_shift_search = inf; % iteration number from which the engine will: refine farfield position of the beam (ie angle) from iteration == probe_fourier_shift_search
eng. estimate_NF_distance = inf; % iteration number from which the engine will: try to estimate the nearfield propagation distance using gradient descent optimization
eng. detector_rotation_search = inf; % iteration number from which the engine will: search for optimal detector rotation, preferably use with option mirror_scan = true , rotation of the detector axis with respect to the sample axis, similar as rotation option in the position refinement geometry model but works also for 0/180deg rotation shared scans
eng. detector_scale_search = inf; % iteration number from which the engine will: refine pixel scale of the detector, can be used to refine propagation distance in ptycho
eng. variable_probe = variable_probe_modes>0; % Use SVD to account for variable illumination during a single (coupled) scan, see for more details: Odstrcil, M. et al. Optics express 24.8 (2016): 8360-8369.
eng. variable_probe_modes = variable_probe_modes; % OPRP settings , number of SVD modes using to describe the probe evolution.
eng. variable_probe_smooth = 0; % OPRP settings , enforce of smooth evolution of the OPRP modes -> N is order of polynomial fit used for smoothing, 0 == do not apply any smoothing. Smoothing is useful if only a smooth drift is assumed during the ptycho acquisition
eng. variable_intensity = variable_probe_modes>0; % account to changes in probe intensity
% extra analysis
eng. get_fsc_score = false; % measure evolution of the Fourier ring correlation during convergence
eng. mirror_objects = false; % mirror objects, useful for 0/180deg scan sharing -> geometry refinement for tomography, works only if 2 scans are provided
% custom data adjustments, useful for offaxis ptychography
eng.auto_center_data = false; % autoestimate the center of mass from data and shift the diffraction patterns so that the average center of mass corresponds to center of mass of the provided probe
eng.auto_center_probe = false; % center the probe position in real space before reconstruction is started
eng.custom_data_flip = [0,0,0]; % apply custom flip of the data [fliplr, flipud, transpose] - can be used for quick testing of reconstruction with various flips or for reflection ptychography
eng.apply_tilted_plane_correction = ''; % if any(p.sample_rotation_angles([1,2]) ~= 0), this option will apply tilted plane correction. (a) 'diffraction' apply correction into the data, note that it is valid only for "low NA" illumination Gardner, D. et al., Optics express 20.17 (2012): 19050-19059. (b) 'propagation' - use tilted plane propagation, (c) '' - will not apply any correction
% I/O
eng.plot_results_every = Niter_plot_results;
eng.save_results_every = Niter_save_results;
eng.save_images ={'obj_ph','obj_mag','probe_mag','probe'};
eng.extraPrintInfo = par.extra_print_info;
% eng.extraPrintInfo = strcat('MoS2');
resultDir = strcat(par.result_dir,sprintf(p.scan.format, p.scan_number),'/roi',p.scan.roi_label,'/');
[eng.fout, p.suffix] = generateResultDir(eng, resultDir);
%add engine
[p, ~] = core.append_engine(p, eng); % Adds this engine to the reconstruction process
%% Run the reconstruction
tic
out = core.ptycho_recons(p);
toc
end
+369
View File
@@ -0,0 +1,369 @@
function run_multislice_new(parfile)
par = parameter_builder(parfile);
addpath(strcat(pwd,'/utils/'))
addpath(core.find_base_package)
%%%%%%%%%%%%%%%%%%%% data parameters %%%%%%%%%%%%%%%%%%%%
base_path = par.result_dir;
roi_label = par.roi_label;
scan_number = par.scan_number;
scan_string_format = '%01d';
Ndpx = par.CBED_size; % size of cbed
alpha0 = par.alpha_max; % semi-convergence angle (mrad)
rbf = par.rbf; % radius of the BF disk in cbed. Can be used to calculate dk
voltage = par.voltage;
rot_ang = par.rot_ang; %angle between cbed and scan coord.
scan_step_size = par.scan_step_size; %angstrom
N_scan_y = par.N_scan_y; %number of scan points
N_scan_x = par.N_scan_x;
%%%%%%%%%%%%%%%%%%%% reconstruction parameters %%%%%%%%%%%%%%%%%%%%
gpu_id = 1;
Niter = par.Niter;
Niter_save_results = par.Niter_save_results;
Niter_plot_results = inf;
Nprobe = par.Nprobe; % # of probe modes
thickness = par.thickness; % sample thickness in angstrom
Nlayers = round(par.Nlayers); % # of slices for multi-slice, 1 for single-slice
delta_z = thickness / Nlayers;
%% %%%%%%%%%%%%%%%%%% initialize data parameters %%%%%%%%%%%%%%%%%%%%
p = struct();
p. verbose_level = 2; % verbosity for standard output (0-1 for loops, 2-3 for testing and adjustments, >= 4 for debugging)
p. use_display = false; % global switch for display, if [] then true for verbose > 1
p. scan_number = scan_number; % Multiple scan numbers for shared scans
% Geometry
p. z = 1; % Distance from object to detector. Always 1 for electron ptycho
p. asize = [Ndpx,Ndpx]; % Diffr. patt. array size
p. ctr = [fix(Ndpx/2)+1, fix(Ndpx/2)+1]; % Diffr. patt. center coordinates (y,x) (empty means middle of the array); e.g. [100 207;100+20 207+10];
p. beam_source = 'electron'; % Added by YJ for electron pty. Use relativistic corrected formula for wavelength. Also change the units on figures
%p. dk = dk; % Added by YJ. dk is the pixel size in cbed (1/A). This is used to determine pixel size in electron ptycho
p. d_alpha = alpha0/rbf; % Added by YJ. d_alpha is the pixel size in cbed (mrad). This is used to determine pixel size in electron ptycho
p. prop_regime = 'farfield'; % propagation regime: nearfield, farfield (default), !! nearfield is supported only by GPU engines
p. focus_to_sample_distance = []; % sample to focus distance, parameter to be set for nearfield ptychography, otherwise it is ignored
p. energy = voltage; % Energy (in keV), leave empty to use spec entry mokev
%p. affine_angle = 0; % Not used by ptycho_recons at all. This allows you to define a variable for the affine matrix below and keep it in p for future record. This is used later by the affine_matrix_search.m script
%p. affine_matrix = [1 , 0; 0, 1] ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
affine_mat = compose_affine_matrix(1, 0, rot_ang, 0);
p. affine_matrix = affine_mat ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
% Scan meta data
p. src_metadata = 'none'; % source of the meta data, following options are supported: 'spec', 'none' , 'artificial' - or add new to +scan/+meta/
p. queue.lockfile = false; % If true writes a lock file, if lock file exists skips recontruction
% Data preparation
p. detector.name = 'empad'; % see +detectors/ folder
p. detector.check_2_detpos = []; % = []; (ignores) = 270; compares to dettrx to see if p.ctr should be reversed (for OMNY shared scans 1221122), make equal to the middle point of dettrx between the 2 detector positions
p. detector.data_prefix = ''; % Default using current eaccount e.g. e14169_1_
p. detector.binning = false; % = true to perform 2x2 binning of detector pixels, for binning = N do 2^Nx2^N binning
p. detector.upsampling = false; % upsample the measured data by 2^data_upsampling, (transposed operator to the binning), it can be used for superresolution in nearfield ptychography or to account for undersampling in a far-field dataset
p. detector.burst_frames = 1; % number of frames collected per scan position
p. prepare.data_preparator = 'matlab_aps'; % data preparator; 'python' or 'matlab' or 'matlab_aps'
p. prepare.auto_prepare_data = true; % if true: prepare dataset from raw measurements if the prepared data does not exist
p. prepare.force_preparation_data = true; % Prepare dataset even if it exists, it will overwrite the file % Default: @prepare_data_2d
p. prepare.store_prepared_data = false; % store the loaded data to h5 even for non-external engines (i.e. other than c_solver)
p. prepare.prepare_data_function = ''; % (used only if data should be prepared) custom data preparation function handle;
p. prepare.auto_center_data = false; % if matlab data preparator is used, try to automatically center the diffraction pattern to keep center of mass in center of diffraction
% Scan positions
p. src_positions = 'matlab_pos'; % 'spec', 'orchestra', 'load_from_file', 'matlab_pos' (scan params are defined below) or add new position loaders to +scan/+positions/
p. positions_file = ''; %Filename pattern for position files, Example: ['../../specES1/scan_positions/scan_%05d.dat']; (the scan number will be automatically filled in)
% scan parameters for option src_positions = 'matlab_pos';
p. scan.type = 'raster'; % {'round', 'raster', 'round_roi', 'custom'}
p. scan.roi_label = roi_label; % For APS data
p. scan.format = scan_string_format; % For APS data format for scan directory generation
p. scan.radius_in = 0; % round scan: interior radius of the round scan
p. scan.radius_out = 5e-6; % round scan: exterior radius of the round scan
p. scan.nr = 10; % round scan: number of intervals (# of shells - 1)
p. scan.nth = 3; % round scan: number of points in the first shell
p. scan.lx = 20e-6; % round_roi scan: width of the roi
p. scan.ly = 20e-6; % round_roi scan: height of the roi
p. scan.dr = 1.5e-6; % round_roi scan: shell step size
p. scan.nx = N_scan_x; %size(dp,3) % raster scan: number of steps in x
p. scan.ny = N_scan_y; % raster scan: number of steps in y
p. scan.step_size_x = scan_step_size; % raster scan: step size (grid spacing)
p. scan.step_size_y = scan_step_size; % raster scan: step size (grid spacing)
p. scan.custom_flip = [1,1,1]; % raster scan: apply custom flip [fliplr, flipud, transpose] to positions- similar to eng.custom_data_flip in GPU engines. Added by ZC.
p. scan.step_randn_offset = 0; % raster scan: relative random offset from the ideal periodic grid to avoid the raster grid pathology
p. scan.b = 0; % fermat: angular offset
p. scan.n_max = 1e4; % fermat: maximal number of points generated
p. scan.step = 0.5e-6; % fermat: step size
p. scan.cenxy = [0,0]; % fermat: position of center offset
p. scan.roi = []; % Region of interest in the object [xmin xmax ymin ymax] in meters. Points outside this region are not used for reconstruction.
% (relative to upper corner for raster scans and to center for round scans)
% custom: a string name of a function that defines the positions; also accepts mat file with entry 'pos', see +scans/+positions/+mat_pos.m
p. scan.custom_positions_source = '';
p. scan.custom_params = []; % custom: the parameters to feed to the custom position function.
% I/O
p. prefix = ''; % For automatic output filenames. If empty: scan number
p. suffix = strcat('ML_recon'); % Optional suffix for reconstruction
p. scan_string_format = scan_string_format; % format for scan string generation, it is used e.g for plotting and data saving
%%%p. base_path = '../../'; % base path : used for automatic generation of other paths
p. base_path = base_path; % base path : used for automatic generation of other paths
p. specfile = ''; % Name of spec file to get motor positions and check end of scan, defaut is p.spec_file == p.base_path;
p. ptycho_matlab_path = ''; % cSAXS ptycho package path
p. cSAXS_matlab_path = ''; % cSAXS base package path
p. raw_data_path{1} = ''; % Default using compile_x12sa_filename, used only if data should be prepared automatically
p. prepare_data_path = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. prepare_data_filename = []; % Leave empty for default file name generation, otherwise use [sprintf('S%05d_data_%03dx%03d',p.scan_number(1), p.asize(1), p.asize(2)) p.prep_data_suffix '.h5'] as default
p. save_path{1} = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. io.default_mask_file = ''; % load detector mask defined in this file instead of the mask in the detector packages, (used only if data should be prepared)
p. io.default_mask_type = 'binary'; % (used only if data should be prepared) ['binary', 'indices']. Default: 'binary'
p. io.file_compression = 0; % reconstruction file compression for HDF5 files; 0 for no compression
p. io.data_compression = 3; % prepared data file compression for HDF5 files; 0 for no compression
p. io.load_prep_pos = false; % load positions from prepared data file and ignore positions provided by metadata
p. io.data_descriptor = par.extra_print_info; %added by YJ. A short string that describe data when sending notifications
p. io.phone_number = ''; % phone number for sending messages
p. io.send_failed_scans_SMS = false; % send message if p.queue_max_attempts is exceeded
p. io.send_finished_recon_SMS = false; % send message after the reconstruction is completed
p. io.send_crashed_recon_SMS = false; % send message if the reconstruction crashes
p. io.SMS_sleep = 1800; % max 1 message per SMS_sleep seconds
p. io.script_name = mfilename; % added by YJ. store matlab script name
p. artificial_data_file = 'template_artificial_data'; % artificial data parameters, set p.src_metadata = 'artificial' to use this template
%% Reconstruction
% Initial iterate object, load from previous results if
% load_results_path is in the parameter file. Use random object and
% ideal probe otherwise.
if isfield(par, 'load_object_path')
p.model_object = false;
p.initial_iterate_object_file{1} = par.load_object_path;
if isfield(par, 'load_probe_path')
p.initial_probe_file = par.load_probe_path;
else
p.initial_probe_file = par.load_object_path;
end
p.multiple_layers_obj = true;
else
initial_probe_file = fullfile(par.result_dir, num2str(scan_number), '/init_probe.mat');
p.model_object = true;
p.model.object_type = 'rand';
p.initial_probe_file = initial_probe_file;
end
% Initial iterate probe
p. model_probe = false; % Use model probe, if false load it from file
p. model.probe_alpha_max = par.alpha_max; % Modal STEM probe's aperture size
p. model.probe_df = par.defocus; % Modal STEM probe's defocus
p. model.probe_c3 = 0; % Modal STEM probe's third-order spherical aberration in angstrom (optional)
p. model.probe_c5 = 0; % Modal STEM probe's fifth-order spherical aberration in angstrom (optional)
p. model.probe_c7 = 0; % Modal STEM probe's seventh-order spherical aberration in angstrom (optional)
p. model.probe_f_a2 = 0; % Modal STEM probe's twofold astigmatism in angstrom (optional)
p. model.probe_theta_a2 = 0; % Modal STEM probe's twofold azimuthal orientation in radian (optional)
p. model.probe_f_a3 = 0; % Modal STEM probe's threefold astigmatism in angstrom (optional)
p. model.probe_theta_a3 = 0; % Modal STEM probe's threefold azimuthal orientation in radian (optional)
p. model.probe_f_c3 = 0; % Modal STEM probe's coma in angstrom (optional)
p. model.probe_theta_c3 = 0; % Modal STEM probe's coma azimuthal orientation in radian (optional)
%Use probe from this mat-file (not used if model_probe is true)
p. probe_file_propagation = 0.0e-3; % Distance for propagating the probe from file in meters, = 0 to ignore
p. normalize_init_probe = true; % Added by YJ. Can be used to disable normalization of initial probes
% Shared scans - Currently working only for sharing probe and object
p. share_probe = 0; % Share probe between scans. Can be either a number/boolean or a list of numbers, specifying the probe index; e.g. [1 2 2] to share the probes between the second and third scan.
p. share_object = 0; % Share object between scans. Can be either a number/boolean or a list of numbers, specifying the object index; e.g. [1 2 2] to share the objects between the second and third scan.
% Modes
p. probe_modes = Nprobe; % Number of coherent modes for probe
p. object_modes = 1; % Number of coherent modes for object
% Mode starting guess
p. mode_start_pow = 0.02; % Normalized intensity on probe modes > 1. Can be a number (all higher modes equal) or a vector
p. mode_start = 'herm'; % (for probe) = 'rand', = 'herm' (Hermitian-like base), = 'hermver' (vertical modes only), = 'hermhor' (horizontal modes only)
p. ortho_probes = true; % orthogonalize probes after each engine
%% Plot, save and analyze
p. plot.prepared_data = false; % plot prepared data
p. plot.interval = []; % plot each interval-th iteration, does not work for c_solver code
p. plot.log_scale = [0 0]; % Plot on log scale for x and y
p. plot.realaxes = true; % Plots show scale in microns
p. plot.remove_phase_ramp = false; % Remove phase ramp from the plotted / saved phase figures
p. plot.fov_box = false; % Plot the scanning FOV box on the object (both phase and amplitude)
p. plot.fov_box_color = 'r'; % Color of the scanning FOV box
p. plot.positions = true; % Plot the scanning positions
p. plot.mask_bool = true; % Mask the noisy contour of the reconstructed object in plots
p. plot.windowautopos = true; % First plotting will auto position windows
p. plot.obj_apod = false; % Apply apodization to the reconstructed object;
p. plot.prop_obj = 0; % Distance to propagate reconstructed object before plotting [m]
p. plot.show_layers = true; % show each layer in multilayer reconstruction
p. plot.show_layers_stack = false; % show each layer in multilayer reconstruction by imagesc3D
p. plot.object_spectrum = []; % Plot propagated object (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.probe_spectrum = []; % Plot propagated probe (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.conjugate = false; % plot complex conjugate of the reconstruction
p. plot.horz_fact = 2.5; % Scales the space that the ptycho figures take horizontally
p. plot.FP_maskdim = 180e-6; % Filter the backpropagation (Fourier Ptychography)
p. plot.calc_FSC = false; % Calculate the Fourier Shell correlation for 2 scans or compare with model in case of artificial data tests
p. plot.show_FSC = false; % Show the FSC plots, including the cropped FOV
p. plot.residua = false; % highlight phase-residua in the image of the reconstructed phase
p. save.external = true; % Use a new Matlab session to run save final figures (saves ~6s per reconstruction). Please be aware that this might lead to an accumulation of Matlab sessions if your single reconstruction is very fast.
p. save.store_images = false; % Write preview images containing the final reconstructions in [p.base_path,'analysis/online/ptycho/'] if p.use_display = 0 then the figures are opened invisible in order to create the nice layout. It writes images in analysis/online/ptycho
p. save.store_images_intermediate = false; % save images to disk after each engine
p. save.store_images_ids = 1:4; % identifiers of the figure to be stored, 1=obj. amplitude, 2=obj. phase, 3=probes, 4=errors, 5=probes spectrum, 6=object spectrum
p. save.store_images_format = 'png'; % data type of the stored images jpg or png
p. save.store_images_dpi = 150; % DPI of the stored bitmap images
p. save.exclude = {'fmag', 'fmask', 'illum_sum'}; % exclude variables to reduce the file size on disk
p. save.save_reconstructions_intermediate = false; % save final object and probes after each engine
p. save.save_reconstructions = false; % save reconstructed object and probe when full reconstruction is finished
p. save.output_file = 'h5'; % data type of reconstruction file; 'h5' or 'mat'
if isfield(par, 'diff_pattern_blur')
p. diff_pattern_blur = par.diff_pattern_blur;
end
%% %%%%%%%%%%%%%%%%%% initialize reconstruction parameters %%%%%%%%%%%%%%%%%%%%
% --------- GPU engines ------------- See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng = struct(); % reset settings for this engine
eng. name = 'GPU_MS';
eng. use_gpu = true; % if false, run CPU code, but it will get very slow
eng. keep_on_gpu = true; % keep data + projections on GPU, false is useful for large data if DM is used
eng. compress_data = false; % use automatic online memory compression to limit need of GPU memory
eng. gpu_id = gpu_id; % default GPU id, [] means choosen by matlab
eng. check_gpu_load = true; % check available GPU memory before starting GPU engines
% general
eng. number_iterations = Niter; % number of iterations for selected method
if isfield(par, 'CBED_crop')
eng.asize_presolve = [par.CBED_crop, par.CBED_crop];
else
eng. asize_presolve = [par.CBED_size, par.CBED_size]; % crop data to "asize_presolve" size to get low resolution estimate that can be used in the next engine as a good initial guess
end
eng. align_shared_objects = false; % before merging multiple unshared objects into one shared, the object will be aligned and the probes shifted by the same distance -> use for alignement and shared reconstruction of drifting scans
eng. method = 'MLs'; % choose GPU solver: DM, ePIE, hPIE, MLc, Mls, -- recommended are MLc and MLs
eng. opt_errmetric = 'L1'; % optimization likelihood - poisson, L1
if isfield(par, 'grouping')
eng.grouping = par.grouping;
else
eng.grouping = 64;
end % size of processed blocks, larger blocks need more memory but they use GPU more effeciently, !!! grouping == inf means use as large as possible to fit into memory
% * for hPIE, ePIE, MLs methods smaller blocks lead to faster convergence,
% * for MLc the convergence is similar
% * for DM is has no effect on convergence
eng. probe_modes = p.probe_modes; % Number of coherent modes for probe
if isfield(par, 'object_change_start')
eng. object_change_start = par.object_change_start;
else
eng. object_change_start = 1; % Start updating object at this iteration number
end
if isfield(par, 'probe_change_start')
eng.probe_change_start = par.probe_change_start;
else
eng. probe_change_start = 20; % Start updating probe at this iteration number
end
% regularizations
if isfield(par, 'reg_mu')
eng.reg_mu = par.reg_mu; % Regularization (smooting) constant ( reg_mu = 0 for no regularization)
else
eng.reg_mu = 0;
end
eng. delta = 0; % press values to zero out of the illumination area in th object, usually 1e-2 is enough
eng. positivity_constraint_object = 0; % enforce weak (relaxed) positivity in object, ie O = O*(1-a)+a*|O|, usually a=1e-2 is already enough. Useful in conbination with OPRP or probe_fourier_shift_search
eng. apply_multimodal_update = false; % apply all incoherent modes to object, it can cause isses if the modes collect some crap
eng. probe_backpropagate = 0; % backpropagation distance the probe mask, 0 == apply in the object plane. Useful for pinhole imaging where the support can be applied at the pinhole plane
eng. probe_support_radius = []; % Normalized radius of circular support, = 1 for radius touching the window
eng. probe_support_fft = false; % assume that there is not illumination intensity out of the central FZP cone and enforce this contraint. Useful for imaging with focusing optics. Helps to remove issues from the gaps between detector modules.
% basic recontruction parameters
% PIE / ML methods % See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. beta_object = 1; % object step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. beta_probe = 1; % probe step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. delta_p = 0.1; % LSQ dumping constant, 0 == no preconditioner, 0.1 is usually safe, Preconditioner accelerates convergence and ML methods become approximations of the second order solvers
eng. momentum = 0; % add momentum acceleration term to the MLc method, useful if the probe guess is very poor or for acceleration of multilayer solver, but it is quite computationally expensive to be used in conventional ptycho without any refinement.
% The momentum method works usually well even with the accelerated_gradients option. eng.momentum = multiplication gain for velocity, eng.momentum == 0 -> no acceleration, eng.momentum == 0.5 is a good value
% momentum is enabled only when par.Niter < par.accelerated_gradients_start;
eng. accelerated_gradients_start = inf; % iteration number from which the Nesterov gradient acceleration should be applied, this option is supported only for MLc method. It is very computationally cheap way of convergence acceleration.
% DM
eng. pfft_relaxation = 0.05; % Relaxation in the Fourier domain projection, = 0 for full projection
eng. probe_regularization = 0.1; % Weight factor for the probe update (inertia)
% ADVANCED OPTIONS See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
% position refinement
eng. apply_subpix_shift = true; % apply FFT-based subpixel shift, it is automatically allowed for position refinement
eng. probe_position_search = 50; % iteration number from which the engine will reconstruct probe positions, from iteration == probe_position_search, assume they have to match geometry model with error less than probe_position_error_max
%eng. probe_geometry_model = {'scale', 'asymmetry', 'rotation', 'shear'}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_geometry_model = {}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_position_error_max = inf; % maximal expected random position errors, probe prositions are confined in a circle with radius defined by probe_position_error_max and with center defined by original positions scaled by probe_geometry_model
eng. apply_relaxed_position_constraint = false; % added by YJ. Apply a relaxed constraint to probe positions. default = true. Set to false if there are big jumps in positions.
eng. update_pos_weight_every = inf; % added by YJ. Allow position weight to be updated multiple times. default = inf: only update once.
% multilayer extension
eng. delta_z = delta_z*ones(Nlayers,1); % if not empty, use multilayer ptycho extension , see ML_MS code for example of use, [] == common single layer ptychography , note that delta_z provides only relative propagation distance from the previous layer, ie delta_z can be either positive or negative. If preshift_ML_probe == false, the first layer is defined by position of initial probe plane. It is useful to use eng.momentum for convergence acceleration
if isfield(par, 'regularize_layers')
eng.regularize_layers = par.regularize_layers;
else
eng. regularize_layers = 1; % multilayer extension: 0<R<<1 -> apply regularization on the reconstructed object layers, 0 == no regularization, 0.01 == weak regularization that will slowly symmetrize information content between layers
end
eng. preshift_ML_probe = false; % multilayer extension: if true, assume that the provided probe is reconstructed in center of the sample and the layers are centered around this position
eng. layer4pos = []; % Added by ZC. speficy which layer is used for position correction ; if empty, then default, ceil(Nlayers/2)
eng. init_layer_select = []; % Added by YJ. Select layers in the initial object for pre-processing. If empty (default): use all layers.
eng. init_layer_preprocess = ''; % Added by YJ. Specify how to pre-process initial layers
% '' or 'all' (default): use all layers (do nothing)
% 'avg': average all layers
% 'interp': interpolate layers using spline method. Need to specify desired depths in init_layer_interp
eng. init_layer_interp = []; % Specify desired depths for interpolation. The depths of initial are [1:Nlayer_init]. If empty (default), no interpolation
if isfield(par, 'init_layer_append_mode')
eng.init_layer_append_mode = par.init_layer_append_mode;
else
eng. init_layer_append_mode = 'vac';
end
% Added by YJ. Specify how to initialize extra layers
% '' or 'vac' (default): add vacuum layers
% 'edge': append 1st or last layers
% 'avg': append averaged layer
eng. init_layer_scaling_factor = 1; % Added by YJ. Scale all layers. Default: 1 (no scaling). Useful when delta_z is changed
% other extensions
eng. background = 0; % average background scattering level, for OMNI values around 0.3 for 100ms, for flOMNI <0.1 per 100ms exposure, see for more details: Odstrcil, M., et al., Optics letters 40.23 (2015): 5574-5577.
eng. background_width = inf; % width of the background function in pixels, inf == flat background, background function is then convolved with the average diffraction pattern in order to account for beam diversion
eng. clean_residua = false; % remove phase residua from reconstruction by iterative unwrapping, it will result in low spatial freq. artefacts -> object can be used as an residua-free initial guess for netx engine
% wavefront & camera geometry refinement See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. probe_fourier_shift_search = inf; % iteration number from which the engine will: refine farfield position of the beam (ie angle) from iteration == probe_fourier_shift_search
eng. estimate_NF_distance = inf; % iteration number from which the engine will: try to estimate the nearfield propagation distance using gradient descent optimization
eng. detector_rotation_search = inf; % iteration number from which the engine will: search for optimal detector rotation, preferably use with option mirror_scan = true , rotation of the detector axis with respect to the sample axis, similar as rotation option in the position refinement geometry model but works also for 0/180deg rotation shared scans
eng. detector_scale_search = inf; % iteration number from which the engine will: refine pixel scale of the detector, can be used to refine propagation distance in ptycho
eng. variable_probe = true; % Use SVD to account for variable illumination during a single (coupled) scan, see for more details: Odstrcil, M. et al. Optics express 24.8 (2016): 8360-8369.
eng. variable_probe_modes = 1; % OPRP settings , number of SVD modes using to describe the probe evolution.
eng. variable_probe_smooth = 0; % OPRP settings , enforce of smooth evolution of the OPRP modes -> N is order of polynomial fit used for smoothing, 0 == do not apply any smoothing. Smoothing is useful if only a smooth drift is assumed during the ptycho acquisition
eng. variable_intensity = false; % account to changes in probe intensity
% extra analysis
eng. get_fsc_score = false; % measure evolution of the Fourier ring correlation during convergence
eng. mirror_objects = false; % mirror objects, useful for 0/180deg scan sharing -> geometry refinement for tomography, works only if 2 scans are provided
% custom data adjustments, useful for offaxis ptychography
eng.auto_center_data = false; % autoestimate the center of mass from data and shift the diffraction patterns so that the average center of mass corresponds to center of mass of the provided probe
eng.auto_center_probe = false; % center the probe position in real space before reconstruction is started
eng.custom_data_flip = [0,0,0]; % apply custom flip of the data [fliplr, flipud, transpose] - can be used for quick testing of reconstruction with various flips or for reflection ptychography
eng.apply_tilted_plane_correction = ''; % if any(p.sample_rotation_angles([1,2]) ~= 0), this option will apply tilted plane correction. (a) 'diffraction' apply correction into the data, note that it is valid only for "low NA" illumination Gardner, D. et al., Optics express 20.17 (2012): 19050-19059. (b) 'propagation' - use tilted plane propagation, (c) '' - will not apply any correction
% I/O
eng.plot_results_every = Niter_plot_results;
eng.save_results_every = Niter_save_results;
eng.save_images ={'obj_ph_stack','obj_ph_sum','probe'};
eng.extraPrintInfo = par.extra_print_info;
resultDir = strcat(p.base_path,sprintf(p.scan.format, p.scan_number),'/roi',p.scan.roi_label,'/');
[eng.fout, p.suffix] = generateResultDir(eng, resultDir);
%add engine
[p, ~] = core.append_engine(p, eng); % Adds this engine to the reconstruction process
%% Run the reconstruction
tic
out = core.ptycho_recons(p);
toc
end
+398
View File
@@ -0,0 +1,398 @@
function run_multislice_new(parfile)
par = parameter_builder(parfile);
addpath(strcat(pwd,'/utils/'))
addpath(core.find_base_package)
%%%%%%%%%%%%%%%%%%%% data parameters %%%%%%%%%%%%%%%%%%%%
base_path = par.result_dir;
roi_label = par.roi_label;
scan_number = par.scan_number;
scan_string_format = '%01d';
Ndpx = par.CBED_size; % size of cbed
alpha0 = par.alpha_max; % semi-convergence angle (mrad)
rbf = par.rbf; % radius of the BF disk in cbed. Can be used to calculate dk
voltage = par.voltage;
rot_ang = par.rot_ang; %angle between cbed and scan coord.
scan_step_size = par.scan_step_size; %angstrom
N_scan_y = par.N_scan_y; %number of scan points
N_scan_x = par.N_scan_x;
%%%%%%%%%%%%%%%%%%%% reconstruction parameters %%%%%%%%%%%%%%%%%%%%
gpu_id = 1;
Niter = par.Niter;
Niter_save_results = par.Niter_save_results;
Niter_plot_results = inf;
Nprobe = par.Nprobe; % # of probe modes
thickness = par.thickness; % sample thickness in angstrom
Nlayers = round(par.Nlayers); % # of slices for multi-slice, 1 for single-slice
delta_z = thickness / Nlayers;
%% %%%%%%%%%%%%%%%%%% initialize data parameters %%%%%%%%%%%%%%%%%%%%
p = struct();
p. verbose_level = 2; % verbosity for standard output (0-1 for loops, 2-3 for testing and adjustments, >= 4 for debugging)
p. use_display = false; % global switch for display, if [] then true for verbose > 1
p. scan_number = scan_number; % Multiple scan numbers for shared scans
% Geometry
p. z = 1; % Distance from object to detector. Always 1 for electron ptycho
p. asize = [Ndpx,Ndpx]; % Diffr. patt. array size
p. ctr = [fix(Ndpx/2)+1, fix(Ndpx/2)+1]; % Diffr. patt. center coordinates (y,x) (empty means middle of the array); e.g. [100 207;100+20 207+10];
p. beam_source = 'electron'; % Added by YJ for electron pty. Use relativistic corrected formula for wavelength. Also change the units on figures
%p. dk = dk; % Added by YJ. dk is the pixel size in cbed (1/A). This is used to determine pixel size in electron ptycho
p. d_alpha = alpha0/rbf; % Added by YJ. d_alpha is the pixel size in cbed (mrad). This is used to determine pixel size in electron ptycho
p. prop_regime = 'farfield'; % propagation regime: nearfield, farfield (default), !! nearfield is supported only by GPU engines
p. focus_to_sample_distance = []; % sample to focus distance, parameter to be set for nearfield ptychography, otherwise it is ignored
p. energy = voltage; % Energy (in keV), leave empty to use spec entry mokev
%p. affine_angle = 0; % Not used by ptycho_recons at all. This allows you to define a variable for the affine matrix below and keep it in p for future record. This is used later by the affine_matrix_search.m script
%p. affine_matrix = [1 , 0; 0, 1] ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
affine_mat = compose_affine_matrix(1, 0, rot_ang, 0);
p. affine_matrix = affine_mat ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
% Scan meta data
p. src_metadata = 'none'; % source of the meta data, following options are supported: 'spec', 'none' , 'artificial' - or add new to +scan/+meta/
p. queue.lockfile = false; % If true writes a lock file, if lock file exists skips recontruction
% Data preparation
p. detector.name = 'empad'; % see +detectors/ folder
p. detector.check_2_detpos = []; % = []; (ignores) = 270; compares to dettrx to see if p.ctr should be reversed (for OMNY shared scans 1221122), make equal to the middle point of dettrx between the 2 detector positions
p. detector.data_prefix = ''; % Default using current eaccount e.g. e14169_1_
p. detector.binning = false; % = true to perform 2x2 binning of detector pixels, for binning = N do 2^Nx2^N binning
p. detector.upsampling = false; % upsample the measured data by 2^data_upsampling, (transposed operator to the binning), it can be used for superresolution in nearfield ptychography or to account for undersampling in a far-field dataset
p. detector.burst_frames = 1; % number of frames collected per scan position
p. prepare.data_preparator = 'matlab_aps'; % data preparator; 'python' or 'matlab' or 'matlab_aps'
p. prepare.auto_prepare_data = true; % if true: prepare dataset from raw measurements if the prepared data does not exist
p. prepare.force_preparation_data = true; % Prepare dataset even if it exists, it will overwrite the file % Default: @prepare_data_2d
p. prepare.store_prepared_data = false; % store the loaded data to h5 even for non-external engines (i.e. other than c_solver)
p. prepare.prepare_data_function = ''; % (used only if data should be prepared) custom data preparation function handle;
p. prepare.auto_center_data = false; % if matlab data preparator is used, try to automatically center the diffraction pattern to keep center of mass in center of diffraction
% Scan positions
p. src_positions = 'matlab_pos'; % 'spec', 'orchestra', 'load_from_file', 'matlab_pos' (scan params are defined below) or add new position loaders to +scan/+positions/
p. positions_file = ''; %Filename pattern for position files, Example: ['../../specES1/scan_positions/scan_%05d.dat']; (the scan number will be automatically filled in)
% scan parameters for option src_positions = 'matlab_pos';
p. scan.type = 'raster'; % {'round', 'raster', 'round_roi', 'custom'}
p. scan.roi_label = roi_label; % For APS data
p. scan.format = scan_string_format; % For APS data format for scan directory generation
p. scan.radius_in = 0; % round scan: interior radius of the round scan
p. scan.radius_out = 5e-6; % round scan: exterior radius of the round scan
p. scan.nr = 10; % round scan: number of intervals (# of shells - 1)
p. scan.nth = 3; % round scan: number of points in the first shell
p. scan.lx = 20e-6; % round_roi scan: width of the roi
p. scan.ly = 20e-6; % round_roi scan: height of the roi
p. scan.dr = 1.5e-6; % round_roi scan: shell step size
p. scan.nx = N_scan_x; %size(dp,3) % raster scan: number of steps in x
p. scan.ny = N_scan_y; % raster scan: number of steps in y
p. scan.step_size_x = scan_step_size; % raster scan: step size (grid spacing)
p. scan.step_size_y = scan_step_size; % raster scan: step size (grid spacing)
p. scan.custom_flip = [1,1,1]; % raster scan: apply custom flip [fliplr, flipud, transpose] to positions- similar to eng.custom_data_flip in GPU engines. Added by ZC.
p. scan.step_randn_offset = 0; % raster scan: relative random offset from the ideal periodic grid to avoid the raster grid pathology
p. scan.b = 0; % fermat: angular offset
p. scan.n_max = 1e4; % fermat: maximal number of points generated
p. scan.step = 0.5e-6; % fermat: step size
p. scan.cenxy = [0,0]; % fermat: position of center offset
p. scan.roi = []; % Region of interest in the object [xmin xmax ymin ymax] in meters. Points outside this region are not used for reconstruction.
% (relative to upper corner for raster scans and to center for round scans)
% custom: a string name of a function that defines the positions; also accepts mat file with entry 'pos', see +scans/+positions/+mat_pos.m
p. scan.custom_positions_source = '';
p. scan.custom_params = []; % custom: the parameters to feed to the custom position function.
% I/O
p. prefix = ''; % For automatic output filenames. If empty: scan number
p. suffix = strcat('ML_recon'); % Optional suffix for reconstruction
p. scan_string_format = scan_string_format; % format for scan string generation, it is used e.g for plotting and data saving
%%%p. base_path = '../../'; % base path : used for automatic generation of other paths
p. base_path = base_path; % base path : used for automatic generation of other paths
p. specfile = ''; % Name of spec file to get motor positions and check end of scan, defaut is p.spec_file == p.base_path;
p. ptycho_matlab_path = ''; % cSAXS ptycho package path
p. cSAXS_matlab_path = ''; % cSAXS base package path
p. raw_data_path{1} = ''; % Default using compile_x12sa_filename, used only if data should be prepared automatically
p. prepare_data_path = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. prepare_data_filename = []; % Leave empty for default file name generation, otherwise use [sprintf('S%05d_data_%03dx%03d',p.scan_number(1), p.asize(1), p.asize(2)) p.prep_data_suffix '.h5'] as default
p. save_path{1} = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. io.default_mask_file = ''; % load detector mask defined in this file instead of the mask in the detector packages, (used only if data should be prepared)
p. io.default_mask_type = 'binary'; % (used only if data should be prepared) ['binary', 'indices']. Default: 'binary'
p. io.file_compression = 0; % reconstruction file compression for HDF5 files; 0 for no compression
p. io.data_compression = 3; % prepared data file compression for HDF5 files; 0 for no compression
p. io.load_prep_pos = false; % load positions from prepared data file and ignore positions provided by metadata
p. io.data_descriptor = par.extra_print_info; %added by YJ. A short string that describe data when sending notifications
p. io.phone_number = ''; % phone number for sending messages
p. io.send_failed_scans_SMS = false; % send message if p.queue_max_attempts is exceeded
p. io.send_finished_recon_SMS = false; % send message after the reconstruction is completed
p. io.send_crashed_recon_SMS = false; % send message if the reconstruction crashes
p. io.SMS_sleep = 1800; % max 1 message per SMS_sleep seconds
p. io.script_name = mfilename; % added by YJ. store matlab script name
p. artificial_data_file = 'template_artificial_data'; % artificial data parameters, set p.src_metadata = 'artificial' to use this template
%% Reconstruction
% Initial iterate object, load from previous results if
% load_results_path is in the parameter file. Use random object and
% ideal probe otherwise.
if isfield(par, 'load_object_path')
p.model_object = false;
p.initial_iterate_object_file{1} = par.load_object_path;
if isfield(par, 'load_probe_path')
p.initial_probe_file = par.load_probe_path;
else
p.initial_probe_file = par.load_object_path;
end
p.multiple_layers_obj = true;
else
initial_probe_file = fullfile(par.result_dir, num2str(scan_number), '/init_probe.mat');
p.model_object = true;
p.model.object_type = 'rand';
p.initial_probe_file = initial_probe_file;
end
%%line to have only probe loaded instead of both probe and object
if isfield(par, 'load_probe_path')
p.initial_probe_file = par.load_probe_path;
else
initial_probe_file = fullfile(par.result_dir, num2str(scan_number), '/init_probe.mat');
p.initial_probe_file = initial_probe_file;
end
% Initial iterate probe
p. model_probe = false; % Use model probe, if false load it from file
p. model.probe_alpha_max = par.alpha_max; % Modal STEM probe's aperture size
p. model.probe_df = par.defocus; % Modal STEM probe's defocus
p. model.probe_c3 = 0; % Modal STEM probe's third-order spherical aberration in angstrom (optional)
p. model.probe_c5 = 0; % Modal STEM probe's fifth-order spherical aberration in angstrom (optional)
p. model.probe_c7 = 0; % Modal STEM probe's seventh-order spherical aberration in angstrom (optional)
p. model.probe_f_a2 = 0; % Modal STEM probe's twofold astigmatism in angstrom (optional)
p. model.probe_theta_a2 = 0; % Modal STEM probe's twofold azimuthal orientation in radian (optional)
p. model.probe_f_a3 = 0; % Modal STEM probe's threefold astigmatism in angstrom (optional)
p. model.probe_theta_a3 = 0; % Modal STEM probe's threefold azimuthal orientation in radian (optional)
p. model.probe_f_c3 = 0; % Modal STEM probe's coma in angstrom (optional)
p. model.probe_theta_c3 = 0; % Modal STEM probe's coma azimuthal orientation in radian (optional)
%Use probe from this mat-file (not used if model_probe is true)
p. probe_file_propagation = 0.0e-3; % Distance for propagating the probe from file in meters, = 0 to ignore
p. normalize_init_probe = true; % Added by YJ. Can be used to disable normalization of initial probes
% Shared scans - Currently working only for sharing probe and object
p. share_probe = 0; % Share probe between scans. Can be either a number/boolean or a list of numbers, specifying the probe index; e.g. [1 2 2] to share the probes between the second and third scan.
p. share_object = 0; % Share object between scans. Can be either a number/boolean or a list of numbers, specifying the object index; e.g. [1 2 2] to share the objects between the second and third scan.
% Modes
p. probe_modes = Nprobe; % Number of coherent modes for probe
p. object_modes = 1; % Number of coherent modes for object
% Mode starting guess
p. mode_start_pow = 0.02; % Normalized intensity on probe modes > 1. Can be a number (all higher modes equal) or a vector
p. mode_start = 'herm'; % (for probe) = 'rand', = 'herm' (Hermitian-like base), = 'hermver' (vertical modes only), = 'hermhor' (horizontal modes only)
p. ortho_probes = true; % orthogonalize probes after each engine
%% Plot, save and analyze
p. plot.prepared_data = false; % plot prepared data
p. plot.interval = []; % plot each interval-th iteration, does not work for c_solver code
p. plot.log_scale = [0 0]; % Plot on log scale for x and y
p. plot.realaxes = true; % Plots show scale in microns
p. plot.remove_phase_ramp = false; % Remove phase ramp from the plotted / saved phase figures
p. plot.fov_box = false; % Plot the scanning FOV box on the object (both phase and amplitude)
p. plot.fov_box_color = 'r'; % Color of the scanning FOV box
p. plot.positions = true; % Plot the scanning positions
p. plot.mask_bool = true; % Mask the noisy contour of the reconstructed object in plots
p. plot.windowautopos = true; % First plotting will auto position windows
p. plot.obj_apod = false; % Apply apodization to the reconstructed object;
p. plot.prop_obj = 0; % Distance to propagate reconstructed object before plotting [m]
p. plot.show_layers = true; % show each layer in multilayer reconstruction
p. plot.show_layers_stack = false; % show each layer in multilayer reconstruction by imagesc3D
p. plot.object_spectrum = []; % Plot propagated object (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.probe_spectrum = []; % Plot propagated probe (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.conjugate = false; % plot complex conjugate of the reconstruction
p. plot.horz_fact = 2.5; % Scales the space that the ptycho figures take horizontally
p. plot.FP_maskdim = 180e-6; % Filter the backpropagation (Fourier Ptychography)
p. plot.calc_FSC = false; % Calculate the Fourier Shell correlation for 2 scans or compare with model in case of artificial data tests
p. plot.show_FSC = false; % Show the FSC plots, including the cropped FOV
p. plot.residua = false; % highlight phase-residua in the image of the reconstructed phase
p. save.external = true; % Use a new Matlab session to run save final figures (saves ~6s per reconstruction). Please be aware that this might lead to an accumulation of Matlab sessions if your single reconstruction is very fast.
p. save.store_images = false; % Write preview images containing the final reconstructions in [p.base_path,'analysis/online/ptycho/'] if p.use_display = 0 then the figures are opened invisible in order to create the nice layout. It writes images in analysis/online/ptycho
p. save.store_images_intermediate = false; % save images to disk after each engine
p. save.store_images_ids = 1:4; % identifiers of the figure to be stored, 1=obj. amplitude, 2=obj. phase, 3=probes, 4=errors, 5=probes spectrum, 6=object spectrum
p. save.store_images_format = 'png'; % data type of the stored images jpg or png
p. save.store_images_dpi = 150; % DPI of the stored bitmap images
p. save.exclude = {'fmag', 'fmask', 'illum_sum'}; % exclude variables to reduce the file size on disk
p. save.save_reconstructions_intermediate = false; % save final object and probes after each engine
p. save.save_reconstructions = false; % save reconstructed object and probe when full reconstruction is finished
p. save.output_file = 'h5'; % data type of reconstruction file; 'h5' or 'mat'
if isfield(par, 'diff_pattern_blur')
p. diff_pattern_blur = par.diff_pattern_blur;
end
%% %%%%%%%%%%%%%%%%%% initialize reconstruction parameters %%%%%%%%%%%%%%%%%%%%
% --------- GPU engines ------------- See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng = struct(); % reset settings for this engine
eng. name = 'GPU_MS';
eng. use_gpu = true; % if false, run CPU code, but it will get very slow
eng. keep_on_gpu = true; % keep data + projections on GPU, false is useful for large data if DM is used
eng. compress_data = false; % use automatic online memory compression to limit need of GPU memory
eng. gpu_id = gpu_id; % default GPU id, [] means choosen by matlab
eng. check_gpu_load = true; % check available GPU memory before starting GPU engines
% general
eng. number_iterations = Niter; % number of iterations for selected method
if isfield(par, 'CBED_crop')
eng.asize_presolve = [par.CBED_crop, par.CBED_crop];
else
eng. asize_presolve = [par.CBED_size, par.CBED_size]; % crop data to "asize_presolve" size to get low resolution estimate that can be used in the next engine as a good initial guess
end
eng. align_shared_objects = false; % before merging multiple unshared objects into one shared, the object will be aligned and the probes shifted by the same distance -> use for alignement and shared reconstruction of drifting scans
eng. method = 'MLs'; % choose GPU solver: DM, ePIE, hPIE, MLc, Mls, -- recommended are MLc and MLs
eng. opt_errmetric = 'L1'; % optimization likelihood - poisson, L1
if isfield(par, 'grouping')
eng.grouping = par.grouping;
else
eng.grouping = 64;
end % size of processed blocks, larger blocks need more memory but they use GPU more effeciently, !!! grouping == inf means use as large as possible to fit into memory
% * for hPIE, ePIE, MLs methods smaller blocks lead to faster convergence,
% * for MLc the convergence is similar
% * for DM is has no effect on convergence
eng. probe_modes = p.probe_modes; % Number of coherent modes for probe
if isfield(par, 'object_change_start')
eng. object_change_start = par.object_change_start;
else
eng. object_change_start = 1; % Start updating object at this iteration number
end
if isfield(par, 'probe_change_start')
eng.probe_change_start = par.probe_change_start;
else
eng. probe_change_start = 1; % Start updating probe at this iteration number
end
% regularizations
if isfield(par, 'reg_mu')
eng.reg_mu = par.reg_mu; % Regularization (smooting) constant ( reg_mu = 0 for no regularization)
else
eng.reg_mu = 0;
end
eng. delta = 0; % press values to zero out of the illumination area in th object, usually 1e-2 is enough
eng. positivity_constraint_object = 0; % enforce weak (relaxed) positivity in object, ie O = O*(1-a)+a*|O|, usually a=1e-2 is already enough. Useful in conbination with OPRP or probe_fourier_shift_search
eng. apply_multimodal_update = false; % apply all incoherent modes to object, it can cause isses if the modes collect some crap
eng. probe_backpropagate = 0; % backpropagation distance the probe mask, 0 == apply in the object plane. Useful for pinhole imaging where the support can be applied at the pinhole plane
eng. probe_support_radius = []; % Normalized radius of circular support, = 1 for radius touching the window
eng. probe_support_fft = false; % assume that there is not illumination intensity out of the central FZP cone and enforce this contraint. Useful for imaging with focusing optics. Helps to remove issues from the gaps between detector modules.
% basic recontruction parameters
% PIE / ML methods % See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. beta_object = 1; % object step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. beta_probe = 1; % probe step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. delta_p = 0.1; % LSQ dumping constant, 0 == no preconditioner, 0.1 is usually safe, Preconditioner accelerates convergence and ML methods become approximations of the second order solvers
eng. momentum = 0; % add momentum acceleration term to the MLc method, useful if the probe guess is very poor or for acceleration of multilayer solver, but it is quite computationally expensive to be used in conventional ptycho without any refinement.
% The momentum method works usually well even with the accelerated_gradients option. eng.momentum = multiplication gain for velocity, eng.momentum == 0 -> no acceleration, eng.momentum == 0.5 is a good value
% momentum is enabled only when par.Niter < par.accelerated_gradients_start;
eng. accelerated_gradients_start = inf; % iteration number from which the Nesterov gradient acceleration should be applied, this option is supported only for MLc method. It is very computationally cheap way of convergence acceleration.
% DM
eng. pfft_relaxation = 0.05; % Relaxation in the Fourier domain projection, = 0 for full projection
eng. probe_regularization = 0.1; % Weight factor for the probe update (inertia)
% ADVANCED OPTIONS See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
% position refinement
eng. apply_subpix_shift = true; % apply FFT-based subpixel shift, it is automatically allowed for position refinement
if isfield(par, 'probe_position_search')
eng.probe_position_search = par.probe_position_search;
else
eng. probe_position_search = 50; % iteration number from which the engine will reconstruct probe positions, from iteration == probe_position_search, assume they have to match geometry model with error less than probe_position_error_max
end
%eng. probe_geometry_model = {'scale', 'asymmetry', 'rotation', 'shear'}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_geometry_model = {}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_position_error_max = inf; % maximal expected random position errors, probe prositions are confined in a circle with radius defined by probe_position_error_max and with center defined by original positions scaled by probe_geometry_model
eng. apply_relaxed_position_constraint = false; % added by YJ. Apply a relaxed constraint to probe positions. default = true. Set to false if there are big jumps in positions.
eng. update_pos_weight_every = inf; % added by YJ. Allow position weight to be updated multiple times. default = inf: only update once.
% multilayer extension
eng. delta_z = delta_z*ones(Nlayers,1); % if not empty, use multilayer ptycho extension , see ML_MS code for example of use, [] == common single layer ptychography , note that delta_z provides only relative propagation distance from the previous layer, ie delta_z can be either positive or negative. If preshift_ML_probe == false, the first layer is defined by position of initial probe plane. It is useful to use eng.momentum for convergence acceleration
if isfield(par, 'regularize_layers')
eng.regularize_layers = par.regularize_layers;
else
eng. regularize_layers = 1; % multilayer extension: 0<R<<1 -> apply regularization on the reconstructed object layers, 0 == no regularization, 0.01 == weak regularization that will slowly symmetrize information content between layers
end
eng. preshift_ML_probe = false; % multilayer extension: if true, assume that the provided probe is reconstructed in center of the sample and the layers are centered around this position
eng. layer4pos = []; % Added by ZC. speficy which layer is used for position correction ; if empty, then default, ceil(Nlayers/2)
eng. init_layer_select = []; % Added by YJ. Select layers in the initial object for pre-processing. If empty (default): use all layers.
eng. init_layer_preprocess = ''; % Added by YJ. Specify how to pre-process initial layers
% '' or 'all' (default): use all layers (do nothing)
% 'avg': average all layers
% 'interp': interpolate layers using spline method. Need to specify desired depths in init_layer_interp
eng. init_layer_interp = []; % Specify desired depths for interpolation. The depths of initial are [1:Nlayer_init]. If empty (default), no interpolation
if isfield(par, 'init_layer_append_mode')
eng.init_layer_append_mode = par.init_layer_append_mode;
else
eng. init_layer_append_mode = 'vac';
end
% Added by YJ. Specify how to initialize extra layers
% '' or 'vac' (default): add vacuum layers
% 'edge': append 1st or last layers
% 'avg': append averaged layer
eng. init_layer_scaling_factor = 1; % Added by YJ. Scale all layers. Default: 1 (no scaling). Useful when delta_z is changed
% other extensions
eng. background = 0; % average background scattering level, for OMNI values around 0.3 for 100ms, for flOMNI <0.1 per 100ms exposure, see for more details: Odstrcil, M., et al., Optics letters 40.23 (2015): 5574-5577.
eng. background_width = inf; % width of the background function in pixels, inf == flat background, background function is then convolved with the average diffraction pattern in order to account for beam diversion
eng. clean_residua = false; % remove phase residua from reconstruction by iterative unwrapping, it will result in low spatial freq. artefacts -> object can be used as an residua-free initial guess for netx engine
% wavefront & camera geometry refinement See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. probe_fourier_shift_search = inf; % iteration number from which the engine will: refine farfield position of the beam (ie angle) from iteration == probe_fourier_shift_search
eng. estimate_NF_distance = inf; % iteration number from which the engine will: try to estimate the nearfield propagation distance using gradient descent optimization
eng. detector_rotation_search = inf; % iteration number from which the engine will: search for optimal detector rotation, preferably use with option mirror_scan = true , rotation of the detector axis with respect to the sample axis, similar as rotation option in the position refinement geometry model but works also for 0/180deg rotation shared scans
eng. detector_scale_search = inf; % iteration number from which the engine will: refine pixel scale of the detector, can be used to refine propagation distance in ptycho
if isfield(par, 'variable_probe') && strcmp(par.variable_probe,'false')
eng.variable_probe = false;
else
eng.variable_probe = true;
end
% eng. variable_probe = true; % Use SVD to account for variable illumination during a single (coupled) scan, see for more details: Odstrcil, M. et al. Optics express 24.8 (2016): 8360-8369.
eng. variable_probe_modes = 1; % OPRP settings , number of SVD modes using to describe the probe evolution.
eng. variable_probe_smooth = 0; % OPRP settings , enforce of smooth evolution of the OPRP modes -> N is order of polynomial fit used for smoothing, 0 == do not apply any smoothing. Smoothing is useful if only a smooth drift is assumed during the ptycho acquisition
eng. variable_intensity = false; % account to changes in probe intensity
% extra analysis
eng. get_fsc_score = false; % measure evolution of the Fourier ring correlation during convergence
eng. mirror_objects = false; % mirror objects, useful for 0/180deg scan sharing -> geometry refinement for tomography, works only if 2 scans are provided
% custom data adjustments, useful for offaxis ptychography
eng.auto_center_data = false; % autoestimate the center of mass from data and shift the diffraction patterns so that the average center of mass corresponds to center of mass of the provided probe
eng.auto_center_probe = false; % center the probe position in real space before reconstruction is started
eng.custom_data_flip = [0,0,0]; % apply custom flip of the data [fliplr, flipud, transpose] - can be used for quick testing of reconstruction with various flips or for reflection ptychography
eng.apply_tilted_plane_correction = ''; % if any(p.sample_rotation_angles([1,2]) ~= 0), this option will apply tilted plane correction. (a) 'diffraction' apply correction into the data, note that it is valid only for "low NA" illumination Gardner, D. et al., Optics express 20.17 (2012): 19050-19059. (b) 'propagation' - use tilted plane propagation, (c) '' - will not apply any correction
% tilted plane propagation (units: mrad). Set in parameter txt file.
% tilt_x: tilt along x-axis, tilt_y: tilt along y-axis. 0 = no tilt.
if isfield(par, 'tilt_x')
eng.tilt_x = par.tilt_x;
else
eng.tilt_x = 0;
end
if isfield(par, 'tilt_y')
eng.tilt_y = par.tilt_y;
else
eng.tilt_y = 0;
end
% I/O
eng.plot_results_every = Niter_plot_results;
eng.save_results_every = Niter_save_results;
eng.save_images ={'obj_ph_stack','obj_ph_sum','probe','probe_mag','obj_mag_sum','obj_mag_stack'};
eng.extraPrintInfo = par.extra_print_info;
resultDir = strcat(p.base_path,sprintf(p.scan.format, p.scan_number),'/roi',p.scan.roi_label,'/');
[eng.fout, p.suffix] = generateResultDir(eng, resultDir);
%add engine
[p, ~] = core.append_engine(p, eng); % Adds this engine to the reconstruction process
%% Run the reconstruction
tic
out = core.ptycho_recons(p);
toc
end
+378
View File
@@ -0,0 +1,378 @@
function run_multislice_new_GC(parfile)
par = parameter_builder(parfile);
addpath(strcat(pwd,'/utils/'))
addpath(core.find_base_package)
%%%%%%%%%%%%%%%%%%%% data parameters %%%%%%%%%%%%%%%%%%%%
base_path = par.result_dir;
roi_label = par.roi_label;
scan_number = par.scan_number;
scan_string_format = '%01d';
Ndpx = par.CBED_size; % size of cbed
alpha0 = par.alpha_max; % semi-convergence angle (mrad)
rbf = par.rbf; % radius of the BF disk in cbed. Can be used to calculate dk
voltage = par.voltage;
rot_ang = par.rot_ang; %angle between cbed and scan coord.
scan_step_size = par.scan_step_size; %angstrom
N_scan_y = par.N_scan_y; %number of scan points
N_scan_x = par.N_scan_x;
%%%%%%%%%%%%%%%%%%%% reconstruction parameters %%%%%%%%%%%%%%%%%%%%
gpu_id = 1;
Niter = par.Niter;
Niter_save_results = par.Niter_save_results;
Niter_plot_results = inf;
Nprobe = par.Nprobe; % # of probe modes
thickness = par.thickness; % sample thickness in angstrom
Nlayers = round(par.Nlayers); % # of slices for multi-slice, 1 for single-slice
delta_z = thickness / Nlayers;
%% %%%%%%%%%%%%%%%%%% initialize data parameters %%%%%%%%%%%%%%%%%%%%
p = struct();
p. verbose_level = 2; % verbosity for standard output (0-1 for loops, 2-3 for testing and adjustments, >= 4 for debugging)
p. use_display = false; % global switch for display, if [] then true for verbose > 1
p. scan_number = scan_number; % Multiple scan numbers for shared scans
% Geometry
p. z = 1; % Distance from object to detector. Always 1 for electron ptycho
p. asize = [Ndpx,Ndpx]; % Diffr. patt. array size
p. ctr = [fix(Ndpx/2)+1, fix(Ndpx/2)+1]; % Diffr. patt. center coordinates (y,x) (empty means middle of the array); e.g. [100 207;100+20 207+10];
p. beam_source = 'electron'; % Added by YJ for electron pty. Use relativistic corrected formula for wavelength. Also change the units on figures
%p. dk = dk; % Added by YJ. dk is the pixel size in cbed (1/A). This is used to determine pixel size in electron ptycho
p. d_alpha = alpha0/rbf; % Added by YJ. d_alpha is the pixel size in cbed (mrad). This is used to determine pixel size in electron ptycho
p. prop_regime = 'farfield'; % propagation regime: nearfield, farfield (default), !! nearfield is supported only by GPU engines
p. focus_to_sample_distance = []; % sample to focus distance, parameter to be set for nearfield ptychography, otherwise it is ignored
p. energy = voltage; % Energy (in keV), leave empty to use spec entry mokev
%p. affine_angle = 0; % Not used by ptycho_recons at all. This allows you to define a variable for the affine matrix below and keep it in p for future record. This is used later by the affine_matrix_search.m script
%p. affine_matrix = [1 , 0; 0, 1] ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
affine_mat = compose_affine_matrix(1, 0, rot_ang, 0);
p. affine_matrix = affine_mat ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
% Scan meta data
p. src_metadata = 'none'; % source of the meta data, following options are supported: 'spec', 'none' , 'artificial' - or add new to +scan/+meta/
p. queue.lockfile = false; % If true writes a lock file, if lock file exists skips recontruction
% Data preparation
p. detector.name = 'empad'; % see +detectors/ folder
p. detector.check_2_detpos = []; % = []; (ignores) = 270; compares to dettrx to see if p.ctr should be reversed (for OMNY shared scans 1221122), make equal to the middle point of dettrx between the 2 detector positions
p. detector.data_prefix = ''; % Default using current eaccount e.g. e14169_1_
p. detector.binning = false; % = true to perform 2x2 binning of detector pixels, for binning = N do 2^Nx2^N binning
p. detector.upsampling = false; % upsample the measured data by 2^data_upsampling, (transposed operator to the binning), it can be used for superresolution in nearfield ptychography or to account for undersampling in a far-field dataset
p. detector.burst_frames = 1; % number of frames collected per scan position
p. prepare.data_preparator = 'matlab_aps'; % data preparator; 'python' or 'matlab' or 'matlab_aps'
p. prepare.auto_prepare_data = true; % if true: prepare dataset from raw measurements if the prepared data does not exist
p. prepare.force_preparation_data = true; % Prepare dataset even if it exists, it will overwrite the file % Default: @prepare_data_2d
p. prepare.store_prepared_data = false; % store the loaded data to h5 even for non-external engines (i.e. other than c_solver)
p. prepare.prepare_data_function = ''; % (used only if data should be prepared) custom data preparation function handle;
p. prepare.auto_center_data = false; % if matlab data preparator is used, try to automatically center the diffraction pattern to keep center of mass in center of diffraction
% Scan positions
p. src_positions = 'matlab_pos'; % 'spec', 'orchestra', 'load_from_file', 'matlab_pos' (scan params are defined below) or add new position loaders to +scan/+positions/
p. positions_file = ''; %Filename pattern for position files, Example: ['../../specES1/scan_positions/scan_%05d.dat']; (the scan number will be automatically filled in)
% scan parameters for option src_positions = 'matlab_pos';
p. scan.type = 'raster'; % {'round', 'raster', 'round_roi', 'custom'}
p. scan.roi_label = roi_label; % For APS data
p. scan.format = scan_string_format; % For APS data format for scan directory generation
p. scan.radius_in = 0; % round scan: interior radius of the round scan
p. scan.radius_out = 5e-6; % round scan: exterior radius of the round scan
p. scan.nr = 10; % round scan: number of intervals (# of shells - 1)
p. scan.nth = 3; % round scan: number of points in the first shell
p. scan.lx = 20e-6; % round_roi scan: width of the roi
p. scan.ly = 20e-6; % round_roi scan: height of the roi
p. scan.dr = 1.5e-6; % round_roi scan: shell step size
p. scan.nx = N_scan_x; %size(dp,3) % raster scan: number of steps in x
p. scan.ny = N_scan_y; % raster scan: number of steps in y
p. scan.step_size_x = scan_step_size; % raster scan: step size (grid spacing)
p. scan.step_size_y = scan_step_size; % raster scan: step size (grid spacing)
p. scan.custom_flip = [1,1,1]; % raster scan: apply custom flip [fliplr, flipud, transpose] to positions- similar to eng.custom_data_flip in GPU engines. Added by ZC.
p. scan.step_randn_offset = 0; % raster scan: relative random offset from the ideal periodic grid to avoid the raster grid pathology
p. scan.b = 0; % fermat: angular offset
p. scan.n_max = 1e4; % fermat: maximal number of points generated
p. scan.step = 0.5e-6; % fermat: step size
p. scan.cenxy = [0,0]; % fermat: position of center offset
p. scan.roi = []; % Region of interest in the object [xmin xmax ymin ymax] in meters. Points outside this region are not used for reconstruction.
% (relative to upper corner for raster scans and to center for round scans)
% custom: a string name of a function that defines the positions; also accepts mat file with entry 'pos', see +scans/+positions/+mat_pos.m
p. scan.custom_positions_source = '';
p. scan.custom_params = []; % custom: the parameters to feed to the custom position function.
% I/O
p. prefix = ''; % For automatic output filenames. If empty: scan number
p. suffix = strcat('ML_recon'); % Optional suffix for reconstruction
p. scan_string_format = scan_string_format; % format for scan string generation, it is used e.g for plotting and data saving
%%%p. base_path = '../../'; % base path : used for automatic generation of other paths
p. base_path = base_path; % base path : used for automatic generation of other paths
p. specfile = ''; % Name of spec file to get motor positions and check end of scan, defaut is p.spec_file == p.base_path;
p. ptycho_matlab_path = ''; % cSAXS ptycho package path
p. cSAXS_matlab_path = ''; % cSAXS base package path
p. raw_data_path{1} = ''; % Default using compile_x12sa_filename, used only if data should be prepared automatically
p. prepare_data_path = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. prepare_data_filename = []; % Leave empty for default file name generation, otherwise use [sprintf('S%05d_data_%03dx%03d',p.scan_number(1), p.asize(1), p.asize(2)) p.prep_data_suffix '.h5'] as default
p. save_path{1} = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. io.default_mask_file = ''; % load detector mask defined in this file instead of the mask in the detector packages, (used only if data should be prepared)
p. io.default_mask_type = 'binary'; % (used only if data should be prepared) ['binary', 'indices']. Default: 'binary'
p. io.file_compression = 0; % reconstruction file compression for HDF5 files; 0 for no compression
p. io.data_compression = 3; % prepared data file compression for HDF5 files; 0 for no compression
p. io.load_prep_pos = false; % load positions from prepared data file and ignore positions provided by metadata
p. io.data_descriptor = par.extra_print_info; %added by YJ. A short string that describe data when sending notifications
p. io.phone_number = ''; % phone number for sending messages
p. io.send_failed_scans_SMS = false; % send message if p.queue_max_attempts is exceeded
p. io.send_finished_recon_SMS = false; % send message after the reconstruction is completed
p. io.send_crashed_recon_SMS = false; % send message if the reconstruction crashes
p. io.SMS_sleep = 1800; % max 1 message per SMS_sleep seconds
p. io.script_name = mfilename; % added by YJ. store matlab script name
p. artificial_data_file = 'template_artificial_data'; % artificial data parameters, set p.src_metadata = 'artificial' to use this template
%% Reconstruction
% Initial iterate object, load from previous results if
% load_results_path is in the parameter file. Use random object and
% ideal probe otherwise.
if isfield(par, 'load_object_path')
p.model_object = false;
p.initial_iterate_object_file{1} = par.load_object_path;
if isfield(par, 'load_probe_path')
p.initial_probe_file = par.load_probe_path;
else
p.initial_probe_file = par.load_object_path;
end
p.multiple_layers_obj = true;
else
initial_probe_file = fullfile(par.result_dir, num2str(scan_number), '/init_probe.mat');
p.model_object = true;
p.model.object_type = 'rand';
p.initial_probe_file = initial_probe_file;
end
% Initial iterate probe
p. model_probe = false; % Use model probe, if false load it from file
p. model.probe_alpha_max = par.alpha_max; % Modal STEM probe's aperture size
p. model.probe_df = par.defocus; % Modal STEM probe's defocus
p. model.probe_c3 = 0; % Modal STEM probe's third-order spherical aberration in angstrom (optional)
p. model.probe_c5 = 0; % Modal STEM probe's fifth-order spherical aberration in angstrom (optional)
p. model.probe_c7 = 0; % Modal STEM probe's seventh-order spherical aberration in angstrom (optional)
p. model.probe_f_a2 = 0; % Modal STEM probe's twofold astigmatism in angstrom (optional)
p. model.probe_theta_a2 = 0; % Modal STEM probe's twofold azimuthal orientation in radian (optional)
p. model.probe_f_a3 = 0; % Modal STEM probe's threefold astigmatism in angstrom (optional)
p. model.probe_theta_a3 = 0; % Modal STEM probe's threefold azimuthal orientation in radian (optional)
p. model.probe_f_c3 = 0; % Modal STEM probe's coma in angstrom (optional)
p. model.probe_theta_c3 = 0; % Modal STEM probe's coma azimuthal orientation in radian (optional)
%Use probe from this mat-file (not used if model_probe is true)
p. probe_file_propagation = 0.0e-3; % Distance for propagating the probe from file in meters, = 0 to ignore
p. normalize_init_probe = true; % Added by YJ. Can be used to disable normalization of initial probes
% Shared scans - Currently working only for sharing probe and object
p. share_probe = 0; % Share probe between scans. Can be either a number/boolean or a list of numbers, specifying the probe index; e.g. [1 2 2] to share the probes between the second and third scan.
p. share_object = 0; % Share object between scans. Can be either a number/boolean or a list of numbers, specifying the object index; e.g. [1 2 2] to share the objects between the second and third scan.
% Modes
p. probe_modes = Nprobe; % Number of coherent modes for probe
p. object_modes = 1; % Number of coherent modes for object
% Mode starting guess
p. mode_start_pow = 0.02; % Normalized intensity on probe modes > 1. Can be a number (all higher modes equal) or a vector
p. mode_start = 'herm'; % (for probe) = 'rand', = 'herm' (Hermitian-like base), = 'hermver' (vertical modes only), = 'hermhor' (horizontal modes only)
p. ortho_probes = true; % orthogonalize probes after each engine
%% Plot, save and analyze
p. plot.prepared_data = false; % plot prepared data
p. plot.interval = []; % plot each interval-th iteration, does not work for c_solver code
p. plot.log_scale = [0 0]; % Plot on log scale for x and y
p. plot.realaxes = true; % Plots show scale in microns
p. plot.remove_phase_ramp = false; % Remove phase ramp from the plotted / saved phase figures
p. plot.fov_box = false; % Plot the scanning FOV box on the object (both phase and amplitude)
p. plot.fov_box_color = 'r'; % Color of the scanning FOV box
p. plot.positions = true; % Plot the scanning positions
p. plot.mask_bool = true; % Mask the noisy contour of the reconstructed object in plots
p. plot.windowautopos = true; % First plotting will auto position windows
p. plot.obj_apod = false; % Apply apodization to the reconstructed object;
p. plot.prop_obj = 0; % Distance to propagate reconstructed object before plotting [m]
p. plot.show_layers = true; % show each layer in multilayer reconstruction
p. plot.show_layers_stack = false; % show each layer in multilayer reconstruction by imagesc3D
p. plot.object_spectrum = []; % Plot propagated object (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.probe_spectrum = []; % Plot propagated probe (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.conjugate = false; % plot complex conjugate of the reconstruction
p. plot.horz_fact = 2.5; % Scales the space that the ptycho figures take horizontally
p. plot.FP_maskdim = 180e-6; % Filter the backpropagation (Fourier Ptychography)
p. plot.calc_FSC = false; % Calculate the Fourier Shell correlation for 2 scans or compare with model in case of artificial data tests
p. plot.show_FSC = false; % Show the FSC plots, including the cropped FOV
p. plot.residua = false; % highlight phase-residua in the image of the reconstructed phase
p. save.external = true; % Use a new Matlab session to run save final figures (saves ~6s per reconstruction). Please be aware that this might lead to an accumulation of Matlab sessions if your single reconstruction is very fast.
p. save.store_images = false; % Write preview images containing the final reconstructions in [p.base_path,'analysis/online/ptycho/'] if p.use_display = 0 then the figures are opened invisible in order to create the nice layout. It writes images in analysis/online/ptycho
p. save.store_images_intermediate = false; % save images to disk after each engine
p. save.store_images_ids = 1:4; % identifiers of the figure to be stored, 1=obj. amplitude, 2=obj. phase, 3=probes, 4=errors, 5=probes spectrum, 6=object spectrum
p. save.store_images_format = 'png'; % data type of the stored images jpg or png
p. save.store_images_dpi = 150; % DPI of the stored bitmap images
p. save.exclude = {'fmag', 'fmask', 'illum_sum'}; % exclude variables to reduce the file size on disk
p. save.save_reconstructions_intermediate = false; % save final object and probes after each engine
p. save.save_reconstructions = false; % save reconstructed object and probe when full reconstruction is finished
p. save.output_file = 'h5'; % data type of reconstruction file; 'h5' or 'mat'
if isfield(par, 'diff_pattern_blur')
p. diff_pattern_blur = par.diff_pattern_blur;
end
%% %%%%%%%%%%%%%%%%%% initialize reconstruction parameters %%%%%%%%%%%%%%%%%%%%
% --------- GPU engines ------------- See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng = struct(); % reset settings for this engine
eng. name = 'GPU_MS';
eng. use_gpu = true; % if false, run CPU code, but it will get very slow
eng. keep_on_gpu = true; % keep data + projections on GPU, false is useful for large data if DM is used
eng. compress_data = false; % use automatic online memory compression to limit need of GPU memory
eng. gpu_id = gpu_id; % default GPU id, [] means choosen by matlab
eng. check_gpu_load = true; % check available GPU memory before starting GPU engines
% general
eng. number_iterations = Niter; % number of iterations for selected method
if isfield(par, 'CBED_crop')
eng.asize_presolve = [par.CBED_crop, par.CBED_crop];
else
eng. asize_presolve = [par.CBED_size, par.CBED_size]; % crop data to "asize_presolve" size to get low resolution estimate that can be used in the next engine as a good initial guess
end
eng. align_shared_objects = false; % before merging multiple unshared objects into one shared, the object will be aligned and the probes shifted by the same distance -> use for alignement and shared reconstruction of drifting scans
eng. method = 'MLs'; % choose GPU solver: DM, ePIE, hPIE, MLc, Mls, -- recommended are MLc and MLs
eng. opt_errmetric = 'L1'; % optimization likelihood - poisson, L1
if isfield(par, 'grouping')
eng.grouping = par.grouping;
else
eng.grouping = 64;
end % size of processed blocks, larger blocks need more memory but they use GPU more effeciently, !!! grouping == inf means use as large as possible to fit into memory
% * for hPIE, ePIE, MLs methods smaller blocks lead to faster convergence,
% * for MLc the convergence is similar
% * for DM is has no effect on convergence
eng. probe_modes = p.probe_modes; % Number of coherent modes for probe
if isfield(par, 'object_change_start')
eng. object_change_start = par.object_change_start;
else
eng. object_change_start = 1; % Start updating object at this iteration number
end
if isfield(par, 'probe_change_start')
eng.probe_change_start = par.probe_change_start;
else
eng. probe_change_start = 1; % Start updating probe at this iteration number
end
% regularizations
if isfield(par, 'reg_mu')
eng.reg_mu = par.reg_mu; % Regularization (smooting) constant ( reg_mu = 0 for no regularization)
else
eng.reg_mu = 0;
end
eng. delta = 0; % press values to zero out of the illumination area in th object, usually 1e-2 is enough
eng. positivity_constraint_object = 0; % enforce weak (relaxed) positivity in object, ie O = O*(1-a)+a*|O|, usually a=1e-2 is already enough. Useful in conbination with OPRP or probe_fourier_shift_search
eng. apply_multimodal_update = false; % apply all incoherent modes to object, it can cause isses if the modes collect some crap
eng. probe_backpropagate = 0; % backpropagation distance the probe mask, 0 == apply in the object plane. Useful for pinhole imaging where the support can be applied at the pinhole plane
eng. probe_support_radius = []; % Normalized radius of circular support, = 1 for radius touching the window
eng. probe_support_fft = false; % assume that there is not illumination intensity out of the central FZP cone and enforce this contraint. Useful for imaging with focusing optics. Helps to remove issues from the gaps between detector modules.
% basic recontruction parameters
% PIE / ML methods % See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. beta_object = 1; % object step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. beta_probe = 1; % probe step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. delta_p = 0.1; % LSQ dumping constant, 0 == no preconditioner, 0.1 is usually safe, Preconditioner accelerates convergence and ML methods become approximations of the second order solvers
eng. momentum = 0; % add momentum acceleration term to the MLc method, useful if the probe guess is very poor or for acceleration of multilayer solver, but it is quite computationally expensive to be used in conventional ptycho without any refinement.
% The momentum method works usually well even with the accelerated_gradients option. eng.momentum = multiplication gain for velocity, eng.momentum == 0 -> no acceleration, eng.momentum == 0.5 is a good value
% momentum is enabled only when par.Niter < par.accelerated_gradients_start;
eng. accelerated_gradients_start = inf; % iteration number from which the Nesterov gradient acceleration should be applied, this option is supported only for MLc method. It is very computationally cheap way of convergence acceleration.
% DM
eng. pfft_relaxation = 0.05; % Relaxation in the Fourier domain projection, = 0 for full projection
eng. probe_regularization = 0.1; % Weight factor for the probe update (inertia)
% ADVANCED OPTIONS See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
% position refinement
eng. apply_subpix_shift = true; % apply FFT-based subpixel shift, it is automatically allowed for position refinement
if isfield(par, 'probe_position_search')
eng.probe_position_search = par.probe_position_search;
else
eng. probe_position_search = 50; % iteration number from which the engine will reconstruct probe positions, from iteration == probe_position_search, assume they have to match geometry model with error less than probe_position_error_max
end
eng. probe_geometry_model = {'scale', 'asymmetry', 'rotation', 'shear'}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
%eng. probe_geometry_model = {}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_position_error_max = inf; % maximal expected random position errors, probe prositions are confined in a circle with radius defined by probe_position_error_max and with center defined by original positions scaled by probe_geometry_model
eng. apply_relaxed_position_constraint = false; % added by YJ. Apply a relaxed constraint to probe positions. default = true. Set to false if there are big jumps in positions.
eng. update_pos_weight_every = inf; % added by YJ. Allow position weight to be updated multiple times. default = inf: only update once.
% multilayer extension
eng. delta_z = delta_z*ones(Nlayers,1); % if not empty, use multilayer ptycho extension , see ML_MS code for example of use, [] == common single layer ptychography , note that delta_z provides only relative propagation distance from the previous layer, ie delta_z can be either positive or negative. If preshift_ML_probe == false, the first layer is defined by position of initial probe plane. It is useful to use eng.momentum for convergence acceleration
if isfield(par, 'regularize_layers')
eng.regularize_layers = par.regularize_layers;
else
eng. regularize_layers = 1; % multilayer extension: 0<R<<1 -> apply regularization on the reconstructed object layers, 0 == no regularization, 0.01 == weak regularization that will slowly symmetrize information content between layers
end
eng. preshift_ML_probe = false; % multilayer extension: if true, assume that the provided probe is reconstructed in center of the sample and the layers are centered around this position
eng. layer4pos = []; % Added by ZC. speficy which layer is used for position correction ; if empty, then default, ceil(Nlayers/2)
eng. init_layer_select = []; % Added by YJ. Select layers in the initial object for pre-processing. If empty (default): use all layers.
eng. init_layer_preprocess = ''; % Added by YJ. Specify how to pre-process initial layers
% '' or 'all' (default): use all layers (do nothing)
% 'avg': average all layers
% 'interp': interpolate layers using spline method. Need to specify desired depths in init_layer_interp
eng. init_layer_interp = []; % Specify desired depths for interpolation. The depths of initial are [1:Nlayer_init]. If empty (default), no interpolation
if isfield(par, 'init_layer_append_mode')
eng.init_layer_append_mode = par.init_layer_append_mode;
else
eng. init_layer_append_mode = 'vac';
end
% Added by YJ. Specify how to initialize extra layers
% '' or 'vac' (default): add vacuum layers
% 'edge': append 1st or last layers
% 'avg': append averaged layer
eng. init_layer_scaling_factor = 1; % Added by YJ. Scale all layers. Default: 1 (no scaling). Useful when delta_z is changed
% other extensions
eng. background = 0; % average background scattering level, for OMNI values around 0.3 for 100ms, for flOMNI <0.1 per 100ms exposure, see for more details: Odstrcil, M., et al., Optics letters 40.23 (2015): 5574-5577.
eng. background_width = inf; % width of the background function in pixels, inf == flat background, background function is then convolved with the average diffraction pattern in order to account for beam diversion
eng. clean_residua = false; % remove phase residua from reconstruction by iterative unwrapping, it will result in low spatial freq. artefacts -> object can be used as an residua-free initial guess for netx engine
% wavefront & camera geometry refinement See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. probe_fourier_shift_search = inf; % iteration number from which the engine will: refine farfield position of the beam (ie angle) from iteration == probe_fourier_shift_search
eng. estimate_NF_distance = inf; % iteration number from which the engine will: try to estimate the nearfield propagation distance using gradient descent optimization
eng. detector_rotation_search = inf; % iteration number from which the engine will: search for optimal detector rotation, preferably use with option mirror_scan = true , rotation of the detector axis with respect to the sample axis, similar as rotation option in the position refinement geometry model but works also for 0/180deg rotation shared scans
eng. detector_scale_search = inf; % iteration number from which the engine will: refine pixel scale of the detector, can be used to refine propagation distance in ptycho
if isfield(par, 'variable_probe') && strcmp(par.variable_probe,'false')
eng.variable_probe = false;
else
eng.variable_probe = true;
end
% eng. variable_probe = true; % Use SVD to account for variable illumination during a single (coupled) scan, see for more details: Odstrcil, M. et al. Optics express 24.8 (2016): 8360-8369.
eng. variable_probe_modes = 1; % OPRP settings , number of SVD modes using to describe the probe evolution.
eng. variable_probe_smooth = 0; % OPRP settings , enforce of smooth evolution of the OPRP modes -> N is order of polynomial fit used for smoothing, 0 == do not apply any smoothing. Smoothing is useful if only a smooth drift is assumed during the ptycho acquisition
eng. variable_intensity = false; % account to changes in probe intensity
% extra analysis
eng. get_fsc_score = false; % measure evolution of the Fourier ring correlation during convergence
eng. mirror_objects = false; % mirror objects, useful for 0/180deg scan sharing -> geometry refinement for tomography, works only if 2 scans are provided
% custom data adjustments, useful for offaxis ptychography
eng.auto_center_data = false; % autoestimate the center of mass from data and shift the diffraction patterns so that the average center of mass corresponds to center of mass of the provided probe
eng.auto_center_probe = false; % center the probe position in real space before reconstruction is started
eng.custom_data_flip = [0,0,0]; % apply custom flip of the data [fliplr, flipud, transpose] - can be used for quick testing of reconstruction with various flips or for reflection ptychography
eng.apply_tilted_plane_correction = ''; % if any(p.sample_rotation_angles([1,2]) ~= 0), this option will apply tilted plane correction. (a) 'diffraction' apply correction into the data, note that it is valid only for "low NA" illumination Gardner, D. et al., Optics express 20.17 (2012): 19050-19059. (b) 'propagation' - use tilted plane propagation, (c) '' - will not apply any correction
% I/O
eng.plot_results_every = Niter_plot_results;
eng.save_results_every = Niter_save_results;
eng.save_images ={'obj_ph_stack','obj_ph_sum','probe'};
eng.extraPrintInfo = par.extra_print_info;
resultDir = strcat(p.base_path,sprintf(p.scan.format, p.scan_number),'/roi',p.scan.roi_label,'/');
[eng.fout, p.suffix] = generateResultDir(eng, resultDir);
%add engine
[p, ~] = core.append_engine(p, eng); % Adds this engine to the reconstruction process
%% Run the reconstruction
tic
out = core.ptycho_recons(p);
toc
end
+385
View File
@@ -0,0 +1,385 @@
function run_multislice_new(parfile)
par = parameter_builder(parfile);
addpath(strcat(pwd,'/utils/'))
addpath(core.find_base_package)
%%%%%%%%%%%%%%%%%%%% data parameters %%%%%%%%%%%%%%%%%%%%
base_path = par.result_dir;
roi_label = par.roi_label;
scan_number = par.scan_number;
scan_string_format = '%01d';
Ndpx = par.CBED_size; % size of cbed
alpha0 = par.alpha_max; % semi-convergence angle (mrad)
rbf = par.rbf; % radius of the BF disk in cbed. Can be used to calculate dk
voltage = par.voltage;
rot_ang = par.rot_ang; %angle between cbed and scan coord.
scan_step_size = par.scan_step_size; %angstrom
N_scan_y = par.N_scan_y; %number of scan points
N_scan_x = par.N_scan_x;
%%%%%%%%%%%%%%%%%%%% reconstruction parameters %%%%%%%%%%%%%%%%%%%%
gpu_id = 1;
Niter = par.Niter;
Niter_save_results = par.Niter_save_results;
Niter_plot_results = inf;
Nprobe = par.Nprobe; % # of probe modes
thickness = par.thickness; % sample thickness in angstrom
Nlayers = round(par.Nlayers); % # of slices for multi-slice, 1 for single-slice
delta_z = thickness / Nlayers;
%% %%%%%%%%%%%%%%%%%% initialize data parameters %%%%%%%%%%%%%%%%%%%%
p = struct();
p. verbose_level = 2; % verbosity for standard output (0-1 for loops, 2-3 for testing and adjustments, >= 4 for debugging)
p. use_display = false; % global switch for display, if [] then true for verbose > 1
p. scan_number = scan_number; % Multiple scan numbers for shared scans
% Geometry
p. z = 1; % Distance from object to detector. Always 1 for electron ptycho
p. asize = [Ndpx,Ndpx]; % Diffr. patt. array size
p. ctr = [fix(Ndpx/2)+1, fix(Ndpx/2)+1]; % Diffr. patt. center coordinates (y,x) (empty means middle of the array); e.g. [100 207;100+20 207+10];
p. beam_source = 'electron'; % Added by YJ for electron pty. Use relativistic corrected formula for wavelength. Also change the units on figures
%p. dk = dk; % Added by YJ. dk is the pixel size in cbed (1/A). This is used to determine pixel size in electron ptycho
p. d_alpha = alpha0/rbf; % Added by YJ. d_alpha is the pixel size in cbed (mrad). This is used to determine pixel size in electron ptycho
p. prop_regime = 'farfield'; % propagation regime: nearfield, farfield (default), !! nearfield is supported only by GPU engines
p. focus_to_sample_distance = []; % sample to focus distance, parameter to be set for nearfield ptychography, otherwise it is ignored
p. energy = voltage; % Energy (in keV), leave empty to use spec entry mokev
%p. affine_angle = 0; % Not used by ptycho_recons at all. This allows you to define a variable for the affine matrix below and keep it in p for future record. This is used later by the affine_matrix_search.m script
%p. affine_matrix = [1 , 0; 0, 1] ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
affine_mat = compose_affine_matrix(1, 0, rot_ang, 0);
p. affine_matrix = affine_mat ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
% Scan meta data
p. src_metadata = 'none'; % source of the meta data, following options are supported: 'spec', 'none' , 'artificial' - or add new to +scan/+meta/
p. queue.lockfile = false; % If true writes a lock file, if lock file exists skips recontruction
% Data preparation
p. detector.name = 'empad'; % see +detectors/ folder
p. detector.check_2_detpos = []; % = []; (ignores) = 270; compares to dettrx to see if p.ctr should be reversed (for OMNY shared scans 1221122), make equal to the middle point of dettrx between the 2 detector positions
p. detector.data_prefix = ''; % Default using current eaccount e.g. e14169_1_
p. detector.binning = false; % = true to perform 2x2 binning of detector pixels, for binning = N do 2^Nx2^N binning
p. detector.upsampling = false; % upsample the measured data by 2^data_upsampling, (transposed operator to the binning), it can be used for superresolution in nearfield ptychography or to account for undersampling in a far-field dataset
p. detector.burst_frames = 1; % number of frames collected per scan position
p. prepare.data_preparator = 'matlab_aps'; % data preparator; 'python' or 'matlab' or 'matlab_aps'
p. prepare.auto_prepare_data = true; % if true: prepare dataset from raw measurements if the prepared data does not exist
p. prepare.force_preparation_data = true; % Prepare dataset even if it exists, it will overwrite the file % Default: @prepare_data_2d
p. prepare.store_prepared_data = false; % store the loaded data to h5 even for non-external engines (i.e. other than c_solver)
p. prepare.prepare_data_function = ''; % (used only if data should be prepared) custom data preparation function handle;
p. prepare.auto_center_data = false; % if matlab data preparator is used, try to automatically center the diffraction pattern to keep center of mass in center of diffraction
% Scan positions
p. src_positions = 'matlab_pos'; % 'spec', 'orchestra', 'load_from_file', 'matlab_pos' (scan params are defined below) or add new position loaders to +scan/+positions/
p. positions_file = ''; %Filename pattern for position files, Example: ['../../specES1/scan_positions/scan_%05d.dat']; (the scan number will be automatically filled in)
% scan parameters for option src_positions = 'matlab_pos';
p. scan.type = 'raster'; % {'round', 'raster', 'round_roi', 'custom'}
p. scan.roi_label = roi_label; % For APS data
p. scan.format = scan_string_format; % For APS data format for scan directory generation
p. scan.radius_in = 0; % round scan: interior radius of the round scan
p. scan.radius_out = 5e-6; % round scan: exterior radius of the round scan
p. scan.nr = 10; % round scan: number of intervals (# of shells - 1)
p. scan.nth = 3; % round scan: number of points in the first shell
p. scan.lx = 20e-6; % round_roi scan: width of the roi
p. scan.ly = 20e-6; % round_roi scan: height of the roi
p. scan.dr = 1.5e-6; % round_roi scan: shell step size
p. scan.nx = N_scan_x; %size(dp,3) % raster scan: number of steps in x
p. scan.ny = N_scan_y; % raster scan: number of steps in y
p. scan.step_size_x = scan_step_size; % raster scan: step size (grid spacing)
p. scan.step_size_y = scan_step_size; % raster scan: step size (grid spacing)
p. scan.custom_flip = [1,1,1]; % raster scan: apply custom flip [fliplr, flipud, transpose] to positions- similar to eng.custom_data_flip in GPU engines. Added by ZC.
p. scan.step_randn_offset = 0; % raster scan: relative random offset from the ideal periodic grid to avoid the raster grid pathology
p. scan.b = 0; % fermat: angular offset
p. scan.n_max = 1e4; % fermat: maximal number of points generated
p. scan.step = 0.5e-6; % fermat: step size
p. scan.cenxy = [0,0]; % fermat: position of center offset
p. scan.roi = []; % Region of interest in the object [xmin xmax ymin ymax] in meters. Points outside this region are not used for reconstruction.
% (relative to upper corner for raster scans and to center for round scans)
% custom: a string name of a function that defines the positions; also accepts mat file with entry 'pos', see +scans/+positions/+mat_pos.m
p. scan.custom_positions_source = '';
p. scan.custom_params = []; % custom: the parameters to feed to the custom position function.
% I/O
p. prefix = ''; % For automatic output filenames. If empty: scan number
p. suffix = strcat('ML_recon'); % Optional suffix for reconstruction
p. scan_string_format = scan_string_format; % format for scan string generation, it is used e.g for plotting and data saving
%%%p. base_path = '../../'; % base path : used for automatic generation of other paths
p. base_path = base_path; % base path : used for automatic generation of other paths
p. specfile = ''; % Name of spec file to get motor positions and check end of scan, defaut is p.spec_file == p.base_path;
p. ptycho_matlab_path = ''; % cSAXS ptycho package path
p. cSAXS_matlab_path = ''; % cSAXS base package path
p. raw_data_path{1} = ''; % Default using compile_x12sa_filename, used only if data should be prepared automatically
p. prepare_data_path = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. prepare_data_filename = []; % Leave empty for default file name generation, otherwise use [sprintf('S%05d_data_%03dx%03d',p.scan_number(1), p.asize(1), p.asize(2)) p.prep_data_suffix '.h5'] as default
p. save_path{1} = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. io.default_mask_file = ''; % load detector mask defined in this file instead of the mask in the detector packages, (used only if data should be prepared)
p. io.default_mask_type = 'binary'; % (used only if data should be prepared) ['binary', 'indices']. Default: 'binary'
p. io.file_compression = 0; % reconstruction file compression for HDF5 files; 0 for no compression
p. io.data_compression = 3; % prepared data file compression for HDF5 files; 0 for no compression
p. io.load_prep_pos = false; % load positions from prepared data file and ignore positions provided by metadata
p. io.data_descriptor = par.extra_print_info; %added by YJ. A short string that describe data when sending notifications
p. io.phone_number = ''; % phone number for sending messages
p. io.send_failed_scans_SMS = false; % send message if p.queue_max_attempts is exceeded
p. io.send_finished_recon_SMS = false; % send message after the reconstruction is completed
p. io.send_crashed_recon_SMS = false; % send message if the reconstruction crashes
p. io.SMS_sleep = 1800; % max 1 message per SMS_sleep seconds
p. io.script_name = mfilename; % added by YJ. store matlab script name
p. artificial_data_file = 'template_artificial_data'; % artificial data parameters, set p.src_metadata = 'artificial' to use this template
%% Reconstruction
% Initial iterate object, load from previous results if
% load_results_path is in the parameter file. Use random object and
% ideal probe otherwise.
if isfield(par, 'load_object_path')
p.model_object = false;
p.initial_iterate_object_file{1} = par.load_object_path;
if isfield(par, 'load_probe_path')
p.initial_probe_file = par.load_probe_path;
else
p.initial_probe_file = par.load_object_path;
end
p.multiple_layers_obj = true;
else
initial_probe_file = fullfile(par.result_dir, num2str(scan_number), '/init_probe.mat');
p.model_object = true;
p.model.object_type = 'rand';
p.initial_probe_file = initial_probe_file;
end
%%line to have only probe loaded instead of both probe and object
if isfield(par, 'load_probe_path')
p.initial_probe_file = par.load_probe_path;
else
initial_probe_file = fullfile(par.result_dir, num2str(scan_number), '/init_probe.mat');
p.initial_probe_file = initial_probe_file;
end
% Initial iterate probe
p. model_probe = false; % Use model probe, if false load it from file
p. model.probe_alpha_max = par.alpha_max; % Modal STEM probe's aperture size
p. model.probe_df = par.defocus; % Modal STEM probe's defocus
p. model.probe_c3 = 0; % Modal STEM probe's third-order spherical aberration in angstrom (optional)
p. model.probe_c5 = 0; % Modal STEM probe's fifth-order spherical aberration in angstrom (optional)
p. model.probe_c7 = 0; % Modal STEM probe's seventh-order spherical aberration in angstrom (optional)
p. model.probe_f_a2 = 0; % Modal STEM probe's twofold astigmatism in angstrom (optional)
p. model.probe_theta_a2 = 0; % Modal STEM probe's twofold azimuthal orientation in radian (optional)
p. model.probe_f_a3 = 0; % Modal STEM probe's threefold astigmatism in angstrom (optional)
p. model.probe_theta_a3 = 0; % Modal STEM probe's threefold azimuthal orientation in radian (optional)
p. model.probe_f_c3 = 0; % Modal STEM probe's coma in angstrom (optional)
p. model.probe_theta_c3 = 0; % Modal STEM probe's coma azimuthal orientation in radian (optional)
%Use probe from this mat-file (not used if model_probe is true)
p. probe_file_propagation = 0.0e-3; % Distance for propagating the probe from file in meters, = 0 to ignore
p. normalize_init_probe = true; % Added by YJ. Can be used to disable normalization of initial probes
% Shared scans - Currently working only for sharing probe and object
p. share_probe = 0; % Share probe between scans. Can be either a number/boolean or a list of numbers, specifying the probe index; e.g. [1 2 2] to share the probes between the second and third scan.
p. share_object = 0; % Share object between scans. Can be either a number/boolean or a list of numbers, specifying the object index; e.g. [1 2 2] to share the objects between the second and third scan.
% Modes
p. probe_modes = Nprobe; % Number of coherent modes for probe
p. object_modes = 1; % Number of coherent modes for object
% Mode starting guess
p. mode_start_pow = 0.02; % Normalized intensity on probe modes > 1. Can be a number (all higher modes equal) or a vector
p. mode_start = 'herm'; % (for probe) = 'rand', = 'herm' (Hermitian-like base), = 'hermver' (vertical modes only), = 'hermhor' (horizontal modes only)
p. ortho_probes = true; % orthogonalize probes after each engine
%% Plot, save and analyze
p. plot.prepared_data = false; % plot prepared data
p. plot.interval = []; % plot each interval-th iteration, does not work for c_solver code
p. plot.log_scale = [0 0]; % Plot on log scale for x and y
p. plot.realaxes = true; % Plots show scale in microns
p. plot.remove_phase_ramp = false; % Remove phase ramp from the plotted / saved phase figures
p. plot.fov_box = false; % Plot the scanning FOV box on the object (both phase and amplitude)
p. plot.fov_box_color = 'r'; % Color of the scanning FOV box
p. plot.positions = true; % Plot the scanning positions
p. plot.mask_bool = true; % Mask the noisy contour of the reconstructed object in plots
p. plot.windowautopos = true; % First plotting will auto position windows
p. plot.obj_apod = false; % Apply apodization to the reconstructed object;
p. plot.prop_obj = 0; % Distance to propagate reconstructed object before plotting [m]
p. plot.show_layers = true; % show each layer in multilayer reconstruction
p. plot.show_layers_stack = false; % show each layer in multilayer reconstruction by imagesc3D
p. plot.object_spectrum = []; % Plot propagated object (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.probe_spectrum = []; % Plot propagated probe (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.conjugate = false; % plot complex conjugate of the reconstruction
p. plot.horz_fact = 2.5; % Scales the space that the ptycho figures take horizontally
p. plot.FP_maskdim = 180e-6; % Filter the backpropagation (Fourier Ptychography)
p. plot.calc_FSC = false; % Calculate the Fourier Shell correlation for 2 scans or compare with model in case of artificial data tests
p. plot.show_FSC = false; % Show the FSC plots, including the cropped FOV
p. plot.residua = false; % highlight phase-residua in the image of the reconstructed phase
p. save.external = true; % Use a new Matlab session to run save final figures (saves ~6s per reconstruction). Please be aware that this might lead to an accumulation of Matlab sessions if your single reconstruction is very fast.
p. save.store_images = false; % Write preview images containing the final reconstructions in [p.base_path,'analysis/online/ptycho/'] if p.use_display = 0 then the figures are opened invisible in order to create the nice layout. It writes images in analysis/online/ptycho
p. save.store_images_intermediate = false; % save images to disk after each engine
p. save.store_images_ids = 1:4; % identifiers of the figure to be stored, 1=obj. amplitude, 2=obj. phase, 3=probes, 4=errors, 5=probes spectrum, 6=object spectrum
p. save.store_images_format = 'png'; % data type of the stored images jpg or png
p. save.store_images_dpi = 150; % DPI of the stored bitmap images
p. save.exclude = {'fmag', 'fmask', 'illum_sum'}; % exclude variables to reduce the file size on disk
p. save.save_reconstructions_intermediate = false; % save final object and probes after each engine
p. save.save_reconstructions = false; % save reconstructed object and probe when full reconstruction is finished
p. save.output_file = 'h5'; % data type of reconstruction file; 'h5' or 'mat'
if isfield(par, 'diff_pattern_blur')
p. diff_pattern_blur = par.diff_pattern_blur;
end
%% %%%%%%%%%%%%%%%%%% initialize reconstruction parameters %%%%%%%%%%%%%%%%%%%%
% --------- GPU engines ------------- See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng = struct(); % reset settings for this engine
eng. name = 'GPU_MS';
eng. use_gpu = true; % if false, run CPU code, but it will get very slow
eng. keep_on_gpu = true; % keep data + projections on GPU, false is useful for large data if DM is used
eng. compress_data = false; % use automatic online memory compression to limit need of GPU memory
eng. gpu_id = gpu_id; % default GPU id, [] means choosen by matlab
eng. check_gpu_load = true; % check available GPU memory before starting GPU engines
% general
eng. number_iterations = Niter; % number of iterations for selected method
if isfield(par, 'CBED_crop')
eng.asize_presolve = [par.CBED_crop, par.CBED_crop];
else
eng. asize_presolve = [par.CBED_size, par.CBED_size]; % crop data to "asize_presolve" size to get low resolution estimate that can be used in the next engine as a good initial guess
end
eng. align_shared_objects = false; % before merging multiple unshared objects into one shared, the object will be aligned and the probes shifted by the same distance -> use for alignement and shared reconstruction of drifting scans
eng. method = 'MLs'; % choose GPU solver: DM, ePIE, hPIE, MLc, Mls, -- recommended are MLc and MLs
eng. opt_errmetric = 'L1'; % optimization likelihood - poisson, L1
if isfield(par, 'grouping')
eng.grouping = par.grouping;
else
eng.grouping = 64;
end % size of processed blocks, larger blocks need more memory but they use GPU more effeciently, !!! grouping == inf means use as large as possible to fit into memory
% * for hPIE, ePIE, MLs methods smaller blocks lead to faster convergence,
% * for MLc the convergence is similar
% * for DM is has no effect on convergence
eng. probe_modes = p.probe_modes; % Number of coherent modes for probe
if isfield(par, 'object_change_start')
eng. object_change_start = par.object_change_start;
else
eng. object_change_start = 1; % Start updating object at this iteration number
end
if isfield(par, 'probe_change_start')
eng.probe_change_start = par.probe_change_start;
else
eng. probe_change_start = 1; % Start updating probe at this iteration number
end
% regularizations
if isfield(par, 'reg_mu')
eng.reg_mu = par.reg_mu; % Regularization (smooting) constant ( reg_mu = 0 for no regularization)
else
eng.reg_mu = 0;
end
eng. delta = 0; % press values to zero out of the illumination area in th object, usually 1e-2 is enough
eng. positivity_constraint_object = 0; % enforce weak (relaxed) positivity in object, ie O = O*(1-a)+a*|O|, usually a=1e-2 is already enough. Useful in conbination with OPRP or probe_fourier_shift_search
eng. apply_multimodal_update = false; % apply all incoherent modes to object, it can cause isses if the modes collect some crap
eng. probe_backpropagate = 0; % backpropagation distance the probe mask, 0 == apply in the object plane. Useful for pinhole imaging where the support can be applied at the pinhole plane
eng. probe_support_radius = []; % Normalized radius of circular support, = 1 for radius touching the window
eng. probe_support_fft = false; % assume that there is not illumination intensity out of the central FZP cone and enforce this contraint. Useful for imaging with focusing optics. Helps to remove issues from the gaps between detector modules.
% basic recontruction parameters
% PIE / ML methods % See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. beta_object = 1; % object step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. beta_probe = 1; % probe step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. delta_p = 0.1; % LSQ dumping constant, 0 == no preconditioner, 0.1 is usually safe, Preconditioner accelerates convergence and ML methods become approximations of the second order solvers
eng. momentum = 0; % add momentum acceleration term to the MLc method, useful if the probe guess is very poor or for acceleration of multilayer solver, but it is quite computationally expensive to be used in conventional ptycho without any refinement.
% The momentum method works usually well even with the accelerated_gradients option. eng.momentum = multiplication gain for velocity, eng.momentum == 0 -> no acceleration, eng.momentum == 0.5 is a good value
% momentum is enabled only when par.Niter < par.accelerated_gradients_start;
eng. accelerated_gradients_start = inf; % iteration number from which the Nesterov gradient acceleration should be applied, this option is supported only for MLc method. It is very computationally cheap way of convergence acceleration.
% DM
eng. pfft_relaxation = 0.05; % Relaxation in the Fourier domain projection, = 0 for full projection
eng. probe_regularization = 0.1; % Weight factor for the probe update (inertia)
% ADVANCED OPTIONS See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
% position refinement
eng. apply_subpix_shift = true; % apply FFT-based subpixel shift, it is automatically allowed for position refinement
if isfield(par, 'probe_position_search')
eng.probe_position_search = par.probe_position_search;
else
eng. probe_position_search = 50; % iteration number from which the engine will reconstruct probe positions, from iteration == probe_position_search, assume they have to match geometry model with error less than probe_position_error_max
end
%eng. probe_geometry_model = {'scale', 'asymmetry', 'rotation', 'shear'}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_geometry_model = {}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_position_error_max = inf; % maximal expected random position errors, probe prositions are confined in a circle with radius defined by probe_position_error_max and with center defined by original positions scaled by probe_geometry_model
eng. apply_relaxed_position_constraint = false; % added by YJ. Apply a relaxed constraint to probe positions. default = true. Set to false if there are big jumps in positions.
eng. update_pos_weight_every = inf; % added by YJ. Allow position weight to be updated multiple times. default = inf: only update once.
% multilayer extension
eng. delta_z = delta_z*ones(Nlayers,1); % if not empty, use multilayer ptycho extension , see ML_MS code for example of use, [] == common single layer ptychography , note that delta_z provides only relative propagation distance from the previous layer, ie delta_z can be either positive or negative. If preshift_ML_probe == false, the first layer is defined by position of initial probe plane. It is useful to use eng.momentum for convergence acceleration
if isfield(par, 'regularize_layers')
eng.regularize_layers = par.regularize_layers;
else
eng. regularize_layers = 1; % multilayer extension: 0<R<<1 -> apply regularization on the reconstructed object layers, 0 == no regularization, 0.01 == weak regularization that will slowly symmetrize information content between layers
end
eng. preshift_ML_probe = false; % multilayer extension: if true, assume that the provided probe is reconstructed in center of the sample and the layers are centered around this position
eng. layer4pos = []; % Added by ZC. speficy which layer is used for position correction ; if empty, then default, ceil(Nlayers/2)
eng. init_layer_select = []; % Added by YJ. Select layers in the initial object for pre-processing. If empty (default): use all layers.
eng. init_layer_preprocess = ''; % Added by YJ. Specify how to pre-process initial layers
% '' or 'all' (default): use all layers (do nothing)
% 'avg': average all layers
% 'interp': interpolate layers using spline method. Need to specify desired depths in init_layer_interp
eng. init_layer_interp = []; % Specify desired depths for interpolation. The depths of initial are [1:Nlayer_init]. If empty (default), no interpolation
if isfield(par, 'init_layer_append_mode')
eng.init_layer_append_mode = par.init_layer_append_mode;
else
eng. init_layer_append_mode = 'vac';
end
% Added by YJ. Specify how to initialize extra layers
% '' or 'vac' (default): add vacuum layers
% 'edge': append 1st or last layers
% 'avg': append averaged layer
eng. init_layer_scaling_factor = 1; % Added by YJ. Scale all layers. Default: 1 (no scaling). Useful when delta_z is changed
% other extensions
eng. background = 0; % average background scattering level, for OMNI values around 0.3 for 100ms, for flOMNI <0.1 per 100ms exposure, see for more details: Odstrcil, M., et al., Optics letters 40.23 (2015): 5574-5577.
eng. background_width = inf; % width of the background function in pixels, inf == flat background, background function is then convolved with the average diffraction pattern in order to account for beam diversion
eng. clean_residua = false; % remove phase residua from reconstruction by iterative unwrapping, it will result in low spatial freq. artefacts -> object can be used as an residua-free initial guess for netx engine
% wavefront & camera geometry refinement See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. probe_fourier_shift_search = inf; % iteration number from which the engine will: refine farfield position of the beam (ie angle) from iteration == probe_fourier_shift_search
eng. estimate_NF_distance = inf; % iteration number from which the engine will: try to estimate the nearfield propagation distance using gradient descent optimization
eng. detector_rotation_search = inf; % iteration number from which the engine will: search for optimal detector rotation, preferably use with option mirror_scan = true , rotation of the detector axis with respect to the sample axis, similar as rotation option in the position refinement geometry model but works also for 0/180deg rotation shared scans
eng. detector_scale_search = inf; % iteration number from which the engine will: refine pixel scale of the detector, can be used to refine propagation distance in ptycho
if isfield(par, 'variable_probe') && strcmp(par.variable_probe,'false')
eng.variable_probe = false;
else
eng.variable_probe = true;
end
% eng. variable_probe = true; % Use SVD to account for variable illumination during a single (coupled) scan, see for more details: Odstrcil, M. et al. Optics express 24.8 (2016): 8360-8369.
eng. variable_probe_modes = 1; % OPRP settings , number of SVD modes using to describe the probe evolution.
eng. variable_probe_smooth = 0; % OPRP settings , enforce of smooth evolution of the OPRP modes -> N is order of polynomial fit used for smoothing, 0 == do not apply any smoothing. Smoothing is useful if only a smooth drift is assumed during the ptycho acquisition
eng. variable_intensity = false; % account to changes in probe intensity
% extra analysis
eng. get_fsc_score = false; % measure evolution of the Fourier ring correlation during convergence
eng. mirror_objects = false; % mirror objects, useful for 0/180deg scan sharing -> geometry refinement for tomography, works only if 2 scans are provided
% custom data adjustments, useful for offaxis ptychography
eng.auto_center_data = false; % autoestimate the center of mass from data and shift the diffraction patterns so that the average center of mass corresponds to center of mass of the provided probe
eng.auto_center_probe = false; % center the probe position in real space before reconstruction is started
eng.custom_data_flip = [0,0,0]; % apply custom flip of the data [fliplr, flipud, transpose] - can be used for quick testing of reconstruction with various flips or for reflection ptychography
eng.apply_tilted_plane_correction = ''; % if any(p.sample_rotation_angles([1,2]) ~= 0), this option will apply tilted plane correction. (a) 'diffraction' apply correction into the data, note that it is valid only for "low NA" illumination Gardner, D. et al., Optics express 20.17 (2012): 19050-19059. (b) 'propagation' - use tilted plane propagation, (c) '' - will not apply any correction
% I/O
eng.plot_results_every = Niter_plot_results;
eng.save_results_every = Niter_save_results;
eng.save_images ={'obj_ph_stack','obj_ph_sum','probe'};
eng.extraPrintInfo = par.extra_print_info;
resultDir = strcat(p.base_path,sprintf(p.scan.format, p.scan_number),'/roi',p.scan.roi_label,'/');
[eng.fout, p.suffix] = generateResultDir(eng, resultDir);
%add engine
[p, ~] = core.append_engine(p, eng); % Adds this engine to the reconstruction process
%% Run the reconstruction
tic
out = core.ptycho_recons(p);
toc
end
+390
View File
@@ -0,0 +1,390 @@
function run_multislice_new_bio(parfile)
par = parameter_builder(parfile);
addpath(strcat(pwd,'/utils/'))
addpath(core.find_base_package)
%%%%%%%%%%%%%%%%%%%% data parameters %%%%%%%%%%%%%%%%%%%%
base_path = par.result_dir;
roi_label = par.roi_label;
scan_number = par.scan_number;
scan_string_format = '%01d';
Ndpx = par.CBED_size; % size of cbed
alpha0 = par.alpha_max; % semi-convergence angle (mrad)
rbf = par.rbf; % radius of the BF disk in cbed. Can be used to calculate dk
voltage = par.voltage;
rot_ang = par.rot_ang; %angle between cbed and scan coord.
scan_step_size = par.scan_step_size; %angstrom
N_scan_y = par.N_scan_y; %number of scan points
N_scan_x = par.N_scan_x;
%%%%%%%%%%%%%%%%%%%% reconstruction parameters %%%%%%%%%%%%%%%%%%%%
gpu_id = 1;
Niter = par.Niter;
Niter_save_results = par.Niter_save_results;
Niter_plot_results = inf;
Nprobe = par.Nprobe; % # of probe modes
thickness = par.thickness; % sample thickness in angstrom
Nlayers = round(par.Nlayers); % # of slices for multi-slice, 1 for single-slice
delta_z = thickness / Nlayers;
%% %%%%%%%%%%%%%%%%%% initialize data parameters %%%%%%%%%%%%%%%%%%%%
p = struct();
p. verbose_level = 2; % verbosity for standard output (0-1 for loops, 2-3 for testing and adjustments, >= 4 for debugging)
p. use_display = false; % global switch for display, if [] then true for verbose > 1
p. scan_number = scan_number; % Multiple scan numbers for shared scans
% Geometry
p. z = 1; % Distance from object to detector. Always 1 for electron ptycho
p. asize = [Ndpx,Ndpx]; % Diffr. patt. array size
p. ctr = [fix(Ndpx/2)+1, fix(Ndpx/2)+1]; % Diffr. patt. center coordinates (y,x) (empty means middle of the array); e.g. [100 207;100+20 207+10];
p. beam_source = 'electron'; % Added by YJ for electron pty. Use relativistic corrected formula for wavelength. Also change the units on figures
%p. dk = dk; % Added by YJ. dk is the pixel size in cbed (1/A). This is used to determine pixel size in electron ptycho
p. d_alpha = alpha0/rbf; % Added by YJ. d_alpha is the pixel size in cbed (mrad). This is used to determine pixel size in electron ptycho
p. prop_regime = 'farfield'; % propagation regime: nearfield, farfield (default), !! nearfield is supported only by GPU engines
p. focus_to_sample_distance = []; % sample to focus distance, parameter to be set for nearfield ptychography, otherwise it is ignored
p. energy = voltage; % Energy (in keV), leave empty to use spec entry mokev
%p. affine_angle = 0; % Not used by ptycho_recons at all. This allows you to define a variable for the affine matrix below and keep it in p for future record. This is used later by the affine_matrix_search.m script
%p. affine_matrix = [1 , 0; 0, 1] ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
affine_mat = compose_affine_matrix(1, 0, rot_ang, 0);
p. affine_matrix = affine_mat ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
% Scan meta data
p. src_metadata = 'none'; % source of the meta data, following options are supported: 'spec', 'none' , 'artificial' - or add new to +scan/+meta/
p. queue.lockfile = false; % If true writes a lock file, if lock file exists skips recontruction
% Data preparation
p. detector.name = 'empad'; % see +detectors/ folder
p. detector.check_2_detpos = []; % = []; (ignores) = 270; compares to dettrx to see if p.ctr should be reversed (for OMNY shared scans 1221122), make equal to the middle point of dettrx between the 2 detector positions
p. detector.data_prefix = ''; % Default using current eaccount e.g. e14169_1_
p. detector.binning = false; % = true to perform 2x2 binning of detector pixels, for binning = N do 2^Nx2^N binning
p. detector.upsampling = false; % upsample the measured data by 2^data_upsampling, (transposed operator to the binning), it can be used for superresolution in nearfield ptychography or to account for undersampling in a far-field dataset
p. detector.burst_frames = 1; % number of frames collected per scan position
p. prepare.data_preparator = 'matlab_aps'; % data preparator; 'python' or 'matlab' or 'matlab_aps'
p. prepare.auto_prepare_data = true; % if true: prepare dataset from raw measurements if the prepared data does not exist
p. prepare.force_preparation_data = true; % Prepare dataset even if it exists, it will overwrite the file % Default: @prepare_data_2d
p. prepare.store_prepared_data = false; % store the loaded data to h5 even for non-external engines (i.e. other than c_solver)
p. prepare.prepare_data_function = ''; % (used only if data should be prepared) custom data preparation function handle;
p. prepare.auto_center_data = false; % if matlab data preparator is used, try to automatically center the diffraction pattern to keep center of mass in center of diffraction
% Scan positions
p. src_positions = 'matlab_pos'; % 'spec', 'orchestra', 'load_from_file', 'matlab_pos' (scan params are defined below) or add new position loaders to +scan/+positions/
p. positions_file = ''; %Filename pattern for position files, Example: ['../../specES1/scan_positions/scan_%05d.dat']; (the scan number will be automatically filled in)
% scan parameters for option src_positions = 'matlab_pos';
p. scan.type = 'raster'; % {'round', 'raster', 'round_roi', 'custom'}
p. scan.roi_label = roi_label; % For APS data
p. scan.format = scan_string_format; % For APS data format for scan directory generation
p. scan.radius_in = 0; % round scan: interior radius of the round scan
p. scan.radius_out = 5e-6; % round scan: exterior radius of the round scan
p. scan.nr = 10; % round scan: number of intervals (# of shells - 1)
p. scan.nth = 3; % round scan: number of points in the first shell
p. scan.lx = 20e-6; % round_roi scan: width of the roi
p. scan.ly = 20e-6; % round_roi scan: height of the roi
p. scan.dr = 1.5e-6; % round_roi scan: shell step size
p. scan.nx = N_scan_x; %size(dp,3) % raster scan: number of steps in x
p. scan.ny = N_scan_y; % raster scan: number of steps in y
p. scan.step_size_x = scan_step_size; % raster scan: step size (grid spacing)
p. scan.step_size_y = scan_step_size; % raster scan: step size (grid spacing)
p. scan.custom_flip = [1,1,1]; % raster scan: apply custom flip [fliplr, flipud, transpose] to positions- similar to eng.custom_data_flip in GPU engines. Added by ZC.
p. scan.step_randn_offset = 0; % raster scan: relative random offset from the ideal periodic grid to avoid the raster grid pathology
p. scan.b = 0; % fermat: angular offset
p. scan.n_max = 1e4; % fermat: maximal number of points generated
p. scan.step = 0.5e-6; % fermat: step size
p. scan.cenxy = [0,0]; % fermat: position of center offset
p. scan.roi = []; % Region of interest in the object [xmin xmax ymin ymax] in meters. Points outside this region are not used for reconstruction.
% (relative to upper corner for raster scans and to center for round scans)
% custom: a string name of a function that defines the positions; also accepts mat file with entry 'pos', see +scans/+positions/+mat_pos.m
p. scan.custom_positions_source = '';
p. scan.custom_params = []; % custom: the parameters to feed to the custom position function.
% I/O
p. prefix = ''; % For automatic output filenames. If empty: scan number
p. suffix = strcat('ML_recon'); % Optional suffix for reconstruction
p. scan_string_format = scan_string_format; % format for scan string generation, it is used e.g for plotting and data saving
%%%p. base_path = '../../'; % base path : used for automatic generation of other paths
p. base_path = base_path; % base path : used for automatic generation of other paths
p. specfile = ''; % Name of spec file to get motor positions and check end of scan, defaut is p.spec_file == p.base_path;
p. ptycho_matlab_path = ''; % cSAXS ptycho package path
p. cSAXS_matlab_path = ''; % cSAXS base package path
p. raw_data_path{1} = ''; % Default using compile_x12sa_filename, used only if data should be prepared automatically
p. prepare_data_path = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. prepare_data_filename = []; % Leave empty for default file name generation, otherwise use [sprintf('S%05d_data_%03dx%03d',p.scan_number(1), p.asize(1), p.asize(2)) p.prep_data_suffix '.h5'] as default
p. save_path{1} = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. io.default_mask_file = ''; % load detector mask defined in this file instead of the mask in the detector packages, (used only if data should be prepared)
p. io.default_mask_type = 'binary'; % (used only if data should be prepared) ['binary', 'indices']. Default: 'binary'
p. io.file_compression = 0; % reconstruction file compression for HDF5 files; 0 for no compression
p. io.data_compression = 3; % prepared data file compression for HDF5 files; 0 for no compression
p. io.load_prep_pos = false; % load positions from prepared data file and ignore positions provided by metadata
p. io.data_descriptor = par.extra_print_info; %added by YJ. A short string that describe data when sending notifications
p. io.phone_number = ''; % phone number for sending messages
p. io.send_failed_scans_SMS = false; % send message if p.queue_max_attempts is exceeded
p. io.send_finished_recon_SMS = false; % send message after the reconstruction is completed
p. io.send_crashed_recon_SMS = false; % send message if the reconstruction crashes
p. io.SMS_sleep = 1800; % max 1 message per SMS_sleep seconds
p. io.script_name = mfilename; % added by YJ. store matlab script name
p. artificial_data_file = 'template_artificial_data'; % artificial data parameters, set p.src_metadata = 'artificial' to use this template
%% Reconstruction
% Initial iterate object, load from previous results if
% load_results_path is in the parameter file. Use random object and
% ideal probe otherwise.
if isfield(par, 'load_object_path')
p.model_object = false;
p.initial_iterate_object_file{1} = par.load_object_path;
% CHANGE FROM ORIGINAL CODE TO LOAD ONLY OBJECT AND NOT PROBE
% ALONG WITH IT
% if isfield(par, 'load_probe_path')
% p.initial_probe_file = par.load_probe_path;
% else
% p.initial_probe_file = par.load_object_path;
% end
% p.multiple_layers_obj = true;
initial_probe_file = fullfile(par.result_dir, num2str(scan_number), '/init_probe.mat');
p.initial_probe_file = initial_probe_file;
else
initial_probe_file = fullfile(par.result_dir, num2str(scan_number), '/init_probe.mat');
p.model_object = true;
p.model.object_type = 'rand';
p.initial_probe_file = initial_probe_file;
end
% Initial iterate probe
p. model_probe = false; % Use model probe, if false load it from file
p. model.probe_alpha_max = par.alpha_max; % Modal STEM probe's aperture size
p. model.probe_df = par.defocus; % Modal STEM probe's defocus
p. model.probe_c3 = 0; % Modal STEM probe's third-order spherical aberration in angstrom (optional)
p. model.probe_c5 = 0; % Modal STEM probe's fifth-order spherical aberration in angstrom (optional)
p. model.probe_c7 = 0; % Modal STEM probe's seventh-order spherical aberration in angstrom (optional)
p. model.probe_f_a2 = 0; % Modal STEM probe's twofold astigmatism in angstrom (optional)
p. model.probe_theta_a2 = 0; % Modal STEM probe's twofold azimuthal orientation in radian (optional)
p. model.probe_f_a3 = 0; % Modal STEM probe's threefold astigmatism in angstrom (optional)
p. model.probe_theta_a3 = 0; % Modal STEM probe's threefold azimuthal orientation in radian (optional)
p. model.probe_f_c3 = 0; % Modal STEM probe's coma in angstrom (optional)
p. model.probe_theta_c3 = 0; % Modal STEM probe's coma azimuthal orientation in radian (optional)
%Use probe from this mat-file (not used if model_probe is true)
p. probe_file_propagation = 0.0e-3; % Distance for propagating the probe from file in meters, = 0 to ignore
p. normalize_init_probe = true; % Added by YJ. Can be used to disable normalization of initial probes
% Shared scans - Currently working only for sharing probe and object
p. share_probe = 0; % Share probe between scans. Can be either a number/boolean or a list of numbers, specifying the probe index; e.g. [1 2 2] to share the probes between the second and third scan.
p. share_object = 0; % Share object between scans. Can be either a number/boolean or a list of numbers, specifying the object index; e.g. [1 2 2] to share the objects between the second and third scan.
% Modes
p. probe_modes = Nprobe; % Number of coherent modes for probe
p. object_modes = 1; % Number of coherent modes for object
% Mode starting guess
p. mode_start_pow = 0.02; % Normalized intensity on probe modes > 1. Can be a number (all higher modes equal) or a vector
p. mode_start = 'herm'; % (for probe) = 'rand', = 'herm' (Hermitian-like base), = 'hermver' (vertical modes only), = 'hermhor' (horizontal modes only)
p. ortho_probes = true; % orthogonalize probes after each engine
%% Plot, save and analyze
p. plot.prepared_data = false; % plot prepared data
p. plot.interval = []; % plot each interval-th iteration, does not work for c_solver code
p. plot.log_scale = [0 0]; % Plot on log scale for x and y
p. plot.realaxes = true; % Plots show scale in microns
p. plot.remove_phase_ramp = false; % Remove phase ramp from the plotted / saved phase figures
p. plot.fov_box = false; % Plot the scanning FOV box on the object (both phase and amplitude)
p. plot.fov_box_color = 'r'; % Color of the scanning FOV box
p. plot.positions = true; % Plot the scanning positions
p. plot.mask_bool = true; % Mask the noisy contour of the reconstructed object in plots
p. plot.windowautopos = true; % First plotting will auto position windows
p. plot.obj_apod = false; % Apply apodization to the reconstructed object;
p. plot.prop_obj = 0; % Distance to propagate reconstructed object before plotting [m]
p. plot.show_layers = true; % show each layer in multilayer reconstruction
p. plot.show_layers_stack = false; % show each layer in multilayer reconstruction by imagesc3D
p. plot.object_spectrum = []; % Plot propagated object (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.probe_spectrum = []; % Plot propagated probe (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.conjugate = false; % plot complex conjugate of the reconstruction
p. plot.horz_fact = 2.5; % Scales the space that the ptycho figures take horizontally
p. plot.FP_maskdim = 180e-6; % Filter the backpropagation (Fourier Ptychography)
p. plot.calc_FSC = false; % Calculate the Fourier Shell correlation for 2 scans or compare with model in case of artificial data tests
p. plot.show_FSC = false; % Show the FSC plots, including the cropped FOV
p. plot.residua = false; % highlight phase-residua in the image of the reconstructed phase
p. save.external = true; % Use a new Matlab session to run save final figures (saves ~6s per reconstruction). Please be aware that this might lead to an accumulation of Matlab sessions if your single reconstruction is very fast.
p. save.store_images = false; % Write preview images containing the final reconstructions in [p.base_path,'analysis/online/ptycho/'] if p.use_display = 0 then the figures are opened invisible in order to create the nice layout. It writes images in analysis/online/ptycho
p. save.store_images_intermediate = false; % save images to disk after each engine
p. save.store_images_ids = 1:4; % identifiers of the figure to be stored, 1=obj. amplitude, 2=obj. phase, 3=probes, 4=errors, 5=probes spectrum, 6=object spectrum
p. save.store_images_format = 'png'; % data type of the stored images jpg or png
p. save.store_images_dpi = 150; % DPI of the stored bitmap images
p. save.exclude = {'fmag', 'fmask', 'illum_sum'}; % exclude variables to reduce the file size on disk
p. save.save_reconstructions_intermediate = false; % save final object and probes after each engine
p. save.save_reconstructions = false; % save reconstructed object and probe when full reconstruction is finished
p. save.output_file = 'h5'; % data type of reconstruction file; 'h5' or 'mat'
if isfield(par, 'diff_pattern_blur')
p. diff_pattern_blur = par.diff_pattern_blur;
end
%% %%%%%%%%%%%%%%%%%% initialize reconstruction parameters %%%%%%%%%%%%%%%%%%%%
% --------- GPU engines ------------- See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng = struct(); % reset settings for this engine
eng. name = 'GPU_MS';
eng. use_gpu = true; % if false, run CPU code, but it will get very slow
eng. keep_on_gpu = true; % keep data + projections on GPU, false is useful for large data if DM is used
eng. compress_data = false; % use automatic online memory compression to limit need of GPU memory
eng. gpu_id = gpu_id; % default GPU id, [] means choosen by matlab
eng. check_gpu_load = true; % check available GPU memory before starting GPU engines
% general
eng. number_iterations = Niter; % number of iterations for selected method
if isfield(par, 'CBED_crop')
eng.asize_presolve = [par.CBED_crop, par.CBED_crop];
else
eng. asize_presolve = [par.CBED_size, par.CBED_size]; % crop data to "asize_presolve" size to get low resolution estimate that can be used in the next engine as a good initial guess
end
eng. align_shared_objects = false; % before merging multiple unshared objects into one shared, the object will be aligned and the probes shifted by the same distance -> use for alignement and shared reconstruction of drifting scans
eng. method = 'MLc'; % choose GPU solver: DM, ePIE, hPIE, MLc, Mls, -- recommended are MLc and MLs
eng. opt_errmetric = 'L1'; % optimization likelihood - poisson, L1
if isfield(par, 'grouping')
eng.grouping = par.grouping;
else
eng.grouping = 64;
end % size of processed blocks, larger blocks need more memory but they use GPU more effeciently, !!! grouping == inf means use as large as possible to fit into memory
% * for hPIE, ePIE, MLs methods smaller blocks lead to faster convergence,
% * for MLc the convergence is similar
% * for DM is has no effect on convergence
eng. probe_modes = p.probe_modes; % Number of coherent modes for probe
if isfield(par, 'object_change_start')
eng. object_change_start = par.object_change_start;
else
eng. object_change_start = 1; % Start updating object at this iteration number
end
if isfield(par, 'probe_change_start')
eng.probe_change_start = par.probe_change_start;
else
eng. probe_change_start = 1; % Start updating probe at this iteration number
end
% regularizations
if isfield(par, 'reg_mu')
eng.reg_mu = par.reg_mu; % Regularization (smooting) constant ( reg_mu = 0 for no regularization)
else
eng.reg_mu = 0;
end
eng. delta = 0; % press values to zero out of the illumination area in th object, usually 1e-2 is enough
eng. positivity_constraint_object = 0; % enforce weak (relaxed) positivity in object, ie O = O*(1-a)+a*|O|, usually a=1e-2 is already enough. Useful in conbination with OPRP or probe_fourier_shift_search
eng. apply_multimodal_update = false; % apply all incoherent modes to object, it can cause isses if the modes collect some crap
eng. probe_backpropagate = 0; % backpropagation distance the probe mask, 0 == apply in the object plane. Useful for pinhole imaging where the support can be applied at the pinhole plane
eng. probe_support_radius = []; % Normalized radius of circular support, = 1 for radius touching the window
eng. probe_support_fft = false; % assume that there is not illumination intensity out of the central FZP cone and enforce this contraint. Useful for imaging with focusing optics. Helps to remove issues from the gaps between detector modules.
% basic recontruction parameters
% PIE / ML methods % See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. beta_object = 1.0; % object step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. beta_probe = 1.0; % probe step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. delta_p = 0.1; % LSQ dumping constant, 0 == no preconditioner, 0.1 is usually safe, Preconditioner accelerates convergence and ML methods become approximations of the second order solvers
eng. momentum = 0.5; % add momentum acceleration term to the MLc method, useful if the probe guess is very poor or for acceleration of multilayer solver, but it is quite computationally expensive to be used in conventional ptycho without any refinement.
% The momentum method works usually well even with the accelerated_gradients option. eng.momentum = multiplication gain for velocity, eng.momentum == 0 -> no acceleration, eng.momentum == 0.5 is a good value
% momentum is enabled only when par.Niter < par.accelerated_gradients_start;
eng. accelerated_gradients_start = 10; % iteration number from which the Nesterov gradient acceleration should be applied, this option is supported only for MLc method. It is very computationally cheap way of convergence acceleration.
% DM
eng. pfft_relaxation = 0.05; % Relaxation in the Fourier domain projection, = 0 for full projection
eng. probe_regularization = 0.1; % Weight factor for the probe update (inertia)
% ADVANCED OPTIONS See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
% position refinement
eng. apply_subpix_shift = true; % apply FFT-based subpixel shift, it is automatically allowed for position refinement
if isfield(par, 'probe_position_search')
eng.probe_position_search = par.probe_position_search;
else
eng. probe_position_search = 50; % iteration number from which the engine will reconstruct probe positions, from iteration == probe_position_search, assume they have to match geometry model with error less than probe_position_error_max
end
%eng. probe_geometry_model = {'scale', 'asymmetry', 'rotation', 'shear'}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_geometry_model = {}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_position_error_max = inf; % maximal expected random position errors, probe prositions are confined in a circle with radius defined by probe_position_error_max and with center defined by original positions scaled by probe_geometry_model
eng. apply_relaxed_position_constraint = false; % added by YJ. Apply a relaxed constraint to probe positions. default = true. Set to false if there are big jumps in positions.
eng. update_pos_weight_every = inf; % added by YJ. Allow position weight to be updated multiple times. default = inf: only update once.
% multilayer extension
eng. delta_z = delta_z*ones(Nlayers,1); % if not empty, use multilayer ptycho extension , see ML_MS code for example of use, [] == common single layer ptychography , note that delta_z provides only relative propagation distance from the previous layer, ie delta_z can be either positive or negative. If preshift_ML_probe == false, the first layer is defined by position of initial probe plane. It is useful to use eng.momentum for convergence acceleration
if isfield(par, 'regularize_layers')
eng.regularize_layers = par.regularize_layers;
else
eng. regularize_layers = 1; % multilayer extension: 0<R<<1 -> apply regularization on the reconstructed object layers, 0 == no regularization, 0.01 == weak regularization that will slowly symmetrize information content between layers
end
eng. preshift_ML_probe = false; % multilayer extension: if true, assume that the provided probe is reconstructed in center of the sample and the layers are centered around this position
eng. layer4pos = []; % Added by ZC. speficy which layer is used for position correction ; if empty, then default, ceil(Nlayers/2)
eng. init_layer_select = []; % Added by YJ. Select layers in the initial object for pre-processing. If empty (default): use all layers.
eng. init_layer_preprocess = ''; % Added by YJ. Specify how to pre-process initial layers
% '' or 'all' (default): use all layers (do nothing)
% 'avg': average all layers
% 'interp': interpolate layers using spline method. Need to specify desired depths in init_layer_interp
eng. init_layer_interp = []; % Specify desired depths for interpolation. The depths of initial are [1:Nlayer_init]. If empty (default), no interpolation
if isfield(par, 'init_layer_append_mode')
eng.init_layer_append_mode = par.init_layer_append_mode;
else
eng. init_layer_append_mode = 'vac';
end
% Added by YJ. Specify how to initialize extra layers
% '' or 'vac' (default): add vacuum layers
% 'edge': append 1st or last layers
% 'avg': append averaged layer
eng. init_layer_scaling_factor = 1; % Added by YJ. Scale all layers. Default: 1 (no scaling). Useful when delta_z is changed
% other extensions
eng. background = 0; % average background scattering level, for OMNI values around 0.3 for 100ms, for flOMNI <0.1 per 100ms exposure, see for more details: Odstrcil, M., et al., Optics letters 40.23 (2015): 5574-5577.
eng. background_width = inf; % width of the background function in pixels, inf == flat background, background function is then convolved with the average diffraction pattern in order to account for beam diversion
eng. clean_residua = false; % remove phase residua from reconstruction by iterative unwrapping, it will result in low spatial freq. artefacts -> object can be used as an residua-free initial guess for netx engine
% wavefront & camera geometry refinement See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. probe_fourier_shift_search = inf; % iteration number from which the engine will: refine farfield position of the beam (ie angle) from iteration == probe_fourier_shift_search
eng. estimate_NF_distance = inf; % iteration number from which the engine will: try to estimate the nearfield propagation distance using gradient descent optimization
eng. detector_rotation_search = inf; % iteration number from which the engine will: search for optimal detector rotation, preferably use with option mirror_scan = true , rotation of the detector axis with respect to the sample axis, similar as rotation option in the position refinement geometry model but works also for 0/180deg rotation shared scans
eng. detector_scale_search = inf; % iteration number from which the engine will: refine pixel scale of the detector, can be used to refine propagation distance in ptycho
if isfield(par, 'variable_probe') && strcmp(par.variable_probe,'false')
eng.variable_probe = false;
else
eng.variable_probe = true;
end
% eng. variable_probe = true; % Use SVD to account for variable illumination during a single (coupled) scan, see for more details: Odstrcil, M. et al. Optics express 24.8 (2016): 8360-8369.
eng. variable_probe_modes = 1; % OPRP settings , number of SVD modes using to describe the probe evolution.
eng. variable_probe_smooth = 0; % OPRP settings , enforce of smooth evolution of the OPRP modes -> N is order of polynomial fit used for smoothing, 0 == do not apply any smoothing. Smoothing is useful if only a smooth drift is assumed during the ptycho acquisition
eng. variable_intensity = false; % account to changes in probe intensity
% extra analysis
eng. get_fsc_score = false; % measure evolution of the Fourier ring correlation during convergence
eng. mirror_objects = false; % mirror objects, useful for 0/180deg scan sharing -> geometry refinement for tomography, works only if 2 scans are provided
% custom data adjustments, useful for offaxis ptychography
eng.auto_center_data = false; % autoestimate the center of mass from data and shift the diffraction patterns so that the average center of mass corresponds to center of mass of the provided probe
eng.auto_center_probe = false; % center the probe position in real space before reconstruction is started
eng.custom_data_flip = [0,0,0]; % apply custom flip of the data [fliplr, flipud, transpose] - can be used for quick testing of reconstruction with various flips or for reflection ptychography
eng.apply_tilted_plane_correction = ''; % if any(p.sample_rotation_angles([1,2]) ~= 0), this option will apply tilted plane correction. (a) 'diffraction' apply correction into the data, note that it is valid only for "low NA" illumination Gardner, D. et al., Optics express 20.17 (2012): 19050-19059. (b) 'propagation' - use tilted plane propagation, (c) '' - will not apply any correction
% I/O
eng.plot_results_every = Niter_plot_results;
eng.save_results_every = Niter_save_results;
eng.save_images ={'obj_ph_stack','obj_ph_sum','probe','probe_mag','obj_mag_sum','obj_mag_stack'};
eng.extraPrintInfo = par.extra_print_info;
resultDir = strcat(p.base_path,sprintf(p.scan.format, p.scan_number),'/roi',p.scan.roi_label,'/');
[eng.fout, p.suffix] = generateResultDir(eng, resultDir);
%add engine
[p, ~] = core.append_engine(p, eng); % Adds this engine to the reconstruction process
%% Run the reconstruction
tic
out = core.ptycho_recons(p);
toc
end
+389
View File
@@ -0,0 +1,389 @@
function run_multislice_new_bio_DM(parfile)
par = parameter_builder(parfile);
addpath(strcat(pwd,'/utils/'))
addpath(core.find_base_package)
%%%%%%%%%%%%%%%%%%%% data parameters %%%%%%%%%%%%%%%%%%%%
base_path = par.result_dir;
roi_label = par.roi_label;
scan_number = par.scan_number;
scan_string_format = '%01d';
Ndpx = par.CBED_size; % size of cbed
alpha0 = par.alpha_max; % semi-convergence angle (mrad)
rbf = par.rbf; % radius of the BF disk in cbed. Can be used to calculate dk
voltage = par.voltage;
rot_ang = par.rot_ang; %angle between cbed and scan coord.
scan_step_size = par.scan_step_size; %angstrom
N_scan_y = par.N_scan_y; %number of scan points
N_scan_x = par.N_scan_x;
%%%%%%%%%%%%%%%%%%%% reconstruction parameters %%%%%%%%%%%%%%%%%%%%
gpu_id = 1;
Niter = par.Niter;
Niter_save_results = par.Niter_save_results;
Niter_plot_results = inf;
Nprobe = par.Nprobe; % # of probe modes
thickness = par.thickness; % sample thickness in angstrom
Nlayers = round(par.Nlayers); % # of slices for multi-slice, 1 for single-slice
delta_z = thickness / Nlayers;
%% %%%%%%%%%%%%%%%%%% initialize data parameters %%%%%%%%%%%%%%%%%%%%
p = struct();
p. verbose_level = 2; % verbosity for standard output (0-1 for loops, 2-3 for testing and adjustments, >= 4 for debugging)
p. use_display = false; % global switch for display, if [] then true for verbose > 1
p. scan_number = scan_number; % Multiple scan numbers for shared scans
% Geometry
p. z = 1; % Distance from object to detector. Always 1 for electron ptycho
p. asize = [Ndpx,Ndpx]; % Diffr. patt. array size
p. ctr = [fix(Ndpx/2)+1, fix(Ndpx/2)+1]; % Diffr. patt. center coordinates (y,x) (empty means middle of the array); e.g. [100 207;100+20 207+10];
p. beam_source = 'electron'; % Added by YJ for electron pty. Use relativistic corrected formula for wavelength. Also change the units on figures
%p. dk = dk; % Added by YJ. dk is the pixel size in cbed (1/A). This is used to determine pixel size in electron ptycho
p. d_alpha = alpha0/rbf; % Added by YJ. d_alpha is the pixel size in cbed (mrad). This is used to determine pixel size in electron ptycho
p. prop_regime = 'farfield'; % propagation regime: nearfield, farfield (default), !! nearfield is supported only by GPU engines
p. focus_to_sample_distance = []; % sample to focus distance, parameter to be set for nearfield ptychography, otherwise it is ignored
p. energy = voltage; % Energy (in keV), leave empty to use spec entry mokev
%p. affine_angle = 0; % Not used by ptycho_recons at all. This allows you to define a variable for the affine matrix below and keep it in p for future record. This is used later by the affine_matrix_search.m script
%p. affine_matrix = [1 , 0; 0, 1] ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
affine_mat = compose_affine_matrix(1, 0, rot_ang, 0);
p. affine_matrix = affine_mat ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
% Scan meta data
p. src_metadata = 'none'; % source of the meta data, following options are supported: 'spec', 'none' , 'artificial' - or add new to +scan/+meta/
p. queue.lockfile = false; % If true writes a lock file, if lock file exists skips recontruction
% Data preparation
p. detector.name = 'empad'; % see +detectors/ folder
p. detector.check_2_detpos = []; % = []; (ignores) = 270; compares to dettrx to see if p.ctr should be reversed (for OMNY shared scans 1221122), make equal to the middle point of dettrx between the 2 detector positions
p. detector.data_prefix = ''; % Default using current eaccount e.g. e14169_1_
p. detector.binning = false; % = true to perform 2x2 binning of detector pixels, for binning = N do 2^Nx2^N binning
p. detector.upsampling = false; % upsample the measured data by 2^data_upsampling, (transposed operator to the binning), it can be used for superresolution in nearfield ptychography or to account for undersampling in a far-field dataset
p. detector.burst_frames = 1; % number of frames collected per scan position
p. prepare.data_preparator = 'matlab_aps'; % data preparator; 'python' or 'matlab' or 'matlab_aps'
p. prepare.auto_prepare_data = true; % if true: prepare dataset from raw measurements if the prepared data does not exist
p. prepare.force_preparation_data = true; % Prepare dataset even if it exists, it will overwrite the file % Default: @prepare_data_2d
p. prepare.store_prepared_data = false; % store the loaded data to h5 even for non-external engines (i.e. other than c_solver)
p. prepare.prepare_data_function = ''; % (used only if data should be prepared) custom data preparation function handle;
p. prepare.auto_center_data = false; % if matlab data preparator is used, try to automatically center the diffraction pattern to keep center of mass in center of diffraction
% Scan positions
p. src_positions = 'matlab_pos'; % 'spec', 'orchestra', 'load_from_file', 'matlab_pos' (scan params are defined below) or add new position loaders to +scan/+positions/
p. positions_file = ''; %Filename pattern for position files, Example: ['../../specES1/scan_positions/scan_%05d.dat']; (the scan number will be automatically filled in)
% scan parameters for option src_positions = 'matlab_pos';
p. scan.type = 'raster'; % {'round', 'raster', 'round_roi', 'custom'}
p. scan.roi_label = roi_label; % For APS data
p. scan.format = scan_string_format; % For APS data format for scan directory generation
p. scan.radius_in = 0; % round scan: interior radius of the round scan
p. scan.radius_out = 5e-6; % round scan: exterior radius of the round scan
p. scan.nr = 10; % round scan: number of intervals (# of shells - 1)
p. scan.nth = 3; % round scan: number of points in the first shell
p. scan.lx = 20e-6; % round_roi scan: width of the roi
p. scan.ly = 20e-6; % round_roi scan: height of the roi
p. scan.dr = 1.5e-6; % round_roi scan: shell step size
p. scan.nx = N_scan_x; %size(dp,3) % raster scan: number of steps in x
p. scan.ny = N_scan_y; % raster scan: number of steps in y
p. scan.step_size_x = scan_step_size; % raster scan: step size (grid spacing)
p. scan.step_size_y = scan_step_size; % raster scan: step size (grid spacing)
p. scan.custom_flip = [1,1,1]; % raster scan: apply custom flip [fliplr, flipud, transpose] to positions- similar to eng.custom_data_flip in GPU engines. Added by ZC.
p. scan.step_randn_offset = 0; % raster scan: relative random offset from the ideal periodic grid to avoid the raster grid pathology
p. scan.b = 0; % fermat: angular offset
p. scan.n_max = 1e4; % fermat: maximal number of points generated
p. scan.step = 0.5e-6; % fermat: step size
p. scan.cenxy = [0,0]; % fermat: position of center offset
p. scan.roi = []; % Region of interest in the object [xmin xmax ymin ymax] in meters. Points outside this region are not used for reconstruction.
% (relative to upper corner for raster scans and to center for round scans)
% custom: a string name of a function that defines the positions; also accepts mat file with entry 'pos', see +scans/+positions/+mat_pos.m
p. scan.custom_positions_source = '';
p. scan.custom_params = []; % custom: the parameters to feed to the custom position function.
% I/O
p. prefix = ''; % For automatic output filenames. If empty: scan number
p. suffix = strcat('ML_recon'); % Optional suffix for reconstruction
p. scan_string_format = scan_string_format; % format for scan string generation, it is used e.g for plotting and data saving
%%%p. base_path = '../../'; % base path : used for automatic generation of other paths
p. base_path = base_path; % base path : used for automatic generation of other paths
p. specfile = ''; % Name of spec file to get motor positions and check end of scan, defaut is p.spec_file == p.base_path;
p. ptycho_matlab_path = ''; % cSAXS ptycho package path
p. cSAXS_matlab_path = ''; % cSAXS base package path
p. raw_data_path{1} = ''; % Default using compile_x12sa_filename, used only if data should be prepared automatically
p. prepare_data_path = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. prepare_data_filename = []; % Leave empty for default file name generation, otherwise use [sprintf('S%05d_data_%03dx%03d',p.scan_number(1), p.asize(1), p.asize(2)) p.prep_data_suffix '.h5'] as default
p. save_path{1} = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. io.default_mask_file = ''; % load detector mask defined in this file instead of the mask in the detector packages, (used only if data should be prepared)
p. io.default_mask_type = 'binary'; % (used only if data should be prepared) ['binary', 'indices']. Default: 'binary'
p. io.file_compression = 0; % reconstruction file compression for HDF5 files; 0 for no compression
p. io.data_compression = 3; % prepared data file compression for HDF5 files; 0 for no compression
p. io.load_prep_pos = false; % load positions from prepared data file and ignore positions provided by metadata
p. io.data_descriptor = par.extra_print_info; %added by YJ. A short string that describe data when sending notifications
p. io.phone_number = ''; % phone number for sending messages
p. io.send_failed_scans_SMS = false; % send message if p.queue_max_attempts is exceeded
p. io.send_finished_recon_SMS = false; % send message after the reconstruction is completed
p. io.send_crashed_recon_SMS = false; % send message if the reconstruction crashes
p. io.SMS_sleep = 1800; % max 1 message per SMS_sleep seconds
p. io.script_name = mfilename; % added by YJ. store matlab script name
p. artificial_data_file = 'template_artificial_data'; % artificial data parameters, set p.src_metadata = 'artificial' to use this template
%% Reconstruction
% Initial iterate object, load from previous results if
% load_results_path is in the parameter file. Use random object and
% ideal probe otherwise.
if isfield(par, 'load_object_path')
p.model_object = false;
p.initial_iterate_object_file{1} = par.load_object_path;
% CHANGE FROM ORIGINAL CODE TO LOAD ONLY OBJECT AND NOT PROBE
% ALONG WITH IT
% if isfield(par, 'load_probe_path')
% p.initial_probe_file = par.load_probe_path;
% else
% p.initial_probe_file = par.load_object_path;
% end
% p.multiple_layers_obj = true;
initial_probe_file = fullfile(par.result_dir, num2str(scan_number), '/init_probe.mat');
p.initial_probe_file = initial_probe_file;
else
initial_probe_file = fullfile(par.result_dir, num2str(scan_number), '/init_probe.mat');
p.model_object = true;
p.model.object_type = 'rand';
p.initial_probe_file = initial_probe_file;
end
% Initial iterate probe
p. model_probe = false; % Use model probe, if false load it from file
p. model.probe_alpha_max = par.alpha_max; % Modal STEM probe's aperture size
p. model.probe_df = par.defocus; % Modal STEM probe's defocus
p. model.probe_c3 = 0; % Modal STEM probe's third-order spherical aberration in angstrom (optional)
p. model.probe_c5 = 0; % Modal STEM probe's fifth-order spherical aberration in angstrom (optional)
p. model.probe_c7 = 0; % Modal STEM probe's seventh-order spherical aberration in angstrom (optional)
p. model.probe_f_a2 = 0; % Modal STEM probe's twofold astigmatism in angstrom (optional)
p. model.probe_theta_a2 = 0; % Modal STEM probe's twofold azimuthal orientation in radian (optional)
p. model.probe_f_a3 = 0; % Modal STEM probe's threefold astigmatism in angstrom (optional)
p. model.probe_theta_a3 = 0; % Modal STEM probe's threefold azimuthal orientation in radian (optional)
p. model.probe_f_c3 = 0; % Modal STEM probe's coma in angstrom (optional)
p. model.probe_theta_c3 = 0; % Modal STEM probe's coma azimuthal orientation in radian (optional)
%Use probe from this mat-file (not used if model_probe is true)
p. probe_file_propagation = 0.0e-3; % Distance for propagating the probe from file in meters, = 0 to ignore
p. normalize_init_probe = true; % Added by YJ. Can be used to disable normalization of initial probes
% Shared scans - Currently working only for sharing probe and object
p. share_probe = 0; % Share probe between scans. Can be either a number/boolean or a list of numbers, specifying the probe index; e.g. [1 2 2] to share the probes between the second and third scan.
p. share_object = 0; % Share object between scans. Can be either a number/boolean or a list of numbers, specifying the object index; e.g. [1 2 2] to share the objects between the second and third scan.
% Modes
p. probe_modes = Nprobe; % Number of coherent modes for probe
p. object_modes = 1; % Number of coherent modes for object
% Mode starting guess
p. mode_start_pow = 0.02; % Normalized intensity on probe modes > 1. Can be a number (all higher modes equal) or a vector
p. mode_start = 'herm'; % (for probe) = 'rand', = 'herm' (Hermitian-like base), = 'hermver' (vertical modes only), = 'hermhor' (horizontal modes only)
p. ortho_probes = true; % orthogonalize probes after each engine
%% Plot, save and analyze
p. plot.prepared_data = false; % plot prepared data
p. plot.interval = []; % plot each interval-th iteration, does not work for c_solver code
p. plot.log_scale = [0 0]; % Plot on log scale for x and y
p. plot.realaxes = true; % Plots show scale in microns
p. plot.remove_phase_ramp = false; % Remove phase ramp from the plotted / saved phase figures
p. plot.fov_box = false; % Plot the scanning FOV box on the object (both phase and amplitude)
p. plot.fov_box_color = 'r'; % Color of the scanning FOV box
p. plot.positions = true; % Plot the scanning positions
p. plot.mask_bool = true; % Mask the noisy contour of the reconstructed object in plots
p. plot.windowautopos = true; % First plotting will auto position windows
p. plot.obj_apod = false; % Apply apodization to the reconstructed object;
p. plot.prop_obj = 0; % Distance to propagate reconstructed object before plotting [m]
p. plot.show_layers = true; % show each layer in multilayer reconstruction
p. plot.show_layers_stack = false; % show each layer in multilayer reconstruction by imagesc3D
p. plot.object_spectrum = []; % Plot propagated object (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.probe_spectrum = []; % Plot propagated probe (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.conjugate = false; % plot complex conjugate of the reconstruction
p. plot.horz_fact = 2.5; % Scales the space that the ptycho figures take horizontally
p. plot.FP_maskdim = 180e-6; % Filter the backpropagation (Fourier Ptychography)
p. plot.calc_FSC = false; % Calculate the Fourier Shell correlation for 2 scans or compare with model in case of artificial data tests
p. plot.show_FSC = false; % Show the FSC plots, including the cropped FOV
p. plot.residua = false; % highlight phase-residua in the image of the reconstructed phase
p. save.external = true; % Use a new Matlab session to run save final figures (saves ~6s per reconstruction). Please be aware that this might lead to an accumulation of Matlab sessions if your single reconstruction is very fast.
p. save.store_images = false; % Write preview images containing the final reconstructions in [p.base_path,'analysis/online/ptycho/'] if p.use_display = 0 then the figures are opened invisible in order to create the nice layout. It writes images in analysis/online/ptycho
p. save.store_images_intermediate = false; % save images to disk after each engine
p. save.store_images_ids = 1:4; % identifiers of the figure to be stored, 1=obj. amplitude, 2=obj. phase, 3=probes, 4=errors, 5=probes spectrum, 6=object spectrum
p. save.store_images_format = 'png'; % data type of the stored images jpg or png
p. save.store_images_dpi = 150; % DPI of the stored bitmap images
p. save.exclude = {'fmag', 'fmask', 'illum_sum'}; % exclude variables to reduce the file size on disk
p. save.save_reconstructions_intermediate = false; % save final object and probes after each engine
p. save.save_reconstructions = false; % save reconstructed object and probe when full reconstruction is finished
p. save.output_file = 'h5'; % data type of reconstruction file; 'h5' or 'mat'
if isfield(par, 'diff_pattern_blur')
p. diff_pattern_blur = par.diff_pattern_blur;
end
%% %%%%%%%%%%%%%%%%%% initialize reconstruction parameters %%%%%%%%%%%%%%%%%%%%
% --------- GPU engines ------------- See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng = struct(); % reset settings for this engine
eng. name = 'GPU_MS';
eng. use_gpu = true; % if false, run CPU code, but it will get very slow
eng. keep_on_gpu = true; % keep data + projections on GPU, false is useful for large data if DM is used
eng. compress_data = false; % use automatic online memory compression to limit need of GPU memory
eng. gpu_id = gpu_id; % default GPU id, [] means choosen by matlab
eng. check_gpu_load = true; % check available GPU memory before starting GPU engines
% general
eng. number_iterations = Niter; % number of iterations for selected method
if isfield(par, 'CBED_crop')
eng.asize_presolve = [par.CBED_crop, par.CBED_crop];
else
eng. asize_presolve = [par.CBED_size, par.CBED_size]; % crop data to "asize_presolve" size to get low resolution estimate that can be used in the next engine as a good initial guess
end
eng. align_shared_objects = false; % before merging multiple unshared objects into one shared, the object will be aligned and the probes shifted by the same distance -> use for alignement and shared reconstruction of drifting scans
eng. method = 'DM'; % choose GPU solver: DM, ePIE, hPIE, MLc, Mls, -- recommended are MLc and MLs
eng. opt_errmetric = 'L1'; % optimization likelihood - poisson, L1
if isfield(par, 'grouping')
eng.grouping = par.grouping;
else
eng.grouping = 64;
end % size of processed blocks, larger blocks need more memory but they use GPU more effeciently, !!! grouping == inf means use as large as possible to fit into memory
% * for hPIE, ePIE, MLs methods smaller blocks lead to faster convergence,
% * for MLc the convergence is similar
% * for DM is has no effect on convergence
eng. probe_modes = p.probe_modes; % Number of coherent modes for probe
if isfield(par, 'object_change_start')
eng. object_change_start = par.object_change_start;
else
eng. object_change_start = 1; % Start updating object at this iteration number
end
if isfield(par, 'probe_change_start')
eng.probe_change_start = par.probe_change_start;
else
eng. probe_change_start = 1; % Start updating probe at this iteration number
end
% regularizations
if isfield(par, 'reg_mu')
eng.reg_mu = par.reg_mu; % Regularization (smooting) constant ( reg_mu = 0 for no regularization)
else
eng.reg_mu = 0;
end
eng. delta = 0; % press values to zero out of the illumination area in th object, usually 1e-2 is enough
eng. positivity_constraint_object = 0; % enforce weak (relaxed) positivity in object, ie O = O*(1-a)+a*|O|, usually a=1e-2 is already enough. Useful in conbination with OPRP or probe_fourier_shift_search
eng. apply_multimodal_update = false; % apply all incoherent modes to object, it can cause isses if the modes collect some crap
eng. probe_backpropagate = 0; % backpropagation distance the probe mask, 0 == apply in the object plane. Useful for pinhole imaging where the support can be applied at the pinhole plane
eng. probe_support_radius = []; % Normalized radius of circular support, = 1 for radius touching the window
eng. probe_support_fft = false; % assume that there is not illumination intensity out of the central FZP cone and enforce this contraint. Useful for imaging with focusing optics. Helps to remove issues from the gaps between detector modules.
% basic recontruction parameters
% PIE / ML methods % See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. beta_object = 1; % object step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. beta_probe = 1; % probe step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. delta_p = 0.1; % LSQ dumping constant, 0 == no preconditioner, 0.1 is usually safe, Preconditioner accelerates convergence and ML methods become approximations of the second order solvers
eng. momentum = 0.5; % add momentum acceleration term to the MLc method, useful if the probe guess is very poor or for acceleration of multilayer solver, but it is quite computationally expensive to be used in conventional ptycho without any refinement.
% The momentum method works usually well even with the accelerated_gradients option. eng.momentum = multiplication gain for velocity, eng.momentum == 0 -> no acceleration, eng.momentum == 0.5 is a good value
% momentum is enabled only when par.Niter < par.accelerated_gradients_start;
eng. accelerated_gradients_start = inf; % iteration number from which the Nesterov gradient acceleration should be applied, this option is supported only for MLc method. It is very computationally cheap way of convergence acceleration.
% DM
eng. pfft_relaxation = 0.05; % Relaxation in the Fourier domain projection, = 0 for full projection
eng. probe_regularization = 0.1; % Weight factor for the probe update (inertia)
% ADVANCED OPTIONS See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
% position refinement
eng. apply_subpix_shift = true; % apply FFT-based subpixel shift, it is automatically allowed for position refinement
if isfield(par, 'probe_position_search')
eng.probe_position_search = par.probe_position_search;
else
eng. probe_position_search = 50; % iteration number from which the engine will reconstruct probe positions, from iteration == probe_position_search, assume they have to match geometry model with error less than probe_position_error_max
end
%eng. probe_geometry_model = {'scale', 'asymmetry', 'rotation', 'shear'}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_geometry_model = {}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_position_error_max = inf; % maximal expected random position errors, probe prositions are confined in a circle with radius defined by probe_position_error_max and with center defined by original positions scaled by probe_geometry_model
eng. apply_relaxed_position_constraint = false; % added by YJ. Apply a relaxed constraint to probe positions. default = true. Set to false if there are big jumps in positions.
eng. update_pos_weight_every = inf; % added by YJ. Allow position weight to be updated multiple times. default = inf: only update once.
% multilayer extension
eng. delta_z = delta_z*ones(Nlayers,1); % if not empty, use multilayer ptycho extension , see ML_MS code for example of use, [] == common single layer ptychography , note that delta_z provides only relative propagation distance from the previous layer, ie delta_z can be either positive or negative. If preshift_ML_probe == false, the first layer is defined by position of initial probe plane. It is useful to use eng.momentum for convergence acceleration
if isfield(par, 'regularize_layers')
eng.regularize_layers = par.regularize_layers;
else
eng. regularize_layers = 1; % multilayer extension: 0<R<<1 -> apply regularization on the reconstructed object layers, 0 == no regularization, 0.01 == weak regularization that will slowly symmetrize information content between layers
end
eng. preshift_ML_probe = false; % multilayer extension: if true, assume that the provided probe is reconstructed in center of the sample and the layers are centered around this position
eng. layer4pos = []; % Added by ZC. speficy which layer is used for position correction ; if empty, then default, ceil(Nlayers/2)
eng. init_layer_select = []; % Added by YJ. Select layers in the initial object for pre-processing. If empty (default): use all layers.
eng. init_layer_preprocess = ''; % Added by YJ. Specify how to pre-process initial layers
% '' or 'all' (default): use all layers (do nothing)
% 'avg': average all layers
% 'interp': interpolate layers using spline method. Need to specify desired depths in init_layer_interp
eng. init_layer_interp = []; % Specify desired depths for interpolation. The depths of initial are [1:Nlayer_init]. If empty (default), no interpolation
if isfield(par, 'init_layer_append_mode')
eng.init_layer_append_mode = par.init_layer_append_mode;
else
eng. init_layer_append_mode = 'vac';
end
% Added by YJ. Specify how to initialize extra layers
% '' or 'vac' (default): add vacuum layers
% 'edge': append 1st or last layers
% 'avg': append averaged layer
eng. init_layer_scaling_factor = 1; % Added by YJ. Scale all layers. Default: 1 (no scaling). Useful when delta_z is changed
% other extensions
eng. background = 0; % average background scattering level, for OMNI values around 0.3 for 100ms, for flOMNI <0.1 per 100ms exposure, see for more details: Odstrcil, M., et al., Optics letters 40.23 (2015): 5574-5577.
eng. background_width = inf; % width of the background function in pixels, inf == flat background, background function is then convolved with the average diffraction pattern in order to account for beam diversion
eng. clean_residua = false; % remove phase residua from reconstruction by iterative unwrapping, it will result in low spatial freq. artefacts -> object can be used as an residua-free initial guess for netx engine
% wavefront & camera geometry refinement See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. probe_fourier_shift_search = inf; % iteration number from which the engine will: refine farfield position of the beam (ie angle) from iteration == probe_fourier_shift_search
eng. estimate_NF_distance = inf; % iteration number from which the engine will: try to estimate the nearfield propagation distance using gradient descent optimization
eng. detector_rotation_search = inf; % iteration number from which the engine will: search for optimal detector rotation, preferably use with option mirror_scan = true , rotation of the detector axis with respect to the sample axis, similar as rotation option in the position refinement geometry model but works also for 0/180deg rotation shared scans
eng. detector_scale_search = inf; % iteration number from which the engine will: refine pixel scale of the detector, can be used to refine propagation distance in ptycho
if isfield(par, 'variable_probe') && strcmp(par.variable_probe,'false')
eng.variable_probe = false;
else
eng.variable_probe = true;
end
% eng. variable_probe = true; % Use SVD to account for variable illumination during a single (coupled) scan, see for more details: Odstrcil, M. et al. Optics express 24.8 (2016): 8360-8369.
eng. variable_probe_modes = 1; % OPRP settings , number of SVD modes using to describe the probe evolution.
eng. variable_probe_smooth = 0; % OPRP settings , enforce of smooth evolution of the OPRP modes -> N is order of polynomial fit used for smoothing, 0 == do not apply any smoothing. Smoothing is useful if only a smooth drift is assumed during the ptycho acquisition
eng. variable_intensity = false; % account to changes in probe intensity
% extra analysis
eng. get_fsc_score = false; % measure evolution of the Fourier ring correlation during convergence
eng. mirror_objects = false; % mirror objects, useful for 0/180deg scan sharing -> geometry refinement for tomography, works only if 2 scans are provided
% custom data adjustments, useful for offaxis ptychography
eng.auto_center_data = false; % autoestimate the center of mass from data and shift the diffraction patterns so that the average center of mass corresponds to center of mass of the provided probe
eng.auto_center_probe = false; % center the probe position in real space before reconstruction is started
eng.custom_data_flip = [0,0,0]; % apply custom flip of the data [fliplr, flipud, transpose] - can be used for quick testing of reconstruction with various flips or for reflection ptychography
eng.apply_tilted_plane_correction = ''; % if any(p.sample_rotation_angles([1,2]) ~= 0), this option will apply tilted plane correction. (a) 'diffraction' apply correction into the data, note that it is valid only for "low NA" illumination Gardner, D. et al., Optics express 20.17 (2012): 19050-19059. (b) 'propagation' - use tilted plane propagation, (c) '' - will not apply any correction
% I/O
eng.plot_results_every = Niter_plot_results;
eng.save_results_every = Niter_save_results;
eng.save_images ={'obj_ph_stack','obj_ph_sum','probe'};
eng.extraPrintInfo = par.extra_print_info;
resultDir = strcat(p.base_path,sprintf(p.scan.format, p.scan_number),'/roi',p.scan.roi_label,'/');
[eng.fout, p.suffix] = generateResultDir(eng, resultDir);
%add engine
[p, ~] = core.append_engine(p, eng); % Adds this engine to the reconstruction process
%% Run the reconstruction
tic
out = core.ptycho_recons(p);
toc
end
+378
View File
@@ -0,0 +1,378 @@
function run_multislice_new_bio_MLs(parfile)
par = parameter_builder(parfile);
addpath(strcat(pwd,'/utils/'))
addpath(core.find_base_package)
%%%%%%%%%%%%%%%%%%%% data parameters %%%%%%%%%%%%%%%%%%%%
base_path = par.result_dir;
roi_label = par.roi_label;
scan_number = par.scan_number;
scan_string_format = '%01d';
Ndpx = par.CBED_size; % size of cbed
alpha0 = par.alpha_max; % semi-convergence angle (mrad)
rbf = par.rbf; % radius of the BF disk in cbed. Can be used to calculate dk
voltage = par.voltage;
rot_ang = par.rot_ang; %angle between cbed and scan coord.
scan_step_size = par.scan_step_size; %angstrom
N_scan_y = par.N_scan_y; %number of scan points
N_scan_x = par.N_scan_x;
%%%%%%%%%%%%%%%%%%%% reconstruction parameters %%%%%%%%%%%%%%%%%%%%
gpu_id = 1;
Niter = par.Niter;
Niter_save_results = par.Niter_save_results;
Niter_plot_results = inf;
Nprobe = par.Nprobe; % # of probe modes
thickness = par.thickness; % sample thickness in angstrom
Nlayers = round(par.Nlayers); % # of slices for multi-slice, 1 for single-slice
delta_z = thickness / Nlayers;
%% %%%%%%%%%%%%%%%%%% initialize data parameters %%%%%%%%%%%%%%%%%%%%
p = struct();
p. verbose_level = 2; % verbosity for standard output (0-1 for loops, 2-3 for testing and adjustments, >= 4 for debugging)
p. use_display = false; % global switch for display, if [] then true for verbose > 1
p. scan_number = scan_number; % Multiple scan numbers for shared scans
% Geometry
p. z = 1; % Distance from object to detector. Always 1 for electron ptycho
p. asize = [Ndpx,Ndpx]; % Diffr. patt. array size
p. ctr = [fix(Ndpx/2)+1, fix(Ndpx/2)+1]; % Diffr. patt. center coordinates (y,x) (empty means middle of the array); e.g. [100 207;100+20 207+10];
p. beam_source = 'electron'; % Added by YJ for electron pty. Use relativistic corrected formula for wavelength. Also change the units on figures
%p. dk = dk; % Added by YJ. dk is the pixel size in cbed (1/A). This is used to determine pixel size in electron ptycho
p. d_alpha = alpha0/rbf; % Added by YJ. d_alpha is the pixel size in cbed (mrad). This is used to determine pixel size in electron ptycho
p. prop_regime = 'farfield'; % propagation regime: nearfield, farfield (default), !! nearfield is supported only by GPU engines
p. focus_to_sample_distance = []; % sample to focus distance, parameter to be set for nearfield ptychography, otherwise it is ignored
p. energy = voltage; % Energy (in keV), leave empty to use spec entry mokev
%p. affine_angle = 0; % Not used by ptycho_recons at all. This allows you to define a variable for the affine matrix below and keep it in p for future record. This is used later by the affine_matrix_search.m script
%p. affine_matrix = [1 , 0; 0, 1] ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
affine_mat = compose_affine_matrix(1, 0, rot_ang, 0);
p. affine_matrix = affine_mat ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
% Scan meta data
p. src_metadata = 'none'; % source of the meta data, following options are supported: 'spec', 'none' , 'artificial' - or add new to +scan/+meta/
p. queue.lockfile = false; % If true writes a lock file, if lock file exists skips recontruction
% Data preparation
p. detector.name = 'empad'; % see +detectors/ folder
p. detector.check_2_detpos = []; % = []; (ignores) = 270; compares to dettrx to see if p.ctr should be reversed (for OMNY shared scans 1221122), make equal to the middle point of dettrx between the 2 detector positions
p. detector.data_prefix = ''; % Default using current eaccount e.g. e14169_1_
p. detector.binning = false; % = true to perform 2x2 binning of detector pixels, for binning = N do 2^Nx2^N binning
p. detector.upsampling = false; % upsample the measured data by 2^data_upsampling, (transposed operator to the binning), it can be used for superresolution in nearfield ptychography or to account for undersampling in a far-field dataset
p. detector.burst_frames = 1; % number of frames collected per scan position
p. prepare.data_preparator = 'matlab_aps'; % data preparator; 'python' or 'matlab' or 'matlab_aps'
p. prepare.auto_prepare_data = true; % if true: prepare dataset from raw measurements if the prepared data does not exist
p. prepare.force_preparation_data = true; % Prepare dataset even if it exists, it will overwrite the file % Default: @prepare_data_2d
p. prepare.store_prepared_data = false; % store the loaded data to h5 even for non-external engines (i.e. other than c_solver)
p. prepare.prepare_data_function = ''; % (used only if data should be prepared) custom data preparation function handle;
p. prepare.auto_center_data = false; % if matlab data preparator is used, try to automatically center the diffraction pattern to keep center of mass in center of diffraction
% Scan positions
p. src_positions = 'matlab_pos'; % 'spec', 'orchestra', 'load_from_file', 'matlab_pos' (scan params are defined below) or add new position loaders to +scan/+positions/
p. positions_file = ''; %Filename pattern for position files, Example: ['../../specES1/scan_positions/scan_%05d.dat']; (the scan number will be automatically filled in)
% scan parameters for option src_positions = 'matlab_pos';
p. scan.type = 'raster'; % {'round', 'raster', 'round_roi', 'custom'}
p. scan.roi_label = roi_label; % For APS data
p. scan.format = scan_string_format; % For APS data format for scan directory generation
p. scan.radius_in = 0; % round scan: interior radius of the round scan
p. scan.radius_out = 5e-6; % round scan: exterior radius of the round scan
p. scan.nr = 10; % round scan: number of intervals (# of shells - 1)
p. scan.nth = 3; % round scan: number of points in the first shell
p. scan.lx = 20e-6; % round_roi scan: width of the roi
p. scan.ly = 20e-6; % round_roi scan: height of the roi
p. scan.dr = 1.5e-6; % round_roi scan: shell step size
p. scan.nx = N_scan_x; %size(dp,3) % raster scan: number of steps in x
p. scan.ny = N_scan_y; % raster scan: number of steps in y
p. scan.step_size_x = scan_step_size; % raster scan: step size (grid spacing)
p. scan.step_size_y = scan_step_size; % raster scan: step size (grid spacing)
p. scan.custom_flip = [1,1,1]; % raster scan: apply custom flip [fliplr, flipud, transpose] to positions- similar to eng.custom_data_flip in GPU engines. Added by ZC.
p. scan.step_randn_offset = 0; % raster scan: relative random offset from the ideal periodic grid to avoid the raster grid pathology
p. scan.b = 0; % fermat: angular offset
p. scan.n_max = 1e4; % fermat: maximal number of points generated
p. scan.step = 0.5e-6; % fermat: step size
p. scan.cenxy = [0,0]; % fermat: position of center offset
p. scan.roi = []; % Region of interest in the object [xmin xmax ymin ymax] in meters. Points outside this region are not used for reconstruction.
% (relative to upper corner for raster scans and to center for round scans)
% custom: a string name of a function that defines the positions; also accepts mat file with entry 'pos', see +scans/+positions/+mat_pos.m
p. scan.custom_positions_source = '';
p. scan.custom_params = []; % custom: the parameters to feed to the custom position function.
% I/O
p. prefix = ''; % For automatic output filenames. If empty: scan number
p. suffix = strcat('ML_recon'); % Optional suffix for reconstruction
p. scan_string_format = scan_string_format; % format for scan string generation, it is used e.g for plotting and data saving
%%%p. base_path = '../../'; % base path : used for automatic generation of other paths
p. base_path = base_path; % base path : used for automatic generation of other paths
p. specfile = ''; % Name of spec file to get motor positions and check end of scan, defaut is p.spec_file == p.base_path;
p. ptycho_matlab_path = ''; % cSAXS ptycho package path
p. cSAXS_matlab_path = ''; % cSAXS base package path
p. raw_data_path{1} = ''; % Default using compile_x12sa_filename, used only if data should be prepared automatically
p. prepare_data_path = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. prepare_data_filename = []; % Leave empty for default file name generation, otherwise use [sprintf('S%05d_data_%03dx%03d',p.scan_number(1), p.asize(1), p.asize(2)) p.prep_data_suffix '.h5'] as default
p. save_path{1} = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. io.default_mask_file = ''; % load detector mask defined in this file instead of the mask in the detector packages, (used only if data should be prepared)
p. io.default_mask_type = 'binary'; % (used only if data should be prepared) ['binary', 'indices']. Default: 'binary'
p. io.file_compression = 0; % reconstruction file compression for HDF5 files; 0 for no compression
p. io.data_compression = 3; % prepared data file compression for HDF5 files; 0 for no compression
p. io.load_prep_pos = false; % load positions from prepared data file and ignore positions provided by metadata
p. io.data_descriptor = par.extra_print_info; %added by YJ. A short string that describe data when sending notifications
p. io.phone_number = ''; % phone number for sending messages
p. io.send_failed_scans_SMS = false; % send message if p.queue_max_attempts is exceeded
p. io.send_finished_recon_SMS = false; % send message after the reconstruction is completed
p. io.send_crashed_recon_SMS = false; % send message if the reconstruction crashes
p. io.SMS_sleep = 1800; % max 1 message per SMS_sleep seconds
p. io.script_name = mfilename; % added by YJ. store matlab script name
p. artificial_data_file = 'template_artificial_data'; % artificial data parameters, set p.src_metadata = 'artificial' to use this template
%% Reconstruction
% Initial iterate object, load from previous results if
% load_results_path is in the parameter file. Use random object and
% ideal probe otherwise.
if isfield(par, 'load_object_path')
p.model_object = false;
p.initial_iterate_object_file{1} = par.load_object_path;
if isfield(par, 'load_probe_path')
p.initial_probe_file = par.load_probe_path;
else
p.initial_probe_file = par.load_object_path;
end
p.multiple_layers_obj = true;
else
initial_probe_file = fullfile(par.result_dir, num2str(scan_number), '/init_probe.mat');
p.model_object = true;
p.model.object_type = 'rand';
p.initial_probe_file = initial_probe_file;
end
% Initial iterate probe
p. model_probe = false; % Use model probe, if false load it from file
p. model.probe_alpha_max = par.alpha_max; % Modal STEM probe's aperture size
p. model.probe_df = par.defocus; % Modal STEM probe's defocus
p. model.probe_c3 = 0; % Modal STEM probe's third-order spherical aberration in angstrom (optional)
p. model.probe_c5 = 0; % Modal STEM probe's fifth-order spherical aberration in angstrom (optional)
p. model.probe_c7 = 0; % Modal STEM probe's seventh-order spherical aberration in angstrom (optional)
p. model.probe_f_a2 = 0; % Modal STEM probe's twofold astigmatism in angstrom (optional)
p. model.probe_theta_a2 = 0; % Modal STEM probe's twofold azimuthal orientation in radian (optional)
p. model.probe_f_a3 = 0; % Modal STEM probe's threefold astigmatism in angstrom (optional)
p. model.probe_theta_a3 = 0; % Modal STEM probe's threefold azimuthal orientation in radian (optional)
p. model.probe_f_c3 = 0; % Modal STEM probe's coma in angstrom (optional)
p. model.probe_theta_c3 = 0; % Modal STEM probe's coma azimuthal orientation in radian (optional)
%Use probe from this mat-file (not used if model_probe is true)
p. probe_file_propagation = 0.0e-3; % Distance for propagating the probe from file in meters, = 0 to ignore
p. normalize_init_probe = true; % Added by YJ. Can be used to disable normalization of initial probes
% Shared scans - Currently working only for sharing probe and object
p. share_probe = 0; % Share probe between scans. Can be either a number/boolean or a list of numbers, specifying the probe index; e.g. [1 2 2] to share the probes between the second and third scan.
p. share_object = 0; % Share object between scans. Can be either a number/boolean or a list of numbers, specifying the object index; e.g. [1 2 2] to share the objects between the second and third scan.
% Modes
p. probe_modes = Nprobe; % Number of coherent modes for probe
p. object_modes = 1; % Number of coherent modes for object
% Mode starting guess
p. mode_start_pow = 0.02; % Normalized intensity on probe modes > 1. Can be a number (all higher modes equal) or a vector
p. mode_start = 'herm'; % (for probe) = 'rand', = 'herm' (Hermitian-like base), = 'hermver' (vertical modes only), = 'hermhor' (horizontal modes only)
p. ortho_probes = true; % orthogonalize probes after each engine
%% Plot, save and analyze
p. plot.prepared_data = false; % plot prepared data
p. plot.interval = []; % plot each interval-th iteration, does not work for c_solver code
p. plot.log_scale = [0 0]; % Plot on log scale for x and y
p. plot.realaxes = true; % Plots show scale in microns
p. plot.remove_phase_ramp = false; % Remove phase ramp from the plotted / saved phase figures
p. plot.fov_box = false; % Plot the scanning FOV box on the object (both phase and amplitude)
p. plot.fov_box_color = 'r'; % Color of the scanning FOV box
p. plot.positions = true; % Plot the scanning positions
p. plot.mask_bool = true; % Mask the noisy contour of the reconstructed object in plots
p. plot.windowautopos = true; % First plotting will auto position windows
p. plot.obj_apod = false; % Apply apodization to the reconstructed object;
p. plot.prop_obj = 0; % Distance to propagate reconstructed object before plotting [m]
p. plot.show_layers = true; % show each layer in multilayer reconstruction
p. plot.show_layers_stack = false; % show each layer in multilayer reconstruction by imagesc3D
p. plot.object_spectrum = []; % Plot propagated object (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.probe_spectrum = []; % Plot propagated probe (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.conjugate = false; % plot complex conjugate of the reconstruction
p. plot.horz_fact = 2.5; % Scales the space that the ptycho figures take horizontally
p. plot.FP_maskdim = 180e-6; % Filter the backpropagation (Fourier Ptychography)
p. plot.calc_FSC = false; % Calculate the Fourier Shell correlation for 2 scans or compare with model in case of artificial data tests
p. plot.show_FSC = false; % Show the FSC plots, including the cropped FOV
p. plot.residua = false; % highlight phase-residua in the image of the reconstructed phase
p. save.external = true; % Use a new Matlab session to run save final figures (saves ~6s per reconstruction). Please be aware that this might lead to an accumulation of Matlab sessions if your single reconstruction is very fast.
p. save.store_images = false; % Write preview images containing the final reconstructions in [p.base_path,'analysis/online/ptycho/'] if p.use_display = 0 then the figures are opened invisible in order to create the nice layout. It writes images in analysis/online/ptycho
p. save.store_images_intermediate = false; % save images to disk after each engine
p. save.store_images_ids = 1:4; % identifiers of the figure to be stored, 1=obj. amplitude, 2=obj. phase, 3=probes, 4=errors, 5=probes spectrum, 6=object spectrum
p. save.store_images_format = 'png'; % data type of the stored images jpg or png
p. save.store_images_dpi = 150; % DPI of the stored bitmap images
p. save.exclude = {'fmag', 'fmask', 'illum_sum'}; % exclude variables to reduce the file size on disk
p. save.save_reconstructions_intermediate = false; % save final object and probes after each engine
p. save.save_reconstructions = false; % save reconstructed object and probe when full reconstruction is finished
p. save.output_file = 'h5'; % data type of reconstruction file; 'h5' or 'mat'
if isfield(par, 'diff_pattern_blur')
p. diff_pattern_blur = par.diff_pattern_blur;
end
%% %%%%%%%%%%%%%%%%%% initialize reconstruction parameters %%%%%%%%%%%%%%%%%%%%
% --------- GPU engines ------------- See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng = struct(); % reset settings for this engine
eng. name = 'GPU_MS';
eng. use_gpu = true; % if false, run CPU code, but it will get very slow
eng. keep_on_gpu = true; % keep data + projections on GPU, false is useful for large data if DM is used
eng. compress_data = false; % use automatic online memory compression to limit need of GPU memory
eng. gpu_id = gpu_id; % default GPU id, [] means choosen by matlab
eng. check_gpu_load = true; % check available GPU memory before starting GPU engines
% general
eng. number_iterations = Niter; % number of iterations for selected method
if isfield(par, 'CBED_crop')
eng.asize_presolve = [par.CBED_crop, par.CBED_crop];
else
eng. asize_presolve = [par.CBED_size, par.CBED_size]; % crop data to "asize_presolve" size to get low resolution estimate that can be used in the next engine as a good initial guess
end
eng. align_shared_objects = false; % before merging multiple unshared objects into one shared, the object will be aligned and the probes shifted by the same distance -> use for alignement and shared reconstruction of drifting scans
eng. method = 'MLs'; % choose GPU solver: DM, ePIE, hPIE, MLc, Mls, -- recommended are MLc and MLs
eng. opt_errmetric = 'poisson'; % optimization likelihood - poisson, L1
if isfield(par, 'grouping')
eng.grouping = par.grouping;
else
eng.grouping = 64;
end % size of processed blocks, larger blocks need more memory but they use GPU more effeciently, !!! grouping == inf means use as large as possible to fit into memory
% * for hPIE, ePIE, MLs methods smaller blocks lead to faster convergence,
% * for MLc the convergence is similar
% * for DM is has no effect on convergence
eng. probe_modes = p.probe_modes; % Number of coherent modes for probe
if isfield(par, 'object_change_start')
eng. object_change_start = par.object_change_start;
else
eng. object_change_start = 1; % Start updating object at this iteration number
end
if isfield(par, 'probe_change_start')
eng.probe_change_start = par.probe_change_start;
else
eng. probe_change_start = 1; % Start updating probe at this iteration number
end
% regularizations
if isfield(par, 'reg_mu')
eng.reg_mu = par.reg_mu; % Regularization (smooting) constant ( reg_mu = 0 for no regularization)
else
eng.reg_mu = 0;
end
eng. delta = 0; % press values to zero out of the illumination area in th object, usually 1e-2 is enough
eng. positivity_constraint_object = 0; % enforce weak (relaxed) positivity in object, ie O = O*(1-a)+a*|O|, usually a=1e-2 is already enough. Useful in conbination with OPRP or probe_fourier_shift_search
eng. apply_multimodal_update = false; % apply all incoherent modes to object, it can cause isses if the modes collect some crap
eng. probe_backpropagate = 0; % backpropagation distance the probe mask, 0 == apply in the object plane. Useful for pinhole imaging where the support can be applied at the pinhole plane
eng. probe_support_radius = []; % Normalized radius of circular support, = 1 for radius touching the window
eng. probe_support_fft = false; % assume that there is not illumination intensity out of the central FZP cone and enforce this contraint. Useful for imaging with focusing optics. Helps to remove issues from the gaps between detector modules.
% basic recontruction parameters
% PIE / ML methods % See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. beta_object = 1.0; % object step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. beta_probe = 1.0; % probe step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. delta_p = 0.1; % LSQ dumping constant, 0 == no preconditioner, 0.1 is usually safe, Preconditioner accelerates convergence and ML methods become approximations of the second order solvers
eng. momentum = 0; % add momentum acceleration term to the MLc method, useful if the probe guess is very poor or for acceleration of multilayer solver, but it is quite computationally expensive to be used in conventional ptycho without any refinement.
% The momentum method works usually well even with the accelerated_gradients option. eng.momentum = multiplication gain for velocity, eng.momentum == 0 -> no acceleration, eng.momentum == 0.5 is a good value
% momentum is enabled only when par.Niter < par.accelerated_gradients_start;
eng. accelerated_gradients_start = inf; % iteration number from which the Nesterov gradient acceleration should be applied, this option is supported only for MLc method. It is very computationally cheap way of convergence acceleration.
% DM
eng. pfft_relaxation = 0.05; % Relaxation in the Fourier domain projection, = 0 for full projection
eng. probe_regularization = 0.1; % Weight factor for the probe update (inertia)
% ADVANCED OPTIONS See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
% position refinement
eng. apply_subpix_shift = true; % apply FFT-based subpixel shift, it is automatically allowed for position refinement
if isfield(par, 'probe_position_search')
eng.probe_position_search = par.probe_position_search;
else
eng. probe_position_search = 50; % iteration number from which the engine will reconstruct probe positions, from iteration == probe_position_search, assume they have to match geometry model with error less than probe_position_error_max
end
%eng. probe_geometry_model = {'scale', 'asymmetry', 'rotation', 'shear'}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_geometry_model = {}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_position_error_max = inf; % maximal expected random position errors, probe prositions are confined in a circle with radius defined by probe_position_error_max and with center defined by original positions scaled by probe_geometry_model
eng. apply_relaxed_position_constraint = false; % added by YJ. Apply a relaxed constraint to probe positions. default = true. Set to false if there are big jumps in positions.
eng. update_pos_weight_every = inf; % added by YJ. Allow position weight to be updated multiple times. default = inf: only update once.
% multilayer extension
eng. delta_z = delta_z*ones(Nlayers,1); % if not empty, use multilayer ptycho extension , see ML_MS code for example of use, [] == common single layer ptychography , note that delta_z provides only relative propagation distance from the previous layer, ie delta_z can be either positive or negative. If preshift_ML_probe == false, the first layer is defined by position of initial probe plane. It is useful to use eng.momentum for convergence acceleration
if isfield(par, 'regularize_layers')
eng.regularize_layers = par.regularize_layers;
else
eng. regularize_layers = 1; % multilayer extension: 0<R<<1 -> apply regularization on the reconstructed object layers, 0 == no regularization, 0.01 == weak regularization that will slowly symmetrize information content between layers
end
eng. preshift_ML_probe = false; % multilayer extension: if true, assume that the provided probe is reconstructed in center of the sample and the layers are centered around this position
eng. layer4pos = []; % Added by ZC. speficy which layer is used for position correction ; if empty, then default, ceil(Nlayers/2)
eng. init_layer_select = []; % Added by YJ. Select layers in the initial object for pre-processing. If empty (default): use all layers.
eng. init_layer_preprocess = ''; % Added by YJ. Specify how to pre-process initial layers
% '' or 'all' (default): use all layers (do nothing)
% 'avg': average all layers
% 'interp': interpolate layers using spline method. Need to specify desired depths in init_layer_interp
eng. init_layer_interp = []; % Specify desired depths for interpolation. The depths of initial are [1:Nlayer_init]. If empty (default), no interpolation
if isfield(par, 'init_layer_append_mode')
eng.init_layer_append_mode = par.init_layer_append_mode;
else
eng. init_layer_append_mode = 'vac';
end
% Added by YJ. Specify how to initialize extra layers
% '' or 'vac' (default): add vacuum layers
% 'edge': append 1st or last layers
% 'avg': append averaged layer
eng. init_layer_scaling_factor = 1; % Added by YJ. Scale all layers. Default: 1 (no scaling). Useful when delta_z is changed
% other extensions
eng. background = 0; % average background scattering level, for OMNI values around 0.3 for 100ms, for flOMNI <0.1 per 100ms exposure, see for more details: Odstrcil, M., et al., Optics letters 40.23 (2015): 5574-5577.
eng. background_width = inf; % width of the background function in pixels, inf == flat background, background function is then convolved with the average diffraction pattern in order to account for beam diversion
eng. clean_residua = false; % remove phase residua from reconstruction by iterative unwrapping, it will result in low spatial freq. artefacts -> object can be used as an residua-free initial guess for netx engine
% wavefront & camera geometry refinement See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. probe_fourier_shift_search = inf; % iteration number from which the engine will: refine farfield position of the beam (ie angle) from iteration == probe_fourier_shift_search
eng. estimate_NF_distance = inf; % iteration number from which the engine will: try to estimate the nearfield propagation distance using gradient descent optimization
eng. detector_rotation_search = inf; % iteration number from which the engine will: search for optimal detector rotation, preferably use with option mirror_scan = true , rotation of the detector axis with respect to the sample axis, similar as rotation option in the position refinement geometry model but works also for 0/180deg rotation shared scans
eng. detector_scale_search = inf; % iteration number from which the engine will: refine pixel scale of the detector, can be used to refine propagation distance in ptycho
if isfield(par, 'variable_probe') && strcmp(par.variable_probe,'false')
eng.variable_probe = false;
else
eng.variable_probe = true;
end
% eng. variable_probe = true; % Use SVD to account for variable illumination during a single (coupled) scan, see for more details: Odstrcil, M. et al. Optics express 24.8 (2016): 8360-8369.
eng. variable_probe_modes = 1; % OPRP settings , number of SVD modes using to describe the probe evolution.
eng. variable_probe_smooth = 0; % OPRP settings , enforce of smooth evolution of the OPRP modes -> N is order of polynomial fit used for smoothing, 0 == do not apply any smoothing. Smoothing is useful if only a smooth drift is assumed during the ptycho acquisition
eng. variable_intensity = false; % account to changes in probe intensity
% extra analysis
eng. get_fsc_score = false; % measure evolution of the Fourier ring correlation during convergence
eng. mirror_objects = false; % mirror objects, useful for 0/180deg scan sharing -> geometry refinement for tomography, works only if 2 scans are provided
% custom data adjustments, useful for offaxis ptychography
eng.auto_center_data = false; % autoestimate the center of mass from data and shift the diffraction patterns so that the average center of mass corresponds to center of mass of the provided probe
eng.auto_center_probe = false; % center the probe position in real space before reconstruction is started
eng.custom_data_flip = [0,0,0]; % apply custom flip of the data [fliplr, flipud, transpose] - can be used for quick testing of reconstruction with various flips or for reflection ptychography
eng.apply_tilted_plane_correction = ''; % if any(p.sample_rotation_angles([1,2]) ~= 0), this option will apply tilted plane correction. (a) 'diffraction' apply correction into the data, note that it is valid only for "low NA" illumination Gardner, D. et al., Optics express 20.17 (2012): 19050-19059. (b) 'propagation' - use tilted plane propagation, (c) '' - will not apply any correction
% I/O
eng.plot_results_every = Niter_plot_results;
eng.save_results_every = Niter_save_results;
eng.save_images ={'obj_ph_stack','obj_ph_sum','probe'};
eng.extraPrintInfo = par.extra_print_info;
resultDir = strcat(p.base_path,sprintf(p.scan.format, p.scan_number),'/roi',p.scan.roi_label,'/');
[eng.fout, p.suffix] = generateResultDir(eng, resultDir);
%add engine
[p, ~] = core.append_engine(p, eng); % Adds this engine to the reconstruction process
%% Run the reconstruction
tic
out = core.ptycho_recons(p);
toc
end
+388
View File
@@ -0,0 +1,388 @@
function run_multislice_new_probepad(parfile)
par = parameter_builder(parfile);
addpath(strcat(pwd,'/utils/'))
addpath(core.find_base_package)
%%%%%%%%%%%%%%%%%%%% data parameters %%%%%%%%%%%%%%%%%%%%
base_path = par.result_dir;
roi_label = par.roi_label;
scan_number = par.scan_number;
scan_string_format = '%01d';
Ndpx = par.CBED_size; % size of cbed
alpha0 = par.alpha_max; % semi-convergence angle (mrad)
rbf = par.rbf; % radius of the BF disk in cbed. Can be used to calculate dk
voltage = par.voltage;
rot_ang = par.rot_ang; %angle between cbed and scan coord.
scan_step_size = par.scan_step_size; %angstrom
N_scan_y = par.N_scan_y; %number of scan points
N_scan_x = par.N_scan_x;
%%%%%%%%%%%%%%%%%%%% reconstruction parameters %%%%%%%%%%%%%%%%%%%%
gpu_id = 1;
Niter = par.Niter;
Niter_save_results = par.Niter_save_results;
Niter_plot_results = inf;
Nprobe = par.Nprobe; % # of probe modes
thickness = par.thickness; % sample thickness in angstrom
Nlayers = round(par.Nlayers); % # of slices for multi-slice, 1 for single-slice
delta_z = thickness / Nlayers;
%% %%%%%%%%%%%%%%%%%% initialize data parameters %%%%%%%%%%%%%%%%%%%%
p = struct();
p. verbose_level = 2; % verbosity for standard output (0-1 for loops, 2-3 for testing and adjustments, >= 4 for debugging)
p. use_display = false; % global switch for display, if [] then true for verbose > 1
p. scan_number = scan_number; % Multiple scan numbers for shared scans
% Geometry
p. z = 1; % Distance from object to detector. Always 1 for electron ptycho
p. asize = [Ndpx,Ndpx]; % Diffr. patt. array size
p. ctr = [fix(Ndpx/2)+1, fix(Ndpx/2)+1]; % Diffr. patt. center coordinates (y,x) (empty means middle of the array); e.g. [100 207;100+20 207+10];
p. beam_source = 'electron'; % Added by YJ for electron pty. Use relativistic corrected formula for wavelength. Also change the units on figures
%p. dk = dk; % Added by YJ. dk is the pixel size in cbed (1/A). This is used to determine pixel size in electron ptycho
p. d_alpha = alpha0/rbf; % Added by YJ. d_alpha is the pixel size in cbed (mrad). This is used to determine pixel size in electron ptycho
p. prop_regime = 'farfield'; % propagation regime: nearfield, farfield (default), !! nearfield is supported only by GPU engines
p. focus_to_sample_distance = []; % sample to focus distance, parameter to be set for nearfield ptychography, otherwise it is ignored
p. energy = voltage; % Energy (in keV), leave empty to use spec entry mokev
%p. affine_angle = 0; % Not used by ptycho_recons at all. This allows you to define a variable for the affine matrix below and keep it in p for future record. This is used later by the affine_matrix_search.m script
%p. affine_matrix = [1 , 0; 0, 1] ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
affine_mat = compose_affine_matrix(1, 0, rot_ang, 0);
p. affine_matrix = affine_mat ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
% Scan meta data
p. src_metadata = 'none'; % source of the meta data, following options are supported: 'spec', 'none' , 'artificial' - or add new to +scan/+meta/
p. queue.lockfile = false; % If true writes a lock file, if lock file exists skips recontruction
% Data preparation
p. detector.name = 'empad'; % see +detectors/ folder
p. detector.check_2_detpos = []; % = []; (ignores) = 270; compares to dettrx to see if p.ctr should be reversed (for OMNY shared scans 1221122), make equal to the middle point of dettrx between the 2 detector positions
p. detector.data_prefix = ''; % Default using current eaccount e.g. e14169_1_
p. detector.binning = false; % = true to perform 2x2 binning of detector pixels, for binning = N do 2^Nx2^N binning
%p. detector.upsampling = false; % upsample the measured data by 2^data_upsampling, (transposed operator to the binning), it can be used for superresolution in nearfield ptychography or to account for undersampling in a far-field dataset
p. detector.burst_frames = 1; % number of frames collected per scan position
p. detector.upsampling = 1; % Lopa Edit for padding the porbe (aka interpolating the diffraction pattern)
p. prepare.data_preparator = 'matlab_aps'; % data preparator; 'python' or 'matlab' or 'matlab_aps'
p. prepare.auto_prepare_data = true; % if true: prepare dataset from raw measurements if the prepared data does not exist
p. prepare.force_preparation_data = true; % Prepare dataset even if it exists, it will overwrite the file % Default: @prepare_data_2d
p. prepare.store_prepared_data = false; % store the loaded data to h5 even for non-external engines (i.e. other than c_solver)
p. prepare.prepare_data_function = ''; % (used only if data should be prepared) custom data preparation function handle;
p. prepare.auto_center_data = false; % if matlab data preparator is used, try to automatically center the diffraction pattern to keep center of mass in center of diffraction
% Scan positions
p. src_positions = 'matlab_pos'; % 'spec', 'orchestra', 'load_from_file', 'matlab_pos' (scan params are defined below) or add new position loaders to +scan/+positions/
p. positions_file = ''; %Filename pattern for position files, Example: ['../../specES1/scan_positions/scan_%05d.dat']; (the scan number will be automatically filled in)
% scan parameters for option src_positions = 'matlab_pos';
p. scan.type = 'raster'; % {'round', 'raster', 'round_roi', 'custom'}
p. scan.roi_label = roi_label; % For APS data
p. scan.format = scan_string_format; % For APS data format for scan directory generation
p. scan.radius_in = 0; % round scan: interior radius of the round scan
p. scan.radius_out = 5e-6; % round scan: exterior radius of the round scan
p. scan.nr = 10; % round scan: number of intervals (# of shells - 1)
p. scan.nth = 3; % round scan: number of points in the first shell
p. scan.lx = 20e-6; % round_roi scan: width of the roi
p. scan.ly = 20e-6; % round_roi scan: height of the roi
p. scan.dr = 1.5e-6; % round_roi scan: shell step size
p. scan.nx = N_scan_x; %size(dp,3) % raster scan: number of steps in x
p. scan.ny = N_scan_y; % raster scan: number of steps in y
p. scan.step_size_x = scan_step_size; % raster scan: step size (grid spacing)
p. scan.step_size_y = scan_step_size; % raster scan: step size (grid spacing)
p. scan.custom_flip = [1,1,1]; % raster scan: apply custom flip [fliplr, flipud, transpose] to positions- similar to eng.custom_data_flip in GPU engines. Added by ZC.
p. scan.step_randn_offset = 0; % raster scan: relative random offset from the ideal periodic grid to avoid the raster grid pathology
p. scan.b = 0; % fermat: angular offset
p. scan.n_max = 1e4; % fermat: maximal number of points generated
p. scan.step = 0.5e-6; % fermat: step size
p. scan.cenxy = [0,0]; % fermat: position of center offset
p. scan.roi = []; % Region of interest in the object [xmin xmax ymin ymax] in meters. Points outside this region are not used for reconstruction.
% (relative to upper corner for raster scans and to center for round scans)
% custom: a string name of a function that defines the positions; also accepts mat file with entry 'pos', see +scans/+positions/+mat_pos.m
p. scan.custom_positions_source = '';
p. scan.custom_params = []; % custom: the parameters to feed to the custom position function.
% I/O
p. prefix = ''; % For automatic output filenames. If empty: scan number
p. suffix = strcat('ML_recon'); % Optional suffix for reconstruction
p. scan_string_format = scan_string_format; % format for scan string generation, it is used e.g for plotting and data saving
%%%p. base_path = '../../'; % base path : used for automatic generation of other paths
p. base_path = base_path; % base path : used for automatic generation of other paths
p. specfile = ''; % Name of spec file to get motor positions and check end of scan, defaut is p.spec_file == p.base_path;
p. ptycho_matlab_path = ''; % cSAXS ptycho package path
p. cSAXS_matlab_path = ''; % cSAXS base package path
p. raw_data_path{1} = ''; % Default using compile_x12sa_filename, used only if data should be prepared automatically
p. prepare_data_path = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. prepare_data_filename = []; % Leave empty for default file name generation, otherwise use [sprintf('S%05d_data_%03dx%03d',p.scan_number(1), p.asize(1), p.asize(2)) p.prep_data_suffix '.h5'] as default
p. save_path{1} = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. io.default_mask_file = ''; % load detector mask defined in this file instead of the mask in the detector packages, (used only if data should be prepared)
p. io.default_mask_type = 'binary'; % (used only if data should be prepared) ['binary', 'indices']. Default: 'binary'
p. io.file_compression = 0; % reconstruction file compression for HDF5 files; 0 for no compression
p. io.data_compression = 3; % prepared data file compression for HDF5 files; 0 for no compression
p. io.load_prep_pos = false; % load positions from prepared data file and ignore positions provided by metadata
p. io.data_descriptor = par.extra_print_info; %added by YJ. A short string that describe data when sending notifications
p. io.phone_number = ''; % phone number for sending messages
p. io.send_failed_scans_SMS = false; % send message if p.queue_max_attempts is exceeded
p. io.send_finished_recon_SMS = false; % send message after the reconstruction is completed
p. io.send_crashed_recon_SMS = false; % send message if the reconstruction crashes
p. io.SMS_sleep = 1800; % max 1 message per SMS_sleep seconds
p. io.script_name = mfilename; % added by YJ. store matlab script name
p. artificial_data_file = 'template_artificial_data'; % artificial data parameters, set p.src_metadata = 'artificial' to use this template
%% Reconstruction
% Initial iterate object, load from previous results if
% load_results_path is in the parameter file. Use random object and
% ideal probe otherwise.
if isfield(par, 'load_object_path')
p.model_object = false;
p.initial_iterate_object_file{1} = par.load_object_path;
if isfield(par, 'load_probe_path')
p.initial_probe_file = par.load_probe_path;
else
p.initial_probe_file = par.load_object_path;
end
p.multiple_layers_obj = true;
else
initial_probe_file = fullfile(par.result_dir, num2str(scan_number), '/init_probe.mat');
p.model_object = true;
p.model.object_type = 'rand';
p.initial_probe_file = initial_probe_file;
end
%%line to have only probe loaded instead of both probe and object
if isfield(par, 'load_probe_path')
p.initial_probe_file = par.load_probe_path;
else
initial_probe_file = fullfile(par.result_dir, num2str(scan_number), '/init_probe.mat');
p.initial_probe_file = initial_probe_file;
end
% Initial iterate probe
p. model_probe = false; % Use model probe, if false load it from file
p. model.probe_alpha_max = par.alpha_max; % Modal STEM probe's aperture size
p. model.probe_df = par.defocus; % Modal STEM probe's defocus
p. model.probe_c3 = 0; % Modal STEM probe's third-order spherical aberration in angstrom (optional)
p. model.probe_c5 = 0; % Modal STEM probe's fifth-order spherical aberration in angstrom (optional)
p. model.probe_c7 = 0; % Modal STEM probe's seventh-order spherical aberration in angstrom (optional)
p. model.probe_f_a2 = 0; % Modal STEM probe's twofold astigmatism in angstrom (optional)
p. model.probe_theta_a2 = 0; % Modal STEM probe's twofold azimuthal orientation in radian (optional)
p. model.probe_f_a3 = 0; % Modal STEM probe's threefold astigmatism in angstrom (optional)
p. model.probe_theta_a3 = 0; % Modal STEM probe's threefold azimuthal orientation in radian (optional)
p. model.probe_f_c3 = 0; % Modal STEM probe's coma in angstrom (optional)
p. model.probe_theta_c3 = 0; % Modal STEM probe's coma azimuthal orientation in radian (optional)
%Use probe from this mat-file (not used if model_probe is true)
p. probe_file_propagation = 0.0e-3; % Distance for propagating the probe from file in meters, = 0 to ignore
p. normalize_init_probe = true; % Added by YJ. Can be used to disable normalization of initial probes
p. crop_pad_init_probe = true; % Lopa Edit for padding the probe
% Shared scans - Currently working only for sharing probe and object
p. share_probe = 0; % Share probe between scans. Can be either a number/boolean or a list of numbers, specifying the probe index; e.g. [1 2 2] to share the probes between the second and third scan.
p. share_object = 0; % Share object between scans. Can be either a number/boolean or a list of numbers, specifying the object index; e.g. [1 2 2] to share the objects between the second and third scan.
% Modes
p. probe_modes = Nprobe; % Number of coherent modes for probe
p. object_modes = 1; % Number of coherent modes for object
% Mode starting guess
p. mode_start_pow = 0.02; % Normalized intensity on probe modes > 1. Can be a number (all higher modes equal) or a vector
p. mode_start = 'herm'; % (for probe) = 'rand', = 'herm' (Hermitian-like base), = 'hermver' (vertical modes only), = 'hermhor' (horizontal modes only)
p. ortho_probes = true; % orthogonalize probes after each engine
%% Plot, save and analyze
p. plot.prepared_data = false; % plot prepared data
p. plot.interval = []; % plot each interval-th iteration, does not work for c_solver code
p. plot.log_scale = [0 0]; % Plot on log scale for x and y
p. plot.realaxes = true; % Plots show scale in microns
p. plot.remove_phase_ramp = false; % Remove phase ramp from the plotted / saved phase figures
p. plot.fov_box = false; % Plot the scanning FOV box on the object (both phase and amplitude)
p. plot.fov_box_color = 'r'; % Color of the scanning FOV box
p. plot.positions = true; % Plot the scanning positions
p. plot.mask_bool = true; % Mask the noisy contour of the reconstructed object in plots
p. plot.windowautopos = true; % First plotting will auto position windows
p. plot.obj_apod = false; % Apply apodization to the reconstructed object;
p. plot.prop_obj = 0; % Distance to propagate reconstructed object before plotting [m]
p. plot.show_layers = true; % show each layer in multilayer reconstruction
p. plot.show_layers_stack = false; % show each layer in multilayer reconstruction by imagesc3D
p. plot.object_spectrum = []; % Plot propagated object (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.probe_spectrum = []; % Plot propagated probe (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.conjugate = false; % plot complex conjugate of the reconstruction
p. plot.horz_fact = 2.5; % Scales the space that the ptycho figures take horizontally
p. plot.FP_maskdim = 180e-6; % Filter the backpropagation (Fourier Ptychography)
p. plot.calc_FSC = false; % Calculate the Fourier Shell correlation for 2 scans or compare with model in case of artificial data tests
p. plot.show_FSC = false; % Show the FSC plots, including the cropped FOV
p. plot.residua = false; % highlight phase-residua in the image of the reconstructed phase
p. save.external = true; % Use a new Matlab session to run save final figures (saves ~6s per reconstruction). Please be aware that this might lead to an accumulation of Matlab sessions if your single reconstruction is very fast.
p. save.store_images = false; % Write preview images containing the final reconstructions in [p.base_path,'analysis/online/ptycho/'] if p.use_display = 0 then the figures are opened invisible in order to create the nice layout. It writes images in analysis/online/ptycho
p. save.store_images_intermediate = false; % save images to disk after each engine
p. save.store_images_ids = 1:4; % identifiers of the figure to be stored, 1=obj. amplitude, 2=obj. phase, 3=probes, 4=errors, 5=probes spectrum, 6=object spectrum
p. save.store_images_format = 'png'; % data type of the stored images jpg or png
p. save.store_images_dpi = 150; % DPI of the stored bitmap images
p. save.exclude = {'fmag', 'fmask', 'illum_sum'}; % exclude variables to reduce the file size on disk
p. save.save_reconstructions_intermediate = false; % save final object and probes after each engine
p. save.save_reconstructions = false; % save reconstructed object and probe when full reconstruction is finished
p. save.output_file = 'h5'; % data type of reconstruction file; 'h5' or 'mat'
if isfield(par, 'diff_pattern_blur')
p. diff_pattern_blur = par.diff_pattern_blur;
end
%% %%%%%%%%%%%%%%%%%% initialize reconstruction parameters %%%%%%%%%%%%%%%%%%%%
% --------- GPU engines ------------- See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng = struct(); % reset settings for this engine
eng. name = 'GPU_MS';
eng. use_gpu = true; % if false, run CPU code, but it will get very slow
eng. keep_on_gpu = true; % keep data + projections on GPU, false is useful for large data if DM is used
eng. compress_data = false; % use automatic online memory compression to limit need of GPU memory
eng. gpu_id = gpu_id; % default GPU id, [] means choosen by matlab
eng. check_gpu_load = true; % check available GPU memory before starting GPU engines
% general
eng. number_iterations = Niter; % number of iterations for selected method
if isfield(par, 'CBED_crop')
eng.asize_presolve = [par.CBED_crop, par.CBED_crop];
else
eng. asize_presolve = [par.CBED_size, par.CBED_size]; % crop data to "asize_presolve" size to get low resolution estimate that can be used in the next engine as a good initial guess
end
eng. align_shared_objects = false; % before merging multiple unshared objects into one shared, the object will be aligned and the probes shifted by the same distance -> use for alignement and shared reconstruction of drifting scans
eng. method = 'MLs'; % choose GPU solver: DM, ePIE, hPIE, MLc, Mls, -- recommended are MLc and MLs
eng. opt_errmetric = 'L1'; % optimization likelihood - poisson, L1
if isfield(par, 'grouping')
eng.grouping = par.grouping;
else
eng.grouping = 64;
end % size of processed blocks, larger blocks need more memory but they use GPU more effeciently, !!! grouping == inf means use as large as possible to fit into memory
% * for hPIE, ePIE, MLs methods smaller blocks lead to faster convergence,
% * for MLc the convergence is similar
% * for DM is has no effect on convergence
eng. probe_modes = p.probe_modes; % Number of coherent modes for probe
if isfield(par, 'object_change_start')
eng. object_change_start = par.object_change_start;
else
eng. object_change_start = 1; % Start updating object at this iteration number
end
if isfield(par, 'probe_change_start')
eng.probe_change_start = par.probe_change_start;
else
eng. probe_change_start = 1; % Start updating probe at this iteration number
end
% regularizations
if isfield(par, 'reg_mu')
eng.reg_mu = par.reg_mu; % Regularization (smooting) constant ( reg_mu = 0 for no regularization)
else
eng.reg_mu = 0;
end
eng. delta = 0; % press values to zero out of the illumination area in th object, usually 1e-2 is enough
eng. positivity_constraint_object = 0; % enforce weak (relaxed) positivity in object, ie O = O*(1-a)+a*|O|, usually a=1e-2 is already enough. Useful in conbination with OPRP or probe_fourier_shift_search
eng. apply_multimodal_update = false; % apply all incoherent modes to object, it can cause isses if the modes collect some crap
eng. probe_backpropagate = 0; % backpropagation distance the probe mask, 0 == apply in the object plane. Useful for pinhole imaging where the support can be applied at the pinhole plane
eng. probe_support_radius = []; % Normalized radius of circular support, = 1 for radius touching the window
eng. probe_support_fft = false; % assume that there is not illumination intensity out of the central FZP cone and enforce this contraint. Useful for imaging with focusing optics. Helps to remove issues from the gaps between detector modules.
% basic recontruction parameters
% PIE / ML methods % See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. beta_object = 1; % object step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. beta_probe = 1; % probe step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. delta_p = 0.1; % LSQ dumping constant, 0 == no preconditioner, 0.1 is usually safe, Preconditioner accelerates convergence and ML methods become approximations of the second order solvers
eng. momentum = 0; % add momentum acceleration term to the MLc method, useful if the probe guess is very poor or for acceleration of multilayer solver, but it is quite computationally expensive to be used in conventional ptycho without any refinement.
% The momentum method works usually well even with the accelerated_gradients option. eng.momentum = multiplication gain for velocity, eng.momentum == 0 -> no acceleration, eng.momentum == 0.5 is a good value
% momentum is enabled only when par.Niter < par.accelerated_gradients_start;
eng. accelerated_gradients_start = inf; % iteration number from which the Nesterov gradient acceleration should be applied, this option is supported only for MLc method. It is very computationally cheap way of convergence acceleration.
% DM
eng. pfft_relaxation = 0.05; % Relaxation in the Fourier domain projection, = 0 for full projection
eng. probe_regularization = 0.1; % Weight factor for the probe update (inertia)
% ADVANCED OPTIONS See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
% position refinement
eng. apply_subpix_shift = true; % apply FFT-based subpixel shift, it is automatically allowed for position refinement
if isfield(par, 'probe_position_search')
eng.probe_position_search = par.probe_position_search;
else
eng. probe_position_search = 50; % iteration number from which the engine will reconstruct probe positions, from iteration == probe_position_search, assume they have to match geometry model with error less than probe_position_error_max
end
%eng. probe_geometry_model = {'scale', 'asymmetry', 'rotation', 'shear'}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_geometry_model = {}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_position_error_max = inf; % maximal expected random position errors, probe prositions are confined in a circle with radius defined by probe_position_error_max and with center defined by original positions scaled by probe_geometry_model
eng. apply_relaxed_position_constraint = false; % added by YJ. Apply a relaxed constraint to probe positions. default = true. Set to false if there are big jumps in positions.
eng. update_pos_weight_every = inf; % added by YJ. Allow position weight to be updated multiple times. default = inf: only update once.
% multilayer extension
eng. delta_z = delta_z*ones(Nlayers,1); % if not empty, use multilayer ptycho extension , see ML_MS code for example of use, [] == common single layer ptychography , note that delta_z provides only relative propagation distance from the previous layer, ie delta_z can be either positive or negative. If preshift_ML_probe == false, the first layer is defined by position of initial probe plane. It is useful to use eng.momentum for convergence acceleration
if isfield(par, 'regularize_layers')
eng.regularize_layers = par.regularize_layers;
else
eng. regularize_layers = 1; % multilayer extension: 0<R<<1 -> apply regularization on the reconstructed object layers, 0 == no regularization, 0.01 == weak regularization that will slowly symmetrize information content between layers
end
eng. preshift_ML_probe = false; % multilayer extension: if true, assume that the provided probe is reconstructed in center of the sample and the layers are centered around this position
eng. layer4pos = []; % Added by ZC. speficy which layer is used for position correction ; if empty, then default, ceil(Nlayers/2)
eng. init_layer_select = []; % Added by YJ. Select layers in the initial object for pre-processing. If empty (default): use all layers.
eng. init_layer_preprocess = ''; % Added by YJ. Specify how to pre-process initial layers
% '' or 'all' (default): use all layers (do nothing)
% 'avg': average all layers
% 'interp': interpolate layers using spline method. Need to specify desired depths in init_layer_interp
eng. init_layer_interp = []; % Specify desired depths for interpolation. The depths of initial are [1:Nlayer_init]. If empty (default), no interpolation
if isfield(par, 'init_layer_append_mode')
eng.init_layer_append_mode = par.init_layer_append_mode;
else
eng. init_layer_append_mode = 'vac';
end
% Added by YJ. Specify how to initialize extra layers
% '' or 'vac' (default): add vacuum layers
% 'edge': append 1st or last layers
% 'avg': append averaged layer
eng. init_layer_scaling_factor = 1; % Added by YJ. Scale all layers. Default: 1 (no scaling). Useful when delta_z is changed
% other extensions
eng. background = 0; % average background scattering level, for OMNI values around 0.3 for 100ms, for flOMNI <0.1 per 100ms exposure, see for more details: Odstrcil, M., et al., Optics letters 40.23 (2015): 5574-5577.
eng. background_width = inf; % width of the background function in pixels, inf == flat background, background function is then convolved with the average diffraction pattern in order to account for beam diversion
eng. clean_residua = false; % remove phase residua from reconstruction by iterative unwrapping, it will result in low spatial freq. artefacts -> object can be used as an residua-free initial guess for netx engine
% wavefront & camera geometry refinement See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. probe_fourier_shift_search = inf; % iteration number from which the engine will: refine farfield position of the beam (ie angle) from iteration == probe_fourier_shift_search
eng. estimate_NF_distance = inf; % iteration number from which the engine will: try to estimate the nearfield propagation distance using gradient descent optimization
eng. detector_rotation_search = inf; % iteration number from which the engine will: search for optimal detector rotation, preferably use with option mirror_scan = true , rotation of the detector axis with respect to the sample axis, similar as rotation option in the position refinement geometry model but works also for 0/180deg rotation shared scans
eng. detector_scale_search = inf; % iteration number from which the engine will: refine pixel scale of the detector, can be used to refine propagation distance in ptycho
if isfield(par, 'variable_probe') && strcmp(par.variable_probe,'false')
eng.variable_probe = false;
else
eng.variable_probe = true;
end
% eng. variable_probe = true; % Use SVD to account for variable illumination during a single (coupled) scan, see for more details: Odstrcil, M. et al. Optics express 24.8 (2016): 8360-8369.
eng. variable_probe_modes = 1; % OPRP settings , number of SVD modes using to describe the probe evolution.
eng. variable_probe_smooth = 0; % OPRP settings , enforce of smooth evolution of the OPRP modes -> N is order of polynomial fit used for smoothing, 0 == do not apply any smoothing. Smoothing is useful if only a smooth drift is assumed during the ptycho acquisition
eng. variable_intensity = false; % account to changes in probe intensity
% extra analysis
eng. get_fsc_score = false; % measure evolution of the Fourier ring correlation during convergence
eng. mirror_objects = false; % mirror objects, useful for 0/180deg scan sharing -> geometry refinement for tomography, works only if 2 scans are provided
% custom data adjustments, useful for offaxis ptychography
eng.auto_center_data = false; % autoestimate the center of mass from data and shift the diffraction patterns so that the average center of mass corresponds to center of mass of the provided probe
eng.auto_center_probe = false; % center the probe position in real space before reconstruction is started
eng.custom_data_flip = [0,0,0]; % apply custom flip of the data [fliplr, flipud, transpose] - can be used for quick testing of reconstruction with various flips or for reflection ptychography
eng.apply_tilted_plane_correction = ''; % if any(p.sample_rotation_angles([1,2]) ~= 0), this option will apply tilted plane correction. (a) 'diffraction' apply correction into the data, note that it is valid only for "low NA" illumination Gardner, D. et al., Optics express 20.17 (2012): 19050-19059. (b) 'propagation' - use tilted plane propagation, (c) '' - will not apply any correction
% I/O
eng.plot_results_every = Niter_plot_results;
eng.save_results_every = Niter_save_results;
eng.save_images ={'obj_ph_stack','obj_ph_sum','probe'};
eng.extraPrintInfo = par.extra_print_info;
resultDir = strcat(p.base_path,sprintf(p.scan.format, p.scan_number),'/roi',p.scan.roi_label,'/');
[eng.fout, p.suffix] = generateResultDir(eng, resultDir);
%add engine
[p, ~] = core.append_engine(p, eng); % Adds this engine to the reconstruction process
%% Run the reconstruction
tic
out = core.ptycho_recons(p);
toc
end
+379
View File
@@ -0,0 +1,379 @@
function run_multislice_new(parfile)
par = parameter_builder(parfile);
addpath(strcat(pwd,'/utils/'))
addpath(core.find_base_package)
%%%%%%%%%%%%%%%%%%%% data parameters %%%%%%%%%%%%%%%%%%%%
base_path = par.result_dir;
roi_label = par.roi_label;
scan_number = par.scan_number;
scan_string_format = '%01d';
Ndpx = par.CBED_size; % size of cbed
alpha0 = par.alpha_max; % semi-convergence angle (mrad)
rbf = par.rbf; % radius of the BF disk in cbed. Can be used to calculate dk
voltage = par.voltage;
rot_ang = par.rot_ang; %angle between cbed and scan coord.
scan_step_size_x = par.scan_step_size_x; %angstrom
scan_step_size_y = par.scan_step_size_y; %angstrom
N_scan_y = par.N_scan_y; %number of scan points
N_scan_x = par.N_scan_x;
%%%%%%%%%%%%%%%%%%%% reconstruction parameters %%%%%%%%%%%%%%%%%%%%
gpu_id = 1;
Niter = par.Niter;
Niter_save_results = par.Niter_save_results;
Niter_plot_results = inf;
Nprobe = par.Nprobe; % # of probe modes
thickness = par.thickness; % sample thickness in angstrom
Nlayers = round(par.Nlayers); % # of slices for multi-slice, 1 for single-slice
delta_z = thickness / Nlayers;
%% %%%%%%%%%%%%%%%%%% initialize data parameters %%%%%%%%%%%%%%%%%%%%
p = struct();
p. verbose_level = 2; % verbosity for standard output (0-1 for loops, 2-3 for testing and adjustments, >= 4 for debugging)
p. use_display = false; % global switch for display, if [] then true for verbose > 1
p. scan_number = scan_number; % Multiple scan numbers for shared scans
% Geometry
p. z = 1; % Distance from object to detector. Always 1 for electron ptycho
p. asize = [Ndpx,Ndpx]; % Diffr. patt. array size
p. ctr = [fix(Ndpx/2)+1, fix(Ndpx/2)+1]; % Diffr. patt. center coordinates (y,x) (empty means middle of the array); e.g. [100 207;100+20 207+10];
p. beam_source = 'electron'; % Added by YJ for electron pty. Use relativistic corrected formula for wavelength. Also change the units on figures
%p. dk = dk; % Added by YJ. dk is the pixel size in cbed (1/A). This is used to determine pixel size in electron ptycho
p. d_alpha = alpha0/rbf; % Added by YJ. d_alpha is the pixel size in cbed (mrad). This is used to determine pixel size in electron ptycho
p. prop_regime = 'farfield'; % propagation regime: nearfield, farfield (default), !! nearfield is supported only by GPU engines
p. focus_to_sample_distance = []; % sample to focus distance, parameter to be set for nearfield ptychography, otherwise it is ignored
p. energy = voltage; % Energy (in keV), leave empty to use spec entry mokev
%p. affine_angle = 0; % Not used by ptycho_recons at all. This allows you to define a variable for the affine matrix below and keep it in p for future record. This is used later by the affine_matrix_search.m script
%p. affine_matrix = [1 , 0; 0, 1] ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
affine_mat = compose_affine_matrix(1, 0, rot_ang, 0);
p. affine_matrix = affine_mat ; % Applies affine transformation (e.g. rotation, stretching) to the positions (ignore by = []). Convention [yn;xn] = M*[y;x].
% Scan meta data
p. src_metadata = 'none'; % source of the meta data, following options are supported: 'spec', 'none' , 'artificial' - or add new to +scan/+meta/
p. queue.lockfile = false; % If true writes a lock file, if lock file exists skips recontruction
% Data preparation
p. detector.name = 'empad'; % see +detectors/ folder
p. detector.check_2_detpos = []; % = []; (ignores) = 270; compares to dettrx to see if p.ctr should be reversed (for OMNY shared scans 1221122), make equal to the middle point of dettrx between the 2 detector positions
p. detector.data_prefix = ''; % Default using current eaccount e.g. e14169_1_
p. detector.binning = false; % = true to perform 2x2 binning of detector pixels, for binning = N do 2^Nx2^N binning
p. detector.upsampling = false; % upsample the measured data by 2^data_upsampling, (transposed operator to the binning), it can be used for superresolution in nearfield ptychography or to account for undersampling in a far-field dataset
p. detector.burst_frames = 1; % number of frames collected per scan position
p. prepare.data_preparator = 'matlab_aps'; % data preparator; 'python' or 'matlab' or 'matlab_aps'
p. prepare.auto_prepare_data = true; % if true: prepare dataset from raw measurements if the prepared data does not exist
p. prepare.force_preparation_data = true; % Prepare dataset even if it exists, it will overwrite the file % Default: @prepare_data_2d
p. prepare.store_prepared_data = false; % store the loaded data to h5 even for non-external engines (i.e. other than c_solver)
p. prepare.prepare_data_function = ''; % (used only if data should be prepared) custom data preparation function handle;
p. prepare.auto_center_data = false; % if matlab data preparator is used, try to automatically center the diffraction pattern to keep center of mass in center of diffraction
% Scan positions
p. src_positions = 'matlab_pos'; % 'spec', 'orchestra', 'load_from_file', 'matlab_pos' (scan params are defined below) or add new position loaders to +scan/+positions/
p. positions_file = ''; %Filename pattern for position files, Example: ['../../specES1/scan_positions/scan_%05d.dat']; (the scan number will be automatically filled in)
% scan parameters for option src_positions = 'matlab_pos';
p. scan.type = 'raster'; % {'round', 'raster', 'round_roi', 'custom'}
p. scan.roi_label = roi_label; % For APS data
p. scan.format = scan_string_format; % For APS data format for scan directory generation
p. scan.radius_in = 0; % round scan: interior radius of the round scan
p. scan.radius_out = 5e-6; % round scan: exterior radius of the round scan
p. scan.nr = 10; % round scan: number of intervals (# of shells - 1)
p. scan.nth = 3; % round scan: number of points in the first shell
p. scan.lx = 20e-6; % round_roi scan: width of the roi
p. scan.ly = 20e-6; % round_roi scan: height of the roi
p. scan.dr = 1.5e-6; % round_roi scan: shell step size
p. scan.nx = N_scan_x; %size(dp,3) % raster scan: number of steps in x
p. scan.ny = N_scan_y; % raster scan: number of steps in y
p. scan.step_size_x = scan_step_size_x; % raster scan: step size (grid spacing)
p. scan.step_size_y = scan_step_size_y; % raster scan: step size (grid spacing)
p. scan.custom_flip = [1,1,1]; % raster scan: apply custom flip [fliplr, flipud, transpose] to positions- similar to eng.custom_data_flip in GPU engines. Added by ZC.
p. scan.step_randn_offset = 0; % raster scan: relative random offset from the ideal periodic grid to avoid the raster grid pathology
p. scan.b = 0; % fermat: angular offset
p. scan.n_max = 1e4; % fermat: maximal number of points generated
p. scan.step = 0.5e-6; % fermat: step size
p. scan.cenxy = [0,0]; % fermat: position of center offset
p. scan.roi = []; % Region of interest in the object [xmin xmax ymin ymax] in meters. Points outside this region are not used for reconstruction.
% (relative to upper corner for raster scans and to center for round scans)
% custom: a string name of a function that defines the positions; also accepts mat file with entry 'pos', see +scans/+positions/+mat_pos.m
p. scan.custom_positions_source = '';
p. scan.custom_params = []; % custom: the parameters to feed to the custom position function.
% I/O
p. prefix = ''; % For automatic output filenames. If empty: scan number
p. suffix = strcat('ML_recon'); % Optional suffix for reconstruction
p. scan_string_format = scan_string_format; % format for scan string generation, it is used e.g for plotting and data saving
%%%p. base_path = '../../'; % base path : used for automatic generation of other paths
p. base_path = base_path; % base path : used for automatic generation of other paths
p. specfile = ''; % Name of spec file to get motor positions and check end of scan, defaut is p.spec_file == p.base_path;
p. ptycho_matlab_path = ''; % cSAXS ptycho package path
p. cSAXS_matlab_path = ''; % cSAXS base package path
p. raw_data_path{1} = ''; % Default using compile_x12sa_filename, used only if data should be prepared automatically
p. prepare_data_path = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. prepare_data_filename = []; % Leave empty for default file name generation, otherwise use [sprintf('S%05d_data_%03dx%03d',p.scan_number(1), p.asize(1), p.asize(2)) p.prep_data_suffix '.h5'] as default
p. save_path{1} = ''; % Default: base_path + 'analysis'. Other example: '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/'; also supports %u to insert the scan number at a later point (e.g. '/afs/psi.ch/project/CDI/cSAXS_project/analysis2/S%.5u')
p. io.default_mask_file = ''; % load detector mask defined in this file instead of the mask in the detector packages, (used only if data should be prepared)
p. io.default_mask_type = 'binary'; % (used only if data should be prepared) ['binary', 'indices']. Default: 'binary'
p. io.file_compression = 0; % reconstruction file compression for HDF5 files; 0 for no compression
p. io.data_compression = 3; % prepared data file compression for HDF5 files; 0 for no compression
p. io.load_prep_pos = false; % load positions from prepared data file and ignore positions provided by metadata
p. io.data_descriptor = par.extra_print_info; %added by YJ. A short string that describe data when sending notifications
p. io.phone_number = ''; % phone number for sending messages
p. io.send_failed_scans_SMS = false; % send message if p.queue_max_attempts is exceeded
p. io.send_finished_recon_SMS = false; % send message after the reconstruction is completed
p. io.send_crashed_recon_SMS = false; % send message if the reconstruction crashes
p. io.SMS_sleep = 1800; % max 1 message per SMS_sleep seconds
p. io.script_name = mfilename; % added by YJ. store matlab script name
p. artificial_data_file = 'template_artificial_data'; % artificial data parameters, set p.src_metadata = 'artificial' to use this template
%% Reconstruction
% Initial iterate object, load from previous results if
% load_results_path is in the parameter file. Use random object and
% ideal probe otherwise.
if isfield(par, 'load_object_path')
p.model_object = false;
p.initial_iterate_object_file{1} = par.load_object_path;
if isfield(par, 'load_probe_path')
p.initial_probe_file = par.load_probe_path;
else
p.initial_probe_file = par.load_object_path;
end
p.multiple_layers_obj = true;
else
initial_probe_file = fullfile(par.result_dir, num2str(scan_number), '/init_probe.mat');
p.model_object = true;
p.model.object_type = 'rand';
p.initial_probe_file = initial_probe_file;
end
% Initial iterate probe
p. model_probe = false; % Use model probe, if false load it from file
p. model.probe_alpha_max = par.alpha_max; % Modal STEM probe's aperture size
p. model.probe_df = par.defocus; % Modal STEM probe's defocus
p. model.probe_c3 = 0; % Modal STEM probe's third-order spherical aberration in angstrom (optional)
p. model.probe_c5 = 0; % Modal STEM probe's fifth-order spherical aberration in angstrom (optional)
p. model.probe_c7 = 0; % Modal STEM probe's seventh-order spherical aberration in angstrom (optional)
p. model.probe_f_a2 = 0; % Modal STEM probe's twofold astigmatism in angstrom (optional)
p. model.probe_theta_a2 = 0; % Modal STEM probe's twofold azimuthal orientation in radian (optional)
p. model.probe_f_a3 = 0; % Modal STEM probe's threefold astigmatism in angstrom (optional)
p. model.probe_theta_a3 = 0; % Modal STEM probe's threefold azimuthal orientation in radian (optional)
p. model.probe_f_c3 = 0; % Modal STEM probe's coma in angstrom (optional)
p. model.probe_theta_c3 = 0; % Modal STEM probe's coma azimuthal orientation in radian (optional)
%Use probe from this mat-file (not used if model_probe is true)
p. probe_file_propagation = 0.0e-3; % Distance for propagating the probe from file in meters, = 0 to ignore
p. normalize_init_probe = true; % Added by YJ. Can be used to disable normalization of initial probes
% Shared scans - Currently working only for sharing probe and object
p. share_probe = 0; % Share probe between scans. Can be either a number/boolean or a list of numbers, specifying the probe index; e.g. [1 2 2] to share the probes between the second and third scan.
p. share_object = 0; % Share object between scans. Can be either a number/boolean or a list of numbers, specifying the object index; e.g. [1 2 2] to share the objects between the second and third scan.
% Modes
p. probe_modes = Nprobe; % Number of coherent modes for probe
p. object_modes = 1; % Number of coherent modes for object
% Mode starting guess
p. mode_start_pow = 0.02; % Normalized intensity on probe modes > 1. Can be a number (all higher modes equal) or a vector
p. mode_start = 'herm'; % (for probe) = 'rand', = 'herm' (Hermitian-like base), = 'hermver' (vertical modes only), = 'hermhor' (horizontal modes only)
p. ortho_probes = true; % orthogonalize probes after each engine
%% Plot, save and analyze
p. plot.prepared_data = false; % plot prepared data
p. plot.interval = []; % plot each interval-th iteration, does not work for c_solver code
p. plot.log_scale = [0 0]; % Plot on log scale for x and y
p. plot.realaxes = true; % Plots show scale in microns
p. plot.remove_phase_ramp = false; % Remove phase ramp from the plotted / saved phase figures
p. plot.fov_box = false; % Plot the scanning FOV box on the object (both phase and amplitude)
p. plot.fov_box_color = 'r'; % Color of the scanning FOV box
p. plot.positions = true; % Plot the scanning positions
p. plot.mask_bool = true; % Mask the noisy contour of the reconstructed object in plots
p. plot.windowautopos = true; % First plotting will auto position windows
p. plot.obj_apod = false; % Apply apodization to the reconstructed object;
p. plot.prop_obj = 0; % Distance to propagate reconstructed object before plotting [m]
p. plot.show_layers = true; % show each layer in multilayer reconstruction
p. plot.show_layers_stack = false; % show each layer in multilayer reconstruction by imagesc3D
p. plot.object_spectrum = []; % Plot propagated object (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.probe_spectrum = []; % Plot propagated probe (FFT for conventional ptycho); if empty then default is false if verbose_level < 3 and true otherwise
p. plot.conjugate = false; % plot complex conjugate of the reconstruction
p. plot.horz_fact = 2.5; % Scales the space that the ptycho figures take horizontally
p. plot.FP_maskdim = 180e-6; % Filter the backpropagation (Fourier Ptychography)
p. plot.calc_FSC = false; % Calculate the Fourier Shell correlation for 2 scans or compare with model in case of artificial data tests
p. plot.show_FSC = false; % Show the FSC plots, including the cropped FOV
p. plot.residua = false; % highlight phase-residua in the image of the reconstructed phase
p. save.external = true; % Use a new Matlab session to run save final figures (saves ~6s per reconstruction). Please be aware that this might lead to an accumulation of Matlab sessions if your single reconstruction is very fast.
p. save.store_images = false; % Write preview images containing the final reconstructions in [p.base_path,'analysis/online/ptycho/'] if p.use_display = 0 then the figures are opened invisible in order to create the nice layout. It writes images in analysis/online/ptycho
p. save.store_images_intermediate = false; % save images to disk after each engine
p. save.store_images_ids = 1:4; % identifiers of the figure to be stored, 1=obj. amplitude, 2=obj. phase, 3=probes, 4=errors, 5=probes spectrum, 6=object spectrum
p. save.store_images_format = 'png'; % data type of the stored images jpg or png
p. save.store_images_dpi = 150; % DPI of the stored bitmap images
p. save.exclude = {'fmag', 'fmask', 'illum_sum'}; % exclude variables to reduce the file size on disk
p. save.save_reconstructions_intermediate = false; % save final object and probes after each engine
p. save.save_reconstructions = false; % save reconstructed object and probe when full reconstruction is finished
p. save.output_file = 'h5'; % data type of reconstruction file; 'h5' or 'mat'
if isfield(par, 'diff_pattern_blur')
p. diff_pattern_blur = par.diff_pattern_blur;
end
%% %%%%%%%%%%%%%%%%%% initialize reconstruction parameters %%%%%%%%%%%%%%%%%%%%
% --------- GPU engines ------------- See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng = struct(); % reset settings for this engine
eng. name = 'GPU_MS';
eng. use_gpu = true; % if false, run CPU code, but it will get very slow
eng. keep_on_gpu = true; % keep data + projections on GPU, false is useful for large data if DM is used
eng. compress_data = false; % use automatic online memory compression to limit need of GPU memory
eng. gpu_id = gpu_id; % default GPU id, [] means choosen by matlab
eng. check_gpu_load = true; % check available GPU memory before starting GPU engines
% general
eng. number_iterations = Niter; % number of iterations for selected method
if isfield(par, 'CBED_crop')
eng.asize_presolve = [par.CBED_crop, par.CBED_crop];
else
eng. asize_presolve = [par.CBED_size, par.CBED_size]; % crop data to "asize_presolve" size to get low resolution estimate that can be used in the next engine as a good initial guess
end
eng. align_shared_objects = false; % before merging multiple unshared objects into one shared, the object will be aligned and the probes shifted by the same distance -> use for alignement and shared reconstruction of drifting scans
eng. method = 'MLs'; % choose GPU solver: DM, ePIE, hPIE, MLc, Mls, -- recommended are MLc and MLs
eng. opt_errmetric = 'L1'; % optimization likelihood - poisson, L1
if isfield(par, 'grouping')
eng.grouping = par.grouping;
else
eng.grouping = 64;
end % size of processed blocks, larger blocks need more memory but they use GPU more effeciently, !!! grouping == inf means use as large as possible to fit into memory
% * for hPIE, ePIE, MLs methods smaller blocks lead to faster convergence,
% * for MLc the convergence is similar
% * for DM is has no effect on convergence
eng. probe_modes = p.probe_modes; % Number of coherent modes for probe
if isfield(par, 'object_change_start')
eng. object_change_start = par.object_change_start;
else
eng. object_change_start = 1; % Start updating object at this iteration number
end
if isfield(par, 'probe_change_start')
eng.probe_change_start = par.probe_change_start;
else
eng. probe_change_start = 1; % Start updating probe at this iteration number
end
% regularizations
if isfield(par, 'reg_mu')
eng.reg_mu = par.reg_mu; % Regularization (smooting) constant ( reg_mu = 0 for no regularization)
else
eng.reg_mu = 0;
end
eng. delta = 0; % press values to zero out of the illumination area in th object, usually 1e-2 is enough
eng. positivity_constraint_object = 0; % enforce weak (relaxed) positivity in object, ie O = O*(1-a)+a*|O|, usually a=1e-2 is already enough. Useful in conbination with OPRP or probe_fourier_shift_search
eng. apply_multimodal_update = false; % apply all incoherent modes to object, it can cause isses if the modes collect some crap
eng. probe_backpropagate = 0; % backpropagation distance the probe mask, 0 == apply in the object plane. Useful for pinhole imaging where the support can be applied at the pinhole plane
eng. probe_support_radius = []; % Normalized radius of circular support, = 1 for radius touching the window
eng. probe_support_fft = false; % assume that there is not illumination intensity out of the central FZP cone and enforce this contraint. Useful for imaging with focusing optics. Helps to remove issues from the gaps between detector modules.
% basic recontruction parameters
% PIE / ML methods % See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. beta_object = 1; % object step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. beta_probe = 1; % probe step size, larger == faster convergence, smaller == more robust, should not exceed 1
eng. delta_p = 0.1; % LSQ dumping constant, 0 == no preconditioner, 0.1 is usually safe, Preconditioner accelerates convergence and ML methods become approximations of the second order solvers
eng. momentum = 0; % add momentum acceleration term to the MLc method, useful if the probe guess is very poor or for acceleration of multilayer solver, but it is quite computationally expensive to be used in conventional ptycho without any refinement.
% The momentum method works usually well even with the accelerated_gradients option. eng.momentum = multiplication gain for velocity, eng.momentum == 0 -> no acceleration, eng.momentum == 0.5 is a good value
% momentum is enabled only when par.Niter < par.accelerated_gradients_start;
eng. accelerated_gradients_start = inf; % iteration number from which the Nesterov gradient acceleration should be applied, this option is supported only for MLc method. It is very computationally cheap way of convergence acceleration.
% DM
eng. pfft_relaxation = 0.05; % Relaxation in the Fourier domain projection, = 0 for full projection
eng. probe_regularization = 0.1; % Weight factor for the probe update (inertia)
% ADVANCED OPTIONS See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
% position refinement
eng. apply_subpix_shift = true; % apply FFT-based subpixel shift, it is automatically allowed for position refinement
if isfield(par, 'probe_position_search')
eng.probe_position_search = par.probe_position_search;
else
eng. probe_position_search = 50; % iteration number from which the engine will reconstruct probe positions, from iteration == probe_position_search, assume they have to match geometry model with error less than probe_position_error_max
end
%eng. probe_geometry_model = {'scale', 'asymmetry', 'rotation', 'shear'}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_geometry_model = {}; % list of free parameters in the geometry model, choose from: {'scale', 'asymmetry', 'rotation', 'shear'}
eng. probe_position_error_max = inf; % maximal expected random position errors, probe prositions are confined in a circle with radius defined by probe_position_error_max and with center defined by original positions scaled by probe_geometry_model
eng. apply_relaxed_position_constraint = false; % added by YJ. Apply a relaxed constraint to probe positions. default = true. Set to false if there are big jumps in positions.
eng. update_pos_weight_every = inf; % added by YJ. Allow position weight to be updated multiple times. default = inf: only update once.
% multilayer extension
eng. delta_z = delta_z*ones(Nlayers,1); % if not empty, use multilayer ptycho extension , see ML_MS code for example of use, [] == common single layer ptychography , note that delta_z provides only relative propagation distance from the previous layer, ie delta_z can be either positive or negative. If preshift_ML_probe == false, the first layer is defined by position of initial probe plane. It is useful to use eng.momentum for convergence acceleration
if isfield(par, 'regularize_layers')
eng.regularize_layers = par.regularize_layers;
else
eng. regularize_layers = 1; % multilayer extension: 0<R<<1 -> apply regularization on the reconstructed object layers, 0 == no regularization, 0.01 == weak regularization that will slowly symmetrize information content between layers
end
eng. preshift_ML_probe = false; % multilayer extension: if true, assume that the provided probe is reconstructed in center of the sample and the layers are centered around this position
eng. layer4pos = []; % Added by ZC. speficy which layer is used for position correction ; if empty, then default, ceil(Nlayers/2)
eng. init_layer_select = []; % Added by YJ. Select layers in the initial object for pre-processing. If empty (default): use all layers.
eng. init_layer_preprocess = ''; % Added by YJ. Specify how to pre-process initial layers
% '' or 'all' (default): use all layers (do nothing)
% 'avg': average all layers
% 'interp': interpolate layers using spline method. Need to specify desired depths in init_layer_interp
eng. init_layer_interp = []; % Specify desired depths for interpolation. The depths of initial are [1:Nlayer_init]. If empty (default), no interpolation
if isfield(par, 'init_layer_append_mode')
eng.init_layer_append_mode = par.init_layer_append_mode;
else
eng. init_layer_append_mode = 'vac';
end
% Added by YJ. Specify how to initialize extra layers
% '' or 'vac' (default): add vacuum layers
% 'edge': append 1st or last layers
% 'avg': append averaged layer
eng. init_layer_scaling_factor = 1; % Added by YJ. Scale all layers. Default: 1 (no scaling). Useful when delta_z is changed
% other extensions
eng. background = 0; % average background scattering level, for OMNI values around 0.3 for 100ms, for flOMNI <0.1 per 100ms exposure, see for more details: Odstrcil, M., et al., Optics letters 40.23 (2015): 5574-5577.
eng. background_width = inf; % width of the background function in pixels, inf == flat background, background function is then convolved with the average diffraction pattern in order to account for beam diversion
eng. clean_residua = false; % remove phase residua from reconstruction by iterative unwrapping, it will result in low spatial freq. artefacts -> object can be used as an residua-free initial guess for netx engine
% wavefront & camera geometry refinement See for more details: Odstrčil M, et al., Optics express. 2018 Feb 5;26(3):3108-23.
eng. probe_fourier_shift_search = inf; % iteration number from which the engine will: refine farfield position of the beam (ie angle) from iteration == probe_fourier_shift_search
eng. estimate_NF_distance = inf; % iteration number from which the engine will: try to estimate the nearfield propagation distance using gradient descent optimization
eng. detector_rotation_search = inf; % iteration number from which the engine will: search for optimal detector rotation, preferably use with option mirror_scan = true , rotation of the detector axis with respect to the sample axis, similar as rotation option in the position refinement geometry model but works also for 0/180deg rotation shared scans
eng. detector_scale_search = inf; % iteration number from which the engine will: refine pixel scale of the detector, can be used to refine propagation distance in ptycho
if isfield(par, 'variable_probe') && strcmp(par.variable_probe,'false')
eng.variable_probe = false;
else
eng.variable_probe = true;
end
% eng. variable_probe = true; % Use SVD to account for variable illumination during a single (coupled) scan, see for more details: Odstrcil, M. et al. Optics express 24.8 (2016): 8360-8369.
eng. variable_probe_modes = 1; % OPRP settings , number of SVD modes using to describe the probe evolution.
eng. variable_probe_smooth = 0; % OPRP settings , enforce of smooth evolution of the OPRP modes -> N is order of polynomial fit used for smoothing, 0 == do not apply any smoothing. Smoothing is useful if only a smooth drift is assumed during the ptycho acquisition
eng. variable_intensity = false; % account to changes in probe intensity
% extra analysis
eng. get_fsc_score = false; % measure evolution of the Fourier ring correlation during convergence
eng. mirror_objects = false; % mirror objects, useful for 0/180deg scan sharing -> geometry refinement for tomography, works only if 2 scans are provided
% custom data adjustments, useful for offaxis ptychography
eng.auto_center_data = false; % autoestimate the center of mass from data and shift the diffraction patterns so that the average center of mass corresponds to center of mass of the provided probe
eng.auto_center_probe = false; % center the probe position in real space before reconstruction is started
eng.custom_data_flip = [0,0,0]; % apply custom flip of the data [fliplr, flipud, transpose] - can be used for quick testing of reconstruction with various flips or for reflection ptychography
eng.apply_tilted_plane_correction = ''; % if any(p.sample_rotation_angles([1,2]) ~= 0), this option will apply tilted plane correction. (a) 'diffraction' apply correction into the data, note that it is valid only for "low NA" illumination Gardner, D. et al., Optics express 20.17 (2012): 19050-19059. (b) 'propagation' - use tilted plane propagation, (c) '' - will not apply any correction
% I/O
eng.plot_results_every = Niter_plot_results;
eng.save_results_every = Niter_save_results;
eng.save_images ={'obj_ph_stack','obj_ph_sum','probe'};
eng.extraPrintInfo = par.extra_print_info;
resultDir = strcat(p.base_path,sprintf(p.scan.format, p.scan_number),'/roi',p.scan.roi_label,'/');
[eng.fout, p.suffix] = generateResultDir(eng, resultDir);
%add engine
[p, ~] = core.append_engine(p, eng); % Adds this engine to the reconstruction process
%% Run the reconstruction
tic
out = core.ptycho_recons(p);
toc
end
+164
View File
@@ -0,0 +1,164 @@
%simulate CBED for FSC analysis
%% parameters
addpath(fullfile(pwd,'utils_electron'))
FOV = 60; %fixed FOV in angstrom
N = 128; % size of diffraction pattern in pixels. only square dp allowed
scan_step_size = 3; %scan step size in angstrom
N_scans_h = round(FOV/scan_step_size); % number of scan positions along horizontal direction
N_scans_v = round(FOV/scan_step_size); % number of scan positions along vertical direction
maxPosError = 0; %largest randrom position error
dose = 5e4; %total electron dose (e/A^2)
Nc_avg = dose*scan_step_size^2/N^2; %average electron count per detector pixel. For poisson noise, SNR = sqrt(Nc_avg);
base_dir = '/home/beams2/YJIANG/research/algorithm/simulation/FSC_study/electron_ptycho_temp/';
%% load test object
disp('Load test object...')
%load(fullfile(pwd,'utils_electron','CuPcCl.mat'))
load(fullfile(pwd,'utils_electron','amorphous_random.mat'))
%pad object in case of large FOV is needed
%phase_true = padarray(phase_true,[6400,6400],'circular','post');
r = 4; %resample phase
phase_true = imresize(phase_true, 1/r);
%create a complex object
object_true = ones(size(phase_true)).*exp(1i*phase_true);
dx = dx*r; %real-space pixel size in angstrom
N_obj = size(object_true,1); %only square object allowed
ind_obj_center = floor(N_obj/2)+1;
%% generate probe function
disp('Generate probe function...')
par_probe = {};
par_probe.df = 800; %defocus in angstrom
par_probe.C3 = 0; %third-order spherical aberration in angstrom
par_probe.voltage = 300; %beam voltage in keV
par_probe.alpha_max = 18; %semi-convergence angle in mrad
par_probe.plotting = true;
[probe_true, ~] = make_tem_probe(dx,N,par_probe);
%calculate rbf
lambda = 12.398/sqrt((2*511.0+par_probe.voltage).*par_probe.voltage); %angstrom
dk = 1/dx/N; %fourier-space pixel size in 1/A
rbf = par_probe.alpha_max/1e3/lambda/dk;
%% save initial probe and parameters
probe = probe_true;
data_dir = strcat('amorph_ss',num2str(scan_step_size),'_a',num2str(par_probe.alpha_max),'_df',num2str(par_probe.df),'_dose',num2str(dose),'/');
mkdir(fullfile(base_dir,data_dir))
p = {};
p.binning = false;
p.detector.binning = false;
p.dk = dk;
p.N_scans_h = N_scans_h;
p.N_scans_v = N_scans_v;
save(strcat(base_dir,data_dir,'init_probe'),'probe','p','par_probe')
%% Generate scan positions
disp('Generate scan positions...')
pos_h = (1 + (0:N_scans_h-1) *scan_step_size);
pos_v = (1 + (0:N_scans_v-1) *scan_step_size);
% centre this
pos_h = pos_h - (mean(pos_h));
pos_v = pos_v - (mean(pos_v));
[Y,X] = meshgrid(pos_h, pos_v);
Y = Y';
X = X';
pos_true_h = X(:); % true posoition
pos_true_v = Y(:);
pos_recon_init_h = pos_true_h;
pos_recon_init_v = pos_true_v;
%add random position errors - to simulate scan noise
pos_recon_init_h = pos_recon_init_h + maxPosError*(rand(size(pos_recon_init_h))*2-1);
pos_recon_init_v = pos_recon_init_v + maxPosError*(rand(size(pos_recon_init_v))*2-1);
%
%calculate indicies for all scans
N_scan = length(pos_true_h);
%position = pi(integer) + pf(fraction)
pv_i = round(pos_true_v/dx);
pv_f = pos_true_v - pv_i*dx;
ph_i = round(pos_true_h/dx);
ph_f = pos_true_h - ph_i*dx;
ind_h_lb = ph_i - floor(N/2) + ind_obj_center;
ind_h_ub = ph_i + ceil(N/2) -1 + ind_obj_center;
ind_v_lb = pv_i - floor(N/2) + ind_obj_center;
ind_v_ub = pv_i + ceil(N/2) -1 + ind_obj_center;
%% generate two datasets (required by FSC)
disp('Generating diffraction patterns...')
close all
for j=1:2
disp(j)
dp = zeros(N,N,N_scan);
dp_true = zeros(N,N,N_scan);
snr = ones(N_scan,1)*inf; %signal-to-noise ratio of each diffraction pattern
f = waitbar(0,'1','Name','Simulating diffraction patterns...',...
'CreateCancelBtn','setappdata(gcbf,''canceling'',1)');
setappdata(f,'canceling',0);
for i=1:N_scan
% Check for clicked Cancel button
if getappdata(f,'canceling')
break
end
% Update waitbar and message
waitbar(i/N_scan,f,sprintf('No.%d/%d',i,N_scan))
probe_s = shift(probe_true, dx, dx, ph_f(i), pv_f(i));
obj_roi = object_true(ind_v_lb(i):ind_v_ub(i),ind_h_lb(i):ind_h_ub(i));
psi = obj_roi .* probe_s;
%FFT to get diffraction pattern
dp_true(:,:,i) = abs(fftshift(fft2(ifftshift(psi)))).^2;
dp(:,:,i) = dp_true(:,:,i);
%Add poisson noise
if Nc_avg<inf
dp_true_temp = dp_true(:,:,i);
dp_temp = dp_true_temp/sum(dp_true_temp(:))*(N^2*Nc_avg);
dp_temp = poissrnd(dp_temp);
dp_temp = dp_temp*sum(dp_true_temp(:))/(N^2*Nc_avg);
snr(i) = mean((dp_true_temp(:)))/std(dp_true_temp(:) - dp_temp(:));
dp(:,:,i) = dp_temp;
end
end
delete(f)
disp('Generating diffraction patterns...done')
% save cbed
disp('Saving diffraction patterns...')
save_dir = fullfile(base_dir,data_dir,strcat('data',num2str(j)));
mkdir(save_dir)
save_name = strcat('data_roi0_dp.hdf5'); %save diffraction patterns
h5create(fullfile(save_dir,save_name), '/dp', size(dp),'ChunkSize',[size(dp,1) size(dp,1), 1],'Deflate',4)
h5write(fullfile(save_dir,save_name), '/dp', dp*100)
save_name = strcat('data_roi0_para.hdf5'); %save scan positions
hdf5write(fullfile(save_dir,save_name), '/ppX', pos_true_h)
hdf5write(fullfile(save_dir,save_name), '/ppY', pos_true_v,'WriteMode','append')
disp('done')
end
%% run ptychosheleves script to prepare reconstruction parameters
template = 'ptycho_electron_simulation_template';
% you can adjust more parameters in the template
base_path_ptycho = fullfile(base_dir,data_dir); %base path needed by ptychoshelves
grouping = N_scans_h; %adjust group size based on total # of diffraction patterns
run(template)
% start reconstruction
tic
out = core.ptycho_recons(p);
toc
%% To exam the final FSC score, load the .mat file generated by PtychoSheleves
%for example:
load(fullfile(eng.fout,'Niter200.mat'))
fsc = p.dx_spec(1)/outputs.fsc_score{end}.resolution; %unit: angstrom
disp(fsc)