mirror of
https://github.com/c-sooyoung/fold_slice.git
synced 2026-09-18 00:59:11 +09:00
initial commit
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
% ADD_MOMENTUM_OBJECT speed up convergence by adding momentum / integral term into the
|
||||
% update direction for the MLc method
|
||||
%
|
||||
% [self, cache] = add_momentum_object(self, cache, par, object_upd_sum, iter, fourier_error)
|
||||
%
|
||||
% ** self structure containing inputs: e.g. current reconstruction results, data, mask, positions, pixel size, ..
|
||||
% ** cache structure with precalculated values to avoid unnecessary overhead
|
||||
% ** par structure containing parameters for the engines
|
||||
% ** object_upd_sum cell of arrays containing update direction from the LSQML method
|
||||
% ** iter current iteation numebr
|
||||
% ** fourier_error array [Npos,1] containing evolution of reconstruction error
|
||||
%
|
||||
% returns:
|
||||
% ++ self structure containing inputs: e.g. current reconstruction results, data, mask, positions, pixel size, ..
|
||||
% ++ cache structure with precalculated values to avoid unnecessary overhead
|
||||
%
|
||||
%
|
||||
|
||||
|
||||
% Academic License Agreement
|
||||
%
|
||||
% Source Code
|
||||
%
|
||||
% Introduction
|
||||
% • This license agreement sets forth the terms and conditions under which the PAUL SCHERRER INSTITUT (PSI), CH-5232 Villigen-PSI, Switzerland (hereafter "LICENSOR")
|
||||
% will grant you (hereafter "LICENSEE") a royalty-free, non-exclusive license for academic, non-commercial purposes only (hereafter "LICENSE") to use the cSAXS
|
||||
% ptychography MATLAB package computer software program and associated documentation furnished hereunder (hereafter "PROGRAM").
|
||||
%
|
||||
% Terms and Conditions of the LICENSE
|
||||
% 1. LICENSOR grants to LICENSEE a royalty-free, non-exclusive license to use the PROGRAM for academic, non-commercial purposes, upon the terms and conditions
|
||||
% hereinafter set out and until termination of this license as set forth below.
|
||||
% 2. LICENSEE acknowledges that the PROGRAM is a research tool still in the development stage. The PROGRAM is provided without any related services, improvements
|
||||
% or warranties from LICENSOR and that the LICENSE is entered into in order to enable others to utilize the PROGRAM in their academic activities. It is the
|
||||
% LICENSEE’s responsibility to ensure its proper use and the correctness of the results.”
|
||||
% 3. THE PROGRAM IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR
|
||||
% A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. IN NO EVENT SHALL THE LICENSOR, THE AUTHORS OR THE COPYRIGHT
|
||||
% HOLDERS BE LIABLE FOR ANY CLAIM, DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR OTHER LIABILITY ARISING FROM, OUT OF OR IN CONNECTION WITH THE PROGRAM OR THE USE
|
||||
% OF THE PROGRAM OR OTHER DEALINGS IN THE PROGRAM.
|
||||
% 4. LICENSEE agrees that it will use the PROGRAM and any modifications, improvements, or derivatives of PROGRAM that LICENSEE may create (collectively,
|
||||
% "IMPROVEMENTS") solely for academic, non-commercial purposes and that any copy of PROGRAM or derivatives thereof shall be distributed only under the same
|
||||
% license as PROGRAM. The terms "academic, non-commercial", as used in this Agreement, mean academic or other scholarly research which (a) is not undertaken for
|
||||
% profit, or (b) is not intended to produce works, services, or data for commercial use, or (c) is neither conducted, nor funded, by a person or an entity engaged
|
||||
% in the commercial use, application or exploitation of works similar to the PROGRAM.
|
||||
% 5. LICENSEE agrees that it shall make the following acknowledgement in any publication resulting from the use of the PROGRAM or any translation of the code into
|
||||
% another computing language:
|
||||
% "Data processing was carried out using the cSAXS ptychography MATLAB package developed by the Science IT and the coherent X-ray scattering (CXS) groups, Paul
|
||||
% Scherrer Institut, Switzerland."
|
||||
%
|
||||
% Additionally, any publication using the package, or any translation of the code into another computing language should cite for difference map:
|
||||
% P. Thibault, M. Dierolf, A. Menzel, O. Bunk, C. David, F. Pfeiffer, High-resolution scanning X-ray diffraction microscopy, Science 321, 379–382 (2008).
|
||||
% (doi: 10.1126/science.1158573),
|
||||
% for mixed coherent modes:
|
||||
% P. Thibault and A. Menzel, Reconstructing state mixtures from diffraction measurements, Nature 494, 68–71 (2013). (doi: 10.1038/nature11806),
|
||||
% for LSQ-ML method
|
||||
% M. Odstrcil, A. Menzel, M.G. Sicairos, Iterative least-squares solver for generalized maximum-likelihood ptychography, Optics Express, 2018
|
||||
% for OPRP method
|
||||
% M. Odstrcil, P. Baksh, S. A. Boden, R. Card, J. E. Chad, J. G. Frey, W. S. Brocklesby, "Ptychographic coherent diffractive imaging with orthogonal probe relaxation." Optics express 24.8 (2016): 8360-8369
|
||||
% and/or for multislice:
|
||||
% E. H. R. Tsai, I. Usov, A. Diaz, A. Menzel, and M. Guizar-Sicairos, X-ray ptychography with extended depth of field, Opt. Express 24, 29089–29108 (2016).
|
||||
% 6. Except for the above-mentioned acknowledgment, LICENSEE shall not use the PROGRAM title or the names or logos of LICENSOR, nor any adaptation thereof, nor the
|
||||
% names of any of its employees or laboratories, in any advertising, promotional or sales material without prior written consent obtained from LICENSOR in each case.
|
||||
% 7. Ownership of all rights, including copyright in the PROGRAM and in any material associated therewith, shall at all times remain with LICENSOR, and LICENSEE
|
||||
% agrees to preserve same. LICENSEE agrees not to use any portion of the PROGRAM or of any IMPROVEMENTS in any machine-readable form outside the PROGRAM, nor to
|
||||
% make any copies except for its internal use, without prior written consent of LICENSOR. LICENSEE agrees to place the following copyright notice on any such copies:
|
||||
% © All rights reserved. PAUL SCHERRER INSTITUT, Switzerland, Laboratory for Macromolecules and Bioimaging, 2017.
|
||||
% 8. The LICENSE shall not be construed to confer any rights upon LICENSEE by implication or otherwise except as specifically set forth herein.
|
||||
% 9. DISCLAIMER: LICENSEE shall be aware that Phase Focus Limited of Sheffield, UK has an international portfolio of patents and pending applications which relate
|
||||
% to ptychography and that the PROGRAM may be capable of being used in circumstances which may fall within the claims of one or more of the Phase Focus patents,
|
||||
% in particular of patent with international application number PCT/GB2005/001464. The LICENSOR explicitly declares not to indemnify the users of the software
|
||||
% in case Phase Focus or any other third party will open a legal action against the LICENSEE due to the use of the program.
|
||||
% 10. This Agreement shall be governed by the material laws of Switzerland and any dispute arising out of this Agreement or use of the PROGRAM shall be brought before
|
||||
% the courts of Zürich, Switzerland.
|
||||
|
||||
|
||||
|
||||
|
||||
function [self, cache] = add_momentum_object(self, cache, par, object_upd_sum, iter, fourier_error, beta_object)
|
||||
|
||||
import utils.*
|
||||
import engines.GPU.GPU_wrapper.*
|
||||
import math.*
|
||||
|
||||
verbose(1, 'Adding momentum to object')
|
||||
|
||||
|
||||
object_modes = size(self.object,1);
|
||||
|
||||
% create velocity maps in the first iterations
|
||||
if iter == par.object_change_start
|
||||
cache.object_upd_sum = cell(object_modes,1);
|
||||
for ll = 1:object_modes
|
||||
for jj = 1:par.Nlayers
|
||||
cache.velocity_map_object{ll,jj} = Gzeros(self.Np_o);
|
||||
cache.object_upd_sum{ll,jj} = [];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
% store previous update directions
|
||||
for ll = 1:object_modes
|
||||
for jj = 1:par.Nlayers
|
||||
upd = object_upd_sum{ll,jj}(cache.object_ROI{:})* mean(beta_object(:,jj));
|
||||
upd = upd / norm2(upd);
|
||||
cache.object_upd_sum{ll,jj} = [cache.object_upd_sum{ll,jj}, {upd}];
|
||||
end
|
||||
end
|
||||
|
||||
% how many steps are stored to calculate optimal friction
|
||||
momentum_memory = 2;
|
||||
|
||||
% use Fourier error to avoid issues with convergence
|
||||
ind_compare = find(all(~isnan(fourier_error),2),3,'last');
|
||||
if length(ind_compare) > 2
|
||||
merr = mean(fourier_error,2);
|
||||
ferr_ok = max(merr(ind_compare([1,2]))) > min(merr(ind_compare([2,3])));
|
||||
else
|
||||
ferr_ok = true;
|
||||
end
|
||||
|
||||
if iter > momentum_memory+par.object_change_start
|
||||
for ll = 1:object_modes
|
||||
for jj = 1:par.Nlayers
|
||||
cache.object_upd_sum{ll,jj}(1) = []; % delete the oldest stored object update
|
||||
corr_level = nan;
|
||||
|
||||
if ferr_ok
|
||||
% caculate correlation between updated to estimate optimal
|
||||
% friction, !! NOTE that cache.object_upd_sum contains only the
|
||||
% object_ROI region !!
|
||||
%
|
||||
switch momentum_memory
|
||||
case 2, [aux{1}, aux{2}] = compare_upd_directions_2(cache.object_upd_sum{ll,jj}{:});
|
||||
case 3, [aux{1}, aux{2}, aux{3}] = compare_upd_directions_2(cache.object_upd_sum{ll,jj}{:});
|
||||
othewise, error('Not implemented')
|
||||
end
|
||||
for kk = 1:momentum_memory
|
||||
corr_level(kk) = real(Ggather(mean2(aux{kk})));
|
||||
end
|
||||
end
|
||||
|
||||
if ferr_ok && all(corr_level > 0 )
|
||||
|
||||
|
||||
% estimate optimal friction from previous steps
|
||||
poly_fit = polyfit(0:momentum_memory,[0,log(corr_level)],1);
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
gain = par.momentum; % smaller -> lower relative speed (less momentum)
|
||||
friction = 0.5*max(-poly_fit(1),0); % smaller -> longer memory, more momentum
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
% update object by the momentum gradient
|
||||
[self.object{ll,jj}, cache.velocity_map_object{ll,jj}] = update_momentum(self.object{ll,jj}, cache.velocity_map_object{ll,jj}, object_upd_sum{ll,jj}, friction, gain, cache.illum_sum_0{ll}, cache.MAX_ILLUM(ll));
|
||||
else
|
||||
% error was increased or updates are not well correlated, skip acceleration
|
||||
gain = 0; friction = inf;
|
||||
cache.velocity_map_object{ll,jj} = cache.velocity_map_object{ll,jj}/2;
|
||||
end
|
||||
|
||||
if verbose()> 1
|
||||
norm_upd = norm2(object_upd_sum{ll,jj});
|
||||
norm_vmap = norm2(gain.*cache.velocity_map_object{ll,jj});
|
||||
verbose(2,['Object %i Corr=', repmat('1:%5.2f ',1,momentum_memory)],ll, corr_level )
|
||||
verbose(0, 'Momentum: friction=%3.1e \tacceleration %1.1fx',friction, 1+norm_vmap/norm_upd)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
% plotting.smart_figure(25454)
|
||||
% img = cat(1,cat(2, cache.velocity_map_object{:}) .* cat(2,cache.illum_sum_0{:}), cat(2, object_upd_sum{:}) .* cat(2,cache.illum_sum_0{:}));
|
||||
% aimg = abs(img);
|
||||
% img = min(aimg, quantile(aimg(:), 0.99)) .* img ./ (aimg+1e-3);
|
||||
% plotting.imagesc3D(img(1:4:end, 1:4:end))
|
||||
% axis off image xy
|
||||
% drawnow
|
||||
|
||||
try
|
||||
if verbose()> 2
|
||||
plotting.smart_figure(121)
|
||||
subplot(1,2,1)
|
||||
plotting.imagesc3D(cache.velocity_map_object{1,1})
|
||||
axis off image
|
||||
title(sprintf('Velocity, iter=%i', iter))
|
||||
subplot(1,2,2)
|
||||
plotting.imagesc3D(object_upd_sum{1,1})
|
||||
axis off image
|
||||
title('Gradient')
|
||||
drawnow
|
||||
end
|
||||
catch
|
||||
keyboard
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function [object, Vmap] = update_momentum(object, Vmap, Vmap_upd, friction, gain, weight, w_max)
|
||||
% auxiliary function
|
||||
weight = weight ./ (0.1*w_max+weight);
|
||||
Vmap = (1-friction)*Vmap + Vmap_upd;
|
||||
object = object + weight.*gain.*Vmap;
|
||||
end
|
||||
|
||||
function [out1, out2] = compare_upd_directions_2(upd1, upd2, upd3)
|
||||
% compare updates
|
||||
upd3 = conj(upd3);
|
||||
out2 = upd1 .* upd3;
|
||||
out1 = upd2 .* upd3;
|
||||
end
|
||||
function [out1, out2, out3] = compare_upd_directions_3(upd1, upd2, upd3, upd4)
|
||||
% compare updates
|
||||
upd4 = conj(upd4);
|
||||
out3 = upd1 .* upd4;
|
||||
out2 = upd2 .* upd4;
|
||||
out1 = upd3 .* upd4;
|
||||
end
|
||||
@@ -0,0 +1,200 @@
|
||||
% ADD_MOMENTUM_PROBE speed up convergence by adding momentum / integral term into the
|
||||
% update direction for the MLc method
|
||||
%
|
||||
% [self, cache] = add_momentum_probe(self, cache, par, probe_upd, iter, fourier_error)
|
||||
%
|
||||
% ** self structure containing inputs: e.g. current reconstruction results, data, mask, positions, pixel size, ..
|
||||
% ** cache structure with precalculated values to avoid unnecessary overhead
|
||||
% ** par structure containing parameters for the engines
|
||||
% ** probe_upd cell of arrays containing update direction from the LSQML method
|
||||
% ** iter current iteation numebr
|
||||
% ** fourier_error array [Npos,1] containing evolution of reconstruction error
|
||||
%
|
||||
% returns:
|
||||
% ++ self structure containing inputs: e.g. current reconstruction results, data, mask, positions, pixel size, ..
|
||||
% ++ cache structure with precalculated values to avoid unnecessary overhead
|
||||
%
|
||||
%
|
||||
|
||||
|
||||
|
||||
% Academic License Agreement
|
||||
%
|
||||
% Source Code
|
||||
%
|
||||
% Introduction
|
||||
% • This license agreement sets forth the terms and conditions under which the PAUL SCHERRER INSTITUT (PSI), CH-5232 Villigen-PSI, Switzerland (hereafter "LICENSOR")
|
||||
% will grant you (hereafter "LICENSEE") a royalty-free, non-exclusive license for academic, non-commercial purposes only (hereafter "LICENSE") to use the cSAXS
|
||||
% ptychography MATLAB package computer software program and associated documentation furnished hereunder (hereafter "PROGRAM").
|
||||
%
|
||||
% Terms and Conditions of the LICENSE
|
||||
% 1. LICENSOR grants to LICENSEE a royalty-free, non-exclusive license to use the PROGRAM for academic, non-commercial purposes, upon the terms and conditions
|
||||
% hereinafter set out and until termination of this license as set forth below.
|
||||
% 2. LICENSEE acknowledges that the PROGRAM is a research tool still in the development stage. The PROGRAM is provided without any related services, improvements
|
||||
% or warranties from LICENSOR and that the LICENSE is entered into in order to enable others to utilize the PROGRAM in their academic activities. It is the
|
||||
% LICENSEE’s responsibility to ensure its proper use and the correctness of the results.”
|
||||
% 3. THE PROGRAM IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR
|
||||
% A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. IN NO EVENT SHALL THE LICENSOR, THE AUTHORS OR THE COPYRIGHT
|
||||
% HOLDERS BE LIABLE FOR ANY CLAIM, DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR OTHER LIABILITY ARISING FROM, OUT OF OR IN CONNECTION WITH THE PROGRAM OR THE USE
|
||||
% OF THE PROGRAM OR OTHER DEALINGS IN THE PROGRAM.
|
||||
% 4. LICENSEE agrees that it will use the PROGRAM and any modifications, improvements, or derivatives of PROGRAM that LICENSEE may create (collectively,
|
||||
% "IMPROVEMENTS") solely for academic, non-commercial purposes and that any copy of PROGRAM or derivatives thereof shall be distributed only under the same
|
||||
% license as PROGRAM. The terms "academic, non-commercial", as used in this Agreement, mean academic or other scholarly research which (a) is not undertaken for
|
||||
% profit, or (b) is not intended to produce works, services, or data for commercial use, or (c) is neither conducted, nor funded, by a person or an entity engaged
|
||||
% in the commercial use, application or exploitation of works similar to the PROGRAM.
|
||||
% 5. LICENSEE agrees that it shall make the following acknowledgement in any publication resulting from the use of the PROGRAM or any translation of the code into
|
||||
% another computing language:
|
||||
% "Data processing was carried out using the cSAXS ptychography MATLAB package developed by the Science IT and the coherent X-ray scattering (CXS) groups, Paul
|
||||
% Scherrer Institut, Switzerland."
|
||||
%
|
||||
% Additionally, any publication using the package, or any translation of the code into another computing language should cite for difference map:
|
||||
% P. Thibault, M. Dierolf, A. Menzel, O. Bunk, C. David, F. Pfeiffer, High-resolution scanning X-ray diffraction microscopy, Science 321, 379–382 (2008).
|
||||
% (doi: 10.1126/science.1158573),
|
||||
% for mixed coherent modes:
|
||||
% P. Thibault and A. Menzel, Reconstructing state mixtures from diffraction measurements, Nature 494, 68–71 (2013). (doi: 10.1038/nature11806),
|
||||
% for LSQ-ML method
|
||||
% M. Odstrcil, A. Menzel, M.G. Sicairos, Iterative least-squares solver for generalized maximum-likelihood ptychography, Optics Express, 2018
|
||||
% for OPRP method
|
||||
% M. Odstrcil, P. Baksh, S. A. Boden, R. Card, J. E. Chad, J. G. Frey, W. S. Brocklesby, "Ptychographic coherent diffractive imaging with orthogonal probe relaxation." Optics express 24.8 (2016): 8360-8369
|
||||
% and/or for multislice:
|
||||
% E. H. R. Tsai, I. Usov, A. Diaz, A. Menzel, and M. Guizar-Sicairos, X-ray ptychography with extended depth of field, Opt. Express 24, 29089–29108 (2016).
|
||||
% 6. Except for the above-mentioned acknowledgment, LICENSEE shall not use the PROGRAM title or the names or logos of LICENSOR, nor any adaptation thereof, nor the
|
||||
% names of any of its employees or laboratories, in any advertising, promotional or sales material without prior written consent obtained from LICENSOR in each case.
|
||||
% 7. Ownership of all rights, including copyright in the PROGRAM and in any material associated therewith, shall at all times remain with LICENSOR, and LICENSEE
|
||||
% agrees to preserve same. LICENSEE agrees not to use any portion of the PROGRAM or of any IMPROVEMENTS in any machine-readable form outside the PROGRAM, nor to
|
||||
% make any copies except for its internal use, without prior written consent of LICENSOR. LICENSEE agrees to place the following copyright notice on any such copies:
|
||||
% © All rights reserved. PAUL SCHERRER INSTITUT, Switzerland, Laboratory for Macromolecules and Bioimaging, 2017.
|
||||
% 8. The LICENSE shall not be construed to confer any rights upon LICENSEE by implication or otherwise except as specifically set forth herein.
|
||||
% 9. DISCLAIMER: LICENSEE shall be aware that Phase Focus Limited of Sheffield, UK has an international portfolio of patents and pending applications which relate
|
||||
% to ptychography and that the PROGRAM may be capable of being used in circumstances which may fall within the claims of one or more of the Phase Focus patents,
|
||||
% in particular of patent with international application number PCT/GB2005/001464. The LICENSOR explicitly declares not to indemnify the users of the software
|
||||
% in case Phase Focus or any other third party will open a legal action against the LICENSEE due to the use of the program.
|
||||
% 10. This Agreement shall be governed by the material laws of Switzerland and any dispute arising out of this Agreement or use of the PROGRAM shall be brought before
|
||||
% the courts of Zürich, Switzerland.
|
||||
|
||||
|
||||
|
||||
|
||||
function [self, cache] = add_momentum_probe(self, cache, par, probe_upd, iter, fourier_error, beta_probe)
|
||||
|
||||
import utils.*
|
||||
import engines.GPU.GPU_wrapper.*
|
||||
import math.*
|
||||
|
||||
verbose(1, 'Adding momentum to probe')
|
||||
|
||||
%disp(size(self.probe))
|
||||
|
||||
Nmodes = size(self.probe,1);
|
||||
|
||||
% create velocity maps in the first iterations
|
||||
if iter == par.probe_change_start
|
||||
cache.probe_upd_sum = cell(Nmodes,1);
|
||||
for ll = 1:Nmodes
|
||||
cache.velocity_map_probe{ll} = Gzeros(self.Np_p);
|
||||
cache.probe_upd_sum{ll} = [];
|
||||
end
|
||||
end
|
||||
|
||||
% store previous update directions
|
||||
for ll = 1:Nmodes
|
||||
probe_upd{ll} = probe_upd{ll}(:,:,:,1); % accelerate only the fundamental probe in the variable probe extension
|
||||
probe_upd{ll} = probe_upd{ll} .* mean(beta_probe(:));
|
||||
upd = probe_upd{ll} ./ (norm2(probe_upd{ll})+eps);
|
||||
cache.probe_upd_sum{ll} = [cache.probe_upd_sum{ll}, {upd}];
|
||||
end
|
||||
|
||||
% how many steps are stored to calculate optimal friction
|
||||
momentum_memory = 3;
|
||||
|
||||
if iter > momentum_memory+par.probe_change_start
|
||||
for ll = 1:Nmodes
|
||||
probe_modes= size(self.probe{ll},3);
|
||||
cache.probe_upd_sum{ll}(1) = []; % delete the oldest stored probe update
|
||||
% caculate correlation between updated to estimate optimal
|
||||
% friction,
|
||||
|
||||
[aux{1}, aux{2}, aux{3}] = compare_upd_directions(cache.probe_upd_sum{ll}{:});
|
||||
for kk = 1:momentum_memory
|
||||
corr_level(kk,:) = real(Ggather(mean2(aux{kk})));
|
||||
end
|
||||
|
||||
|
||||
% use Fourier error to avoid issues with convergence
|
||||
ind_compare = find(all(~isnan(fourier_error),2),3,'last');
|
||||
if length(ind_compare) > 2
|
||||
merr = mean(fourier_error,2);
|
||||
ferr_ok = max(merr(ind_compare([1,2]))) > min(merr(ind_compare([2,3])));
|
||||
else
|
||||
ferr_ok = true;
|
||||
end
|
||||
|
||||
if all(corr_level(:) > 0 ) && ferr_ok
|
||||
|
||||
try
|
||||
% estimate optimal friction from previous steps
|
||||
poly_fit = polyfit(repmat(0:momentum_memory,probe_modes,1),[zeros(1,probe_modes);log(corr_level)]',1);
|
||||
catch
|
||||
keyboard
|
||||
end
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
gain = par.momentum; % smaller -> lower relative speed (less momentum)
|
||||
friction = 0.5*max(-poly_fit(1),0); % smaller -> longer memory, more momentum
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
% update probe by the momentum gradient , accelerate only the fundamental probe in the variable probe extension
|
||||
[self.probe{ll}(:,:,:,1), cache.velocity_map_probe{ll}] = update_momentum(self.probe{ll}(:,:,:,1), cache.velocity_map_probe{ll}, probe_upd{ll}, friction, gain);
|
||||
else
|
||||
% error was increased or updates are not well correlated, skip acceleration
|
||||
gain = 0; friction = inf;
|
||||
cache.velocity_map_probe{ll} = cache.velocity_map_probe{ll}/2;
|
||||
end
|
||||
|
||||
if verbose() > 0
|
||||
norm_upd = mean(norm2(probe_upd{ll}));
|
||||
norm_vmap = eps+mean(norm2(gain.*cache.velocity_map_probe{ll}));
|
||||
verbose(2,['Probe %i Corr=', repmat('1:%5.2f ',1,momentum_memory)],ll, corr_level(:,1) )
|
||||
verbose(0, 'Momentum: friction=%3.1e \tacceleration %1.1fx',friction(:,1), 1+norm_vmap./norm_upd(1))
|
||||
end
|
||||
end
|
||||
|
||||
% plotting.smart_figure(25454)
|
||||
% img = cat(1,cat(2, cache.velocity_map_probe{:}) .* cat(2,cache.illum_sum_0{:}), cat(2, probe_upd_sum{:}) .* cat(2,cache.illum_sum_0{:}));
|
||||
% aimg = abs(img);
|
||||
% img = min(aimg, quantile(aimg(:), 0.99)) .* img ./ (aimg+1e-3);
|
||||
% plotting.imagesc3D(img(1:4:end, 1:4:end))
|
||||
% axis off image xy
|
||||
% drawnow
|
||||
|
||||
try
|
||||
if verbose() > 2
|
||||
plotting.smart_figure(1213)
|
||||
subplot(1,2,1)
|
||||
plotting.imagesc3D(cache.velocity_map_probe{1,1})
|
||||
axis off image
|
||||
title(sprintf('Velocity, iter=%i, norm=%g', iter, norm2(cache.velocity_map_probe{1,1})))
|
||||
subplot(1,2,2)
|
||||
plotting.imagesc3D(probe_upd{1})
|
||||
axis off image
|
||||
title(sprintf('Gradient, norm=%g',norm2(probe_upd{1})))
|
||||
drawnow
|
||||
end
|
||||
catch
|
||||
keyboard
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function [probe, Vmap] = update_momentum(probe, Vmap, Vmap_upd, friction, gain)
|
||||
% auxiliary function
|
||||
Vmap = (1-friction)*Vmap + Vmap_upd;
|
||||
probe = probe + gain.*Vmap;
|
||||
end
|
||||
function [out1, out2, out3] = compare_upd_directions(upd1, upd2, upd3, upd4)
|
||||
% compare updates
|
||||
upd4 = conj(upd4);
|
||||
out3 = upd1 .* upd4;
|
||||
out2 = upd2 .* upd4;
|
||||
out1 = upd3 .* upd4;
|
||||
end
|
||||
@@ -0,0 +1,85 @@
|
||||
% GET_FORWARD_MODEL from the provided object and probe calculate the exit wave
|
||||
%
|
||||
% [self, probe, obj_proj, psi] = get_forward_model(self, obj_proj, par, cache, g_ind, p_ind, scan_ids, layer_ids)
|
||||
%
|
||||
% ** self structure containing inputs: e.g. current reconstruction results, data, mask, positions, pixel size, ..
|
||||
% ** obj_proj [Nx,Ny,N] array, just a preallocated array on GPU, can be empty
|
||||
% ** par structure containing parameters for the engines
|
||||
% ** cache structure with precalculated values to avoid unnecessary overhead
|
||||
% ** g_ind indices corresponding to the current group that is solved in parallel
|
||||
% ** p_ind indices containg corresponding probe id for each processed position
|
||||
% ** scan_ids determines to which scan correponds each of the position
|
||||
% ** layer_ids id of the solved layer for multilayer ptycho
|
||||
%
|
||||
%
|
||||
% returns:
|
||||
% ++ self structure containing inputs: e.g. current reconstruction results, data, mask, positions, pixel size, ..
|
||||
% ++ probe either [Nx,Nx,1] or [Nx,Nx,N] aarray of shared probe or variable probe that differs for each position
|
||||
% ++ obj_proj [Nx,Ny,N] array, views of the object for each scan position
|
||||
% ++ psi [Nx,Ny,N] array, complex valued exit-wave (psi = P*O)
|
||||
%
|
||||
% see also: engines.GPU.LSQML
|
||||
|
||||
|
||||
function [self, probe, obj_proj, psi] = get_forward_model(self, obj_proj, par, cache, g_ind, p_ind, scan_ids, layer_ids)
|
||||
import engines.GPU.shared.*
|
||||
import engines.GPU.GPU_wrapper.*
|
||||
import engines.GPU.LSQML.*
|
||||
import math.*
|
||||
import utils.*
|
||||
import plotting.*
|
||||
|
||||
if isempty(obj_proj{1})
|
||||
for ll = 1:par.object_modes
|
||||
obj_proj{ll} = Gzeros([self.Np_p, 0], true);
|
||||
end
|
||||
end
|
||||
probe = self.probe;
|
||||
%length(probe)=par.probe_modes
|
||||
%size(probe{1})=[Np,Np,1,par.variable_probe_modes+1];
|
||||
|
||||
% get illumination probe
|
||||
for ll = 1:par.probe_modes
|
||||
%p_ind{ll} is always 1 for single dataset
|
||||
if (ll == 1 && (par.variable_probe || par.variable_intensity))
|
||||
% add variable probe (OPRP) part into the constant illumination
|
||||
% OPRP only applies to the FIRST probe mode in mixed-states
|
||||
probe{ll,1} = get_variable_probe(self.probe{ll}, self.probe_evolution(g_ind,:),p_ind{ll});
|
||||
% size(probe{ll,1}) = [Np_p(1), Np_p(2), # of probes in this group];
|
||||
else
|
||||
% store the normal (constant) probe(s)
|
||||
probe{ll,1} = self.probe{min(ll,end)}(:,:,min(end,p_ind{ll}),1);
|
||||
% size(probe{ll,1}) = [Np_p(1), Np_p(2), 1]; No OPR for higher probe modes
|
||||
end
|
||||
|
||||
if (ll == 1 && par.apply_subpix_shift && isinf(self.z_distance(end))) || is_used(par,'fly_scan')
|
||||
% only in farfield mode
|
||||
probe{ll} = apply_subpx_shift(probe{ll}, self.modes{min(end,ll)}.sub_px_shift(g_ind,:) );
|
||||
end
|
||||
if (ll == 1)
|
||||
probe{ll} = apply_subpx_shift_fft(probe{ll}, self.modes{1}.probe_fourier_shift(g_ind,:));
|
||||
end
|
||||
end
|
||||
|
||||
% get projection of the object and probe
|
||||
for layer = 1:par.Nlayers
|
||||
for ll = 1:max(par.object_modes, par.probe_modes)
|
||||
llo = min(ll, par.object_modes);
|
||||
llp = min(ll, par.probe_modes);
|
||||
% get objects projections
|
||||
obj_proj{llo} = get_views(self.object, obj_proj{llo},layer_ids(layer),llo, g_ind, cache, scan_ids,[]);
|
||||
if (ll == 1 && par.apply_subpix_shift && ~isinf(self.z_distance(end)))
|
||||
% only in nearfield mode , apply shift in the opposite direction
|
||||
obj_proj{ll} = apply_subpx_shift(obj_proj{ll} .* cache.apodwin, -self.modes{min(end,ll)}.sub_px_shift(g_ind,:) ) ./ cache.apodwin;
|
||||
end
|
||||
|
||||
% get exitwave after each layer
|
||||
psi{ll} = probe{llp,layer} .* obj_proj{llo};
|
||||
% fourier propagation
|
||||
[psi{ll}] = fwd_fourier_proj(psi{ll} , self.modes{layer}, g_ind);
|
||||
if par.Nlayers > 1
|
||||
probe{llp,layer+1} = psi{llp};
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,143 @@
|
||||
% GET_OPTIMAL_LSQ_STEP calculate the optimal step lenght for given update directions and chi array
|
||||
%
|
||||
% [beta_probe, beta_object] = get_optimal_LSQ_step(self,chi,dO,dP,O,P, p_ind, par)
|
||||
%
|
||||
% ** self structure containing inputs: e.g. current reconstruction results, data, mask, positions, pixel size, ..
|
||||
% ** chi [Nx,Ny,N] array, difference between original and updated exit-wave
|
||||
% ** dO [Nx,Ny,N] array, object update direction
|
||||
% ** dP [Nx,Ny,N] array, probe update direction
|
||||
% ** O [Nx,Ny,N] array, object views
|
||||
% ** P [Nx,Ny,1] or [Nx,Ny,N] array, single or variable probe
|
||||
% ** p_ind indices containg corresponding probe id for each processed position
|
||||
% ** par structure containing parameters for the engines
|
||||
%
|
||||
% returns:
|
||||
% ++ beta_probe optimal probe step
|
||||
% ++ beta_object optimal object step
|
||||
%
|
||||
% see also: engines.GPU.LSQML
|
||||
|
||||
|
||||
function [beta_probe, beta_object] = get_optimal_LSQ_step(self,chi,dO,dP,O,P, p_ind, par)
|
||||
|
||||
% find optimal step in the LSQ sense
|
||||
|
||||
import engines.GPU.GPU_wrapper.*
|
||||
import math.*
|
||||
global gpu use_gpu
|
||||
if ~isempty(gpu); wait(gpu); end
|
||||
|
||||
grouping = size(chi,3);
|
||||
lambda_0 = eps(single(1)) / prod(self.Np_p);
|
||||
|
||||
lambda_LSQ = 0.1; % add some small regularization to avoid instabilities
|
||||
|
||||
|
||||
if use_gpu
|
||||
% fast mex based CUDA version
|
||||
if size(dP,3) == grouping
|
||||
p_ind = 1:grouping; % one update for each position
|
||||
elseif size(dP,3) == 1 && numel(p_ind) == 1
|
||||
p_ind = ones(size(chi,3),1); % use only the one update given
|
||||
elseif max(p_ind) <= size(dP,3) && numel(p_ind) == grouping
|
||||
|
||||
else
|
||||
warning('Checkme, untested option')
|
||||
keyboard
|
||||
end
|
||||
try
|
||||
[AA, Atb] = get_LSQ_step_mex(chi,dO,dP,O,P,lambda_0, uint8(p_ind));
|
||||
catch err
|
||||
if any(strcmp(err.identifier, { 'MATLAB:UndefinedFunction','MATLAB:mex:ErrInvalidMEXFile'}))
|
||||
path = fullfile(replace(mfilename('fullpath'), mfilename, ''), 'private');
|
||||
mexcuda('-output', [path, '/get_LSQ_step_mex'], [path, '/get_LSQ_step_mex.cu'])
|
||||
|
||||
[AA, Atb] = get_LSQ_step_mex(chi,dO,dP,O,P,lambda_0, uint8(p_ind));
|
||||
else
|
||||
rethrow(err)
|
||||
end
|
||||
end
|
||||
|
||||
AA = Ggather(AA);
|
||||
Atb = Ggather(Atb);
|
||||
% is seems to be faster to get it first from GPU and then apply some
|
||||
% oprations because the matrices are too small
|
||||
AA = sum(AA,4);
|
||||
Atb = sum(Atb,4);
|
||||
AA = AA + lambda_LSQ*diag(diag(mean(AA,3)));
|
||||
% the system of equations is so small that solving on CPU is good enough
|
||||
[x1, x2] = solve_LSQ(AA(1,1,:), AA(2,1,:), AA(1,2,:), AA(2,2,:), Atb(1,1,:), Atb(2,1,:));
|
||||
LSQ_step = cat(1, x1, x2);
|
||||
else
|
||||
|
||||
|
||||
if ~( par.share_probe || length(unique(p_ind)) == 1 )
|
||||
% in case of multiple scans !!
|
||||
% replicate the update back to the original dP size
|
||||
dP = dP(:,:,p_ind);
|
||||
end
|
||||
tic
|
||||
% prevent ill posed inversion, ideally it should be Garray(mean(abs(AA1)+abs(AA4))/2) but it i show
|
||||
[AA1,AA2,AA4, Atb1,Atb2] = ...
|
||||
Gfun(@get_optimal_step_lsq, chi,dO,dP,...
|
||||
O,P, lambda_0);
|
||||
|
||||
AA1 = sum2(AA1);
|
||||
AA2 = sum2(AA2);
|
||||
AA4 = sum2(AA4);
|
||||
Atb1 = sum2(Atb1);
|
||||
Atb2 = sum2(Atb2);
|
||||
|
||||
% it seems faster to solve it on GPU than using pagefun on GPU
|
||||
AA1 = Ggather(AA1);AA2 = Ggather(AA2);AA4 = Ggather(AA4);Atb1 = Ggather(Atb1);Atb2 = Ggather(Atb2);
|
||||
AA3 = conj(AA2);
|
||||
|
||||
lambda = 0.5; % add some small regularization to avoid unstabilities
|
||||
I = lambda*[mean(AA1), mean(AA4)];
|
||||
|
||||
AA = [ AA1+I(1), AA2; AA3, AA4+I(2)];
|
||||
Atb= [ Atb1; Atb2];
|
||||
|
||||
[x1, x2] = solve_LSQ(AA(1,1,:), AA(2,1,:), AA(1,2,:), AA(2,2,:), Atb(1,1,:), Atb(2,1,:));
|
||||
LSQ_step = cat(1, x1, x2);
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
LSQ_step = max(0, real(LSQ_step));
|
||||
LSQ_step = Ggather(LSQ_step);
|
||||
|
||||
% prevent unwanted oscilation of step gets too high
|
||||
beta_probe = LSQ_step(2,1,:);
|
||||
beta_object = LSQ_step(1,1,:);
|
||||
|
||||
beta_probe = (par.beta_probe *par.beta_LSQ)* beta_probe;
|
||||
beta_object = (par.beta_object*par.beta_LSQ)* beta_object;
|
||||
|
||||
end
|
||||
|
||||
function [AA1,AA2,AA4, Atb1,Atb2] = ...
|
||||
get_optimal_step_lsq(chi,dO,dP,O,P, lambda)
|
||||
% fast kernel for estimation of optimal P and object steps
|
||||
dOP = dO.*P;
|
||||
dPO = dP.*O;
|
||||
cdOP = conj(dOP);
|
||||
cdPO = conj(dPO);
|
||||
|
||||
AA1 = real(dOP .* cdOP)+lambda;
|
||||
AA2 = (dOP .* cdPO);
|
||||
AA4 = real(dPO .* cdPO)+lambda;
|
||||
Atb1 = real(cdOP .* chi);
|
||||
Atb2 = real(cdPO .* chi);
|
||||
end
|
||||
|
||||
|
||||
function [x1, x2] = solve_LSQ(AA1, AA2, AA3, AA4, Atb1, Atb2)
|
||||
% GPU kernel to solve simple 2x2 system of equations
|
||||
det = (AA1.*AA4 - AA2.*AA3);
|
||||
x1 = -conj(AA2.*Atb2-AA4.*Atb1) ./ det;
|
||||
x2 = conj(AA1.*Atb2-AA3.*Atb1) ./ det;
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
% GET_VARIABLE_PROBE calculate variable probe (at different scan positions) for given mean/var probe and its evolution inputs
|
||||
%
|
||||
% probe = get_variable_probe(probe, probe_evolution, p_ind)
|
||||
%
|
||||
% ** probe [Nx,Ny,probe_modes,variable_modes] array, variable probe
|
||||
% ** probe_evolution [Npos,variable_modes] array containing evolution of the varaible modes for each position
|
||||
% ** p_ind indices containg corresponding probe id for each processed position
|
||||
%
|
||||
% returns:
|
||||
% ++ probe [Nx,Ny,N] array, a different probe for each scan position
|
||||
%
|
||||
% see also: engines.GPU.LSQML
|
||||
|
||||
|
||||
function probe = get_variable_probe(probe, probe_evolution, p_ind)
|
||||
|
||||
Np_p = [size(probe,1),size(probe,2)];
|
||||
|
||||
probe = probe(:,:,p_ind,:);
|
||||
|
||||
if length(p_ind) == 1 % in case that only single probe is called
|
||||
probe = reshape(probe,prod(Np_p),[]);
|
||||
probe = reshape(probe * probe_evolution', Np_p(1), Np_p(2), []);
|
||||
|
||||
else % in case multiple scans with unshared probe
|
||||
probe_out = 0;
|
||||
for ii = 1:size(probe,4)
|
||||
probe_out = probe_out + probe(:,:,:,ii).*reshape(probe_evolution(:,ii),1,1,[]);
|
||||
end
|
||||
probe = probe_out;
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,465 @@
|
||||
/*
|
||||
Set complex views to complex object
|
||||
mexcuda -output +engines/+GPU/get_optimal_LSQ_step_mex +engines/+GPU/get_optimal_LSQ_step_mex.cu
|
||||
*/
|
||||
|
||||
#include "mex.h"
|
||||
#include "gpu/mxGPUArray.h"
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
typedef const unsigned int cuint;
|
||||
typedef const uint16_T cuint16;
|
||||
#define MAX_BLOCK_DIM_SIZE 65535
|
||||
|
||||
|
||||
/*
|
||||
* Device code
|
||||
*/
|
||||
|
||||
// allocate shared memory so that all functions can see it
|
||||
extern __shared__ float sdata[];
|
||||
const unsigned int MAX_IND_READ = 10000;
|
||||
__constant__ uint8_T gC_pind[MAX_IND_READ];
|
||||
|
||||
|
||||
int checkLastError(char * msg)
|
||||
{
|
||||
cudaError_t cudaStatus = cudaGetLastError();
|
||||
if (cudaStatus != cudaSuccess) {
|
||||
char err[512];
|
||||
sprintf(err, "get_optimal_LSQ_step_ker failed \n %s: %s. \n", msg, cudaGetErrorString(cudaStatus));
|
||||
mexPrintf(err);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*********** fast inplace version of LSQ step calculation *************/
|
||||
|
||||
template <unsigned int blockSize>
|
||||
__device__ void calculate_AA_matrix( const float2 *P_f, const float2 *O_f,const float2 *dP_f, const float2 *dO_f, const float2 *chi_f,
|
||||
float &AA1, float2 &AA2,float2 &AA3, float &AA4,
|
||||
float &Atb1, float &Atb2 , const float lambda,
|
||||
cuint Np_x, cuint Np_y, cuint Npixz, cuint idz,
|
||||
cuint Nblocks, const bool single_probe, cuint id, cuint tid)
|
||||
{
|
||||
|
||||
float2 dO, dP, O, P, chi;
|
||||
// load to local memory
|
||||
cuint id3 = id + Np_x*Np_y*idz;
|
||||
O = O_f[id3] ;
|
||||
dO = dO_f[id3] ;
|
||||
chi = chi_f[id3];
|
||||
|
||||
if (single_probe) {
|
||||
// single shared 2D probe
|
||||
P = P_f[id];
|
||||
dP = dP_f[id];
|
||||
} else {
|
||||
// unshared probe => size(dp,3) == Nscans
|
||||
dP = dP_f[id + (gC_pind[idz]-1)*Np_x*Np_y];
|
||||
// position in 3D array
|
||||
P = P_f[id3];
|
||||
}
|
||||
|
||||
// make auxiliary variables
|
||||
float2 dOP, dPO, cdPO, cdOP;
|
||||
|
||||
// dOP = dO.*P;
|
||||
dOP.x = dO.x * P.x - dO.y * P.y;
|
||||
dOP.y = dO.y * P.x + dO.x * P.y;
|
||||
|
||||
// dPO = dP.*O;
|
||||
dPO.x = dP.x * O.x - dP.y * O.y;
|
||||
dPO.y = dP.y * O.x + dP.x * O.y;
|
||||
|
||||
// cdOP = conj(dOP);
|
||||
cdOP.x = dOP.x;
|
||||
cdOP.y = -dOP.y;
|
||||
|
||||
// cdPO = conj(dPO);
|
||||
cdPO.x = dPO.x;
|
||||
cdPO.y = -dPO.y;
|
||||
|
||||
// AA1 = abs(dOP).^2+lambda;
|
||||
AA1 = dOP.x * dOP.x + dOP.y * dOP.y ;
|
||||
|
||||
// AA2 = (dOP .* cdPO);
|
||||
AA2.x = dOP.x * cdPO.x - dOP.y * cdPO.y ;
|
||||
AA2.y = dOP.x * cdPO.y + dOP.x * cdPO.y ;
|
||||
|
||||
// AA3 = conj(AA2);
|
||||
AA3.x = AA2.x;
|
||||
AA3.y = -AA2.y;
|
||||
|
||||
// AA4 = abs(dPO)^2+lambda;
|
||||
AA4 = dPO.x * dPO.x + dPO.y * dPO.y ;
|
||||
|
||||
// Atb1 = real(cdOP .* chi);
|
||||
Atb1 = cdOP.x*chi.x - cdOP.y*chi.y;
|
||||
|
||||
// Atb2 = real(cdPO .* chi);
|
||||
Atb2 = cdPO.x*chi.x - cdPO.y*chi.y;
|
||||
|
||||
|
||||
// add to the shared gpu memory
|
||||
sdata[tid ] = AA1;
|
||||
sdata[tid+ blockSize] = AA2.x;
|
||||
sdata[tid+2*blockSize] = AA2.y;
|
||||
sdata[tid+3*blockSize] = AA3.x;
|
||||
sdata[tid+4*blockSize] = AA3.y;
|
||||
sdata[tid+5*blockSize] = AA4;
|
||||
sdata[tid+6*blockSize] = Atb1;
|
||||
sdata[tid+7*blockSize] = Atb2;
|
||||
}
|
||||
|
||||
template <unsigned int blockSize>
|
||||
__device__ void add_to_shared_array( cuint tid, cuint offset )
|
||||
{
|
||||
// another loop unrolling
|
||||
sdata[tid + 0*blockSize] += sdata[tid + 0*blockSize + offset];
|
||||
sdata[tid + 1*blockSize] += sdata[tid + 1*blockSize + offset];
|
||||
sdata[tid + 2*blockSize] += sdata[tid + 2*blockSize + offset];
|
||||
sdata[tid + 3*blockSize] += sdata[tid + 3*blockSize + offset];
|
||||
sdata[tid + 4*blockSize] += sdata[tid + 4*blockSize + offset];
|
||||
sdata[tid + 5*blockSize] += sdata[tid + 5*blockSize + offset];
|
||||
sdata[tid + 6*blockSize] += sdata[tid + 6*blockSize + offset];
|
||||
sdata[tid + 7*blockSize] += sdata[tid + 7*blockSize + offset];
|
||||
}
|
||||
|
||||
|
||||
template <unsigned int blockSize>
|
||||
__device__ void reduce_shared_array( cuint tid )
|
||||
{
|
||||
// do reduction in shared mem using unrolled loops
|
||||
if (blockSize >= 1024){ if (tid < 512) { add_to_shared_array<blockSize>(tid,512); } __syncthreads(); }
|
||||
if (blockSize >= 512) { if (tid < 256) { add_to_shared_array<blockSize>(tid,256); } __syncthreads(); }
|
||||
if (blockSize >= 256) { if (tid < 128) { add_to_shared_array<blockSize>(tid,128); } __syncthreads(); }
|
||||
if (blockSize >= 128) { if (tid < 64) { add_to_shared_array<blockSize>(tid,64); } __syncthreads(); }
|
||||
// why not do the same for all
|
||||
if (blockSize >= 64) { if (tid < 32) { add_to_shared_array<blockSize>(tid,32); } __syncthreads(); }
|
||||
if (blockSize >= 32) { if (tid < 16) { add_to_shared_array<blockSize>(tid,16); } __syncthreads(); }
|
||||
if (blockSize >= 16) { if (tid < 8) { add_to_shared_array<blockSize>(tid,8); } __syncthreads(); }
|
||||
if (blockSize >= 8) { if (tid < 4) { add_to_shared_array<blockSize>(tid,4); } __syncthreads(); }
|
||||
if (blockSize >= 4) { if (tid < 2) { add_to_shared_array<blockSize>(tid,2); } __syncthreads(); }
|
||||
if (blockSize >= 2) { if (tid < 1) { add_to_shared_array<blockSize>(tid,1); } __syncthreads(); }
|
||||
}
|
||||
|
||||
|
||||
// fast kernel for estimation of optimal probe and object steps
|
||||
|
||||
template <unsigned int blockSize>
|
||||
__global__ void get_optimal_LSQ_step_ker( float2 const * P_f, float2 const * O_f,float2 const * dP_f, float2 const * dO_f,
|
||||
float2 const * chi_f, const float lambda,
|
||||
float2 * AA, float * Atb, cuint Np_x,cuint Np_y, cuint Npixz, cuint Nblocks, const bool single_probe) {
|
||||
|
||||
const mwSize tid = threadIdx.x;
|
||||
// do only every second block
|
||||
//cuint i = blockIdx.x*(blockSize*2) + threadIdx.x;
|
||||
const mwSize i = blockIdx.x*(blockDim.x) + threadIdx.x;
|
||||
|
||||
const mwSize N2 = Np_x*Np_y;
|
||||
mwSize AA_page_id, Atb_page_id;
|
||||
|
||||
float2 AA2, AA3;
|
||||
float AA1, AA4, Atb1, Atb2;
|
||||
|
||||
for(int n = 0; n < 8; n++)
|
||||
sdata[tid + n*blockSize ] = 0 ;
|
||||
|
||||
|
||||
if(i < N2)
|
||||
{
|
||||
|
||||
//for(int n = 0; n < 8*blockSize; n++)
|
||||
// sdata[n] = 0 ;
|
||||
|
||||
|
||||
// Page in a 3D matrix
|
||||
for(int idz = 0; idz < Npixz; idz++)
|
||||
{
|
||||
unsigned int ii = i ;
|
||||
|
||||
// empty the share memory
|
||||
for(int n = 0; n < 8; n++)
|
||||
sdata[tid + n*blockSize ] = 0 ;
|
||||
|
||||
|
||||
|
||||
// get coeficients for the AA matrix + right size Atb vector and add them to the shared array
|
||||
calculate_AA_matrix<blockSize>(P_f ,O_f ,dP_f ,dO_f ,chi_f ,
|
||||
AA1, AA2, AA3, AA4, Atb1, Atb2, lambda, Np_x, Np_y, Npixz, idz, Nblocks,single_probe, ii, tid);
|
||||
|
||||
|
||||
__syncthreads();
|
||||
|
||||
|
||||
// reduce the shared memory data
|
||||
reduce_shared_array<blockSize>( tid );
|
||||
|
||||
|
||||
// write result for this block to global mem
|
||||
if (tid == 0) {
|
||||
// store data to the AA matrix
|
||||
AA_page_id = 4*idz + 4*Npixz*blockIdx.x;
|
||||
Atb_page_id = 2*idz + 2*Npixz*blockIdx.x;
|
||||
|
||||
AA[ 0 + AA_page_id].x = sdata[0*blockSize];
|
||||
AA[ 0 + AA_page_id].y = 0; // needs to be set to zero or initalized to zero when created
|
||||
|
||||
AA[ 1 + AA_page_id].x = sdata[1*blockSize];
|
||||
AA[ 1 + AA_page_id].y = sdata[2*blockSize];
|
||||
AA[ 2 + AA_page_id].x = sdata[3*blockSize];
|
||||
AA[ 2 + AA_page_id].y = sdata[4*blockSize];
|
||||
AA[ 3 + AA_page_id].x = sdata[5*blockSize];
|
||||
AA[ 3 + AA_page_id].y = 0;
|
||||
|
||||
Atb[ 0 + Atb_page_id] = sdata[6*blockSize];
|
||||
Atb[ 1 + Atb_page_id] = sdata[7*blockSize];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
unsigned int nextPow2( unsigned int x ) {
|
||||
--x;
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
x |= x >> 8;
|
||||
x |= x >> 16;
|
||||
return ++x;
|
||||
}
|
||||
|
||||
void getNumBlocksAndThreads(int n, int maxBlocks, int maxThreads, int &blocks, int &threads)
|
||||
{
|
||||
threads = (n < maxThreads*2) ? nextPow2((n + 1)/ 2) : maxThreads;
|
||||
blocks = (n + (threads * 2 - 1)) / (threads * 2);
|
||||
blocks = min(maxBlocks, blocks);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mexFunction(int nlhs, mxArray *plhs[],
|
||||
int nrhs, const mxArray *prhs[])
|
||||
{
|
||||
char const * const errId = "parallel:gpu:mexGPUExample:InvalidInput";
|
||||
char const * const errMsg = "Invalid input to MEX file.";
|
||||
|
||||
|
||||
// Check for proper number of arguments.
|
||||
|
||||
if (nrhs != 7)
|
||||
mexErrMsgTxt("Seven input arguments required");
|
||||
|
||||
|
||||
|
||||
const mxGPUArray * m_chi = mxGPUCreateFromMxArray(prhs[0]);
|
||||
if ((mxGPUGetClassID(m_chi) != mxSINGLE_CLASS) || (mxGPUGetComplexity(m_chi) != mxCOMPLEX)) {
|
||||
mexPrintf("m_chi\n");
|
||||
mexErrMsgIdAndTxt(errId, errMsg);
|
||||
}
|
||||
const float2 * p_chi = (float2 *)mxGPUGetDataReadOnly(m_chi);
|
||||
|
||||
const mxGPUArray * m_dO = mxGPUCreateFromMxArray(prhs[1]);
|
||||
if ((mxGPUGetClassID(m_dO) != mxSINGLE_CLASS) || (mxGPUGetComplexity(m_dO) != mxCOMPLEX)) {
|
||||
mexPrintf("m_dO\n");
|
||||
mexErrMsgIdAndTxt(errId, errMsg);
|
||||
}
|
||||
const float2 * p_dO = (float2 *)mxGPUGetDataReadOnly(m_dO);
|
||||
|
||||
const mxGPUArray * m_dP = mxGPUCreateFromMxArray(prhs[2]);
|
||||
if ((mxGPUGetClassID(m_dP) != mxSINGLE_CLASS) || (mxGPUGetComplexity(m_dP) != mxCOMPLEX)) {
|
||||
mexPrintf("m_dP\n");
|
||||
mexErrMsgIdAndTxt(errId, errMsg);
|
||||
}
|
||||
const float2 * p_dP = (float2 *)mxGPUGetDataReadOnly(m_dP);
|
||||
|
||||
const mxGPUArray * m_O = mxGPUCreateFromMxArray(prhs[3]);
|
||||
if ((mxGPUGetClassID(m_O) != mxSINGLE_CLASS) || (mxGPUGetComplexity(m_O) != mxCOMPLEX)) {
|
||||
mexPrintf("m_O\n");
|
||||
mexErrMsgIdAndTxt(errId, errMsg);
|
||||
}
|
||||
const float2 * p_O = (float2 *)mxGPUGetDataReadOnly(m_O);
|
||||
|
||||
const mxGPUArray * m_P = mxGPUCreateFromMxArray(prhs[4]);
|
||||
if ((mxGPUGetClassID(m_P) != mxSINGLE_CLASS) || (mxGPUGetComplexity(m_P) != mxCOMPLEX)) {
|
||||
mexPrintf("m_P\n");
|
||||
mexErrMsgIdAndTxt(errId, errMsg);
|
||||
}
|
||||
const float2 * p_P = (float2 *)mxGPUGetDataReadOnly(m_P);
|
||||
|
||||
const mxGPUArray * m_P_ind = mxGPUCreateFromMxArray(prhs[6]);
|
||||
if (mxGPUGetClassID(m_P_ind) != mxUINT8_CLASS) {
|
||||
mexPrintf("m_P_ind class %i\n", mxGPUGetClassID(m_P_ind));
|
||||
mexErrMsgIdAndTxt(errId, errMsg);
|
||||
}
|
||||
const uint8_T * p_P_ind = (uint8_T *)mxGPUGetDataReadOnly(m_P_ind);
|
||||
const unsigned int Npos = mxGPUGetNumberOfElements(m_P_ind);
|
||||
|
||||
if (Npos > MAX_IND_READ) {
|
||||
mexErrMsgIdAndTxt(errId, "Maximal size of input block exceeded");
|
||||
}
|
||||
|
||||
|
||||
// Get dimension of probe and object
|
||||
const unsigned int Ndims = (unsigned int)mxGPUGetNumberOfDimensions(m_chi);
|
||||
if (Ndims != 3) {
|
||||
mexErrMsgIdAndTxt(errId, "Inputs has to be 3 dimensional\n");
|
||||
}
|
||||
const mwSize * Npix = mxGPUGetDimensions(m_chi);
|
||||
const mwSize * Npix_probe = mxGPUGetDimensions(m_P);
|
||||
const mwSize * Npix_probe_upd = mxGPUGetDimensions(m_dP);
|
||||
const mwSize Ndims_probe = mxGPUGetNumberOfDimensions(m_P);
|
||||
const mwSize Ndims_probe_upd = mxGPUGetNumberOfDimensions(m_dP);
|
||||
|
||||
if ((Npix[2] != Npos)) {
|
||||
mexErrMsgIdAndTxt(errId, "Number of probe indices has to match size of inputs (%i vs %i) \n", Npix[2], Npos);
|
||||
}
|
||||
if ((Npix_probe[2] != Npix[2]) && (Ndims_probe != 2)) {
|
||||
mexErrMsgIdAndTxt(errId, "Dimension of probe has to match size of inputs (%i vs %i) \n", Npix_probe[2], Npix[2]);
|
||||
}
|
||||
|
||||
|
||||
float lambda = mxGetScalar(prhs[5]);
|
||||
|
||||
|
||||
|
||||
const bool single_probe =Ndims_probe == 2 ;
|
||||
|
||||
|
||||
|
||||
cudaMemcpyToSymbol(gC_pind, p_P_ind, Npos*sizeof(uint8_T), 0, cudaMemcpyHostToDevice);
|
||||
checkLastError("after cudaMemcpyToSymbol pos");
|
||||
|
||||
// Choose a reasonably sized number of threads in each dimension for the block.
|
||||
int maxThreads = 1024; // number of threads per block, does not work with 1024, I dont know why
|
||||
int threads = 0, blocks = 0;
|
||||
|
||||
cuint n = Npix[0]*Npix[1];
|
||||
|
||||
threads = (n < maxThreads) ? nextPow2((n + 1)/ 2) : maxThreads;
|
||||
blocks = (n + (threads - 1)) / (threads );
|
||||
|
||||
|
||||
|
||||
dim3 dimBlock(threads, 1, 1);
|
||||
dim3 dimGrid(blocks, 1, 1);
|
||||
|
||||
// allocation size needed for shared GPU memory , it needs to reduce 2 float2 elements and 4 float elements
|
||||
int smemSize = 8* threads * sizeof(float);
|
||||
|
||||
//mexPrintf("threads %i blocks %i smemSize %i \n", threads, blocks, smemSize);
|
||||
|
||||
|
||||
// allocate output fields
|
||||
mwSize matrix_size[4] = {2,2,Npix[2],blocks};
|
||||
mxGPUArray * m_AA = mxGPUCreateGPUArray(
|
||||
4,
|
||||
matrix_size,
|
||||
mxSINGLE_CLASS,
|
||||
mxCOMPLEX,
|
||||
MX_GPU_DO_NOT_INITIALIZE); // MX_GPU_DO_NOT_INITIALIZE , MX_GPU_INITIALIZE_VALUES
|
||||
float2 * p_AA = (float2 *)mxGPUGetData(m_AA);
|
||||
|
||||
mwSize vector_size[4] = {2,1,Npix[2],blocks};
|
||||
mxGPUArray * m_Atb = mxGPUCreateGPUArray(
|
||||
4,
|
||||
vector_size,
|
||||
mxSINGLE_CLASS,
|
||||
mxREAL,
|
||||
MX_GPU_DO_NOT_INITIALIZE);
|
||||
float * p_Atb = (float *)mxGPUGetData(m_Atb);
|
||||
|
||||
|
||||
|
||||
checkLastError("after dimThread");
|
||||
switch (threads)
|
||||
{
|
||||
case 1024:
|
||||
get_optimal_LSQ_step_ker< 1024><<< dimGrid, dimBlock, smemSize>>>( p_P, p_O,p_dP, p_dO, p_chi, lambda,
|
||||
p_AA, p_Atb, Npix[0], Npix[1], Npix[2], blocks, single_probe);
|
||||
break;
|
||||
case 512:
|
||||
get_optimal_LSQ_step_ker< 512><<< dimGrid, dimBlock, smemSize>>>( p_P, p_O,p_dP, p_dO, p_chi, lambda,
|
||||
p_AA, p_Atb, Npix[0], Npix[1], Npix[2], blocks, single_probe);
|
||||
break;
|
||||
case 256:
|
||||
get_optimal_LSQ_step_ker< 256><<< dimGrid, dimBlock, smemSize>>>( p_P, p_O,p_dP, p_dO, p_chi, lambda,
|
||||
p_AA, p_Atb, Npix[0], Npix[1], Npix[2], blocks, single_probe);
|
||||
break;
|
||||
case 128:
|
||||
get_optimal_LSQ_step_ker< 128><<< dimGrid, dimBlock, smemSize>>>( p_P, p_O,p_dP, p_dO, p_chi, lambda,
|
||||
p_AA, p_Atb, Npix[0], Npix[1], Npix[2], blocks, single_probe);
|
||||
break;
|
||||
case 64:
|
||||
get_optimal_LSQ_step_ker< 64><<< dimGrid, dimBlock, smemSize>>>( p_P, p_O,p_dP, p_dO, p_chi, lambda,
|
||||
p_AA, p_Atb, Npix[0], Npix[1], Npix[2], blocks, single_probe);
|
||||
break;
|
||||
case 32:
|
||||
get_optimal_LSQ_step_ker< 32><<< dimGrid, dimBlock, smemSize>>>( p_P, p_O,p_dP, p_dO, p_chi, lambda,
|
||||
p_AA, p_Atb, Npix[0], Npix[1], Npix[2], blocks, single_probe);
|
||||
break;
|
||||
case 16:
|
||||
get_optimal_LSQ_step_ker< 16><<< dimGrid, dimBlock, smemSize>>>( p_P, p_O,p_dP, p_dO, p_chi, lambda,
|
||||
p_AA, p_Atb, Npix[0], Npix[1], Npix[2], blocks, single_probe);
|
||||
break;
|
||||
case 8:
|
||||
get_optimal_LSQ_step_ker< 8><<< dimGrid, dimBlock, smemSize>>>( p_P, p_O,p_dP, p_dO, p_chi, lambda,
|
||||
p_AA, p_Atb, Npix[0], Npix[1], Npix[2], blocks, single_probe);
|
||||
break;
|
||||
case 4:
|
||||
get_optimal_LSQ_step_ker< 4><<< dimGrid, dimBlock, smemSize>>>( p_P, p_O,p_dP, p_dO, p_chi, lambda,
|
||||
p_AA, p_Atb, Npix[0], Npix[1], Npix[2], blocks, single_probe);
|
||||
break;
|
||||
case 2:
|
||||
get_optimal_LSQ_step_ker< 2><<< dimGrid, dimBlock, smemSize>>>( p_P, p_O,p_dP, p_dO, p_chi, lambda,
|
||||
p_AA, p_Atb, Npix[0], Npix[1], Npix[2], blocks, single_probe);
|
||||
break;
|
||||
case 1:
|
||||
get_optimal_LSQ_step_ker< 1><<< dimGrid, dimBlock, smemSize>>>( p_P, p_O,p_dP, p_dO, p_chi, lambda,
|
||||
p_AA, p_Atb, Npix[0], Npix[1], Npix[2], blocks, single_probe);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
checkLastError("after kernel");
|
||||
|
||||
|
||||
cudaThreadSynchronize();
|
||||
|
||||
|
||||
checkLastError("after kernel");
|
||||
|
||||
// Wrap the result up as a MATLAB gpuArray for return.
|
||||
plhs[0] = mxGPUCreateMxArrayOnGPU(m_AA);
|
||||
plhs[1] = mxGPUCreateMxArrayOnGPU(m_Atb);
|
||||
|
||||
|
||||
mxGPUDestroyGPUArray(m_P);
|
||||
mxGPUDestroyGPUArray(m_O);
|
||||
mxGPUDestroyGPUArray(m_dP);
|
||||
mxGPUDestroyGPUArray(m_dO);
|
||||
mxGPUDestroyGPUArray(m_chi);
|
||||
mxGPUDestroyGPUArray(m_AA);
|
||||
mxGPUDestroyGPUArray(m_Atb);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
% REFINE_OBJECT_UPDATE calculate improved update direction
|
||||
% apply "overlap" constraint to get better estimate of the update direction
|
||||
%
|
||||
% [object_upd_sum,object_update_proj, cache] = ...
|
||||
% refine_object_update(self, object_update_proj,object_upd_sum,layer_ids,scan_ids,g_ind,par, cache)
|
||||
%
|
||||
% ** self structure containing inputs: e.g. current reconstruction results, data, mask, positions, pixel size, ..
|
||||
% ** object_update_proj [Nx, Ny, N] array, estimate of the object update for each scan position, ie conj(P)*chi
|
||||
% ** object_upd_sum cell of object sized arrays containg previous optimal updates
|
||||
% ** g_ind indices corresponding to the current group that is solved in parallel
|
||||
% ** layer_ids id of the solved layer for multilayer ptycho
|
||||
% ** scan_ids determines to which scan correponds each of the position
|
||||
% ** par structure containing parameters for the engines
|
||||
% ** cache structure with precalculated values to avoid unnecessary overhead
|
||||
%
|
||||
% returns:
|
||||
% ++ object_upd_sum cell of object sized arrays containg updated optimal update
|
||||
% ++ object_update_proj [Nx, Ny, N] array, estimate of the refiend object update for each scan position,
|
||||
% ++ cache structure with precalculated values to avoid unnecessary overhead
|
||||
%
|
||||
%
|
||||
% see also: engines.GPU.LSQML
|
||||
|
||||
|
||||
%
|
||||
% Academic License Agreement
|
||||
%
|
||||
% Source Code
|
||||
%
|
||||
% Introduction
|
||||
% • This license agreement sets forth the terms and conditions under which the PAUL SCHERRER INSTITUT (PSI), CH-5232 Villigen-PSI, Switzerland (hereafter "LICENSOR")
|
||||
% will grant you (hereafter "LICENSEE") a royalty-free, non-exclusive license for academic, non-commercial purposes only (hereafter "LICENSE") to use the cSAXS
|
||||
% ptychography MATLAB package computer software program and associated documentation furnished hereunder (hereafter "PROGRAM").
|
||||
%
|
||||
% Terms and Conditions of the LICENSE
|
||||
% 1. LICENSOR grants to LICENSEE a royalty-free, non-exclusive license to use the PROGRAM for academic, non-commercial purposes, upon the terms and conditions
|
||||
% hereinafter set out and until termination of this license as set forth below.
|
||||
% 2. LICENSEE acknowledges that the PROGRAM is a research tool still in the development stage. The PROGRAM is provided without any related services, improvements
|
||||
% or warranties from LICENSOR and that the LICENSE is entered into in order to enable others to utilize the PROGRAM in their academic activities. It is the
|
||||
% LICENSEE’s responsibility to ensure its proper use and the correctness of the results.”
|
||||
% 3. THE PROGRAM IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR
|
||||
% A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. IN NO EVENT SHALL THE LICENSOR, THE AUTHORS OR THE COPYRIGHT
|
||||
% HOLDERS BE LIABLE FOR ANY CLAIM, DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR OTHER LIABILITY ARISING FROM, OUT OF OR IN CONNECTION WITH THE PROGRAM OR THE USE
|
||||
% OF THE PROGRAM OR OTHER DEALINGS IN THE PROGRAM.
|
||||
% 4. LICENSEE agrees that it will use the PROGRAM and any modifications, improvements, or derivatives of PROGRAM that LICENSEE may create (collectively,
|
||||
% "IMPROVEMENTS") solely for academic, non-commercial purposes and that any copy of PROGRAM or derivatives thereof shall be distributed only under the same
|
||||
% license as PROGRAM. The terms "academic, non-commercial", as used in this Agreement, mean academic or other scholarly research which (a) is not undertaken for
|
||||
% profit, or (b) is not intended to produce works, services, or data for commercial use, or (c) is neither conducted, nor funded, by a person or an entity engaged
|
||||
% in the commercial use, application or exploitation of works similar to the PROGRAM.
|
||||
% 5. LICENSEE agrees that it shall make the following acknowledgement in any publication resulting from the use of the PROGRAM or any translation of the code into
|
||||
% another computing language:
|
||||
% "Data processing was carried out using the cSAXS ptychography MATLAB package developed by the Science IT and the coherent X-ray scattering (CXS) groups, Paul
|
||||
% Scherrer Institut, Switzerland."
|
||||
%
|
||||
% Additionally, any publication using the package, or any translation of the code into another computing language should cite for difference map:
|
||||
% P. Thibault, M. Dierolf, A. Menzel, O. Bunk, C. David, F. Pfeiffer, High-resolution scanning X-ray diffraction microscopy, Science 321, 379–382 (2008).
|
||||
% (doi: 10.1126/science.1158573),
|
||||
% for mixed coherent modes:
|
||||
% P. Thibault and A. Menzel, Reconstructing state mixtures from diffraction measurements, Nature 494, 68–71 (2013). (doi: 10.1038/nature11806),
|
||||
% for LSQ-ML method
|
||||
% M. Odstrcil, A. Menzel, M.G. Sicairos, Iterative least-squares solver for generalized maximum-likelihood ptychography, Optics Express, 2018
|
||||
% for OPRP method
|
||||
% M. Odstrcil, P. Baksh, S. A. Boden, R. Card, J. E. Chad, J. G. Frey, W. S. Brocklesby, "Ptychographic coherent diffractive imaging with orthogonal probe relaxation." Optics express 24.8 (2016): 8360-8369
|
||||
% and/or for multislice:
|
||||
% E. H. R. Tsai, I. Usov, A. Diaz, A. Menzel, and M. Guizar-Sicairos, X-ray ptychography with extended depth of field, Opt. Express 24, 29089–29108 (2016).
|
||||
% 6. Except for the above-mentioned acknowledgment, LICENSEE shall not use the PROGRAM title or the names or logos of LICENSOR, nor any adaptation thereof, nor the
|
||||
% names of any of its employees or laboratories, in any advertising, promotional or sales material without prior written consent obtained from LICENSOR in each case.
|
||||
% 7. Ownership of all rights, including copyright in the PROGRAM and in any material associated therewith, shall at all times remain with LICENSOR, and LICENSEE
|
||||
% agrees to preserve same. LICENSEE agrees not to use any portion of the PROGRAM or of any IMPROVEMENTS in any machine-readable form outside the PROGRAM, nor to
|
||||
% make any copies except for its internal use, without prior written consent of LICENSOR. LICENSEE agrees to place the following copyright notice on any such copies:
|
||||
% © All rights reserved. PAUL SCHERRER INSTITUT, Switzerland, Laboratory for Macromolecules and Bioimaging, 2017.
|
||||
% 8. The LICENSE shall not be construed to confer any rights upon LICENSEE by implication or otherwise except as specifically set forth herein.
|
||||
% 9. DISCLAIMER: LICENSEE shall be aware that Phase Focus Limited of Sheffield, UK has an international portfolio of patents and pending applications which relate
|
||||
% to ptychography and that the PROGRAM may be capable of being used in circumstances which may fall within the claims of one or more of the Phase Focus patents,
|
||||
% in particular of patent with international application number PCT/GB2005/001464. The LICENSOR explicitly declares not to indemnify the users of the software
|
||||
% in case Phase Focus or any other third party will open a legal action against the LICENSEE due to the use of the program.
|
||||
% 10. This Agreement shall be governed by the material laws of Switzerland and any dispute arising out of this Agreement or use of the PROGRAM shall be brought before
|
||||
% the courts of Zürich, Switzerland.
|
||||
|
||||
|
||||
|
||||
function [object_upd_sum,object_update_proj, cache] = ...
|
||||
refine_object_update(self, object_update_proj,object_upd_sum,layer_ids,scan_ids,g_ind,par, cache)
|
||||
|
||||
import engines.GPU.shared.*
|
||||
import engines.GPU.GPU_wrapper.*
|
||||
import math.*
|
||||
import utils.*
|
||||
|
||||
if par.share_object
|
||||
obj_ids = 1;
|
||||
else
|
||||
obj_ids = unique(scan_ids);
|
||||
end
|
||||
|
||||
if ~isinf(self.z_distance)
|
||||
% only in nearfield mode , apply shift in the opposite direction
|
||||
object_update_proj = apply_subpx_shift(object_update_proj .* cache.apodwin, self.modes{1}.sub_px_shift(g_ind,:) ) ./ cache.apodwin;
|
||||
end
|
||||
|
||||
|
||||
% calculate update direction
|
||||
% apply "overlap" constraint to get better estimate
|
||||
% of the update directin
|
||||
if is_method(par, 'MLs')
|
||||
for ll_tmp = obj_ids; object_upd_sum{ll_tmp,layer_ids}(:) = eps*1i; end
|
||||
end
|
||||
if par.delta_p == 0 % || par.Nlayers > 1 % layer_ids > 1
|
||||
%no preconditioner as in the original ML method
|
||||
object_upd_sum = set_views(object_upd_sum,object_update_proj,layer_ids,obj_ids, g_ind, cache, scan_ids);
|
||||
|
||||
%plotting.smart_figure(1231)
|
||||
%plotting.imagesc3D(object_upd_sum{1,layer_ids})
|
||||
%drawnow
|
||||
|
||||
object_update_proj = get_views(object_upd_sum,object_update_proj,layer_ids,obj_ids, g_ind, cache, scan_ids);
|
||||
elseif par.delta_p > 0
|
||||
% damped LSQ method (preconditioned update)
|
||||
object_upd_sum = set_views(object_upd_sum,object_update_proj,layer_ids,obj_ids, g_ind, cache, scan_ids);
|
||||
for ll_tmp = obj_ids
|
||||
object_upd_precond{ll_tmp,1} = Gfun(@object_sum_update_Gfun, object_upd_sum{ll_tmp,layer_ids}, cache.illum_sum_0{ll_tmp},cache.MAX_ILLUM(ll_tmp)*(par.delta_p));
|
||||
end
|
||||
object_update_proj = get_views(object_upd_precond,object_update_proj,1,obj_ids, g_ind, cache, scan_ids);
|
||||
if is_method(par, 'MLs')
|
||||
object_upd_sum(:,layer_ids) = object_upd_precond(obj_ids);
|
||||
end
|
||||
else
|
||||
error('Unimplemented option')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function object_upd_sum = object_sum_update_Gfun(object_upd_sum, obj_illum_sq_sum, max)
|
||||
% final update is just weighted mean of the updared object views
|
||||
object_upd_sum = object_upd_sum ./ sqrt(obj_illum_sq_sum.^2+ max.^2);
|
||||
end
|
||||
@@ -0,0 +1,82 @@
|
||||
% REFINE_PROBE_UPDATE calculate improved update direction
|
||||
% apply "overlap" constraint to get better estimate of the update direction
|
||||
% also updates the variable probe estimate
|
||||
%
|
||||
% [ self,m_probe_update, probe_update, cache] = ...
|
||||
% refine_probe_update(self, obj_proj, probe_update, chi,layer_ids,probe_id,p_ind,g_ind, par, cache)
|
||||
%
|
||||
% ** self structure containing inputs: e.g. current reconstruction results, data, mask, positions, pixel size, ..
|
||||
% ** obj_proj [Nx, Ny, N] array, estimate of the object update for each scan position, ie conj(P)*chi
|
||||
% ** probe_update cell of object sized arrays containg previous optimal updates
|
||||
% ** chi indices corresponding to the current group that is solved in parallel
|
||||
% ** layer_ids id of the solved layer for multilayer ptycho
|
||||
% ** probe_id id of incoherent probe mode
|
||||
% ** p_ind indices containg corresponding probe id for each processed position
|
||||
% ** g_ind indices corresponding to the current group that is solved in parallel
|
||||
% ** par structure containing parameters for the engines
|
||||
% ** cache structure with precalculated values to avoid unnecessary overhead
|
||||
%
|
||||
% returns:
|
||||
% ++ object_upd_sum cell of object sized arrays containg updated optimal update
|
||||
% ++ object_update_proj [Nx, Ny, N] array, estimate of the refiend object update for each scan position,
|
||||
% ++ cache structure with precalculated values to avoid unnecessary overhead
|
||||
%
|
||||
%
|
||||
% see also: engines.GPU.LSQML
|
||||
|
||||
|
||||
function [ self,m_probe_update, probe_update, cache] = ...
|
||||
refine_probe_update(self, obj_proj, probe_update, chi,layer_ids,probe_id,p_ind,g_ind, par, cache)
|
||||
% get probe update direction
|
||||
import engines.GPU.shared.*
|
||||
import engines.GPU.LSQML.*
|
||||
import engines.GPU.GPU_wrapper.*
|
||||
import math.*
|
||||
import utils.*
|
||||
|
||||
if layer_ids > 1 % in case of multilayer object
|
||||
m_probe_update = [];
|
||||
return
|
||||
end
|
||||
|
||||
if (probe_id == 1 && par.apply_subpix_shift && isinf(self.z_distance(end))) || is_used(par,'fly_scan')
|
||||
probe_update = apply_subpx_shift(probe_update , -self.modes{min(end,probe_id)}.sub_px_shift(g_ind,:) );
|
||||
end
|
||||
if probe_id == 1
|
||||
probe_update = apply_subpx_shift_fft(probe_update, -self.modes{min(end,probe_id)}.probe_fourier_shift(g_ind,:));
|
||||
end
|
||||
|
||||
|
||||
if par.share_probe || length(unique(p_ind)) == 1
|
||||
% BETTER WAY: assume that sum(|obj_proj|^2,3) is close to 1
|
||||
% and additionally use weighting based on confidence given by illum_sum_0
|
||||
% => apriory weighting giving less importance to the less
|
||||
% illuminated regions
|
||||
%weight_proj = cache.illum_sum_0{1} ./ (cache.illum_sum_0{1}+0.01*cache.MAX_ILLUM(1));
|
||||
%weight_proj = get_views({weight_proj},[],1,1, g_ind, cache);
|
||||
%m_probe_update = mean( weight_proj.* probe_update,3);
|
||||
% or originally was used simple average , good for object >> probe
|
||||
m_probe_update = mean(probe_update,3); % calculate single update for all current positions
|
||||
else % unshared probe and multiple scans in one group (ie shared object)
|
||||
probe_ids = unique(p_ind);
|
||||
m_probe_update = Gzeros([self.Np_p,length(probe_ids)], true);
|
||||
for probe_id =probe_ids(:)'
|
||||
m_probe_update(:,:,probe_id) = mean(probe_update(:,:,p_ind == probe_id),3); % calculate one update for each scan
|
||||
end
|
||||
end
|
||||
|
||||
if (par.variable_probe || par.variable_intensity) && probe_id == 1
|
||||
% ORTHOGONAL PROBE RELAXATION (OPRP) EXTENSION - allow
|
||||
% variable probe wavefront
|
||||
% Odstrcil, M., et al. "Ptychographic coherent diffractive imaging with orthogonal probe relaxation." Optics express 24.8 (2016): 8360-8369.
|
||||
% iterate over all sub probes
|
||||
[self.probe{probe_id}, self.probe_evolution] = ...
|
||||
update_variable_probe(self, self.probe{probe_id}, self.probe_evolution, m_probe_update, probe_update, obj_proj, chi,cache.illum_sum_0{probe_id}, p_ind, g_ind, cache, par);
|
||||
end
|
||||
|
||||
% % apply probe constraints
|
||||
% if probe_id == 1 && (check_option(self,'probe_support') || check_option(self,'probe_support_fft'))
|
||||
% m_probe_update = apply_probe_contraints(m_probe_update, self.modes{probe_id});
|
||||
% end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,162 @@
|
||||
% UPDATE_OBJECT calculate improved update direction
|
||||
% apply "overlap" constraint to get better estimate of the update direction
|
||||
%
|
||||
% [object, object_upd_sum] = update_object(self, object, object_upd_sum, layer,object_ids, g_ind, scan_ids, par, cache, beta_object)
|
||||
%
|
||||
% ** self structure containing inputs: e.g. current reconstruction results, data, mask, positions, pixel size, ..
|
||||
% ** object cell of object arrays
|
||||
% ** object_upd_sum cell of object sized arrays containg previous optimal updates
|
||||
% ** layer_ids id of the solved layer for multilayer ptycho
|
||||
% ** object_ids id of incoherent object mode (not implemented)
|
||||
% ** g_ind indices corresponding to the current group that is solved in parallel
|
||||
% ** scan_ids determines to which scan correponds each of the position
|
||||
% ** par structure containing parameters for the engines
|
||||
% ** cache structure with precalculated values to avoid unnecessary overhead
|
||||
% ** beta_object (scalar) relaxation parameter of the update step
|
||||
%
|
||||
% returns:
|
||||
% ++ object cell of object arrays, after update
|
||||
% ++ object_upd_sum cell of object sized arrays containg updated optimal update
|
||||
%
|
||||
%
|
||||
% see also: engines.GPU.LSQML
|
||||
|
||||
|
||||
%
|
||||
% Academic License Agreement
|
||||
%
|
||||
% Source Code
|
||||
%
|
||||
% Introduction
|
||||
% • This license agreement sets forth the terms and conditions under which the PAUL SCHERRER INSTITUT (PSI), CH-5232 Villigen-PSI, Switzerland (hereafter "LICENSOR")
|
||||
% will grant you (hereafter "LICENSEE") a royalty-free, non-exclusive license for academic, non-commercial purposes only (hereafter "LICENSE") to use the cSAXS
|
||||
% ptychography MATLAB package computer software program and associated documentation furnished hereunder (hereafter "PROGRAM").
|
||||
%
|
||||
% Terms and Conditions of the LICENSE
|
||||
% 1. LICENSOR grants to LICENSEE a royalty-free, non-exclusive license to use the PROGRAM for academic, non-commercial purposes, upon the terms and conditions
|
||||
% hereinafter set out and until termination of this license as set forth below.
|
||||
% 2. LICENSEE acknowledges that the PROGRAM is a research tool still in the development stage. The PROGRAM is provided without any related services, improvements
|
||||
% or warranties from LICENSOR and that the LICENSE is entered into in order to enable others to utilize the PROGRAM in their academic activities. It is the
|
||||
% LICENSEE’s responsibility to ensure its proper use and the correctness of the results.”
|
||||
% 3. THE PROGRAM IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR
|
||||
% A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. IN NO EVENT SHALL THE LICENSOR, THE AUTHORS OR THE COPYRIGHT
|
||||
% HOLDERS BE LIABLE FOR ANY CLAIM, DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR OTHER LIABILITY ARISING FROM, OUT OF OR IN CONNECTION WITH THE PROGRAM OR THE USE
|
||||
% OF THE PROGRAM OR OTHER DEALINGS IN THE PROGRAM.
|
||||
% 4. LICENSEE agrees that it will use the PROGRAM and any modifications, improvements, or derivatives of PROGRAM that LICENSEE may create (collectively,
|
||||
% "IMPROVEMENTS") solely for academic, non-commercial purposes and that any copy of PROGRAM or derivatives thereof shall be distributed only under the same
|
||||
% license as PROGRAM. The terms "academic, non-commercial", as used in this Agreement, mean academic or other scholarly research which (a) is not undertaken for
|
||||
% profit, or (b) is not intended to produce works, services, or data for commercial use, or (c) is neither conducted, nor funded, by a person or an entity engaged
|
||||
% in the commercial use, application or exploitation of works similar to the PROGRAM.
|
||||
% 5. LICENSEE agrees that it shall make the foobject_idswing acknowledgement in any publication resulting from the use of the PROGRAM or any translation of the code into
|
||||
% another computing language:
|
||||
% "Data processing was carried out using the cSAXS ptychography MATLAB package developed by the Science IT and the coherent X-ray scattering (CXS) groups, Paul
|
||||
% Scherrer Institut, Switzerland."
|
||||
%
|
||||
% Additionally, any publication using the package, or any translation of the code into another computing language should cite for difference map:
|
||||
% P. Thibault, M. Dierolf, A. Menzel, O. Bunk, C. David, F. Pfeiffer, High-resolution scanning X-ray diffraction microscopy, Science 321, 379–382 (2008).
|
||||
% (doi: 10.1126/science.1158573),
|
||||
% for mixed coherent modes:
|
||||
% P. Thibault and A. Menzel, Reconstructing state mixtures from diffraction measurements, Nature 494, 68–71 (2013). (doi: 10.1038/nature11806),
|
||||
% for LSQ-ML method
|
||||
% M. Odstrcil, A. Menzel, M.G. Sicairos, Iterative least-squares solver for generalized maximum-likelihood ptychography, Optics Express, 2018
|
||||
% for OPRP method
|
||||
% M. Odstrcil, P. Baksh, S. A. Boden, R. Card, J. E. Chad, J. G. Frey, W. S. Brocklesby, "Ptychographic coherent diffractive imaging with orthogonal probe relaxation." Optics express 24.8 (2016): 8360-8369
|
||||
% and/or for multislice:
|
||||
% E. H. R. Tsai, I. Usov, A. Diaz, A. Menzel, and M. Guizar-Sicairos, X-ray ptychography with extended depth of field, Opt. Express 24, 29089–29108 (2016).
|
||||
% 6. Except for the above-mentioned acknowledgment, LICENSEE shall not use the PROGRAM title or the names or logos of LICENSOR, nor any adaptation thereof, nor the
|
||||
% names of any of its employees or laboratories, in any advertising, promotional or sales material without prior written consent obtained from LICENSOR in each case.
|
||||
% 7. Ownership of all rights, including copyright in the PROGRAM and in any material associated therewith, shall at all times remain with LICENSOR, and LICENSEE
|
||||
% agrees to preserve same. LICENSEE agrees not to use any portion of the PROGRAM or of any IMPROVEMENTS in any machine-readable form outside the PROGRAM, nor to
|
||||
% make any copies except for its internal use, without prior written consent of LICENSOR. LICENSEE agrees to place the foobject_idswing copyright notice on any such copies:
|
||||
% © All rights reserved. PAUL SCHERRER INSTITUT, Switzerland, Laboratory for Macromolecules and Bioimaging, 2017.
|
||||
% 8. The LICENSE shall not be construed to confer any rights upon LICENSEE by implication or otherwise except as specifically set forth herein.
|
||||
% 9. DISCLAIMER: LICENSEE shall be aware that Phase Focus Limited of Sheffield, UK has an international portfolio of patents and pending applications which relate
|
||||
% to ptychography and that the PROGRAM may be capable of being used in circumstances which may fall within the claims of one or more of the Phase Focus patents,
|
||||
% in particular of patent with international application number PCT/GB2005/001464. The LICENSOR explicitly declares not to indemnify the users of the software
|
||||
% in case Phase Focus or any other third party will open a legal action against the LICENSEE due to the use of the program.
|
||||
% 10. This Agreement shall be governed by the material laws of Switzerland and any dispute arising out of this Agreement or use of the PROGRAM shall be brought before
|
||||
% the courts of Zürich, Switzerland.
|
||||
|
||||
|
||||
|
||||
function [object, object_upd_sum] = update_object(self, object, object_upd_sum, layer,object_ids, g_ind, scan_ids, par, cache, beta_object)
|
||||
import engines.GPU.shared.*
|
||||
import engines.GPU.GPU_wrapper.*
|
||||
import math.*
|
||||
import utils.*
|
||||
|
||||
if par.share_object
|
||||
obj_ids = 1;
|
||||
else
|
||||
obj_ids = unique([scan_ids{:}]);
|
||||
end
|
||||
% take single optimal value, works well for most of samples
|
||||
% it is possible to use different weighting for each scan position but
|
||||
% it may become less stable in some cases -> robusness is preferred
|
||||
|
||||
% in case of the MLc method take minimum of the LSQ updates from all
|
||||
% subsets
|
||||
|
||||
if is_method(par, 'MLc')
|
||||
% preconditioner should be applied on the total sum of all object_upd_sum
|
||||
if par.delta_p > 0 % && par.Nlayers == 1
|
||||
for kk = obj_ids
|
||||
object_upd_sum{kk,layer} = Gfun(@object_sum_update_Gfun, object_upd_sum{kk,layer}, cache.illum_sum_0{kk},cache.MAX_ILLUM(kk)*(par.delta_p));
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
% calculate optimal step, apply at least different step for each object (scan)
|
||||
for i = 1:length(g_ind)
|
||||
for kk = obj_ids
|
||||
ind = g_ind{i}(scan_ids{i} == kk);
|
||||
if isempty(ind)
|
||||
beta_object_avg(i,kk) = nan;
|
||||
else
|
||||
beta_object_avg(i,kk) = trimmean(beta_object(ind), 10);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
% take the most pesimistic estimate of the per object
|
||||
beta_object_avg=nanmin(beta_object_avg,[],1);
|
||||
|
||||
% update each of the objects separately
|
||||
for kk = obj_ids
|
||||
if beta_object_avg(kk) > 0
|
||||
object_upd_sum{kk,layer} = object_upd_sum{kk,layer}*beta_object_avg(kk);
|
||||
object{kk,layer} = object{kk,layer}+object_upd_sum{kk,layer};
|
||||
end
|
||||
end
|
||||
|
||||
if verbose()> 3
|
||||
% show applied subsets (update amplitude) and probe update amplitude
|
||||
plotting.smart_figure(11)
|
||||
Nobj = size(object_upd_sum,1);
|
||||
for ll = 1:Nobj
|
||||
subplot(Nobj,2,1+Nobj*(ll-1))
|
||||
cla()
|
||||
o = object_upd_sum{ll,layer}(cache.object_ROI{:});
|
||||
o = min(abs(o), quantile(abs(o(:)), 0.999)) .* o ./ abs(o);
|
||||
plotting.imagesc3D(o);
|
||||
axis image xy off
|
||||
hold all
|
||||
fprintf('Object update norm: %g\n', norm2(object_upd_sum{ll,layer}(cache.object_ROI{:})))
|
||||
% try
|
||||
% for k = 1:length(g_ind)
|
||||
% for i = unique(scan_ids{k})
|
||||
% plot(self.probe_positions_0(g_ind{k}(scan_ids{k}==i),1)+self.Np_o(2)/2,self.probe_positions_0(g_ind{k}(scan_ids{k}==i),2)+self.Np_o(1)/2, '.')
|
||||
% end
|
||||
% end
|
||||
% end
|
||||
end
|
||||
title('Object update')
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
function object_upd_sum = object_sum_update_Gfun(object_upd_sum, obj_illum_sq_sum, max)
|
||||
% final update is just weighted mean of the updared object views
|
||||
object_upd_sum = object_upd_sum ./ sqrt(obj_illum_sq_sum.^2+ max.^2);
|
||||
end
|
||||
@@ -0,0 +1,126 @@
|
||||
% UPDATE_PROBE calculate improved update direction
|
||||
% apply "overlap" constraint to get better estimate of the update direction
|
||||
%
|
||||
% probe = update_probe(probe, m_probe_update, par, p_ind, g_ind, beta_probe, Nind)
|
||||
%
|
||||
% ** self structure containing inputs: e.g. current reconstruction results, data, mask, positions, pixel size, ..
|
||||
% ** object_update_proj [Nx, Ny, N] array, estimate of the object update for each scan position, ie conj(P)*chi
|
||||
% ** object_upd_sum cell of object sized arrays containg previous optimal updates
|
||||
% ** p_ind indices containg corresponding probe id for each processed position
|
||||
% ** g_ind indices corresponding to the current group that is solved in parallel
|
||||
% ** beta_probe (scalar) relaxation parameter of the update step
|
||||
% ** Nind (int) number of groups that are solved serially
|
||||
|
||||
% returns:
|
||||
% ++ probe cell of the updated probes
|
||||
%
|
||||
%
|
||||
% see also: engines.GPU.LSQML
|
||||
|
||||
|
||||
%
|
||||
% Academic License Agreement
|
||||
%
|
||||
% Source Code
|
||||
%
|
||||
% Introduction
|
||||
% • This license agreement sets forth the terms and conditions under which the PAUL SCHERRER INSTITUT (PSI), CH-5232 Villigen-PSI, Switzerland (hereafter "LICENSOR")
|
||||
% will grant you (hereafter "LICENSEE") a royalty-free, non-exclusive license for academic, non-commercial purposes only (hereafter "LICENSE") to use the cSAXS
|
||||
% ptychography MATLAB package computer software program and associated documentation furnished hereunder (hereafter "PROGRAM").
|
||||
%
|
||||
% Terms and Conditions of the LICENSE
|
||||
% 1. LICENSOR grants to LICENSEE a royalty-free, non-exclusive license to use the PROGRAM for academic, non-commercial purposes, upon the terms and conditions
|
||||
% hereinafter set out and until termination of this license as set forth below.
|
||||
% 2. LICENSEE acknowledges that the PROGRAM is a research tool still in the development stage. The PROGRAM is provided without any related services, improvements
|
||||
% or warranties from LICENSOR and that the LICENSE is entered into in order to enable others to utilize the PROGRAM in their academic activities. It is the
|
||||
% LICENSEE’s responsibility to ensure its proper use and the correctness of the results.”
|
||||
% 3. THE PROGRAM IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR
|
||||
% A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. IN NO EVENT SHALL THE LICENSOR, THE AUTHORS OR THE COPYRIGHT
|
||||
% HOLDERS BE LIABLE FOR ANY CLAIM, DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR OTHER LIABILITY ARISING FROM, OUT OF OR IN CONNECTION WITH THE PROGRAM OR THE USE
|
||||
% OF THE PROGRAM OR OTHER DEALINGS IN THE PROGRAM.
|
||||
% 4. LICENSEE agrees that it will use the PROGRAM and any modifications, improvements, or derivatives of PROGRAM that LICENSEE may create (collectively,
|
||||
% "IMPROVEMENTS") solely for academic, non-commercial purposes and that any copy of PROGRAM or derivatives thereof shall be distributed only under the same
|
||||
% license as PROGRAM. The terms "academic, non-commercial", as used in this Agreement, mean academic or other scholarly research which (a) is not undertaken for
|
||||
% profit, or (b) is not intended to produce works, services, or data for commercial use, or (c) is neither conducted, nor funded, by a person or an entity engaged
|
||||
% in the commercial use, application or exploitation of works similar to the PROGRAM.
|
||||
% 5. LICENSEE agrees that it shall make the following acknowledgement in any publication resulting from the use of the PROGRAM or any translation of the code into
|
||||
% another computing language:
|
||||
% "Data processing was carried out using the cSAXS ptychography MATLAB package developed by the Science IT and the coherent X-ray scattering (CXS) groups, Paul
|
||||
% Scherrer Institut, Switzerland."
|
||||
%
|
||||
% Additionally, any publication using the package, or any translation of the code into another computing language should cite for difference map:
|
||||
% P. Thibault, M. Dierolf, A. Menzel, O. Bunk, C. David, F. Pfeiffer, High-resolution scanning X-ray diffraction microscopy, Science 321, 379–382 (2008).
|
||||
% (doi: 10.1126/science.1158573),
|
||||
% for mixed coherent modes:
|
||||
% P. Thibault and A. Menzel, Reconstructing state mixtures from diffraction measurements, Nature 494, 68–71 (2013). (doi: 10.1038/nature11806),
|
||||
% for LSQ-ML method
|
||||
% M. Odstrcil, A. Menzel, M.G. Sicairos, Iterative least-squares solver for generalized maximum-likelihood ptychography, Optics Express, 2018
|
||||
% for OPRP method
|
||||
% M. Odstrcil, P. Baksh, S. A. Boden, R. Card, J. E. Chad, J. G. Frey, W. S. Brocklesby, "Ptychographic coherent diffractive imaging with orthogonal probe relaxation." Optics express 24.8 (2016): 8360-8369
|
||||
% and/or for multislice:
|
||||
% E. H. R. Tsai, I. Usov, A. Diaz, A. Menzel, and M. Guizar-Sicairos, X-ray ptychography with extended depth of field, Opt. Express 24, 29089–29108 (2016).
|
||||
% 6. Except for the above-mentioned acknowledgment, LICENSEE shall not use the PROGRAM title or the names or logos of LICENSOR, nor any adaptation thereof, nor the
|
||||
% names of any of its employees or laboratories, in any advertising, promotional or sales material without prior written consent obtained from LICENSOR in each case.
|
||||
% 7. Ownership of all rights, including copyright in the PROGRAM and in any material associated therewith, shall at all times remain with LICENSOR, and LICENSEE
|
||||
% agrees to preserve same. LICENSEE agrees not to use any portion of the PROGRAM or of any IMPROVEMENTS in any machine-readable form outside the PROGRAM, nor to
|
||||
% make any copies except for its internal use, without prior written consent of LICENSOR. LICENSEE agrees to place the following copyright notice on any such copies:
|
||||
% © All rights reserved. PAUL SCHERRER INSTITUT, Switzerland, Laboratory for Macromolecules and Bioimaging, 2017.
|
||||
% 8. The LICENSE shall not be construed to confer any rights upon LICENSEE by implication or otherwise except as specifically set forth herein.
|
||||
% 9. DISCLAIMER: LICENSEE shall be aware that Phase Focus Limited of Sheffield, UK has an international portfolio of patents and pending applications which relate
|
||||
% to ptychography and that the PROGRAM may be capable of being used in circumstances which may fall within the claims of one or more of the Phase Focus patents,
|
||||
% in particular of patent with international application number PCT/GB2005/001464. The LICENSOR explicitly declares not to indemnify the users of the software
|
||||
% in case Phase Focus or any other third party will open a legal action against the LICENSEE due to the use of the program.
|
||||
% 10. This Agreement shall be governed by the material laws of Switzerland and any dispute arising out of this Agreement or use of the PROGRAM shall be brought before
|
||||
% the courts of Zürich, Switzerland.
|
||||
|
||||
|
||||
|
||||
function probe = update_probe(probe, m_probe_update, par, p_ind, g_ind, beta_probe, Nind)
|
||||
import engines.GPU.shared.*
|
||||
import engines.GPU.GPU_wrapper.*
|
||||
import utils.verbose
|
||||
|
||||
%% update probe
|
||||
beta_probe = beta_probe(g_ind);
|
||||
probe_ids = unique(p_ind);
|
||||
if is_method(par, 'MLc')
|
||||
beta_probe = beta_probe / Nind; % in order to make the compact version closer to original ML method, the accumulated probe step per iteration should be 1
|
||||
end
|
||||
|
||||
if (par.share_probe || par.Nscans == 1) && size(probe,3)==1
|
||||
% most simple case, no multiprobe needed
|
||||
probe = probe + m_probe_update .* mean(beta_probe);
|
||||
elseif length(probe_ids) == 1
|
||||
% variable probe extension with shared probe
|
||||
probe(:,:,probe_ids,1) = probe(:,:,probe_ids,1) + m_probe_update .* mean(beta_probe);
|
||||
else % unshared probe
|
||||
% update each of the probes separately
|
||||
for id = probe_ids(:)'
|
||||
ind = p_ind == id;
|
||||
beta = mean(beta_probe(ind));
|
||||
probe(:,:,id,1) = Gfun(@upd_probe_Gfun, probe(:,:,id,1),m_probe_update(:,:,min(end,id)), beta);
|
||||
end
|
||||
end
|
||||
|
||||
if verbose()> 3
|
||||
% show applied subsets (update amplitude) and probe update
|
||||
% amplitude
|
||||
plotting.smart_figure(11)
|
||||
probe_modes = size(m_probe_update,3);
|
||||
for ll = 1:probe_modes
|
||||
subplot(probe_modes,2,2+probe_modes*(ll-1))
|
||||
p = fftshift(fft2(fftshift(m_probe_update(:,:,ll))));
|
||||
p = min(abs(p), quantile(abs(p(:)), 0.999)) .* p ./ abs(p);
|
||||
plotting.imagesc3D(p);
|
||||
axis off image xy
|
||||
end
|
||||
title('Probe update')
|
||||
colormap bone
|
||||
drawnow
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function probe = upd_probe_Gfun(probe,probe_update, alpha_p)
|
||||
probe = probe + alpha_p.*probe_update;
|
||||
end
|
||||
@@ -0,0 +1,221 @@
|
||||
% UPDATE_VARIABLE_PROBE approximation of the OPRP method to get only the first orthogonal
|
||||
% vector describing the probe
|
||||
%
|
||||
% [probe, probe_evolution] = ...
|
||||
% update_variable_probe(self,probe, probe_evolution, m_probe_update,probe_update, obj_proj, chi, weights, p_ind, g_ind, cache, par)
|
||||
%
|
||||
%
|
||||
%
|
||||
% ** self structure containing inputs: e.g. current reconstruction results, data, mask, positions, pixel size, ..
|
||||
% ** probe [Nx,Nx,probe_modes,variable_modes] variable probe modes
|
||||
% ** probe_evolution [Npos,variable_modes] array containing evolution of the varaible modes for each position
|
||||
% ** m_probe_update precalculated value of mean(dP,3)
|
||||
% ** probe_update probe update, ie conj(O)*chi
|
||||
% ** obj_proj [Nx,Ny,N] array, views of the object for each scan position
|
||||
% ** chi [Nx,Ny,N] array, difference between original and updated exit-wave
|
||||
% ** weights array of relaxation values for object pixel, reduce weight of regions with weak illumination in the variable probe calculation
|
||||
% ** p_ind indices containg corresponding probe id for each processed position
|
||||
% ** g_ind indices corresponding to the current group that is solved in parallel
|
||||
% ** cache structure with precalculated values to avoid unnecessary overhead
|
||||
% ** par structure containing parameters for the engines
|
||||
%
|
||||
% returns:
|
||||
% ++ probe [Nx,Nx,probe_modes,variable_modes] updated variable modes
|
||||
% ++ probe_evolution [Npos,variable_modes] updated array containing evolution of the varaible modes for each position
|
||||
%
|
||||
%
|
||||
% see also: engines.GPU.LSQML
|
||||
|
||||
|
||||
%
|
||||
% Academic License Agreement
|
||||
%
|
||||
% Source Code
|
||||
%
|
||||
% Introduction
|
||||
% • This license agreement sets forth the terms and conditions under which the PAUL SCHERRER INSTITUT (PSI), CH-5232 Villigen-PSI, Switzerland (hereafter "LICENSOR")
|
||||
% will grant you (hereafter "LICENSEE") a royalty-free, non-exclusive license for academic, non-commercial purposes only (hereafter "LICENSE") to use the cSAXS
|
||||
% ptychography MATLAB package computer software program and associated documentation furnished hereunder (hereafter "PROGRAM").
|
||||
%
|
||||
% Terms and Conditions of the LICENSE
|
||||
% 1. LICENSOR grants to LICENSEE a royalty-free, non-exclusive license to use the PROGRAM for academic, non-commercial purposes, upon the terms and conditions
|
||||
% hereinafter set out and until termination of this license as set forth below.
|
||||
% 2. LICENSEE acknowledges that the PROGRAM is a research tool still in the development stage. The PROGRAM is provided without any related services, improvements
|
||||
% or warranties from LICENSOR and that the LICENSE is entered into in order to enable others to utilize the PROGRAM in their academic activities. It is the
|
||||
% LICENSEE’s responsibility to ensure its proper use and the correctness of the results.”
|
||||
% 3. THE PROGRAM IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR
|
||||
% A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. IN NO EVENT SHALL THE LICENSOR, THE AUTHORS OR THE COPYRIGHT
|
||||
% HOLDERS BE LIABLE FOR ANY CLAIM, DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR OTHER LIABILITY ARISING FROM, OUT OF OR IN CONNECTION WITH THE PROGRAM OR THE USE
|
||||
% OF THE PROGRAM OR OTHER DEALINGS IN THE PROGRAM.
|
||||
% 4. LICENSEE agrees that it will use the PROGRAM and any modifications, improvements, or derivatives of PROGRAM that LICENSEE may create (collectively,
|
||||
% "IMPROVEMENTS") solely for academic, non-commercial purposes and that any copy of PROGRAM or derivatives thereof shall be distributed only under the same
|
||||
% license as PROGRAM. The terms "academic, non-commercial", as used in this Agreement, mean academic or other scholarly research which (a) is not undertaken for
|
||||
% profit, or (b) is not intended to produce works, services, or data for commercial use, or (c) is neither conducted, nor funded, by a person or an entity engaged
|
||||
% in the commercial use, application or exploitation of works similar to the PROGRAM.
|
||||
% 5. LICENSEE agrees that it shall make the following acknowledgement in any publication resulting from the use of the PROGRAM or any translation of the code into
|
||||
% another computing language:
|
||||
% "Data processing was carried out using the cSAXS ptychography MATLAB package developed by the Science IT and the coherent X-ray scattering (CXS) groups, Paul
|
||||
% Scherrer Institut, Switzerland."
|
||||
%
|
||||
% Additionally, any publication using the package, or any translation of the code into another computing language should cite for difference map:
|
||||
% P. Thibault, M. Dierolf, A. Menzel, O. Bunk, C. David, F. Pfeiffer, High-resolution scanning X-ray diffraction microscopy, Science 321, 379–382 (2008).
|
||||
% (doi: 10.1126/science.1158573),
|
||||
% for mixed coherent modes:
|
||||
% P. Thibault and A. Menzel, Reconstructing state mixtures from diffraction measurements, Nature 494, 68–71 (2013). (doi: 10.1038/nature11806),
|
||||
% for LSQ-ML method
|
||||
% M. Odstrcil, A. Menzel, M.G. Sicairos, Iterative least-squares solver for generalized maximum-likelihood ptychography, Optics Express, 2018
|
||||
% for OPRP method
|
||||
% M. Odstrcil, P. Baksh, S. A. Boden, R. Card, J. E. Chad, J. G. Frey, W. S. Brocklesby, "Ptychographic coherent diffractive imaging with orthogonal probe relaxation." Optics express 24.8 (2016): 8360-8369
|
||||
% and/or for multislice:
|
||||
% E. H. R. Tsai, I. Usov, A. Diaz, A. Menzel, and M. Guizar-Sicairos, X-ray ptychography with extended depth of field, Opt. Express 24, 29089–29108 (2016).
|
||||
% 6. Except for the above-mentioned acknowledgment, LICENSEE shall not use the PROGRAM title or the names or logos of LICENSOR, nor any adaptation thereof, nor the
|
||||
% names of any of its employees or laboratories, in any advertising, promotional or sales material without prior written consent obtained from LICENSOR in each case.
|
||||
% 7. Ownership of all rights, including copyright in the PROGRAM and in any material associated therewith, shall at all times remain with LICENSOR, and LICENSEE
|
||||
% agrees to preserve same. LICENSEE agrees not to use any portion of the PROGRAM or of any IMPROVEMENTS in any machine-readable form outside the PROGRAM, nor to
|
||||
% make any copies except for its internal use, without prior written consent of LICENSOR. LICENSEE agrees to place the following copyright notice on any such copies:
|
||||
% © All rights reserved. PAUL SCHERRER INSTITUT, Switzerland, Laboratory for Macromolecules and Bioimaging, 2017.
|
||||
% 8. The LICENSE shall not be construed to confer any rights upon LICENSEE by implication or otherwise except as specifically set forth herein.
|
||||
% 9. DISCLAIMER: LICENSEE shall be aware that Phase Focus Limited of Sheffield, UK has an international portfolio of patents and pending applications which relate
|
||||
% to ptychography and that the PROGRAM may be capable of being used in circumstances which may fall within the claims of one or more of the Phase Focus patents,
|
||||
% in particular of patent with international application number PCT/GB2005/001464. The LICENSOR explicitly declares not to indemnify the users of the software
|
||||
% in case Phase Focus or any other third party will open a legal action against the LICENSEE due to the use of the program.
|
||||
% 10. This Agreement shall be governed by the material laws of Switzerland and any dispute arising out of this Agreement or use of the PROGRAM shall be brought before
|
||||
% the courts of Zürich, Switzerland.
|
||||
|
||||
|
||||
|
||||
function [probe, probe_evolution] = ...
|
||||
update_variable_probe(self,probe, probe_evolution, m_probe_update,probe_update, obj_proj, chi, weights, p_ind, g_ind, cache, par)
|
||||
|
||||
import math.*
|
||||
import plotting.*
|
||||
import engines.GPU.GPU_wrapper.*
|
||||
|
||||
%disp(size(probe_evolution))
|
||||
uids = unique(p_ind);
|
||||
for kk = uids
|
||||
if length(uids) == 1 % single or shared probe between the scans
|
||||
% avoid memory copy is possible
|
||||
probe_update_tmp = probe_update;
|
||||
chi_tmp = chi;
|
||||
obj_proj_tmp = obj_proj;
|
||||
g_ind_tmp = g_ind;
|
||||
block_size = length(g_ind);
|
||||
else
|
||||
% otherwise
|
||||
block_ind = p_ind == kk;
|
||||
probe_update_tmp = probe_update(:,:,block_ind);
|
||||
obj_proj_tmp = obj_proj(:,:,block_ind);
|
||||
chi_tmp = chi(:,:,block_ind);
|
||||
g_ind_tmp = g_ind(block_ind);
|
||||
block_size= sum(block_ind);
|
||||
end
|
||||
|
||||
|
||||
if par.variable_probe
|
||||
% use some relaxation to avoid too faster changes
|
||||
relax_U = min(0.1,block_size/self.Npos); %depend on group size
|
||||
relax_V = 1;
|
||||
% make probe_update_tmp orthogonal to the average update
|
||||
probe_update_tmp = probe_update_tmp - m_probe_update(:,:,min(end,kk));
|
||||
|
||||
for ii = 1:par.variable_probe_modes
|
||||
var_probe = probe(:,:,kk,1+ii);
|
||||
probe_evol = probe_evolution(g_ind_tmp,1+ii); % evolution of the 1th SVD mode coeficient
|
||||
|
||||
[var_probe,probe_evol,probe_update_tmp] = get_first_SVD_mode(probe_update_tmp, var_probe, probe_evol,relax_U,relax_V, obj_proj_tmp, chi_tmp);
|
||||
if ii < par.variable_probe_modes
|
||||
% subtract projection of the updated var_probe from the
|
||||
% probe_update_tmp to enforce orthogonality between the
|
||||
% modes
|
||||
projection = sum2(probe_update_tmp .* conj(var_probe)) ./ sum2(abs(var_probe).^2);
|
||||
probe_update_tmp = probe_update_tmp - projection .* var_probe;
|
||||
end
|
||||
% return the updated vector to the probe array
|
||||
probe(:,:,kk,1+ii) = var_probe;
|
||||
probe_evolution(g_ind_tmp,1+ii) = probe_evol;
|
||||
end
|
||||
|
||||
end
|
||||
if par. variable_intensity
|
||||
% correction to account for variable intensity
|
||||
mean_probe = probe(:,:,kk,1);
|
||||
% compare P*0 and chi to estimate best update of the intensity
|
||||
[nom, denom] = Gfun(@get_coefs_intensity,chi_tmp, mean_probe, obj_proj_tmp);
|
||||
|
||||
probe_evolution(g_ind_tmp,1) = probe_evolution(g_ind_tmp,1) + 0.1* squeeze(Ggather(sum2(nom)./ sum2(denom)));
|
||||
end
|
||||
end
|
||||
|
||||
if any(g_ind==1) && utils.verbose() > 3
|
||||
self.probe{1} = probe;
|
||||
self.probe_evolution = probe_evolution;
|
||||
plot_variable_probe(self, par)
|
||||
drawnow
|
||||
end
|
||||
end
|
||||
|
||||
function [var_probe,probe_evol, probe_update] = get_first_SVD_mode(probe_update, var_probe, probe_evol, relax_U,relax_V, obj_proj, chi)
|
||||
import engines.GPU.GPU_wrapper.*
|
||||
import math.*
|
||||
import plotting.*
|
||||
|
||||
% get a weighting function => avoid effect of too strong noise
|
||||
% around edges of the reconstructed region => improve robustness againts outliers
|
||||
% weights = weights / max2(weights);
|
||||
% weight_proj = get_views( weights, Gzeros(size(chi)),1,1, g_ind, cache);
|
||||
weight_proj = 1;
|
||||
|
||||
%% calculate terms needed to calculate update of the variable probe
|
||||
% => U term in SVD decomposition
|
||||
[resid, proj, probe_update] = Gfun(@get_SVD_update,probe_update, weight_proj, var_probe, reshape(probe_evol,1,1,[]), norm(probe_evol));
|
||||
% get update the variable probe
|
||||
var_probe_upd = mean( resid .* mean2(proj), 3);
|
||||
% apply update, prevent too large changes at the beginning of the covergence
|
||||
var_probe = var_probe + relax_U*var_probe_upd / norm2(var_probe_upd);
|
||||
|
||||
%% equivalent but much slower code
|
||||
%[U,S,V] = svd(reshape(weight_proj.*(probe_update - m_probe_update), prod(self.Np_p),[]), 0);
|
||||
%var_probe = var_probe + relax_U*reshape(U(:,1), self.Np_p);
|
||||
|
||||
% keep the eigenprobe normalized
|
||||
var_probe = var_probe ./ norm2(var_probe);
|
||||
|
||||
%% calculate optimal OPRP evolution coeficients
|
||||
[num, denum] = Gfun(@get_SVD_evol,var_probe, obj_proj, chi);
|
||||
num =Ggather(mean2(num));
|
||||
denum = Ggather(mean2(denum));
|
||||
% perform relaxed update => improve robustness againts outliers
|
||||
probe_evol_upd = squeeze(num ./ (denum + 0.1*mean(denum,3))); % caclulate regularized update
|
||||
% add to the coefficients that are already used in the currently
|
||||
% used probe{1} variable
|
||||
|
||||
probe_evol = probe_evol + relax_V*probe_evol_upd;
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
%% GPU kernel merging
|
||||
|
||||
% SVD approximation => calculation of U
|
||||
function [resid, proj, probe_update] = get_SVD_update(probe_update, weight_proj, var_probe, probe_evol, probe_evol_norm)
|
||||
resid = weight_proj .* probe_update;
|
||||
proj = (real(conj(resid) .* var_probe)+ probe_evol) / probe_evol_norm^2;
|
||||
end
|
||||
|
||||
% SVD approximation => calculation of S*V
|
||||
function [num, denum] = get_SVD_evol(var_probe, obj_proj, chi)
|
||||
psi = var_probe .* obj_proj;
|
||||
denum = abs( psi ).^2;
|
||||
num = real(chi .* conj(psi));
|
||||
end
|
||||
|
||||
function [nom1, denom1] = get_coefs_intensity(xi, P, O)
|
||||
OP = O.*P;
|
||||
nom1 = real(conj(OP) .* xi);
|
||||
denom1 = abs(OP).^2;
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user