From 51003bc6d5540285be16d581f9abcb488852df24 Mon Sep 17 00:00:00 2001 From: Qianqian Fang Date: Mon, 1 Jan 2024 18:02:43 -0500 Subject: [PATCH] [format] automatic format all matlab script with miss_hit --- .miss_hit | 11 + example/masktest/plotresults.m | 23 +- example/multipattern/plotresults.m | 14 +- example/polarized/onelayer_plot_results.m | 78 ++- example/shapetest/plotshapemask.m | 11 +- example/sphbox/plotresults.m | 85 ++- example/validation/plotsimudata.m | 167 +++-- mcxlab/examples/bench_reseedlimit.m | 62 +- mcxlab/examples/demo_4layer_head.m | 104 +-- mcxlab/examples/demo_area_source_conv.m | 88 +-- mcxlab/examples/demo_bc_det.m | 32 +- mcxlab/examples/demo_colin27_atlas.m | 72 +-- mcxlab/examples/demo_continuous_mua_mus.m | 91 ++- .../demo_diffuse_reflectance_validation.m | 63 +- mcxlab/examples/demo_digimouse_sfdi.m | 90 +-- mcxlab/examples/demo_focus_mirror_bc.m | 40 +- mcxlab/examples/demo_fullhead_atlas.m | 77 +-- .../examples/demo_infinite_slab_cyclic_bc.m | 49 +- mcxlab/examples/demo_label_continous_hybrid.m | 236 +++---- mcxlab/examples/demo_lambertian_exit_angle.m | 60 +- mcxlab/examples/demo_mcxlab_2d.m | 42 +- mcxlab/examples/demo_mcxlab_basic.m | 38 +- mcxlab/examples/demo_mcxlab_launchangle.m | 67 +- mcxlab/examples/demo_mcxlab_phasefun.m | 36 +- mcxlab/examples/demo_mcxlab_replay.m | 57 +- mcxlab/examples/demo_mcxlab_srctype.m | 607 +++++++++--------- mcxlab/examples/demo_mcxyz_skinvessel.m | 82 +-- mcxlab/examples/demo_multisrc.m | 72 +-- mcxlab/examples/demo_photon_sharing.m | 118 ++-- mcxlab/examples/demo_polarized_photon.m | 102 +-- mcxlab/examples/demo_qtest_subpixel.m | 54 +- mcxlab/examples/demo_replay_frequencydomain.m | 95 ++- mcxlab/examples/demo_replay_timedomain.m | 60 +- .../examples/demo_replay_vs_pmc_timedomain.m | 78 +-- mcxlab/examples/demo_sphere_cube_subpixel.m | 80 +-- mcxlab/examples/demo_svmc_brain19_5.m | 124 ++-- mcxlab/examples/demo_svmc_cubesph.m | 110 ++-- mcxlab/examples/demo_svmc_sphshells.m | 136 ++-- mcxlab/examples/demo_test_csf.m | 79 ++- .../examples/demo_validation_heterogeneous.m | 128 ++-- mcxlab/examples/demo_validation_homogeneous.m | 156 ++--- mcxlab/examples/mcx_gpu_benchmarks.m | 160 ++--- mcxlab/examples/mcx_gpu_contest.m | 78 +-- mcxlab/mcxlab.m | 313 +++++---- utils/cwdiffusion.m | 16 +- utils/cwfluencediffusion.m | 4 +- utils/cwfluxdiffusion.m | 20 +- utils/getdistance.m | 14 +- utils/image3i.m | 107 ++- utils/islicer.m | 46 +- utils/json2mcx.m | 192 +++--- utils/loadmc2.m | 30 +- utils/loadmch.m | 144 +++-- utils/mcx2json.m | 229 ++++--- utils/mcxcreate.m | 134 ++-- utils/mcxcwdref.m | 30 +- utils/mcxdcsg1.m | 111 ++-- utils/mcxdetphoton.m | 78 +-- utils/mcxdettime.m | 36 +- utils/mcxdettpsf.m | 26 +- utils/mcxdetweight.m | 38 +- utils/mcxfluence2energy.m | 40 +- utils/mcxloadfile.m | 31 +- utils/mcxloadnii.m | 213 +++--- utils/mcxmeanpath.m | 14 +- utils/mcxmeanscat.m | 8 +- utils/mcxnuvoxel.m | 235 ++++--- utils/mcxplotphotons.m | 36 +- utils/mcxplotshapes.m | 162 ++--- utils/mcxplotvol.m | 107 ++- utils/mcxpreview.m | 218 +++---- utils/mcxrfreplay.m | 61 +- utils/mcxsvmc.m | 229 ++++--- utils/normalizemcx.m | 18 +- utils/rbgetreff.m | 100 +-- utils/serialcorr.m | 14 +- utils/slice3i.m | 177 +++-- utils/tddiffusion.m | 20 +- 78 files changed, 3665 insertions(+), 3598 deletions(-) create mode 100644 .miss_hit diff --git a/.miss_hit b/.miss_hit new file mode 100644 index 00000000..558c9ea1 --- /dev/null +++ b/.miss_hit @@ -0,0 +1,11 @@ +project_root + +suppress_rule: "redundant_brackets" +suppress_rule: "line_length" +suppress_rule: "file_length" +suppress_rule: "copyright_notice" +suppress_rule: "naming_functions" +suppress_rule: "naming_parameters" +suppress_rule: "naming_scripts" +suppress_rule: "unicode" +indent_function_file_body: false diff --git a/example/masktest/plotresults.m b/example/masktest/plotresults.m index c3f094ef..b861cdf0 100644 --- a/example/masktest/plotresults.m +++ b/example/masktest/plotresults.m @@ -1,16 +1,15 @@ -fid=fopen('mtest.mask','rb'); -dat=fread(fid,inf,'uchar'); +fid = fopen('mtest.mask', 'rb'); +dat = fread(fid, inf, 'uchar'); fclose(fid); -dat=reshape(dat,[8 8 8]); -pcolor(dat(:,:,1)') +dat = reshape(dat, [8 8 8]); +pcolor(dat(:, :, 1)'); -r=3; -s=0:pi/20:2*pi; -c0=[4.9,4.1]; -x=c0(1)+r*cos(s); -y=c0(2)+r*sin(s); - -hold on -plot(x,y,'y-'); +r = 3; +s = 0:pi / 20:2 * pi; +c0 = [4.9, 4.1]; +x = c0(1) + r * cos(s); +y = c0(2) + r * sin(s); +hold on; +plot(x, y, 'y-'); diff --git a/example/multipattern/plotresults.m b/example/multipattern/plotresults.m index e61c9a03..6820e58e 100644 --- a/example/multipattern/plotresults.m +++ b/example/multipattern/plotresults.m @@ -1,11 +1,11 @@ -dat=loadjson('multipattern.jnii',[3 60 60 60]); +dat = loadjson('multipattern.jnii', [3 60 60 60]); figure; subplot(131); -imagesc(squeeze(log10(abs(dat(1,:,:,10))))') -axis equal +imagesc(squeeze(log10(abs(dat(1, :, :, 10))))'); +axis equal; subplot(132); -imagesc(squeeze(log10(abs(dat(2,:,:,10))))') -axis equal +imagesc(squeeze(log10(abs(dat(2, :, :, 10))))'); +axis equal; subplot(133); -imagesc(squeeze(log10(abs(dat(3,:,:,10))))') -axis equal +imagesc(squeeze(log10(abs(dat(3, :, :, 10))))'); +axis equal; diff --git a/example/polarized/onelayer_plot_results.m b/example/polarized/onelayer_plot_results.m index 193b29e8..b6ee810a 100644 --- a/example/polarized/onelayer_plot_results.m +++ b/example/polarized/onelayer_plot_results.m @@ -5,62 +5,78 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% load mcx input and output file -data=loadjson("onelayer_detp.jdat"); -cfg=loadjson("onelayer.json"); +data = loadjson("onelayer_detp.jdat"); +cfg = loadjson("onelayer.json"); %% compute total reflectance -nphotons=cfg.Session.Photons; +nphotons = cfg.Session.Photons; % extract simulation settings needed for post-processing -unitinmm=cfg.Domain.LengthUnit; % dx,dy,dz in mm +unitinmm = cfg.Domain.LengthUnit; % dx,dy,dz in mm % default ambient medium -prop=[0 0 1 1]; +prop = [0 0 1 1]; % absorption coefficent (in 1/mm) of each tissue type -mua=cellfun(@(f)getfield(f,'mua'),cfg.Domain.MieScatter)'; -prop=[prop;mua, zeros(size(mua,1),3)]; +mua = cellfun(@(f)getfield(f, 'mua'), cfg.Domain.MieScatter)'; +prop = [prop; mua, zeros(size(mua, 1), 3)]; % photon exiting direction -u=data(:,6:8); -phi=atan2(u(:,2),u(:,1)); +u = data(:, 6:8); +phi = atan2(u(:, 2), u(:, 1)); % photon exiting Stokes Vector -s=data(:,10:13); -S2=[s(:,1),s(:,2).*cos(2.*phi)+s(:,3).*sin(2.*phi),... - -s(:,2).*sin(2.*phi)+s(:,3).*cos(2.*phi),s(:,4)]; +s = data(:, 10:13); +S2 = [s(:, 1), s(:, 2) .* cos(2 .* phi) + s(:, 3) .* sin(2 .* phi), ... + -s(:, 2) .* sin(2 .* phi) + s(:, 3) .* cos(2 .* phi), s(:, 4)]; % final weight of exiting photons -detphoton=struct(); -detphoton.ppath=data(:,2); -w=mcxdetweight(detphoton,prop,unitinmm); +detphoton = struct(); +detphoton.ppath = data(:, 2); +w = mcxdetweight(detphoton, prop, unitinmm); % total reflected IQUV -R=S2'*w/nphotons; +R = S2' * w / nphotons; %% plot 2-D images for I, Q, U, V % extract x and y values of the exiting positions. -x=data(:,3); -y=data(:,4); +x = data(:, 3); +y = data(:, 4); % define image dimension -NN=100; +NN = 100; % 2D exiting positions are binned on the 2D plane (z=0) -xedges=0:cfg.Domain.Dim(1,1)/NN:cfg.Domain.Dim(1,1); -yedges=0:cfg.Domain.Dim(1,2)/NN:cfg.Domain.Dim(1,2); -ix=discretize(x,xedges); -iy=discretize(y,yedges); -idx1d=sub2ind([NN,NN],iy,ix); % x and y is flipped to match Jessica's code +xedges = 0:cfg.Domain.Dim(1, 1) / NN:cfg.Domain.Dim(1, 1); +yedges = 0:cfg.Domain.Dim(1, 2) / NN:cfg.Domain.Dim(1, 2); +ix = discretize(x, xedges); +iy = discretize(y, yedges); +idx1d = sub2ind([NN, NN], iy, ix); % x and y is flipped to match Jessica's code % accumulate I Q U V -HIQUV=zeros(4,NN,NN); -for i=1:4 - HIQUV(i,:,:)=reshape(accumarray(idx1d,S2(:,i)),[NN,NN]); +HIQUV = zeros(4, NN, NN); +for i = 1:4 + HIQUV(i, :, :) = reshape(accumarray(idx1d, S2(:, i)), [NN, NN]); end % plot -subplot(2,2,1);imagesc(squeeze(HIQUV(1,:,:)));axis equal;title("HI");colorbar; -subplot(2,2,2);imagesc(squeeze(HIQUV(2,:,:)));axis equal;title("HQ");colorbar; -subplot(2,2,3);imagesc(squeeze(HIQUV(3,:,:)));axis equal;title("HU");colorbar; -subplot(2,2,4);imagesc(squeeze(HIQUV(4,:,:)));axis equal;title("HV");colorbar; +subplot(2, 2, 1); +imagesc(squeeze(HIQUV(1, :, :))); +axis equal; +title("HI"); +colorbar; +subplot(2, 2, 2); +imagesc(squeeze(HIQUV(2, :, :))); +axis equal; +title("HQ"); +colorbar; +subplot(2, 2, 3); +imagesc(squeeze(HIQUV(3, :, :))); +axis equal; +title("HU"); +colorbar; +subplot(2, 2, 4); +imagesc(squeeze(HIQUV(4, :, :))); +axis equal; +title("HV"); +colorbar; diff --git a/example/shapetest/plotshapemask.m b/example/shapetest/plotshapemask.m index d74fb608..a5afcd58 100644 --- a/example/shapetest/plotshapemask.m +++ b/example/shapetest/plotshapemask.m @@ -1,9 +1,8 @@ -fid=fopen('jsonshape.mask','rb'); -dat=fread(fid,inf,'uchar'); +fid = fopen('jsonshape.mask', 'rb'); +dat = fread(fid, inf, 'uchar'); fclose(fid); -dat=reshape(dat,[40 60 50]); +dat = reshape(dat, [40 60 50]); figure; -imagesc(squeeze(dat(:,:,15))); -axis equal - +imagesc(squeeze(dat(:, :, 15))); +axis equal; diff --git a/example/sphbox/plotresults.m b/example/sphbox/plotresults.m index b59bd018..d9055197 100644 --- a/example/sphbox/plotresults.m +++ b/example/sphbox/plotresults.m @@ -1,56 +1,55 @@ -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% add paths to the necessary toolboxes -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- -addpath('~/space/Projects/mcx/utils/') -addpath('~/space/Projects/mmc/matlab/') +addpath('~/space/Projects/mcx/utils/'); +addpath('~/space/Projects/mmc/matlab/'); -c0=299792458000; -twin=[5e-11:1e-10:5e-9]; -gates=50; -clines=[-1:0.5:8]; +c0 = 299792458000; +twin = [5e-11:1e-10:5e-9]; +gates = 50; +clines = [-1:0.5:8]; -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% load MCX results -%%----------------------------------------------------------------- -mcx=loadmc2('spherebox.mc2', [60 60 60 gates]); -cwmcx=sum(mcx,4); +%% ----------------------------------------------------------------- +mcx = loadmc2('spherebox.mc2', [60 60 60 gates]); +cwmcx = sum(mcx, 4); -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% generate/load analytical solution for sphere inside infinite slab -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- -%[phi_ana,xa,ya,za]=sphdiffusionslab(0,0,60,-22:0.8:22,0,-30:0.8:10); -%save sphdiffsemiinf.mat phi_ana xa ya za +% [phi_ana,xa,ya,za]=sphdiffusionslab(0,0,60,-22:0.8:22,0,-30:0.8:10); +% save sphdiffsemiinf.mat phi_ana xa ya za -load sphdiffsemiinf.mat -idx=find((xa(:)<-12 | xa(:)>12) & za(:)>-5); -phi_ana(idx)=nan; -idx=find((xa(:)<-10 | xa(:)>10) & za(:)>0); -phi_ana(idx)=nan; +load sphdiffsemiinf.mat; +idx = find((xa(:) < -12 | xa(:) > 12) & za(:) > -5); +phi_ana(idx) = nan; +idx = find((xa(:) < -10 | xa(:) > 10) & za(:) > 0); +phi_ana(idx) = nan; -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% generate the contour of the inclusion -%%----------------------------------------------------------------- - -[xcirc,ycirc] = cylinder(10,200); -xcirc=xcirc(1,:)+30; -ycirc=ycirc(1,:)+30; - -figure -hold on -[cc,hc]=contour(xa+30,za+31,log10(abs(phi_ana))+10,clines,'color',[0.7 0.7 0.7],'linewidth',2); -contour(log10(squeeze(abs(cwmcx(:,30,:)))'),clines,'b-') -plot(xcirc,ycirc,'k--','linewidth',2); - -axis equal -set(gca,'xlim',[1 60]); -set(gca,'ylim',[1 60]); -set(gca,'fontsize',18) -xlabel('x (mm)') -ylabel('z (mm)') -legend('Diffusion','MCX') +%% ----------------------------------------------------------------- + +[xcirc, ycirc] = cylinder(10, 200); +xcirc = xcirc(1, :) + 30; +ycirc = ycirc(1, :) + 30; + +figure; +hold on; +[cc, hc] = contour(xa + 30, za + 31, log10(abs(phi_ana)) + 10, clines, 'color', [0.7 0.7 0.7], 'linewidth', 2); +contour(log10(squeeze(abs(cwmcx(:, 30, :)))'), clines, 'b-'); +plot(xcirc, ycirc, 'k--', 'linewidth', 2); + +axis equal; +set(gca, 'xlim', [1 60]); +set(gca, 'ylim', [1 60]); +set(gca, 'fontsize', 18); +xlabel('x (mm)'); +ylabel('z (mm)'); +legend('Diffusion', 'MCX'); legend boxoff; box on; -set(gcf,'PaperPositionMode','auto'); - +set(gcf, 'PaperPositionMode', 'auto'); diff --git a/example/validation/plotsimudata.m b/example/validation/plotsimudata.m index c717bf1b..ec5ea8ae 100644 --- a/example/validation/plotsimudata.m +++ b/example/validation/plotsimudata.m @@ -2,130 +2,129 @@ % matlab script to produce the validation plots (Fig. 4) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -if(exist('loadjson')~=2) - error('you need to first download and add path to jsonlab (https://github.com/fangq/jsonlab) in order to run this script'); +if (exist('loadjson') ~= 2) + error('you need to first download and add path to jsonlab (https://github.com/fangq/jsonlab) in order to run this script'); end -c0=299792458000; -srcpos=[30 30 1]; -detpos=[30 15 10]; -twin=[5e-11:1e-10:5e-9]; +c0 = 299792458000; +srcpos = [30 30 1]; +detpos = [30 15 10]; +twin = [5e-11:1e-10:5e-9]; -%---------------------------------------------------------------- +% ---------------------------------------------------------------- % Plot time-domain comparison at a given position -%---------------------------------------------------------------- +% ---------------------------------------------------------------- figure; hold on; -mcx=loadjson('semi_infinite.jnii',[60 60 60 50]); -mcx=mcx.NIFTIData; -semilogy((1:50)/10,tddiffusion(0.005, 1, c0, 0, srcpos, detpos,twin),'r'); -semilogy((1:50)/10,squeeze(mcx(30,14,9,:)),'o'); +mcx = loadjson('semi_infinite.jnii', [60 60 60 50]); +mcx = mcx.NIFTIData; +semilogy((1:50) / 10, tddiffusion(0.005, 1, c0, 0, srcpos, detpos, twin), 'r'); +semilogy((1:50) / 10, squeeze(mcx(30, 14, 9, :)), 'o'); -mcxb=loadjson('semi_infinite_b.jnii',[60 60 60 50]); -mcxb=mcxb.NIFTIData; -semilogy((1:50)/10,tddiffusion(0.005, 1, c0/1.37, 0.493, srcpos, detpos,twin),'r--'); -semilogy((1:50)/10,squeeze(mcxb(30,14,9,:)),'+'); +mcxb = loadjson('semi_infinite_b.jnii', [60 60 60 50]); +mcxb = mcxb.NIFTIData; +semilogy((1:50) / 10, tddiffusion(0.005, 1, c0 / 1.37, 0.493, srcpos, detpos, twin), 'r--'); +semilogy((1:50) / 10, squeeze(mcxb(30, 14, 9, :)), '+'); -set(gca,'ylim',[1 10^8.5]); +set(gca, 'ylim', [1 10^8.5]); -legend('Diffusion (no reflection)','MCX (no reflection)','Diffusion (with reflection)','MCX (with reflection)'); +legend('Diffusion (no reflection)', 'MCX (no reflection)', 'Diffusion (with reflection)', 'MCX (with reflection)'); legend boxoff; -set(gca,'yscale','log'); -set(gca,'fontsize',18); -xlabel('time (ns)') -ylabel('Fluence in 1/(m^2s)') +set(gca, 'yscale', 'log'); +set(gca, 'fontsize', 18); +xlabel('time (ns)'); +ylabel('Fluence in 1/(m^2s)'); box on; -saveas(gcf,'td_validate.fig') -print -depsc2 td_validate.eps +saveas(gcf, 'td_validate.fig'); +print -depsc2 td_validate.eps; -%---------------------------------------------------------------- -% Plot CW comparison along a line -%---------------------------------------------------------------- +% ---------------------------------------------------------------- +% Plot CW comparison along a line +% ---------------------------------------------------------------- figure; hold on; -cwmcx=sum(mcx,4); -srcpos=[0 0 0]; -detpos=[0.5+(0:29)', 0.5*ones(30,1),0.5*ones(30,1)]; -phicw=cwdiffusion(0.005, 1, 0, srcpos, detpos); -phimcx=cwmcx(30,:,1); +cwmcx = sum(mcx, 4); +srcpos = [0 0 0]; +detpos = [0.5 + (0:29)', 0.5 * ones(30, 1), 0.5 * ones(30, 1)]; +phicw = cwdiffusion(0.005, 1, 0, srcpos, detpos); +phimcx = cwmcx(30, :, 1); -cwmcxb=sum(mcxb,4); -phicwb=cwdiffusion(0.005, 1, 0.493, srcpos, detpos); -phimcxb=(cwmcxb(30,:,1)); -h=semilogy(1:30, phicw, 'r-', 1:30, phimcx(30:59)*1e-10, 'o', 1:30, phicwb, 'r--', 1:30, phimcxb(30:59)*1e-10, 'b+'); +cwmcxb = sum(mcxb, 4); +phicwb = cwdiffusion(0.005, 1, 0.493, srcpos, detpos); +phimcxb = (cwmcxb(30, :, 1)); +h = semilogy(1:30, phicw, 'r-', 1:30, phimcx(30:59) * 1e-10, 'o', 1:30, phicwb, 'r--', 1:30, phimcxb(30:59) * 1e-10, 'b+'); box on; -set(gca,'yscale','log') +set(gca, 'yscale', 'log'); -legend('Diffusion (no reflection)','MCX (no reflection)','Diffusion (with reflection)','MCX(with reflection)'); +legend('Diffusion (no reflection)', 'MCX (no reflection)', 'Diffusion (with reflection)', 'MCX(with reflection)'); legend boxoff; -set(gca,'fontsize',18); -xlabel('x (mm)') -ylabel('Fluence in 1/(m^2s)') -saveas(gcf,'td_validate_cw.fig') -print -depsc2 td_validate_cw.eps +set(gca, 'fontsize', 18); +xlabel('x (mm)'); +ylabel('Fluence in 1/(m^2s)'); +saveas(gcf, 'td_validate_cw.fig'); +print -depsc2 td_validate_cw.eps; -%---------------------------------------------------------------- +% ---------------------------------------------------------------- % Plot CW comparison at a cross-section -%---------------------------------------------------------------- +% ---------------------------------------------------------------- -figure +figure; hold on; clines = -1.5:-0.5:-4; -srcpos=[29.5 29.5 0.5]; -[xi,yi]=meshgrid(0.5:59.5,0.5:59.5); -detpos=[xi(:) 30*ones(size(xi(:))) yi(:)]; -phicw=reshape(cwdiffusion(0.005, 1.0, 0, srcpos, detpos),size(xi)); - -[c h2]=contour(xi,yi, log10(max(squeeze(phicw),1e-8)), clines, 'k-' ); -[c h1]=contour(log10(max(squeeze(cwmcx(:,30,:)*1e-10)',1e-8)), clines, 'k:' ); -legend('Diffusion','MCX') +srcpos = [29.5 29.5 0.5]; +[xi, yi] = meshgrid(0.5:59.5, 0.5:59.5); +detpos = [xi(:) 30 * ones(size(xi(:))) yi(:)]; +phicw = reshape(cwdiffusion(0.005, 1.0, 0, srcpos, detpos), size(xi)); + +[c h2] = contour(xi, yi, log10(max(squeeze(phicw), 1e-8)), clines, 'k-'); +[c h1] = contour(log10(max(squeeze(cwmcx(:, 30, :) * 1e-10)', 1e-8)), clines, 'k:'); +legend('Diffusion', 'MCX'); legend boxoff; box on; -set(gca,'fontsize',18); -xlabel('x (mm)') -ylabel('z (mm)') -saveas(gcf,'td_validate_cw_2d.fig') -print -depsc2 td_validate_cw_2d.eps +set(gca, 'fontsize', 18); +xlabel('x (mm)'); +ylabel('z (mm)'); +saveas(gcf, 'td_validate_cw_2d.fig'); +print -depsc2 td_validate_cw_2d.eps; -%---------------------------------------------------------------- +% ---------------------------------------------------------------- % Plot time-domain comparison at a cross-section -%---------------------------------------------------------------- +% ---------------------------------------------------------------- -c0=299792458000; -twin=5e-11:1e-10:5e-9; -mua=0.005; -musp=1; -Reff=0; +c0 = 299792458000; +twin = 5e-11:1e-10:5e-9; +mua = 0.005; +musp = 1; +Reff = 0; -srcpos=[29.5 29.5 0]; -[xi,yi]=meshgrid(0.5:59.5,0.5:59.5); +srcpos = [29.5 29.5 0]; +[xi, yi] = meshgrid(0.5:59.5, 0.5:59.5); -detpos=[xi(:) 29.5*ones(size(xi(:))) yi(:)]; -for i=1:length(twin) - phitd(:,:,i)=reshape(tddiffusion(mua,musp,c0,Reff,srcpos,detpos,twin(i)),size(xi)); +detpos = [xi(:) 29.5 * ones(size(xi(:))) yi(:)]; +for i = 1:length(twin) + phitd(:, :, i) = reshape(tddiffusion(mua, musp, c0, Reff, srcpos, detpos, twin(i)), size(xi)); end figure; -hold on +hold on; -for i=1:5:21 - halfmax=max(max(phitd(:,:,i)))/2; - [c h2]=contour(xi, yi,max(squeeze(phitd(:,:,i)),1e-12),[halfmax halfmax], 'k-'); - halfmax=max(max(mcx(:,30,:,i)))/2; - [c h2]=contour(max(squeeze(mcx(:,30,:,i))',1e-12),[halfmax halfmax], 'k:'); +for i = 1:5:21 + halfmax = max(max(phitd(:, :, i))) / 2; + [c h2] = contour(xi, yi, max(squeeze(phitd(:, :, i)), 1e-12), [halfmax halfmax], 'k-'); + halfmax = max(max(mcx(:, 30, :, i))) / 2; + [c h2] = contour(max(squeeze(mcx(:, 30, :, i))', 1e-12), [halfmax halfmax], 'k:'); end -legend('Diffusion','MCX') +legend('Diffusion', 'MCX'); legend boxoff; box on; -set(gca,'fontsize',18); -xlabel('x (mm)') -ylabel('z (mm)') -saveas(gcf,'td_validate_2d.fig') - -print -depsc2 td_validate_2d.eps +set(gca, 'fontsize', 18); +xlabel('x (mm)'); +ylabel('z (mm)'); +saveas(gcf, 'td_validate_2d.fig'); +print -depsc2 td_validate_2d.eps; diff --git a/mcxlab/examples/bench_reseedlimit.m b/mcxlab/examples/bench_reseedlimit.m index 52a8f2b1..1fd4fe11 100644 --- a/mcxlab/examples/bench_reseedlimit.m +++ b/mcxlab/examples/bench_reseedlimit.m @@ -7,43 +7,43 @@ % This file is part of Monte Carlo eXtreme (MCX) URL:http://mcx.sf.net %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -counts=[1e5 sqrt(10)*1e5 1e6 sqrt(10)*1e6 1e7 sqrt(10)*1e7 1e8]; -nrepeat=10; - -clear cfg - -cfg.vol=uint8(ones(60,60,60)); -cfg.srcpos=[30 30 1]; -cfg.srcdir=[0 0 1]; -cfg.gpuid=1; -cfg.autopilot=1; -cfg.prop=[0 0 1 1;0.005 1 0 1.37]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-9; -%cfg.reseedlimit=1e4; +counts = [1e5 sqrt(10) * 1e5 1e6 sqrt(10) * 1e6 1e7 sqrt(10) * 1e7 1e8]; +nrepeat = 10; + +clear cfg; + +cfg.vol = uint8(ones(60, 60, 60)); +cfg.srcpos = [30 30 1]; +cfg.srcdir = [0 0 1]; +cfg.gpuid = 1; +cfg.autopilot = 1; +cfg.prop = [0 0 1 1; 0.005 1 0 1.37]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-9; +% cfg.reseedlimit=1e4; % calculate the flux distribution with the given config -data=zeros(length(counts),nrepeat,numel(cfg.vol)); -for i=1:length(counts) - cfg.nphoton=counts(i); - for j=1:nrepeat - flux=mcxlab(cfg); - cfg.seed=hex2dec('623F9A9E')+i*nrepeat+j; - data(i,j,:)=flux.data(:); - end +data = zeros(length(counts), nrepeat, numel(cfg.vol)); +for i = 1:length(counts) + cfg.nphoton = counts(i); + for j = 1:nrepeat + flux = mcxlab(cfg); + cfg.seed = hex2dec('623F9A9E') + i * nrepeat + j; + data(i, j, :) = flux.data(:); + end end -datastd=zeros(size(data,1),size(data,3)); -for i=1:size(data,1) - datastd(i,:)=std(squeeze(data(i,:,:)),0,1); +datastd = zeros(size(data, 1), size(data, 3)); +for i = 1:size(data, 1) + datastd(i, :) = std(squeeze(data(i, :, :)), 0, 1); end -idx1=sub2ind(size(cfg.vol),30,30,10); -idx2=sub2ind(size(cfg.vol),30,30,30); -idx3=sub2ind(size(cfg.vol),30,30,50); +idx1 = sub2ind(size(cfg.vol), 30, 30, 10); +idx2 = sub2ind(size(cfg.vol), 30, 30, 30); +idx3 = sub2ind(size(cfg.vol), 30, 30, 50); figure; -loglog(counts, datastd(:,[idx1 idx2 idx3]),'-o'); -legend('z=10','z=30','z=50'); \ No newline at end of file +loglog(counts, datastd(:, [idx1 idx2 idx3]), '-o'); +legend('z=10', 'z=30', 'z=50'); diff --git a/mcxlab/examples/demo_4layer_head.m b/mcxlab/examples/demo_4layer_head.m index 51c0eab5..ca96344b 100644 --- a/mcxlab/examples/demo_4layer_head.m +++ b/mcxlab/examples/demo_4layer_head.m @@ -2,7 +2,7 @@ % MCXLAB - Monte Carlo eXtreme for MATLAB/Octave by Qianqina Fang % % In this example, we simulate a 4-layer brain model using MCXLAB. -% We will investigate the differences between the solutions with and +% We will investigate the differences between the solutions with and % witout boundary reflections (both external and internal) and show % you how to display and analyze the resulting data. % @@ -14,94 +14,94 @@ %% preparing the input data % set seed to make the simulation repeatible -cfg.seed=hex2dec('623F9A9E'); +cfg.seed = hex2dec('623F9A9E'); -cfg.nphoton=5e7; +cfg.nphoton = 5e7; % define a 4 layer structure -cfg.vol=ones(100,100,50); -cfg.vol(:,:,21:25)=2; -cfg.vol(:,:,26:35)=3; -cfg.vol(:,:,36:end)=4; -cfg.vol=uint8(cfg.vol); +cfg.vol = ones(100, 100, 50); +cfg.vol(:, :, 21:25) = 2; +cfg.vol(:, :, 26:35) = 3; +cfg.vol(:, :, 36:end) = 4; +cfg.vol = uint8(cfg.vol); % define the source position -cfg.srcpos=[50,50,0]+1; -cfg.srcdir=[0 0 1]; +cfg.srcpos = [50, 50, 0] + 1; +cfg.srcdir = [0 0 1]; % use the brain optical properties defined at % http://mcx.sourceforge.net/cgi-bin/index.cgi?MMC/CollinsAtlasMesh % format: [mua(1/mm) mus(1/mm) g n] -cfg.prop=[0 0 1 1 % medium 0: the environment - 0.019 7.8 0.89 1.37 % medium 1: skin & skull - 0.004 0.009 0.89 1.37 % medium 2: CSF - 0.02 9.0 0.89 1.37 % medium 3: gray matter - 0.08 40.9 0.84 1.37]; % medium 4: white matter +cfg.prop = [0 0 1 1 % medium 0: the environment + 0.019 7.8 0.89 1.37 % medium 1: skin & skull + 0.004 0.009 0.89 1.37 % medium 2: CSF + 0.02 9.0 0.89 1.37 % medium 3: gray matter + 0.08 40.9 0.84 1.37]; % medium 4: white matter % time-domain simulation parameters -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-10; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-10; % GPU thread configuration -cfg.autopilot=1; -cfg.gpuid=1; +cfg.autopilot = 1; +cfg.gpuid = 1; %% running simulation without boundary reflection fprintf('running simulation ... this takes about 35 seconds on a GTX 470\n'); -cfg.isreflect=0; % disable reflection at exterior boundary +cfg.isreflect = 0; % disable reflection at exterior boundary tic; -f1=mcxlab(cfg); +f1 = mcxlab(cfg); toc; %% running simulation with boundary reflection enabled fprintf('running simulation ... this takes about 50 seconds on a GTX 470\n'); -cfg.isreflect=1; % enable reflection at exterior boundary -cfg.isrefint=1; % enable reflection at interior boundary too -cfg.issavedet=1; % enable recording partial pathlength of detected photons -cfg.detpos=[31 51 1 2]; +cfg.isreflect = 1; % enable reflection at exterior boundary +cfg.isrefint = 1; % enable reflection at interior boundary too +cfg.issavedet = 1; % enable recording partial pathlength of detected photons +cfg.detpos = [31 51 1 2]; tic; -[f2,det2]=mcxlab(cfg); +[f2, det2] = mcxlab(cfg); toc; %% plot the results -figure +figure; subplot(221); -contourf(log10(squeeze(sum(f1.data(:,51,:,:),4))'),1:0.5:8); -hold on -plot([0 100],[21 21],'--',[0 100],[26 26],'--',[0 100],[36 36],'--'); +contourf(log10(squeeze(sum(f1.data(:, 51, :, :), 4))'), 1:0.5:8); +hold on; +plot([0 100], [21 21], '--', [0 100], [26 26], '--', [0 100], [36 36], '--'); title('Fluence rate with no reflection'); -set(gca,'clim',[1 8]); +set(gca, 'clim', [1 8]); subplot(222); -contourf(log10(squeeze(sum(f2.data(:,51,:,:),4))'),1:0.5:8); -hold on -plot([0 100],[21 21],'--',[0 100],[26 26],'--',[0 100],[36 36],'--'); +contourf(log10(squeeze(sum(f2.data(:, 51, :, :), 4))'), 1:0.5:8); +hold on; +plot([0 100], [21 21], '--', [0 100], [26 26], '--', [0 100], [36 36], '--'); title('Fluence rate with reflection at boundaries'); -set(gca,'clim',[1 8]); +set(gca, 'clim', [1 8]); subplot(223); hold on; -xi=1e9*((cfg.tstart:cfg.tstep:cfg.tend-cfg.tstep)+0.5*cfg.tstep); -for i=31:49 - semilogy(xi,squeeze(f2.data(51,i,1,:)),'color',[1-(i-25)/25 1-(i-25)/25 1]); +xi = 1e9 * ((cfg.tstart:cfg.tstep:cfg.tend - cfg.tstep) + 0.5 * cfg.tstep); +for i = 31:49 + semilogy(xi, squeeze(f2.data(51, i, 1, :)), 'color', [1 - (i - 25) / 25 1 - (i - 25) / 25 1]); end -xlabel('time (ns)') -ylabel('Fluence rate (1/mm^2/s)') -set(gca,'yscale','log'); +xlabel('time (ns)'); +ylabel('Fluence rate (1/mm^2/s)'); +set(gca, 'yscale', 'log'); title('time point spread functions (TPSF)'); subplot(224); hold on; -[hs1,c1]=hist(det2.ppath(find(det2.ppath(:,1)),1),200); -[hs2,c2]=hist(det2.ppath(find(det2.ppath(:,2)),2),200); -[hs3,c3]=hist(det2.ppath(find(det2.ppath(:,3)),3),200); -[hs4,c4]=hist(det2.ppath(find(det2.ppath(:,4)),4),200); -bar(c1,hs1,'edgecolor','none','facecolor','r'); -bar(c2,hs2,'edgecolor','none','facecolor','b'); -bar(c3,hs3,'edgecolor','none','facecolor','g'); -bar(c4,hs4,'edgecolor','none','facecolor','k'); -legend('tissue 1','tissue 2','tissue 3','tissue 4'); +[hs1, c1] = hist(det2.ppath(find(det2.ppath(:, 1)), 1), 200); +[hs2, c2] = hist(det2.ppath(find(det2.ppath(:, 2)), 2), 200); +[hs3, c3] = hist(det2.ppath(find(det2.ppath(:, 3)), 3), 200); +[hs4, c4] = hist(det2.ppath(find(det2.ppath(:, 4)), 4), 200); +bar(c1, hs1, 'edgecolor', 'none', 'facecolor', 'r'); +bar(c2, hs2, 'edgecolor', 'none', 'facecolor', 'b'); +bar(c3, hs3, 'edgecolor', 'none', 'facecolor', 'g'); +bar(c4, hs4, 'edgecolor', 'none', 'facecolor', 'k'); +legend('tissue 1', 'tissue 2', 'tissue 3', 'tissue 4'); xlabel('partial pathlength (mm)'); -title(sprintf('detected %d photons',size(det2.ppath,1))); +title(sprintf('detected %d photons', size(det2.ppath, 1))); diff --git a/mcxlab/examples/demo_area_source_conv.m b/mcxlab/examples/demo_area_source_conv.m index 7fe83ca3..2bc7194d 100644 --- a/mcxlab/examples/demo_area_source_conv.m +++ b/mcxlab/examples/demo_area_source_conv.m @@ -1,49 +1,49 @@ -%========================================================================== +% ========================================================================== % Comparing directly simulated widefield sources vs aperature-convolved % pencil beam solutions % % Author: Qianqian Fang -%========================================================================== +% ========================================================================== %% first, simulate a pencil beam solution % only clear cfg to avoid accidentally clearing other useful data -clear cfg cfg2 -cfg.nphoton=1e8; -cfg.vol=uint8(ones(60,60,60)); -cfg.srcpos=[29.5 29.5 1]; -cfg.srcdir=[0 0 1]; -cfg.prop=[0 0 1 1;0.005 1 0 1.37]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=cfg.tend; -%cfg.gpuid=1; -%cfg.autopilot=1; +clear cfg cfg2; +cfg.nphoton = 1e8; +cfg.vol = uint8(ones(60, 60, 60)); +cfg.srcpos = [29.5 29.5 1]; +cfg.srcdir = [0 0 1]; +cfg.prop = [0 0 1 1; 0.005 1 0 1.37]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = cfg.tend; +% cfg.gpuid=1; +% cfg.autopilot=1; -flux=mcxlab(cfg); +flux = mcxlab(cfg); %% next, perform a 2D convolution with a 3x7 kernel in the x/y plane -src=ones(3,7); -fluxconv=zeros(size(flux.data)); +src = ones(3, 7); +fluxconv = zeros(size(flux.data)); -for i=1:size(flux.data,3) - fluxconv(:,:,i)=conv2(flux.data(:,:,i), src, 'same'); +for i = 1:size(flux.data, 3) + fluxconv(:, :, i) = conv2(flux.data(:, :, i), src, 'same'); end % normalize the convolved solution using total area fluxconv = fluxconv ./ sum(src(:)); %% then directly simulate such an area source using `planar` source type -cfg2=cfg; -cfg2.srctype='planar'; -cfg2.srcpos=[28, 26, 0]; % notice this is shifted by half grid in x/y to align the two -cfg2.srcparam1=[3,0,0,0]; -cfg2.srcparam2=[0,7,0,0]; -fluxplanar=mcxlab(cfg2); +cfg2 = cfg; +cfg2.srctype = 'planar'; +cfg2.srcpos = [28, 26, 0]; % notice this is shifted by half grid in x/y to align the two +cfg2.srcparam1 = [3, 0, 0, 0]; +cfg2.srcparam2 = [0, 7, 0, 0]; +fluxplanar = mcxlab(cfg2); % %% additionally, we can simulate a pencilarray source -% +% % cfg3=cfg2; % cfg3.srctype='pencilarray'; % cfg3.srcparam1(4)=3; @@ -52,30 +52,30 @@ %% comparing the two solutions -contournum=30; +contournum = 30; figure; subplot(131); -contourf(log10(fluxplanar.data(:,:,5)), contournum) +contourf(log10(fluxplanar.data(:, :, 5)), contournum); hold on; -contour(log10(fluxconv(:,:,5)), contournum, 'r--'); +contour(log10(fluxconv(:, :, 5)), contournum, 'r--'); % contour(log10(fluxpencilarray.data(:,:,5)), contournum, 'c--'); -title('x-y plane (z=5)') -axis equal +title('x-y plane (z=5)'); +axis equal; legend({'planar source', 'convolved pencil beam'}); -subplot(132) -contourf(log10(squeeze(fluxplanar.data(:,30,:))), contournum); -hold on -contour(log10(squeeze(fluxconv(:,30,:))), contournum, 'r--'); -title('x-z plane (y=30)') -axis equal -legend({'planar source', 'convolved pencil beam'}) +subplot(132); +contourf(log10(squeeze(fluxplanar.data(:, 30, :))), contournum); +hold on; +contour(log10(squeeze(fluxconv(:, 30, :))), contournum, 'r--'); +title('x-z plane (y=30)'); +axis equal; +legend({'planar source', 'convolved pencil beam'}); -subplot(133) -contourf(log10(squeeze(fluxplanar.data(30,:,:))), contournum); -hold on -contour(log10(squeeze(fluxconv(30,:,:))), contournum, 'r--'); -title('y-z plane (x=30)') -axis equal -legend({'planar source', 'convolved pencil beam'}) +subplot(133); +contourf(log10(squeeze(fluxplanar.data(30, :, :))), contournum); +hold on; +contour(log10(squeeze(fluxconv(30, :, :))), contournum, 'r--'); +title('y-z plane (x=30)'); +axis equal; +legend({'planar source', 'convolved pencil beam'}); diff --git a/mcxlab/examples/demo_bc_det.m b/mcxlab/examples/demo_bc_det.m index 2fcb2491..a1c7fdf1 100644 --- a/mcxlab/examples/demo_bc_det.m +++ b/mcxlab/examples/demo_bc_det.m @@ -8,23 +8,23 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % only clear cfg to avoid accidentally clearing other useful data -clear cfg cfgs -cfg.nphoton=1e5; -cfg.vol=uint8(ones(60,60,60)); -cfg.srcpos=[30 30 1]; -cfg.srcdir=[0 0 1]; -cfg.gpuid=1; +clear cfg cfgs; +cfg.nphoton = 1e5; +cfg.vol = uint8(ones(60, 60, 60)); +cfg.srcpos = [30 30 1]; +cfg.srcdir = [0 0 1]; +cfg.gpuid = 1; % cfg.gpuid='11'; % use two GPUs together -cfg.autopilot=1; -cfg.prop=[0 0 1 1;0.005 1 0 1.37]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=1e-10; +cfg.autopilot = 1; +cfg.prop = [0 0 1 1; 0.005 1 0 1.37]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 1e-10; % calculate the flux distribution with the given config -cfg.bc='______111110'; % capture photons existing from all faces except z=z_max -cfg.savedetflag='dpx'; +cfg.bc = '______111110'; % capture photons existing from all faces except z=z_max +cfg.savedetflag = 'dpx'; -[flux,detpt]=mcxlab(cfg); -plot3(detpt.p(:,1),detpt.p(:,2),detpt.p(:,3),'r.'); -view([0 0 -1]) \ No newline at end of file +[flux, detpt] = mcxlab(cfg); +plot3(detpt.p(:, 1), detpt.p(:, 2), detpt.p(:, 3), 'r.'); +view([0 0 -1]); diff --git a/mcxlab/examples/demo_colin27_atlas.m b/mcxlab/examples/demo_colin27_atlas.m index 50f00164..62d518cb 100644 --- a/mcxlab/examples/demo_colin27_atlas.m +++ b/mcxlab/examples/demo_colin27_atlas.m @@ -1,8 +1,8 @@ % == Colin27 Brain Atlas Photon Simulations == -% -% In this example, we demonstrate light transport simulation in a full-head +% +% In this example, we demonstrate light transport simulation in a full-head % atlas template (Colin27). There are 7 tissue types: -% +% % 0: background (air) % 1: scalp % 2: skull @@ -10,55 +10,55 @@ % 4: gray matter % 5: white matter % 6: air cavities in the brain -% -% To run the simulation, you must first unzip the domain binary file using +% +% To run the simulation, you must first unzip the domain binary file using % unlzma on Linux or 7-zip on Windows. For example, on Linux: -% +% % unlzma colin27_v3.bin.lzma -% +% % This demo is identical to the MCX simulation used for Fig.6 in % the original MCX paper [Fang2009]. -% -% +% +% % [Fang2009] Qianqian Fang and David A. Boas, "Monte Carlo simulation % of photon migration in 3D turbid media accelerated by graphics processing % units," Opt. Express 17, 20178-20190 (2009) % only clear cfg to avoid accidentally clearing other useful data -clear cfg +clear cfg; -load colin27_v3.mat -cfg.vol=colin27; +load colin27_v3.mat; +cfg.vol = colin27; -cfg.tstart=0; -cfg.tend=5e-09; -cfg.tstep=2e-10; +cfg.tstart = 0; +cfg.tend = 5e-09; +cfg.tstep = 2e-10; -cfg.srcpos=[75 67.38 167.5]; -cfg.srcdir=[0.1636 0.4569 -0.8743]; -cfg.srcdir=cfg.srcdir/norm(cfg.srcdir); +cfg.srcpos = [75 67.38 167.5]; +cfg.srcdir = [0.1636 0.4569 -0.8743]; +cfg.srcdir = cfg.srcdir / norm(cfg.srcdir); -cfg.detpos=[ 75.0000 77.1900 170.3000 3.0000 - 75.0000 89.0000 171.6000 3.0000 - 75.0000 97.6700 172.4000 3.0000 - 75.0000 102.4000 172.0000 3.0000]; +cfg.detpos = [75.0000 77.1900 170.3000 3.0000 + 75.0000 89.0000 171.6000 3.0000 + 75.0000 97.6700 172.4000 3.0000 + 75.0000 102.4000 172.0000 3.0000]; -cfg.issrcfrom0=1; +cfg.issrcfrom0 = 1; -cfg.prop=[ 0 0 1.0000 1.0000 % background/air - 0.0190 7.8182 0.8900 1.3700 % scalp - 0.0190 7.8182 0.8900 1.3700 % skull - 0.0040 0.0090 0.8900 1.3700 % csf - 0.0200 9.0000 0.8900 1.3700 % gray matters - 0.0800 40.9000 0.8400 1.3700 % white matters - 0 0 1.0000 1.0000]; % air pockets +cfg.prop = [0 0 1.0000 1.0000 % background/air + 0.0190 7.8182 0.8900 1.3700 % scalp + 0.0190 7.8182 0.8900 1.3700 % skull + 0.0040 0.0090 0.8900 1.3700 % csf + 0.0200 9.0000 0.8900 1.3700 % gray matters + 0.0800 40.9000 0.8400 1.3700 % white matters + 0 0 1.0000 1.0000]; % air pockets -cfg.seed=29012392; -cfg.nphoton=10000000; -cfg.issaveexit=1; +cfg.seed = 29012392; +cfg.nphoton = 10000000; +cfg.issaveexit = 1; -[flue,detps]=mcxlab(cfg); +[flue, detps] = mcxlab(cfg); mcxplotvol(log10(flue.data)); figure; -plot3(detps.p(:,1), detps.p(:,2), detps.p(:,3),'r.'); -axis equal; \ No newline at end of file +plot3(detps.p(:, 1), detps.p(:, 2), detps.p(:, 3), 'r.'); +axis equal; diff --git a/mcxlab/examples/demo_continuous_mua_mus.m b/mcxlab/examples/demo_continuous_mua_mus.m index 7da29f3e..cc79bda2 100644 --- a/mcxlab/examples/demo_continuous_mua_mus.m +++ b/mcxlab/examples/demo_continuous_mua_mus.m @@ -1,78 +1,77 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % MCXLAB - Monte Carlo eXtreme for MATLAB/Octave by Qianqina Fang % -% In this example, we show how to define continuously varying media +% In this example, we show how to define continuously varying media % (i.e. media optical properties vary from voxel to voxel) % % This file is part of Monte Carlo eXtreme (MCX) URL:http://mcx.sf.net %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % only clear cfg to avoid accidentally clearing other useful data -clear cfg cfgs -cfg.nphoton=1e7; -cfg.vol=uint8(ones(60,60,60)); -cfg.srcpos=[30 30 1]; -cfg.srcdir=[0 0 1]; -cfg.gpuid=1; +clear cfg cfgs; +cfg.nphoton = 1e7; +cfg.vol = uint8(ones(60, 60, 60)); +cfg.srcpos = [30 30 1]; +cfg.srcdir = [0 0 1]; +cfg.gpuid = 1; % cfg.gpuid='11'; % use two GPUs together -cfg.autopilot=1; -cfg.prop=[0 0 1 1;0.005 1 0 1.37]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-9; +cfg.autopilot = 1; +cfg.prop = [0 0 1 1; 0.005 1 0 1.37]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-9; % calculate the flux distribution with the given config %% Approach #1: a 1 x Nx x Ny x Nz floating-point array defines mua(x,y,z) -%define continuously varying media - use a 4D array - 1st dimension defines -%the optical property components of each spatial position +% define continuously varying media - use a 4D array - 1st dimension defines +% the optical property components of each spatial position -mua1=0.003; -mua2=0.1; -mua=single(reshape(repmat([mua1:(mua2-mua1)/(60-1):mua2]',60,60),60,60,60)); -cfg.vol=permute(mua, [4,1,2,3]); % make 1st dimension the property dimension +mua1 = 0.003; +mua2 = 0.1; +mua = single(reshape(repmat([mua1:(mua2 - mua1) / (60 - 1):mua2]', 60, 60), 60, 60, 60)); +cfg.vol = permute(mua, [4, 1, 2, 3]); % make 1st dimension the property dimension -flux=mcxlab(cfg); +flux = mcxlab(cfg); -mcxplotvol(squeeze(double(cfg.vol))) -title('continuously varying absorption coeff \mu_a (1/mm)') -view([-25.5,21.2]); +mcxplotvol(squeeze(double(cfg.vol))); +title('continuously varying absorption coeff \mu_a (1/mm)'); +view([-25.5, 21.2]); -mcxplotvol(log10(double(flux.data))) +mcxplotvol(log10(double(flux.data))); colormap(jet); -title('fluence in continuously varying media (1/mm^2)') -view([-25.5,21.2]); - +title('fluence in continuously varying media (1/mm^2)'); +view([-25.5, 21.2]); %% Approach #2: a 2 x Nx x Ny x Nz float32 array defines [mua,mus] per voxel -mus1=1.0; -mus2=5.0; -mus=single(reshape(repmat([mus1:(mus2-mus1)/(60-1):mus2]',60,60),60,60,60)); -cfg.vol=reshape([mua(:)'; mus(:)'],[2 60 60 60]); +mus1 = 1.0; +mus2 = 5.0; +mus = single(reshape(repmat([mus1:(mus2 - mus1) / (60 - 1):mus2]', 60, 60), 60, 60, 60)); +cfg.vol = reshape([mua(:)'; mus(:)'], [2 60 60 60]); -flux=mcxlab(cfg); +flux = mcxlab(cfg); -mcxplotvol(squeeze(double(cfg.vol(2,:,:,:)))) -title('continuously varying scattering coeff \mu_s (1/mm)') -view([-25.5,21.2]); +mcxplotvol(squeeze(double(cfg.vol(2, :, :, :)))); +title('continuously varying scattering coeff \mu_s (1/mm)'); +view([-25.5, 21.2]); -mcxplotvol(log10(double(flux.data))) +mcxplotvol(log10(double(flux.data))); colormap(jet); -title('fluence in continuously varying media (1/mm^2)') -view([-25.5,21.2]); +title('fluence in continuously varying media (1/mm^2)'); +view([-25.5, 21.2]); %% Approach #3: a 4 x Nx x Ny x Nz float32 array defines [mua,mus,g,n] per voxel -cfg.vol(3,:,:,:)=0; -cfg.vol(4,:,:,:)=1.37; +cfg.vol(3, :, :, :) = 0; +cfg.vol(4, :, :, :) = 1.37; -flux=mcxlab(cfg); +flux = mcxlab(cfg); -mcxplotvol(squeeze(double(cfg.vol(2,:,:,:)))) -title('continuously varying scattering coeff \mu_s (1/mm)') -view([-25.5,21.2]); +mcxplotvol(squeeze(double(cfg.vol(2, :, :, :)))); +title('continuously varying scattering coeff \mu_s (1/mm)'); +view([-25.5, 21.2]); -mcxplotvol(log10(double(flux.data))) +mcxplotvol(log10(double(flux.data))); colormap(jet); -title('fluence in continuously varying media (1/mm^2)') -view([-25.5,21.2]); +title('fluence in continuously varying media (1/mm^2)'); +view([-25.5, 21.2]); diff --git a/mcxlab/examples/demo_diffuse_reflectance_validation.m b/mcxlab/examples/demo_diffuse_reflectance_validation.m index e262b13b..222acb7c 100644 --- a/mcxlab/examples/demo_diffuse_reflectance_validation.m +++ b/mcxlab/examples/demo_diffuse_reflectance_validation.m @@ -5,73 +5,74 @@ % detected photon profiles against analytical solutions computed from % diffusion equations (semi-infinite domain). % -% [Yao2018] Ruoyang Yao, Xavier Intes, and Qianqian Fang, "Direct approach -% to compute Jacobians for diffuse optical tomography using perturbation Monte +% [Yao2018] Ruoyang Yao, Xavier Intes, and Qianqian Fang, "Direct approach +% to compute Jacobians for diffuse optical tomography using perturbation Monte % Carlo-based photon “replay”," Biomed. Opt. Express 9, 4588-4603 (2018) % -% [Kienle1997] Alwin Kienle and Michael S. Patterson, "Improved solutions -% of the steady-state and the time-resolved diffusion equations for reflectance +% [Kienle1997] Alwin Kienle and Michael S. Patterson, "Improved solutions +% of the steady-state and the time-resolved diffusion equations for reflectance % from a semi-infinite turbid medium," J. Opt. Soc. Am. A 14, 246-254 (1997) % % This file is part of Monte Carlo eXtreme (MCX) URL:http://mcx.sf.net %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % only clear cfg to avoid accidentally clearing other useful data -clear cfg +clear cfg; %% Monte Carlo -cfg.nphoton=1e8; % photon number -cfg.vol=uint8(ones(60,60,60)); % size in mm (length,width,height) +cfg.nphoton = 1e8; % photon number +cfg.vol = uint8(ones(60, 60, 60)); % size in mm (length,width,height) -cfg.prop=[0.00 0.0 1.0 1.0; % first row: ambient medium by default - 0.01 10.0 0.9 1.4]; % media optical properties - -cfg.srcpos=[30 30 0]; % (x,y,z) co-ordinates of light source -cfg.srcdir=[0 0 1]; % Direction - positive z-direction -cfg.issrcfrom0=1; +cfg.prop = [0.00 0.0 1.0 1.0 % first row: ambient medium by default + 0.01 10.0 0.9 1.4]; % media optical properties -cfg.gpuid=1; -cfg.autopilot=1; +cfg.srcpos = [30 30 0]; % (x,y,z) co-ordinates of light source +cfg.srcdir = [0 0 1]; % Direction - positive z-direction +cfg.issrcfrom0 = 1; + +cfg.gpuid = 1; +cfg.autopilot = 1; % time window: for time-solved results -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-9; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-9; % save positions & directions of escaping photons -cfg.issaveexit=1; +cfg.issaveexit = 1; % set up detectors: non-overlapping fiber detectors along x = 30 -detpy=31:1:55; % y changes from 31 to 55 -r=0.25; % radius 0.25mm -for i=1:size(detpy,2) - cfg.detpos(i,:) = [30,detpy(i),0,r]; +detpy = 31:1:55; % y changes from 31 to 55 +r = 0.25; % radius 0.25mm +for i = 1:size(detpy, 2) + cfg.detpos(i, :) = [30, detpy(i), 0, r]; end % visualize domain settings -figure(1);mcxpreview(cfg); +figure(1); +mcxpreview(cfg); % launch simulations -[fluence,detp]=mcxlab(cfg); +[fluence, detp] = mcxlab(cfg); % compute diffuse reflectance at detectors drefmc = mcxcwdref(detp, cfg); %% Diffusion % flux at detectors -fluxdiffusion = cwfluxdiffusion(cfg.prop(2,1), cfg.prop(2,2) * (1 - cfg.prop(2,3)), ... - rbgetreff(1.4,1.0), cfg.srcpos, cfg.detpos(:, 1:3)); +fluxdiffusion = cwfluxdiffusion(cfg.prop(2, 1), cfg.prop(2, 2) * (1 - cfg.prop(2, 3)), ... + rbgetreff(1.4, 1.0), cfg.srcpos, cfg.detpos(:, 1:3)); % fluence at detectors -fluencediffusion = cwfluencediffusion(cfg.prop(2,1), cfg.prop(2,2) * (1 - cfg.prop(2,3)), ... - rbgetreff(1.4,1.0), cfg.srcpos, cfg.detpos(:, 1:3)); +fluencediffusion = cwfluencediffusion(cfg.prop(2, 1), cfg.prop(2, 2) * (1 - cfg.prop(2, 3)), ... + rbgetreff(1.4, 1.0), cfg.srcpos, cfg.detpos(:, 1:3)); % surface diffuse reflectance drefdiffusion = 0.118 * fluencediffusion + 0.306 * fluxdiffusion; % Eq. 8 of Kienle1997 %% compare diffuse reflectance figure(2); -h=semilogy(1:length(detpy), drefdiffusion, 'r--', 1:length(detpy), drefmc, 'b+'); +h = semilogy(1:length(detpy), drefdiffusion, 'r--', 1:length(detpy), drefmc, 'b+'); legend("Diffusion", "MC"); title("log10(Diffuse reflectance) [1/mm^{2}]"); -xlabel("Source-Detector seperation [mm]"); \ No newline at end of file +xlabel("Source-Detector seperation [mm]"); diff --git a/mcxlab/examples/demo_digimouse_sfdi.m b/mcxlab/examples/demo_digimouse_sfdi.m index 0c4abcce..a31e2fe6 100644 --- a/mcxlab/examples/demo_digimouse_sfdi.m +++ b/mcxlab/examples/demo_digimouse_sfdi.m @@ -6,11 +6,11 @@ % % This demo is similar to the MCX simulation used for Fig. 2 in % [Fang2012], except this uses a voxelated model instead of a mesh. -% +% % % [Fang2012] Qianqian Fang and David R. Kaeli, "Accelerating mesh-based % Monte Carlo method on modern CPU architectures ," Biomed. Opt. Express -% 3(12), 3223-3230 (2012) +% 3(12), 3223-3230 (2012) % % This file is part of Monte Carlo eXtreme (MCX) URL:http://mcx.sf.net %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -18,53 +18,53 @@ % only clear cfg to avoid accidentally clearing other useful data clear cfg; -load digimouse.mat -cfg.vol=digimouse; +load digimouse.mat; +cfg.vol = digimouse; -cfg.prop=[1 0.0191 6.6 0.9 1.37 -2 0.0136 8.6 0.9 1.37 -3 0.0026 0.01 0.9 1.37 -4 0.0186 11.1 0.9 1.37 -5 0.0186 11.1 0.9 1.37 -6 0.0186 11.1 0.9 1.37 -7 0.0186 11.1 0.9 1.37 -8 0.0186 11.1 0.9 1.37 -9 0.0240 8.9 0.9 1.37 -10 0.0026 0.01 0.9 1.37 -11 0.0240 8.9 0.9 1.37 -12 0.0240 8.9 0.9 1.37 -13 0.0240 8.9 0.9 1.37 -14 0.0240 8.9 0.9 1.37 -15 0.0240 8.9 0.9 1.37 -16 0.072 5.6 0.9 1.37 -17 0.072 5.6 0.9 1.37 -18 0.072 5.6 0.9 1.37 -19 0.050 5.4 0.9 1.37 -20 0.024 8.9 0.9 1.37 -21 0.076 10.9 0.9 1.37]; +cfg.prop = [1 0.0191 6.6 0.9 1.37 + 2 0.0136 8.6 0.9 1.37 + 3 0.0026 0.01 0.9 1.37 + 4 0.0186 11.1 0.9 1.37 + 5 0.0186 11.1 0.9 1.37 + 6 0.0186 11.1 0.9 1.37 + 7 0.0186 11.1 0.9 1.37 + 8 0.0186 11.1 0.9 1.37 + 9 0.0240 8.9 0.9 1.37 + 10 0.0026 0.01 0.9 1.37 + 11 0.0240 8.9 0.9 1.37 + 12 0.0240 8.9 0.9 1.37 + 13 0.0240 8.9 0.9 1.37 + 14 0.0240 8.9 0.9 1.37 + 15 0.0240 8.9 0.9 1.37 + 16 0.072 5.6 0.9 1.37 + 17 0.072 5.6 0.9 1.37 + 18 0.072 5.6 0.9 1.37 + 19 0.050 5.4 0.9 1.37 + 20 0.024 8.9 0.9 1.37 + 21 0.076 10.9 0.9 1.37]; -cfg.prop(:,1)=[]; -cfg.prop(2:end+1,:)=cfg.prop; -cfg.prop(1,:)=[0 0 1 1]; +cfg.prop(:, 1) = []; +cfg.prop(2:end + 1, :) = cfg.prop; +cfg.prop(1, :) = [0 0 1 1]; -cfg.srctype='fourier'; -cfg.srcpos=[50.0 200.0 100.0]; -cfg.srcparam1=[100.0 0.0 0.0 2]; -cfg.srcparam2=[0 100.0 0.0 0]; -cfg.srcdir=[0 0 -1]; -cfg.issrcfrom0=1; +cfg.srctype = 'fourier'; +cfg.srcpos = [50.0 200.0 100.0]; +cfg.srcparam1 = [100.0 0.0 0.0 2]; +cfg.srcparam2 = [0 100.0 0.0 0]; +cfg.srcdir = [0 0 -1]; +cfg.issrcfrom0 = 1; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-9; -cfg.nphoton=1e8; -cfg.autopilot=1; -cfg.gpuid=1; -cfg.unitinmm=0.1*2; -cfg.debuglevel='P'; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-9; +cfg.nphoton = 1e8; +cfg.autopilot = 1; +cfg.gpuid = 1; +cfg.unitinmm = 0.1 * 2; +cfg.debuglevel = 'P'; -flux=mcxlab(cfg); -fcw=flux.data; +flux = mcxlab(cfg); +fcw = flux.data; mcxplotvol(log10(double(fcw))); -%mcx2json(cfg,'digimouse.json'); +% mcx2json(cfg,'digimouse.json'); diff --git a/mcxlab/examples/demo_focus_mirror_bc.m b/mcxlab/examples/demo_focus_mirror_bc.m index 84f7dc79..2a933c94 100644 --- a/mcxlab/examples/demo_focus_mirror_bc.m +++ b/mcxlab/examples/demo_focus_mirror_bc.m @@ -10,25 +10,25 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % only clear cfg to avoid accidentally clearing other useful data -clear cfg -cfg.nphoton=1e7; -cfg.vol=uint8(ones(60,60,60)); -cfg.srctype='pattern'; -cfg.srcpos=[-40,-40, 0]; -cfg.srcparam1=[80 0 0 100]; -cfg.srcparam2=[0 80 0 100]; -cfg.srcdir=[0 0 1 30]; -cfg.issrcfrom0=1; -cfg.srcpattern=zeros(100,100); -cfg.srcpattern(51:end,51:end)=1; -cfg.gpuid=1; -cfg.autopilot=1; -cfg.prop=[0 0 1 1;0.005 0.1 0 1]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-09; -cfg.bc='mm____'; +clear cfg; +cfg.nphoton = 1e7; +cfg.vol = uint8(ones(60, 60, 60)); +cfg.srctype = 'pattern'; +cfg.srcpos = [-40, -40, 0]; +cfg.srcparam1 = [80 0 0 100]; +cfg.srcparam2 = [0 80 0 100]; +cfg.srcdir = [0 0 1 30]; +cfg.issrcfrom0 = 1; +cfg.srcpattern = zeros(100, 100); +cfg.srcpattern(51:end, 51:end) = 1; +cfg.gpuid = 1; +cfg.autopilot = 1; +cfg.prop = [0 0 1 1; 0.005 0.1 0 1]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-09; +cfg.bc = 'mm____'; -flux=mcxlab(cfg); +flux = mcxlab(cfg); -mcxplotvol(log10(double(flux.data))) +mcxplotvol(log10(double(flux.data))); diff --git a/mcxlab/examples/demo_fullhead_atlas.m b/mcxlab/examples/demo_fullhead_atlas.m index 55800bb4..b72628ca 100644 --- a/mcxlab/examples/demo_fullhead_atlas.m +++ b/mcxlab/examples/demo_fullhead_atlas.m @@ -1,8 +1,8 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % MCXLAB - Monte Carlo eXtreme for MATLAB/Octave by Qianqina Fang % -% In this example, we demonstrate light transport simulation in a full-head -% atlas template(USC 19.5 year group[Sanchez2012]). +% In this example, we demonstrate light transport simulation in a full-head +% atlas template(USC 19.5 year group[Sanchez2012]). % % This demo is identical to the MCX simulation used for Fig.9(a) in % TranYan2020. @@ -10,8 +10,8 @@ % [Sanchez2012] C.E.Sanchez J.E.Richards and C.R.Almli, “Age-Specific MRI Templates % for Pediatric Neuroimaging,” Developmental Neuropsychology 37, 379–399 (2012). % -% [TranYan2020] Tran AP+, Yan S+, Fang Q*, (2020) “Improving model-based fNIRS -% analysis using mesh-based anatomical and light-transport models," +% [TranYan2020] Tran AP+, Yan S+, Fang Q*, (2020) “Improving model-based fNIRS +% analysis using mesh-based anatomical and light-transport models," % Neurophotonics, 7(1), 015008 % % This file is part of Monte Carlo eXtreme (MCX) URL:http://mcx.sf.net @@ -19,58 +19,61 @@ load('fullhead_atlas.mat'); %% prepare cfg for MCX simulation -clear cfg -cfg.nphoton=1e8; -cfg.outputtype='fluence'; +clear cfg; +cfg.nphoton = 1e8; +cfg.outputtype = 'fluence'; % tissue labels:0-ambient air,1-scalp,2-skull,3-csf,4-gray matter,5-white matter,6-air cavities -cfg.vol=USC_atlas; -cfg.prop=[0,0,1,1;0.019 7.8 0.89 1.37;0.02 9.0 0.89 1.37;0.004 0.009 0.89 1.37;0.019 7.8 0.89 1.37;0.08 40.9 0.84 1.37;0,0,1,1]; +cfg.vol = USC_atlas; +cfg.prop = [0, 0, 1, 1; 0.019 7.8 0.89 1.37; 0.02 9.0 0.89 1.37; 0.004 0.009 0.89 1.37; 0.019 7.8 0.89 1.37; 0.08 40.9 0.84 1.37; 0, 0, 1, 1]; % light source -cfg.srcnum=1; -cfg.srcpos=[133.5370,90.1988,200.0700]; %pencil beam source placed at EEG 10-5 landmark:"C4h" -cfg.srctype='pencil'; -cfg.srcdir=[-0.5086,-0.1822,-0.8415]; %inward-pointing source -cfg.issrcfrom0=1; +cfg.srcnum = 1; +cfg.srcpos = [133.5370, 90.1988, 200.0700]; % pencil beam source placed at EEG 10-5 landmark:"C4h" +cfg.srctype = 'pencil'; +cfg.srcdir = [-0.5086, -0.1822, -0.8415]; % inward-pointing source +cfg.issrcfrom0 = 1; % time windows -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-10; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-10; % other simulation parameters -cfg.isspecular=0; -cfg.isreflect=1; -cfg.autopilot=1; -cfg.gpuid=1; +cfg.isspecular = 0; +cfg.isreflect = 1; +cfg.autopilot = 1; +cfg.gpuid = 1; %% run MCX simulation -[flux]=mcxlab(cfg); +[flux] = mcxlab(cfg); %% post-simulation data processing and visualization % convert time-resolved fluence to CW fluence -CWfluence=sum(flux.data,4); +CWfluence = sum(flux.data, 4); % coronal plane selected for fluence plot -y_plane=90.5; -[xx,zz]=meshgrid(1:size(cfg.vol,1),1:size(cfg.vol,3)); +y_plane = 90.5; +[xx, zz] = meshgrid(1:size(cfg.vol, 1), 1:size(cfg.vol, 3)); % plot CW fluence distribution using contour lines figure; -clines=-20:0.5:0; -contourf(xx,zz,log10(abs(squeeze(CWfluence(:,ceil(y_plane),:))')),clines,'linestyle','--','color',[0.9100 0.4100 0.1700],'linewidth',1.5,'DisplayName','MCX'); -hold on;axis equal; +clines = -20:0.5:0; +contourf(xx, zz, log10(abs(squeeze(CWfluence(:, ceil(y_plane), :))')), clines, 'linestyle', '--', 'color', [0.9100 0.4100 0.1700], 'linewidth', 1.5, 'DisplayName', 'MCX'); +hold on; +axis equal; colorbar('EastOutside'); % plot tissue boundary contour, source, legend, etc. -contour(squeeze(cfg.vol(:,ceil(y_plane),:))','k--','linewidth',1.25,'HandleVisibility','off'); -plot(cfg.srcpos(1,1),cfg.srcpos(1,3),'o','MarkerEdgeColor','r','MarkerFaceColor','r','MarkerSize',10,'DisplayName','source'); -lg=legend('Location','northeast'); -set(lg,'color','[0.85 0.85 0.85]'); -set(lg,'box','on'); -set(gca,'ylim', [160 225]);ylabel('z [mm]'); -set(gca,'xlim', [10 165]);xlabel('x [mm]'); -set(gca,'clim',[-12 0]); -set(gca,'fontsize',18); +contour(squeeze(cfg.vol(:, ceil(y_plane), :))', 'k--', 'linewidth', 1.25, 'HandleVisibility', 'off'); +plot(cfg.srcpos(1, 1), cfg.srcpos(1, 3), 'o', 'MarkerEdgeColor', 'r', 'MarkerFaceColor', 'r', 'MarkerSize', 10, 'DisplayName', 'source'); +lg = legend('Location', 'northeast'); +set(lg, 'color', '[0.85 0.85 0.85]'); +set(lg, 'box', 'on'); +set(gca, 'ylim', [160 225]); +ylabel('z [mm]'); +set(gca, 'xlim', [10 165]); +xlabel('x [mm]'); +set(gca, 'clim', [-12 0]); +set(gca, 'fontsize', 18); set(gca, 'FontName', 'Times New Roman'); diff --git a/mcxlab/examples/demo_infinite_slab_cyclic_bc.m b/mcxlab/examples/demo_infinite_slab_cyclic_bc.m index a3e752a6..1d19e482 100644 --- a/mcxlab/examples/demo_infinite_slab_cyclic_bc.m +++ b/mcxlab/examples/demo_infinite_slab_cyclic_bc.m @@ -9,35 +9,36 @@ % only clear cfg to avoid accidentally clearing other useful data clear cfg; -cfg.nphoton=1e8; -cfg.issrcfrom0=1; -cfg.vol=uint8(ones(60,60,20)); -cfg.srcdir=[0 0 1]; -cfg.gpuid=1; -cfg.autopilot=1; -cfg.prop=[0 0 1 1;0.005 2 0.8 1.37]; -cfg.tstart=0; -cfg.seed=99999; +cfg.nphoton = 1e8; +cfg.issrcfrom0 = 1; +cfg.vol = uint8(ones(60, 60, 20)); +cfg.srcdir = [0 0 1]; +cfg.gpuid = 1; +cfg.autopilot = 1; +cfg.prop = [0 0 1 1; 0.005 2 0.8 1.37]; +cfg.tstart = 0; +cfg.seed = 99999; % a uniform planar source outside the volume -cfg.srctype='planar'; -cfg.srcpos=[0 0 0]; -cfg.srcparam1=[60 0 0 0]; -cfg.srcparam2=[0 60 0 0]; -cfg.tend=5e-9; -cfg.tstep=5e-9; -cfg.bc='ccrccr'; -flux=mcxlab(cfg); +cfg.srctype = 'planar'; +cfg.srcpos = [0 0 0]; +cfg.srcparam1 = [60 0 0 0]; +cfg.srcparam2 = [0 60 0 0]; +cfg.tend = 5e-9; +cfg.tstep = 5e-9; +cfg.bc = 'ccrccr'; +flux = mcxlab(cfg); -fcw=flux.data*cfg.tstep; +fcw = flux.data * cfg.tstep; subplot(121); -imagesc(log10(abs(squeeze(fcw(:,30,:))))) -axis equal; colorbar -set(gca,'xlim',[0 size(cfg.vol,3)]); +imagesc(log10(abs(squeeze(fcw(:, 30, :))))); +axis equal; +colorbar; +set(gca, 'xlim', [0 size(cfg.vol, 3)]); title('a uniform planar source incident along an infinite slab'); subplot(122); -semilogy(squeeze(mean(mean(fcw,2),1))) +semilogy(squeeze(mean(mean(fcw, 2), 1))); title('averaged light attenuation profile'); -ylabel('averaged CW fluence 1/mm^2') -xlabel('depth (mm)') +ylabel('averaged CW fluence 1/mm^2'); +xlabel('depth (mm)'); diff --git a/mcxlab/examples/demo_label_continous_hybrid.m b/mcxlab/examples/demo_label_continous_hybrid.m index 7562eee7..7b61e34f 100644 --- a/mcxlab/examples/demo_label_continous_hybrid.m +++ b/mcxlab/examples/demo_label_continous_hybrid.m @@ -1,153 +1,155 @@ - %% case 1: homogenous media, update the refractive index from n_old to n_new for all voxels % only clear cfg to avoid accidentally clearing other useful data -clear cfg1 -n_old=1.37; -n_new=1.55; - -cfg1.nphoton=1e8; -cfg1.srcpos=[30 30 1]; -cfg1.srcdir=[0 0 1]; -cfg1.gpuid=1; -cfg1.autopilot=1; -cfg1.tstart=0; -cfg1.tend=5e-9; -cfg1.tstep=5e-9; -cfg1.isreflect=1; +clear cfg1; +n_old = 1.37; +n_new = 1.55; + +cfg1.nphoton = 1e8; +cfg1.srcpos = [30 30 1]; +cfg1.srcdir = [0 0 1]; +cfg1.gpuid = 1; +cfg1.autopilot = 1; +cfg1.tstart = 0; +cfg1.tend = 5e-9; +cfg1.tstep = 5e-9; +cfg1.isreflect = 1; % conventional way to define optical properties: label each voxel with % tissue types -cfg1.vol=uint8(ones(60,60,60)); -cfg1.prop=[0 0 1 1;0.005 1 0 n_new]; -flux1_conventional=mcxlab(cfg1); +cfg1.vol = uint8(ones(60, 60, 60)); +cfg1.prop = [0 0 1 1; 0.005 1 0 n_new]; +flux1_conventional = mcxlab(cfg1); % tissue-type based continuous varying media -cfg1.prop=[0 0 1 1;0.005 1 0 n_old]; % n=1.37 will be updated during simulation -property_substitute=single(3*ones(size(cfg1.vol))); % 0-update mua, 1-update mus, 2-update g, 3-update n -label=single(ones(size(cfg1.vol))); % label-based tissue type -replace_property=single(n_new*ones(size(cfg1.vol))); % values to substitute corresponding optical properties -cfg1.vol=permute(cat(4,replace_property,property_substitute,label),[4 1 2 3]); % Concatenated as a 4-D single array -flux1_new=mcxlab(cfg1); +cfg1.prop = [0 0 1 1; 0.005 1 0 n_old]; % n=1.37 will be updated during simulation +property_substitute = single(3 * ones(size(cfg1.vol))); % 0-update mua, 1-update mus, 2-update g, 3-update n +label = single(ones(size(cfg1.vol))); % label-based tissue type +replace_property = single(n_new * ones(size(cfg1.vol))); % values to substitute corresponding optical properties +cfg1.vol = permute(cat(4, replace_property, property_substitute, label), [4 1 2 3]); % Concatenated as a 4-D single array +flux1_new = mcxlab(cfg1); % compare fluence maps between two approaches figure(1); -clines=-7:1:-1; -contourf(log10(squeeze(flux1_conventional.data(31,:,:))*cfg1.tstep),clines,'r-');axis equal; +clines = -7:1:-1; +contourf(log10(squeeze(flux1_conventional.data(31, :, :)) * cfg1.tstep), clines, 'r-'); +axis equal; hold on; -contour(log10(squeeze(flux1_new.data(31,:,:))*cfg1.tstep),clines,'w--'); -legend('conventional','new'); +contour(log10(squeeze(flux1_new.data(31, :, :)) * cfg1.tstep), clines, 'w--'); +legend('conventional', 'new'); colorbar; title('homogeneous cube'); %% case 2: Two-layer slab: The refractive indices of tissue type 1 and 2 will be updated to 1.45 and 1.6 respectively -clear cfg2 -n_old_1=1.37; -n_new_1=1.45; - -n_old=1.37; -n_new_2=1.6; - -cfg2.nphoton=1e8; -cfg2.srcpos=[30 30 1]; -cfg2.srcdir=[0 0 1]; -cfg2.gpuid=1; -cfg2.autopilot=1; -cfg2.tstart=0; -cfg2.tend=5e-9; -cfg2.tstep=5e-9; -cfg2.isreflect=1; +clear cfg2; +n_old_1 = 1.37; +n_new_1 = 1.45; + +n_old = 1.37; +n_new_2 = 1.6; + +cfg2.nphoton = 1e8; +cfg2.srcpos = [30 30 1]; +cfg2.srcdir = [0 0 1]; +cfg2.gpuid = 1; +cfg2.autopilot = 1; +cfg2.tstart = 0; +cfg2.tend = 5e-9; +cfg2.tstep = 5e-9; +cfg2.isreflect = 1; % conventional way to define optical properties: label each voxel with % tissue types -cfg2.vol=uint8(ones(60,60,60)); -cfg2.vol(:,:,31:60)=2; -cfg2.prop=[0 0 1 1;0.005 1 0 n_new_1;0.01 2 0 n_new_2]; -flux2_conventional=mcxlab(cfg2); +cfg2.vol = uint8(ones(60, 60, 60)); +cfg2.vol(:, :, 31:60) = 2; +cfg2.prop = [0 0 1 1; 0.005 1 0 n_new_1; 0.01 2 0 n_new_2]; +flux2_conventional = mcxlab(cfg2); % tissue-type based continuous varying media -cfg2.prop=[0 0 1 1;0.005 1 0 n_old_1;0.01 2 0 n_old]; % n=1.37 will be updated during the simulation -property_substitute=single(3*ones(size(cfg2.vol))); % 0-update mua, 1-update mus, 2-update g, 3-update n -label=single(ones(size(cfg2.vol))); % label-based tissue type -label(:,:,31:60)=2; -replace_property=single(n_new_1*ones(size(cfg2.vol))); % values to substitute corresponding optical properties -replace_property(:,:,31:60)=n_new_2; -cfg2.vol=permute(cat(4,replace_property,property_substitute,label),[4 1 2 3]); % Concatenated as a 4-D array -flux2_new=mcxlab(cfg2); - -clines=[-10:0.5:-2]; +cfg2.prop = [0 0 1 1; 0.005 1 0 n_old_1; 0.01 2 0 n_old]; % n=1.37 will be updated during the simulation +property_substitute = single(3 * ones(size(cfg2.vol))); % 0-update mua, 1-update mus, 2-update g, 3-update n +label = single(ones(size(cfg2.vol))); % label-based tissue type +label(:, :, 31:60) = 2; +replace_property = single(n_new_1 * ones(size(cfg2.vol))); % values to substitute corresponding optical properties +replace_property(:, :, 31:60) = n_new_2; +cfg2.vol = permute(cat(4, replace_property, property_substitute, label), [4 1 2 3]); % Concatenated as a 4-D array +flux2_new = mcxlab(cfg2); + +clines = [-10:0.5:-2]; % compare figure(2); -contourf(log10(squeeze(flux2_conventional.data(31,:,:))*cfg2.tstep),clines,'r-');axis equal; +contourf(log10(squeeze(flux2_conventional.data(31, :, :)) * cfg2.tstep), clines, 'r-'); +axis equal; hold on; -contour(log10(squeeze(flux2_new.data(31,:,:))*cfg2.tstep),clines,'w--'); -legend('conventional','new'); +contour(log10(squeeze(flux2_new.data(31, :, :)) * cfg2.tstep), clines, 'w--'); +legend('conventional', 'new'); title('two layer slab'); %% case 3: multi-layer slab: mua of tissue type 1 will be updated to 0.05 while the refractive indices of tissue type 2 will be updated to [1.30,1.35,1.40,1.45,1.50,1.55] -clear cfg3 -mua_old_1=0.005; -mua_new_1=0.05; - -n_old=1.37; -n_new_1=1.30; -n_new_2=1.35; -n_new_3=1.40; -n_new_4=1.45; -n_new_5=1.50; -n_new_6=1.55; - -cfg3.nphoton=1e8; -cfg3.srcpos=[30 30 1]; -cfg3.srcdir=[0 0 1]; -cfg3.gpuid=1; -cfg3.autopilot=1; -cfg3.tstart=0; -cfg3.tend=5e-9; -cfg3.tstep=5e-9; -cfg3.isreflect=1; +clear cfg3; +mua_old_1 = 0.005; +mua_new_1 = 0.05; + +n_old = 1.37; +n_new_1 = 1.30; +n_new_2 = 1.35; +n_new_3 = 1.40; +n_new_4 = 1.45; +n_new_5 = 1.50; +n_new_6 = 1.55; + +cfg3.nphoton = 1e8; +cfg3.srcpos = [30 30 1]; +cfg3.srcdir = [0 0 1]; +cfg3.gpuid = 1; +cfg3.autopilot = 1; +cfg3.tstart = 0; +cfg3.tend = 5e-9; +cfg3.tstep = 5e-9; +cfg3.isreflect = 1; % conventional way to define optical properties: label each voxel with % tissue types -cfg3.vol=uint8(ones(60,60,60)); -for i=1:6 % each layer - cfg3.vol(:,:,30+i*5)=i+1; - cfg3.vol(:,:,30+i*5-1)=i+1; - cfg3.vol(:,:,30+i*5-2)=i+1; - cfg3.vol(:,:,30+i*5-3)=i+1; - cfg3.vol(:,:,30+i*5-4)=i+1; +cfg3.vol = uint8(ones(60, 60, 60)); +for i = 1:6 % each layer + cfg3.vol(:, :, 30 + i * 5) = i + 1; + cfg3.vol(:, :, 30 + i * 5 - 1) = i + 1; + cfg3.vol(:, :, 30 + i * 5 - 2) = i + 1; + cfg3.vol(:, :, 30 + i * 5 - 3) = i + 1; + cfg3.vol(:, :, 30 + i * 5 - 4) = i + 1; end -cfg3.prop=[0 0 1 1; - mua_new_1 1 0 1.37; - 0.01 2 0 n_new_1; - 0.01 2 0 n_new_2; - 0.01 2 0 n_new_3; - 0.01 2 0 n_new_4; - 0.01 2 0 n_new_5; - 0.01 2 0 n_new_6]; -flux2_conventional=mcxlab(cfg3); +cfg3.prop = [0 0 1 1 + mua_new_1 1 0 1.37 + 0.01 2 0 n_new_1 + 0.01 2 0 n_new_2 + 0.01 2 0 n_new_3 + 0.01 2 0 n_new_4 + 0.01 2 0 n_new_5 + 0.01 2 0 n_new_6]; +flux2_conventional = mcxlab(cfg3); % tissue-type based continuous varying media -cfg3.prop=[0 0 1 1;0.005 1 0 1.37;0.01 2 0 n_old]; % n=1.37 will be updated during the simulation -property_substitute=single(zeros(size(cfg3.vol))); % 0-update mua, 1-update mus, 2-update g, 3-update n -property_substitute(:,:,31:60)=3; -label=single(ones(size(cfg3.vol))); % label-based tissue type 0-255 -label(:,:,31:60)=2; -replace_property=single(mua_new_1*ones(size(cfg3.vol))); % values to substitute corresponding optical properties -replace_property(:,:,31:35)=n_new_1; -replace_property(:,:,36:40)=n_new_2; -replace_property(:,:,41:45)=n_new_3; -replace_property(:,:,46:50)=n_new_4; -replace_property(:,:,51:55)=n_new_5; -replace_property(:,:,56:60)=n_new_6; -cfg3.vol=permute(cat(4,replace_property,property_substitute,label),[4 1 2 3]); % Concatenated as a 4-D array -flux2_new=mcxlab(cfg3); - -clines=[-12:1:-2]; +cfg3.prop = [0 0 1 1; 0.005 1 0 1.37; 0.01 2 0 n_old]; % n=1.37 will be updated during the simulation +property_substitute = single(zeros(size(cfg3.vol))); % 0-update mua, 1-update mus, 2-update g, 3-update n +property_substitute(:, :, 31:60) = 3; +label = single(ones(size(cfg3.vol))); % label-based tissue type 0-255 +label(:, :, 31:60) = 2; +replace_property = single(mua_new_1 * ones(size(cfg3.vol))); % values to substitute corresponding optical properties +replace_property(:, :, 31:35) = n_new_1; +replace_property(:, :, 36:40) = n_new_2; +replace_property(:, :, 41:45) = n_new_3; +replace_property(:, :, 46:50) = n_new_4; +replace_property(:, :, 51:55) = n_new_5; +replace_property(:, :, 56:60) = n_new_6; +cfg3.vol = permute(cat(4, replace_property, property_substitute, label), [4 1 2 3]); % Concatenated as a 4-D array +flux2_new = mcxlab(cfg3); + +clines = [-12:1:-2]; % compare figure(3); -contourf(log10(squeeze(flux2_conventional.data(31,:,:))*cfg3.tstep),clines,'r-');axis equal; +contourf(log10(squeeze(flux2_conventional.data(31, :, :)) * cfg3.tstep), clines, 'r-'); +axis equal; hold on; -contour(log10(squeeze(flux2_new.data(31,:,:))*cfg3.tstep),clines,'w--'); -legend('conventional','new'); -title('multi-layered slab'); \ No newline at end of file +contour(log10(squeeze(flux2_new.data(31, :, :)) * cfg3.tstep), clines, 'w--'); +legend('conventional', 'new'); +title('multi-layered slab'); diff --git a/mcxlab/examples/demo_lambertian_exit_angle.m b/mcxlab/examples/demo_lambertian_exit_angle.m index 101d7684..c33d9d9e 100644 --- a/mcxlab/examples/demo_lambertian_exit_angle.m +++ b/mcxlab/examples/demo_lambertian_exit_angle.m @@ -1,54 +1,54 @@ -%========================================================================== +% ========================================================================== % Script to verify Lambertian photon exiting angular profile % % Author: Qianqian Fang % Initial version: May 5, 2018 -%========================================================================== +% ========================================================================== -clear cfg -cfg.nphoton=1e8; -cfg.vol=uint8(ones(60,60,60)); -cfg.srcpos=[20, 30, 0]; -cfg.srcdir=[0 0 1]; +clear cfg; +cfg.nphoton = 1e8; +cfg.vol = uint8(ones(60, 60, 60)); +cfg.srcpos = [20, 30, 0]; +cfg.srcdir = [0 0 1]; -cfg.maxdetphoton=1500000; -cfg.gpuid=1; -cfg.autopilot=1; +cfg.maxdetphoton = 1500000; +cfg.gpuid = 1; +cfg.autopilot = 1; -cfg.prop=[0 0 1 1;0.005 1 0 1.37]; +cfg.prop = [0 0 1 1; 0.005 1 0 1.37]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-9; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-9; -cfg.issrcfrom0=1; -cfg.isreflect=1; -cfg.issaveexit=1; +cfg.issrcfrom0 = 1; +cfg.isreflect = 1; +cfg.issaveexit = 1; cfg.detpos = [25 30 0 2]; -%cfg.prop=[0 0 1 1;0.005 0.01 0 1.37]; %try this low-scattering case +% cfg.prop=[0 0 1 1;0.005 0.01 0 1.37]; %try this low-scattering case % calculate the flux distribution with the given config -[flux1,detp1] = mcxlab(cfg); +[flux1, detp1] = mcxlab(cfg); % it took me a while to figure out, but the key is to divide the area :) -el=asin(detp1.v(:,3)); % elevation angle of v, el=0 parallel to surface, el=pi/2 at normal dir +el = asin(detp1.v(:, 3)); % elevation angle of v, el=0 parallel to surface, el=pi/2 at normal dir -edges=linspace(min(el),max(el),100); % angle bins for hisotogram +edges = linspace(min(el), max(el), 100); % angle bins for hisotogram -[ct, bin]=histc(el,edges); % count of photons per angle bin +[ct, bin] = histc(el, edges); % count of photons per angle bin -R=cfg.detpos(1,4); % radius of the det -hedges=abs(R*sin(edges)); % height of each spherical segment for each bin -zonearea=2*pi*R*(diff(hedges)); % area of each spherical segment +R = cfg.detpos(1, 4); % radius of the det +hedges = abs(R * sin(edges)); % height of each spherical segment for each bin +zonearea = 2 * pi * R * (diff(hedges)); % area of each spherical segment -detweight=mmcdetweight(detp1, cfg.prop); % get detected photon weight -angularweight=accumarray(bin,detweight); % sum total weight per zone +detweight = mmcdetweight(detp1, cfg.prop); % get detected photon weight +angularweight = accumarray(bin, detweight); % sum total weight per zone -angularflux=angularweight(1:end-1)'./zonearea; % calculate flux per angle +angularflux = angularweight(1:end - 1)' ./ zonearea; % calculate flux per angle -polar((edges(1:end-1)+edges(2:end))*0.5, angularflux); % plot flux vs angle +polar((edges(1:end - 1) + edges(2:end)) * 0.5, angularflux); % plot flux vs angle hold on; -polar(pi-(edges(1:end-1)+edges(2:end))*0.5, angularflux); % mirror to form a circle \ No newline at end of file +polar(pi - (edges(1:end - 1) + edges(2:end)) * 0.5, angularflux); % mirror to form a circle diff --git a/mcxlab/examples/demo_mcxlab_2d.m b/mcxlab/examples/demo_mcxlab_2d.m index baaab301..1cef97f1 100644 --- a/mcxlab/examples/demo_mcxlab_2d.m +++ b/mcxlab/examples/demo_mcxlab_2d.m @@ -1,8 +1,8 @@ -%========================================================================== +% ========================================================================== % A sample 2D MCX simulation % % Author: Qianqian Fang -%========================================================================== +% ========================================================================== % you must define a 3D array with one singleton dimension (with length 1). % unfortunately if you define z as singleton, matlab will make the array 2D @@ -10,30 +10,30 @@ % singleton. % only clear cfg to avoid accidentally clearing other useful data -clear cfg +clear cfg; -cfg.nphoton=1e6; +cfg.nphoton = 1e6; -cfg.vol=permute(uint8(ones(100,100)), [3,1,2]); % from 2d to 3d -cfg.vol(1,30:70, 10:50)=2; -cfg.issrcfrom0=1; -cfg.srctype='pencil'; +cfg.vol = permute(uint8(ones(100, 100)), [3, 1, 2]); % from 2d to 3d +cfg.vol(1, 30:70, 10:50) = 2; +cfg.issrcfrom0 = 1; +cfg.srctype = 'pencil'; -cfg.srcpos=[0,50,0]; % src position must be located in the 2D plane -cfg.srcdir=[0 0 1]; % src dir must align in the plan (y-z in this case) +cfg.srcpos = [0, 50, 0]; % src position must be located in the 2D plane +cfg.srcdir = [0 0 1]; % src dir must align in the plan (y-z in this case) -cfg.gpuid=1; -cfg.autopilot=1; -cfg.gscatter=100; +cfg.gpuid = 1; +cfg.autopilot = 1; +cfg.gscatter = 100; -myprop=[0.02 0.1 0.9 1.37; 0.02 10 0.9 1.37*5]; +myprop = [0.02 0.1 0.9 1.37; 0.02 10 0.9 1.37 * 5]; -cfg.prop=[0 0 1 1; myprop]; -cfg.tstart=0; -cfg.tend=1e-8; -cfg.tstep=1e-8; -flux=mcxlab(cfg); +cfg.prop = [0 0 1 1; myprop]; +cfg.tstart = 0; +cfg.tend = 1e-8; +cfg.tstep = 1e-8; +flux = mcxlab(cfg); -cw=squeeze(sum(flux.data,4)); +cw = squeeze(sum(flux.data, 4)); figure; -imagesc(log10(abs(cw))) \ No newline at end of file +imagesc(log10(abs(cw))); diff --git a/mcxlab/examples/demo_mcxlab_basic.m b/mcxlab/examples/demo_mcxlab_basic.m index b4def6b6..0a245f46 100644 --- a/mcxlab/examples/demo_mcxlab_basic.m +++ b/mcxlab/examples/demo_mcxlab_basic.m @@ -7,30 +7,30 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % only clear cfg to avoid accidentally clearing other useful data -clear cfg cfgs -cfg.nphoton=1e7; -cfg.vol=uint8(ones(60,60,60)); -cfg.srcpos=[30 30 1]; -cfg.srcdir=[0 0 1]; -cfg.gpuid=1; +clear cfg cfgs; +cfg.nphoton = 1e7; +cfg.vol = uint8(ones(60, 60, 60)); +cfg.srcpos = [30 30 1]; +cfg.srcdir = [0 0 1]; +cfg.gpuid = 1; % cfg.gpuid='11'; % use two GPUs together -cfg.autopilot=1; -cfg.prop=[0 0 1 1;0.005 1 0 1.37]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=1e-10; +cfg.autopilot = 1; +cfg.prop = [0 0 1 1; 0.005 1 0 1.37]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 1e-10; % calculate the flux distribution with the given config -flux=mcxlab(cfg); +flux = mcxlab(cfg); %% define cfg as a struct array to run multiple simulations -cfgs(1)=cfg; -cfgs(2)=cfg; -cfgs(1).isreflect=0; -cfgs(2).isreflect=1; -cfgs(2).detpos=[30 20 1 1;30 40 1 1;20 30 1 1;40 30 1 1]; +cfgs(1) = cfg; +cfgs(2) = cfg; +cfgs(1).isreflect = 0; +cfgs(2).isreflect = 1; +cfgs(2).detpos = [30 20 1 1; 30 40 1 1; 20 30 1 1; 40 30 1 1]; % calculate the flux and partial path lengths for the two configurations -[fluxs,detps]=mcxlab(cfgs); +[fluxs, detps] = mcxlab(cfgs); -imagesc(squeeze(log(fluxs(1).data(:,30,:,1)))-squeeze(log(fluxs(2).data(:,30,:,1)))); +imagesc(squeeze(log(fluxs(1).data(:, 30, :, 1))) - squeeze(log(fluxs(2).data(:, 30, :, 1)))); diff --git a/mcxlab/examples/demo_mcxlab_launchangle.m b/mcxlab/examples/demo_mcxlab_launchangle.m index cfd79f1a..4ef6b4f8 100644 --- a/mcxlab/examples/demo_mcxlab_launchangle.m +++ b/mcxlab/examples/demo_mcxlab_launchangle.m @@ -8,51 +8,48 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % only clear cfg to avoid accidentally clearing other useful data -clear cfg +clear cfg; -cfg.nphoton=1e7; -cfg.vol=uint8(ones(60,60,60)); -cfg.srcpos=[30 30 15]; -cfg.srcdir=[0 0 1]; -cfg.gpuid=1; +cfg.nphoton = 1e7; +cfg.vol = uint8(ones(60, 60, 60)); +cfg.srcpos = [30 30 15]; +cfg.srcdir = [0 0 1]; +cfg.gpuid = 1; % cfg.gpuid='11'; % use two GPUs together -cfg.autopilot=1; -cfg.prop=[0 0 1 1;0 0 1 1]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-9; -cfg.isreflect=0; +cfg.autopilot = 1; +cfg.prop = [0 0 1 1; 0 0 1 1]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-9; +cfg.isreflect = 0; % define angleinvcdf in launch angle using cfg.angleinvcdf -cfg.angleinvcdf=linspace(1/6, 1/5, 5); % launch angle is uniformly distributed between [pi/6 and pi/5] with interpolation (odd-number length) -flux=mcxlab(cfg); - -mcxplotvol(log10(abs(flux.data))) -hold on -plot(cfg.angleinvcdf) +cfg.angleinvcdf = linspace(1 / 6, 1 / 5, 5); % launch angle is uniformly distributed between [pi/6 and pi/5] with interpolation (odd-number length) +flux = mcxlab(cfg); +mcxplotvol(log10(abs(flux.data))); +hold on; +plot(cfg.angleinvcdf); %% test Lambertian/cosine distribution -cfg.angleinvcdf=asin(0:0.01:1)/pi; % Lambertian distribution pdf: PDF(theta)=cos(theta)/pi, CDF=sin(theta)/pi, invcdf=asin(0:1)/pi, with interpolation (cfg.srcdir(4) is not specified) -flux=mcxlab(cfg); -mcxplotvol(log10(abs(flux.data))) - +cfg.angleinvcdf = asin(0:0.01:1) / pi; % Lambertian distribution pdf: PDF(theta)=cos(theta)/pi, CDF=sin(theta)/pi, invcdf=asin(0:1)/pi, with interpolation (cfg.srcdir(4) is not specified) +flux = mcxlab(cfg); +mcxplotvol(log10(abs(flux.data))); %% discrete angles with interpolation -cfg.angleinvcdf=[0 0 0 0 1/6 1/6 1/4]; % interpolatation is used between discrete angular values -flux=mcxlab(cfg); -mcxplotvol(log10(abs(flux.data))) - +cfg.angleinvcdf = [0 0 0 0 1 / 6 1 / 6 1 / 4]; % interpolatation is used between discrete angular values +flux = mcxlab(cfg); +mcxplotvol(log10(abs(flux.data))); %% discrete angles without interpolation (by setting focal-length cfg.srcdir(4) to 1) -cfg.angleinvcdf=[0 0 0 0 1/6 1/6 1/4]; -cfg.srcdir(4)=1; % disable interpolation, use the discrete angles in angleinvcdf elements only -flux=mcxlab(cfg); -mcxplotvol(log10(abs(flux.data))) +cfg.angleinvcdf = [0 0 0 0 1 / 6 1 / 6 1 / 4]; +cfg.srcdir(4) = 1; % disable interpolation, use the discrete angles in angleinvcdf elements only +flux = mcxlab(cfg); +mcxplotvol(log10(abs(flux.data))); %% can be applied to area source - convolve with the area -cfg.srctype='disk'; -cfg.srcparam1=[10,0,0,0]; -cfg.srcdir(4)=0; -flux=mcxlab(cfg); -mcxplotvol(log10(abs(flux.data))) +cfg.srctype = 'disk'; +cfg.srcparam1 = [10, 0, 0, 0]; +cfg.srcdir(4) = 0; +flux = mcxlab(cfg); +mcxplotvol(log10(abs(flux.data))); diff --git a/mcxlab/examples/demo_mcxlab_phasefun.m b/mcxlab/examples/demo_mcxlab_phasefun.m index 1ba45682..8ff25bc8 100644 --- a/mcxlab/examples/demo_mcxlab_phasefun.m +++ b/mcxlab/examples/demo_mcxlab_phasefun.m @@ -7,30 +7,30 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % only clear cfg to avoid accidentally clearing other useful data -clear cfg -cfg.nphoton=1e7; -cfg.vol=uint8(ones(60,60,60)); -cfg.srcpos=[30 30 1]; -cfg.srcdir=[0 0 1]; -cfg.gpuid=1; +clear cfg; +cfg.nphoton = 1e7; +cfg.vol = uint8(ones(60, 60, 60)); +cfg.srcpos = [30 30 1]; +cfg.srcdir = [0 0 1]; +cfg.gpuid = 1; % cfg.gpuid='11'; % use two GPUs together -cfg.autopilot=1; -cfg.prop=[0 0 1 1;0.005 1 0.8 1.37]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-9; +cfg.autopilot = 1; +cfg.prop = [0 0 1 1; 0.005 1 0.8 1.37]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-9; % use built-in Henyey-Greenstein phase function -flux=mcxlab(cfg); +flux = mcxlab(cfg); % define Henyey-Greenstein phase function using cfg.invcdf -invhg =@(u,g) (1 + g*g - ((1-g*g)./(1-g+2*g*u)).^2)./(2*g); -cfg.invcdf=invhg(0.01:0.01:1-0.01, 0.8); -flux=mcxlab(cfg); +invhg = @(u, g) (1 + g * g - ((1 - g * g) ./ (1 - g + 2 * g * u)).^2) ./ (2 * g); +cfg.invcdf = invhg(0.01:0.01:1 - 0.01, 0.8); +flux = mcxlab(cfg); % now use Rayleigh scattering phase function P(cos(theta))=P(u)=3/4*(1+u.^2) -invrayleigh=@(u) (4*u + ((4*u - 2).^2 + 1).^(1/2) - 2).^(1/3) - 1./(4*u + ((4*u - 2).^2 + 1).^(1/2) - 2).^(1/3); -cfg.invcdf=invrayleigh(0.01:0.01:1-0.01); +invrayleigh = @(u) (4 * u + ((4 * u - 2).^2 + 1).^(1 / 2) - 2).^(1 / 3) - 1 ./ (4 * u + ((4 * u - 2).^2 + 1).^(1 / 2) - 2).^(1 / 3); +cfg.invcdf = invrayleigh(0.01:0.01:1 - 0.01); % calculate the flux distribution using Rayleigh scattering phase function -flux=mcxlab(cfg); \ No newline at end of file +flux = mcxlab(cfg); diff --git a/mcxlab/examples/demo_mcxlab_replay.m b/mcxlab/examples/demo_mcxlab_replay.m index 8a0036ec..0e584ced 100644 --- a/mcxlab/examples/demo_mcxlab_replay.m +++ b/mcxlab/examples/demo_mcxlab_replay.m @@ -7,35 +7,36 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % only clear cfg to avoid accidentally clearing other useful data -clear cfg cfgs -cfg.nphoton=1e8; -cfg.vol=uint8(ones(60,60,60)); -cfg.srcpos=[30 30 0]; -cfg.srcdir=[0 0 1]; -cfg.gpuid=1; +clear cfg cfgs; +cfg.nphoton = 1e8; +cfg.vol = uint8(ones(60, 60, 60)); +cfg.srcpos = [30 30 0]; +cfg.srcdir = [0 0 1]; +cfg.gpuid = 1; % cfg.gpuid='11'; % use two GPUs together -cfg.autopilot=1; -cfg.issrcfrom0=1; -cfg.prop=[0 0 1 1;0.005 1 0 1.37]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-10; +cfg.autopilot = 1; +cfg.issrcfrom0 = 1; +cfg.prop = [0 0 1 1; 0.005 1 0 1.37]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-10; % calculate the flux distribution with the given config -cfg.detpos=[15 30 0 2]; -%cfg.savedetflag='dsp'; -[flux, detp, vol, seeds]=mcxlab(cfg); +cfg.detpos = [15 30 0 2]; +% cfg.savedetflag='dsp'; +[flux, detp, vol, seeds] = mcxlab(cfg); -newcfg=cfg; -newcfg.seed=seeds.data; -newcfg.outputtype='jacobian'; -newcfg.detphotons=detp.data; -[flux2, detp2, vol2, seeds2]=mcxlab(newcfg); -jac=sum(flux2.data,4); -imagesc(log10(abs(squeeze(jac(:,30,:))))) +newcfg = cfg; +newcfg.seed = seeds.data; +newcfg.outputtype = 'jacobian'; +newcfg.detphotons = detp.data; +[flux2, detp2, vol2, seeds2] = mcxlab(newcfg); +jac = sum(flux2.data, 4); +imagesc(log10(abs(squeeze(jac(:, 30, :))))); -newcfg.outputtype='rf'; -newcfg.omega=2*pi*100e6; % 100 MHz RF modulation -newcfg.detphotons=detp.data; -rfjac=mcxlab(newcfg); -jac=sum(rfjac.data,4); -figure;imagesc(log10(abs(squeeze(jac(:,30,:))))) +newcfg.outputtype = 'rf'; +newcfg.omega = 2 * pi * 100e6; % 100 MHz RF modulation +newcfg.detphotons = detp.data; +rfjac = mcxlab(newcfg); +jac = sum(rfjac.data, 4); +figure; +imagesc(log10(abs(squeeze(jac(:, 30, :))))); diff --git a/mcxlab/examples/demo_mcxlab_srctype.m b/mcxlab/examples/demo_mcxlab_srctype.m index ab07e331..8d385829 100644 --- a/mcxlab/examples/demo_mcxlab_srctype.m +++ b/mcxlab/examples/demo_mcxlab_srctype.m @@ -1,231 +1,242 @@ -%========================================================================== +% ========================================================================== % wide-field source tests -%========================================================================== +% ========================================================================== %% test group 1 % a regular pencil beam at the center of the volume clear cfg; -cfg.nphoton=1e7; -cfg.vol=uint8(ones(60,60,60)); -cfg.srcpos=[30 30 30]; -cfg.srcdir=[0 0 1]; -cfg.gpuid=1; -cfg.autopilot=1; -cfg.prop=[0 0 1 1;0.005 1 0.8 1.37]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-9; -%cfg.printnum=10; -cfg.seed=99999; -cfg.srctype='pencil'; -flux=mcxlab(cfg); -fcw=flux.data*cfg.tstep; +cfg.nphoton = 1e7; +cfg.vol = uint8(ones(60, 60, 60)); +cfg.srcpos = [30 30 30]; +cfg.srcdir = [0 0 1]; +cfg.gpuid = 1; +cfg.autopilot = 1; +cfg.prop = [0 0 1 1; 0.005 1 0.8 1.37]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-9; +% cfg.printnum=10; +cfg.seed = 99999; +cfg.srctype = 'pencil'; +flux = mcxlab(cfg); +fcw = flux.data * cfg.tstep; figure; subplot(221); -imagesc(log10(abs(squeeze(fcw(:,30,:))))) -axis equal; colorbar +imagesc(log10(abs(squeeze(fcw(:, 30, :))))); +axis equal; +colorbar; title('pencil beam at volume center'); % an isotropic source at the center of the volume -cfg.srctype='isotropic'; -flux=mcxlab(cfg); -fcw=flux.data*cfg.tstep; +cfg.srctype = 'isotropic'; +flux = mcxlab(cfg); +fcw = flux.data * cfg.tstep; subplot(222); -imagesc(log10(abs(squeeze(fcw(:,30,:))))) -axis equal; colorbar +imagesc(log10(abs(squeeze(fcw(:, 30, :))))); +axis equal; +colorbar; title('isotropic source at volume center'); % a pencil beam outside the volume -cfg.srctype='pencil'; -cfg.srcpos=[30 30 -10]; -flux=mcxlab(cfg); -fcw=flux.data*cfg.tstep; +cfg.srctype = 'pencil'; +cfg.srcpos = [30 30 -10]; +flux = mcxlab(cfg); +fcw = flux.data * cfg.tstep; subplot(223); -hs=slice(log10(abs(double(fcw))),[],30,1); -set(hs,'linestyle','none'); -axis equal; colorbar +hs = slice(log10(abs(double(fcw))), [], 30, 1); +set(hs, 'linestyle', 'none'); +axis equal; +colorbar; title('pencil beam launched from outside the volume'); % an isotropic source outside the volume -cfg.srctype='isotropic'; -cfg.srcpos=[30 30 -10]; -cfg.tend=1e-9; -cfg.tstep=1e-9; -flux=mcxlab(cfg); -fcw=flux.data*cfg.tstep; +cfg.srctype = 'isotropic'; +cfg.srcpos = [30 30 -10]; +cfg.tend = 1e-9; +cfg.tstep = 1e-9; +flux = mcxlab(cfg); +fcw = flux.data * cfg.tstep; subplot(224); -hs=slice(log10(abs(double(fcw))),[],30,1); -set(hs,'linestyle','none'); -axis equal; colorbar +hs = slice(log10(abs(double(fcw))), [], 30, 1); +set(hs, 'linestyle', 'none'); +axis equal; +colorbar; title('isotrpoic source at [30 30 -10]'); %% test group 2 clear cfg; figure; -cfg.nphoton=1e7; -cfg.vol=uint8(ones(60,60,60)); -cfg.srcdir=[0 0 1 0]; -cfg.gpuid=1; -cfg.autopilot=1; -cfg.prop=[0 0 1 1;0.005 1 0.8 1.37]; -cfg.tstart=0; -cfg.seed=99999; +cfg.nphoton = 1e7; +cfg.vol = uint8(ones(60, 60, 60)); +cfg.srcdir = [0 0 1 0]; +cfg.gpuid = 1; +cfg.autopilot = 1; +cfg.prop = [0 0 1 1; 0.005 1 0.8 1.37]; +cfg.tstart = 0; +cfg.seed = 99999; % a uniform planar source outside the volume -cfg.srctype='planar'; -cfg.srcpos=[10 10 0]; -cfg.srcparam1=[40 0 0 0]; -cfg.srcparam2=[0 40 0 0]; -cfg.tend=0.4e-10; -cfg.tstep=0.4e-10; -flux=mcxlab(cfg); -fcw=flux.data*cfg.tstep; +cfg.srctype = 'planar'; +cfg.srcpos = [10 10 0]; +cfg.srcparam1 = [40 0 0 0]; +cfg.srcparam2 = [0 40 0 0]; +cfg.tend = 0.4e-10; +cfg.tstep = 0.4e-10; +flux = mcxlab(cfg); +fcw = flux.data * cfg.tstep; subplot(221); -imagesc(log10(abs(squeeze(fcw(:,:,1))))) -axis equal; colorbar +imagesc(log10(abs(squeeze(fcw(:, :, 1))))); +axis equal; +colorbar; title('a uniform planar source'); -cfg.srctype='fourier'; -cfg.srcparam1=[40 10 0 2]; -cfg.srcparam2=[0 40 0 2]; -flux=mcxlab(cfg); -fcw=flux.data*cfg.tstep; +cfg.srctype = 'fourier'; +cfg.srcparam1 = [40 10 0 2]; +cfg.srcparam2 = [0 40 0 2]; +flux = mcxlab(cfg); +fcw = flux.data * cfg.tstep; subplot(222); -imagesc(log10(abs(squeeze(fcw(:,:,1))))) -axis equal; colorbar +imagesc(log10(abs(squeeze(fcw(:, :, 1))))); +axis equal; +colorbar; title('an SFDI source (2,2) in a quadrilateral'); -cfg.srctype='fourier'; -cfg.srcpos=[0 0 70]; -cfg.srcdir=[0 0 -1]; -cfg.srcparam1=[60 0 0 2]; -cfg.srcparam2=[0 60 0 1]; -cfg.tend=1e-9; -cfg.tstep=1e-9; -flux=mcxlab(cfg); -fcw=flux.data*cfg.tstep; +cfg.srctype = 'fourier'; +cfg.srcpos = [0 0 70]; +cfg.srcdir = [0 0 -1]; +cfg.srcparam1 = [60 0 0 2]; +cfg.srcparam2 = [0 60 0 1]; +cfg.tend = 1e-9; +cfg.tstep = 1e-9; +flux = mcxlab(cfg); +fcw = flux.data * cfg.tstep; subplot(223); -hs=slice(log10(abs(double(fcw))),1,1,60); -set(hs,'linestyle','none'); -axis equal; colorbar;box on; +hs = slice(log10(abs(double(fcw))), 1, 1, 60); +set(hs, 'linestyle', 'none'); +axis equal; +colorbar; +box on; title('a spatial frequency domain source (2,1)'); -mcximg=[0 0 0 0 0 0 0 0 0 0 0 -0 1 1 0 0 0 0 0 1 1 0 -0 0 0 1 1 0 1 1 0 0 0 -0 0 0 0 0 1 0 0 0 0 0 -0 0 0 1 1 0 1 1 0 0 0 -0 1 1 0 0 0 0 0 1 1 0 -0 0 0 0 0 0 0 0 0 0 0 -0 0 1 0 0 0 0 0 1 0 0 -0 1 0 0 0 0 0 0 0 1 0 -0 1 0 0 0 0 0 0 0 1 0 -0 1 0 0 0 0 0 0 0 1 0 -0 0 1 1 1 1 1 1 1 0 0 -0 0 0 0 0 0 0 0 0 0 0 -0 1 1 1 1 1 1 1 1 1 0 -0 0 0 1 0 0 0 0 0 0 0 -0 0 0 0 1 1 0 0 0 0 0 -0 0 0 1 0 0 0 0 0 0 0 -0 1 1 1 1 1 1 1 1 1 0 -0 0 0 0 0 0 0 0 0 0 0]; - -cfg.nphoton=1e7; -cfg.srctype='pattern'; -cfg.srcpattern=mcximg; -cfg.srcpos=[-10*sqrt(2) 0 40]; -cfg.srcdir=[1 1 0]/sqrt(2); -cfg.srcparam1=[20/sqrt(2) -20/sqrt(2) 0 size(mcximg,1)]; -cfg.srcparam2=[0 0 -15 size(mcximg,2)]; -cfg.tend=2e-10; -cfg.tstep=2e-10; -cfg.voidtime=0; -flux=mcxlab(cfg); -fcw=flux.data*cfg.tstep; +mcximg = [0 0 0 0 0 0 0 0 0 0 0 + 0 1 1 0 0 0 0 0 1 1 0 + 0 0 0 1 1 0 1 1 0 0 0 + 0 0 0 0 0 1 0 0 0 0 0 + 0 0 0 1 1 0 1 1 0 0 0 + 0 1 1 0 0 0 0 0 1 1 0 + 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 1 0 0 + 0 1 0 0 0 0 0 0 0 1 0 + 0 1 0 0 0 0 0 0 0 1 0 + 0 1 0 0 0 0 0 0 0 1 0 + 0 0 1 1 1 1 1 1 1 0 0 + 0 0 0 0 0 0 0 0 0 0 0 + 0 1 1 1 1 1 1 1 1 1 0 + 0 0 0 1 0 0 0 0 0 0 0 + 0 0 0 0 1 1 0 0 0 0 0 + 0 0 0 1 0 0 0 0 0 0 0 + 0 1 1 1 1 1 1 1 1 1 0 + 0 0 0 0 0 0 0 0 0 0 0]; + +cfg.nphoton = 1e7; +cfg.srctype = 'pattern'; +cfg.srcpattern = mcximg; +cfg.srcpos = [-10 * sqrt(2) 0 40]; +cfg.srcdir = [1 1 0] / sqrt(2); +cfg.srcparam1 = [20 / sqrt(2) -20 / sqrt(2) 0 size(mcximg, 1)]; +cfg.srcparam2 = [0 0 -15 size(mcximg, 2)]; +cfg.tend = 2e-10; +cfg.tstep = 2e-10; +cfg.voidtime = 0; +flux = mcxlab(cfg); +fcw = flux.data * cfg.tstep; subplot(224); -hs=slice(log10(abs(double(fcw))),1,1,60); -set(hs,'linestyle','none'); -axis equal; colorbar +hs = slice(log10(abs(double(fcw))), 1, 1, 60); +set(hs, 'linestyle', 'none'); +axis equal; +colorbar; title('an arbitrary pattern source from an angle'); %% test group 3 clear cfg; figure; -cfg.nphoton=1e8; -cfg.vol=uint8(ones(60,60,60)); -cfg.srcdir=[0 0 1]; -cfg.gpuid=1; -cfg.autopilot=1; -cfg.prop=[0 0 1 1;0.005 1 0.8 1.37]; -cfg.tstart=0; -cfg.seed=99999; +cfg.nphoton = 1e8; +cfg.vol = uint8(ones(60, 60, 60)); +cfg.srcdir = [0 0 1]; +cfg.gpuid = 1; +cfg.autopilot = 1; +cfg.prop = [0 0 1 1; 0.005 1 0.8 1.37]; +cfg.tstart = 0; +cfg.seed = 99999; % a uniform planar source outside the volume -cfg.srctype='fourierx'; -cfg.srcpos=[10 10 -1]; -cfg.srcparam1=[40 0 0 40]; -cfg.srcparam2=[2 1.5 0 0]; -cfg.tend=0.4e-10; -cfg.tstep=0.4e-10; -flux=mcxlab(cfg); -fcw=flux.data*cfg.tstep; +cfg.srctype = 'fourierx'; +cfg.srcpos = [10 10 -1]; +cfg.srcparam1 = [40 0 0 40]; +cfg.srcparam2 = [2 1.5 0 0]; +cfg.tend = 0.4e-10; +cfg.tstep = 0.4e-10; +flux = mcxlab(cfg); +fcw = flux.data * cfg.tstep; subplot(221); -imagesc(log10(abs(squeeze(fcw(:,:,1))))) -axis equal; colorbar +imagesc(log10(abs(squeeze(fcw(:, :, 1))))); +axis equal; +colorbar; title('a general Fourier source (2,1.5)'); % a uniform planar source outside the volume -cfg.srctype='slit'; -cfg.srcpos=[10 30 0]; -cfg.srcdir=[0 1 1]/sqrt(2); -cfg.srcparam1=[40 0 0 0]; -cfg.srcparam2=[0 0 0 0]; -cfg.prop=[0 0 1 1;0.005 0.1 0.9 1.37]; -cfg.tend=5e-9; -cfg.tstep=5e-9; -flux=mcxlab(cfg); -fcw=flux.data*cfg.tstep; +cfg.srctype = 'slit'; +cfg.srcpos = [10 30 0]; +cfg.srcdir = [0 1 1] / sqrt(2); +cfg.srcparam1 = [40 0 0 0]; +cfg.srcparam2 = [0 0 0 0]; +cfg.prop = [0 0 1 1; 0.005 0.1 0.9 1.37]; +cfg.tend = 5e-9; +cfg.tstep = 5e-9; +flux = mcxlab(cfg); +fcw = flux.data * cfg.tstep; subplot(222); -hs=slice(log10(abs(double(fcw))),[],[15 45],1); -set(hs,'linestyle','none'); -axis equal; colorbar +hs = slice(log10(abs(double(fcw))), [], [15 45], 1); +set(hs, 'linestyle', 'none'); +axis equal; +colorbar; title('a slit source'); -cfg.nphoton=1e7; -cfg.vol=uint8(ones(60,60,60)); -cfg.vol(25:35,25:35,25:35)=2; -cfg.prop=[0 0 1 1;0.005 0.01 0.8 1.37;0.01 1,0.8,1.37]; -cfg.srctype='pattern'; -cfg.srcpattern=mcximg(1:6,:); -cfg.srcpos=[-13 13 13]; -cfg.srcdir=[1 0 0]; -cfg.srcparam1=[0 30 0 size(cfg.srcpattern,1)]; -cfg.srcparam2=[0 0 30 size(cfg.srcpattern,2)]; -cfg.tend=0.3e-9; -cfg.tstep=0.1e-10; -cfg.voidtime=0; -flux=mcxlab(cfg); -fcw1=flux.data*cfg.tstep; - -cfg.srcpattern=rot90(mcximg(7:12,:),3); -cfg.srcpos=[17 17 60+1]; -cfg.srcdir=[0 0 -1]; -cfg.srcparam1=[30 0 0 size(cfg.srcpattern,1)]; -cfg.srcparam2=[0 30 0 size(cfg.srcpattern,2)]; -flux=mcxlab(cfg); -fcw2=flux.data*cfg.tstep; - -cfg.srcpattern=mcximg(13:end,:); -cfg.srcpos=[60-15 -1 60-15]; -cfg.srcdir=[0 1 0]; -cfg.srcparam1=[-30 0 0 size(cfg.srcpattern,1)]; -cfg.srcparam2=[0 0 -30 size(cfg.srcpattern,2)]; -flux=mcxlab(cfg); -fcw3=flux.data*cfg.tstep; +cfg.nphoton = 1e7; +cfg.vol = uint8(ones(60, 60, 60)); +cfg.vol(25:35, 25:35, 25:35) = 2; +cfg.prop = [0 0 1 1; 0.005 0.01 0.8 1.37; 0.01 1, 0.8, 1.37]; +cfg.srctype = 'pattern'; +cfg.srcpattern = mcximg(1:6, :); +cfg.srcpos = [-13 13 13]; +cfg.srcdir = [1 0 0]; +cfg.srcparam1 = [0 30 0 size(cfg.srcpattern, 1)]; +cfg.srcparam2 = [0 0 30 size(cfg.srcpattern, 2)]; +cfg.tend = 0.3e-9; +cfg.tstep = 0.1e-10; +cfg.voidtime = 0; +flux = mcxlab(cfg); +fcw1 = flux.data * cfg.tstep; + +cfg.srcpattern = rot90(mcximg(7:12, :), 3); +cfg.srcpos = [17 17 60 + 1]; +cfg.srcdir = [0 0 -1]; +cfg.srcparam1 = [30 0 0 size(cfg.srcpattern, 1)]; +cfg.srcparam2 = [0 30 0 size(cfg.srcpattern, 2)]; +flux = mcxlab(cfg); +fcw2 = flux.data * cfg.tstep; + +cfg.srcpattern = mcximg(13:end, :); +cfg.srcpos = [60 - 15 -1 60 - 15]; +cfg.srcdir = [0 1 0]; +cfg.srcparam1 = [-30 0 0 size(cfg.srcpattern, 1)]; +cfg.srcparam2 = [0 0 -30 size(cfg.srcpattern, 2)]; +flux = mcxlab(cfg); +fcw3 = flux.data * cfg.tstep; % fcw=fcw1+fcw2+fcw3; % @@ -258,181 +269,187 @@ % % movie(mcxframe,3,2); % imwrite(mcxframe,map,'mcx_dice.gif','DelayTime',0.5,'LoopCount',inf); -fcw=sum(fcw1+fcw2+fcw3,4); +fcw = sum(fcw1 + fcw2 + fcw3, 4); subplot(223); -hs=slice(log10(abs(double(fcw))),1,1,60); -set(hs,'linestyle','none'); -axis equal; colorbar +hs = slice(log10(abs(double(fcw))), 1, 1, 60); +set(hs, 'linestyle', 'none'); +axis equal; +colorbar; box on; title('an arbitrary pattern source from an angle'); +%% volumetric source +Rsrc = 20; +[xi, yi, zi] = ndgrid(-Rsrc:Rsrc, -Rsrc:Rsrc, -Rsrc:Rsrc); +sphsrc = ((xi .* xi + yi .* yi + zi .* zi) <= Rsrc * Rsrc); -%% volumetric source -Rsrc=20; -[xi,yi,zi]=ndgrid(-Rsrc:Rsrc,-Rsrc:Rsrc,-Rsrc:Rsrc); -sphsrc=((xi.*xi+yi.*yi+zi.*zi)<=Rsrc*Rsrc); - -dim=60; +dim = 60; % define source pattern clear cfg; % basic settings -cfg.nphoton=1e7; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-9; -cfg.respin=1; -cfg.seed=99999; -cfg.outputtype = 'energy'; %should get the energy deposits in each voxel - -cfg.srctype='pattern3d'; -cfg.srcpattern=sphsrc; -cfg.srcparam1=size(cfg.srcpattern); -cfg.srcpos=[10,10,20]; -cfg.srcdir=[0 0 1 nan]; -cfg.autopilot=1; +cfg.nphoton = 1e7; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-9; +cfg.respin = 1; +cfg.seed = 99999; +cfg.outputtype = 'energy'; % should get the energy deposits in each voxel + +cfg.srctype = 'pattern3d'; +cfg.srcpattern = sphsrc; +cfg.srcparam1 = size(cfg.srcpattern); +cfg.srcpos = [10, 10, 20]; +cfg.srcdir = [0 0 1 nan]; +cfg.autopilot = 1; % define volume and inclusions -cfg.vol=ones(dim,dim,dim); -%%you can use a JSON string to define cfg.shapes -cfg.shapes='{"Shapes":[{"Sphere":{"O":[25,21,10],"R":10,"Tag":2}}]}'; -cfg.prop=[0 0 1 1; % Boundary - 0.003 0.03 0.8 1; % Tissue mua = 0.003 mus = 0.03 n = 1.85/1.37 - 0.006 0.09 0.8 1; % Cancer mus = 1.09 n = 1.37 - 1.3 0.8 0.8 1]; % TAM mua = 0.003, n = 0.095 -cfg.unitinmm=1e-3; +cfg.vol = ones(dim, dim, dim); +%% you can use a JSON string to define cfg.shapes +cfg.shapes = '{"Shapes":[{"Sphere":{"O":[25,21,10],"R":10,"Tag":2}}]}'; +cfg.prop = [0 0 1 1 % Boundary + 0.003 0.03 0.8 1 % Tissue mua = 0.003 mus = 0.03 n = 1.85/1.37 + 0.006 0.09 0.8 1 % Cancer mus = 1.09 n = 1.37 + 1.3 0.8 0.8 1]; % TAM mua = 0.003, n = 0.095 +cfg.unitinmm = 1e-3; flux = mcxlab(cfg); subplot(224); -flux=sum(flux.data,4); -hs=slice(log10(double(flux)),20,40,4); -set(hs,'linestyle','none') -set(gca,'xlim',[0 dim],'ylim',[0 dim],'zlim',[0 dim]); +flux = sum(flux.data, 4); +hs = slice(log10(double(flux)), 20, 40, 4); +set(hs, 'linestyle', 'none'); +set(gca, 'xlim', [0 dim], 'ylim', [0 dim], 'zlim', [0 dim]); axis equal; %% test group 4 clear cfg; figure; -cfg.nphoton=1e7; -cfg.vol=uint8(ones(60,60,60)); -cfg.gpuid=1; -cfg.autopilot=1; -cfg.prop=[0 0 1 1;0.005 1 0.8 1.37]; -cfg.tstart=0; -cfg.seed=99999; +cfg.nphoton = 1e7; +cfg.vol = uint8(ones(60, 60, 60)); +cfg.gpuid = 1; +cfg.autopilot = 1; +cfg.prop = [0 0 1 1; 0.005 1 0.8 1.37]; +cfg.tstart = 0; +cfg.seed = 99999; % a cone beam -cfg.srctype='cone'; -cfg.srcpos=[30 30 -10]; -cfg.srcdir=[0 0 1]; -cfg.tend=5e-11; -cfg.tstep=5e-11; -cfg.srcparam1=[pi/6 0 0 0]; -cfg.srcparam2=[0 0 0 0]; -flux=mcxlab(cfg); -fcw=flux.data*cfg.tstep; +cfg.srctype = 'cone'; +cfg.srcpos = [30 30 -10]; +cfg.srcdir = [0 0 1]; +cfg.tend = 5e-11; +cfg.tstep = 5e-11; +cfg.srcparam1 = [pi / 6 0 0 0]; +cfg.srcparam2 = [0 0 0 0]; +flux = mcxlab(cfg); +fcw = flux.data * cfg.tstep; subplot(221); -imagesc(log10(abs(squeeze(fcw(:,:,1))))) -axis equal; colorbar +imagesc(log10(abs(squeeze(fcw(:, :, 1))))); +axis equal; +colorbar; title('a uniform cone beam (uniform solid-angle)'); % a beam with arcsine distribution profile -cfg.srctype='arcsine'; -flux=mcxlab(cfg); -fcw=flux.data*cfg.tstep; +cfg.srctype = 'arcsine'; +flux = mcxlab(cfg); +fcw = flux.data * cfg.tstep; subplot(222); -imagesc(log10(abs(squeeze(fcw(:,:,1))))) -axis equal; colorbar +imagesc(log10(abs(squeeze(fcw(:, :, 1))))); +axis equal; +colorbar; title('an arcsine-distribution beam'); % a uniform disk source -cfg.srctype='disk'; -cfg.srcparam1=[20 0 0 0]; -cfg.srcparam2=[0 0 0 0]; -flux=mcxlab(cfg); -fcw=flux.data*cfg.tstep; +cfg.srctype = 'disk'; +cfg.srcparam1 = [20 0 0 0]; +cfg.srcparam2 = [0 0 0 0]; +flux = mcxlab(cfg); +fcw = flux.data * cfg.tstep; subplot(223); -imagesc(log10(abs(squeeze(fcw(:,:,1))))) -axis equal; colorbar +imagesc(log10(abs(squeeze(fcw(:, :, 1))))); +axis equal; +colorbar; title('a uniform disk source'); % a gaussian beam source -cfg.srctype='gaussian'; -cfg.srcparam1=[10 0 0 0]; -cfg.srcparam2=[0 0 0 0]; -cfg.tend=5e-11; -cfg.tstep=5e-11; -flux=mcxlab(cfg); -fcw=flux.data*cfg.tstep; +cfg.srctype = 'gaussian'; +cfg.srcparam1 = [10 0 0 0]; +cfg.srcparam2 = [0 0 0 0]; +cfg.tend = 5e-11; +cfg.tstep = 5e-11; +flux = mcxlab(cfg); +fcw = flux.data * cfg.tstep; subplot(224); -imagesc(log10(abs(squeeze(fcw(:,:,1))))) -axis equal; colorbar +imagesc(log10(abs(squeeze(fcw(:, :, 1))))); +axis equal; +colorbar; title('a gaussian beam source'); - %% test group 5 clear cfg; figure; -cfg.nphoton=1e6; -cfg.vol=uint8(ones(60,60,60)); -cfg.gpuid=1; -cfg.autopilot=1; -cfg.prop=[0 0 1 1;0.005 1 0.8 1.37]; -cfg.tstart=0; -cfg.seed=99999; -cfg.tend=5e-11; -cfg.tstep=5e-11; +cfg.nphoton = 1e6; +cfg.vol = uint8(ones(60, 60, 60)); +cfg.gpuid = 1; +cfg.autopilot = 1; +cfg.prop = [0 0 1 1; 0.005 1 0.8 1.37]; +cfg.tstart = 0; +cfg.seed = 99999; +cfg.tend = 5e-11; +cfg.tstep = 5e-11; % a ring beam -cfg.srctype='ring'; -cfg.srcpos=[30 30 -10]; -cfg.srcdir=[0 0 1]; -cfg.srcparam1=[15 10 0 0]; -cfg.srcparam2=[0 0 0 0]; -flux=mcxlab(cfg); -fcw=flux.data*cfg.tstep; +cfg.srctype = 'ring'; +cfg.srcpos = [30 30 -10]; +cfg.srcdir = [0 0 1]; +cfg.srcparam1 = [15 10 0 0]; +cfg.srcparam2 = [0 0 0 0]; +flux = mcxlab(cfg); +fcw = flux.data * cfg.tstep; subplot(221); -imagesc(log10(abs(squeeze(fcw(:,:,1))))) -axis equal; colorbar +imagesc(log10(abs(squeeze(fcw(:, :, 1))))); +axis equal; +colorbar; title('a ring beam'); % a diverging ring sector beam -cfg.srctype='ring'; -cfg.srcpos=[30 30 -10]; -cfg.srcdir=[0 0 1 -20]; -cfg.srcparam1=[15 10 0 2*pi/3]; -cfg.srcparam2=[0 0 0 0]; -flux=mcxlab(cfg); -fcw=flux.data*cfg.tstep; +cfg.srctype = 'ring'; +cfg.srcpos = [30 30 -10]; +cfg.srcdir = [0 0 1 -20]; +cfg.srcparam1 = [15 10 0 2 * pi / 3]; +cfg.srcparam2 = [0 0 0 0]; +flux = mcxlab(cfg); +fcw = flux.data * cfg.tstep; subplot(222); -imagesc(log10(abs(squeeze(fcw(:,:,1))))) -axis equal; colorbar +imagesc(log10(abs(squeeze(fcw(:, :, 1))))); +axis equal; +colorbar; title('a ring-sector beam'); % a ring beam -cfg.srctype='pencilarray'; -cfg.srcpos=[10 10 0]; -cfg.srcdir=[0 0 1]; -cfg.srcparam1=[40 0 0 4]; -cfg.srcparam2=[0 40 0 5]; -flux=mcxlab(cfg); -fcw=flux.data*cfg.tstep; +cfg.srctype = 'pencilarray'; +cfg.srcpos = [10 10 0]; +cfg.srcdir = [0 0 1]; +cfg.srcparam1 = [40 0 0 4]; +cfg.srcparam2 = [0 40 0 5]; +flux = mcxlab(cfg); +fcw = flux.data * cfg.tstep; subplot(223); -imagesc(log10(abs(squeeze(fcw(:,:,1))))) -axis equal; colorbar +imagesc(log10(abs(squeeze(fcw(:, :, 1))))); +axis equal; +colorbar; title('a pencil beam array)'); %% test group 6 -%debug flag to retrieve/test build-in RNG -cfg.vol=uint8(ones(100,100,100)); -cfg.debuglevel='R'; -cfg.isnormalized=0; -flux=mcxlab(cfg); -rng=flux.data(:); -figure -hist(rng,1000); +% debug flag to retrieve/test build-in RNG +cfg.vol = uint8(ones(100, 100, 100)); +cfg.debuglevel = 'R'; +cfg.isnormalized = 0; +flux = mcxlab(cfg); +rng = flux.data(:); +figure; +hist(rng, 1000); title('raw RNG distribution'); -cfg=rmfield(cfg,'debuglevel'); +cfg = rmfield(cfg, 'debuglevel'); diff --git a/mcxlab/examples/demo_mcxyz_skinvessel.m b/mcxlab/examples/demo_mcxyz_skinvessel.m index e4d3b8d9..bc4ce2b4 100644 --- a/mcxlab/examples/demo_mcxyz_skinvessel.m +++ b/mcxlab/examples/demo_mcxyz_skinvessel.m @@ -7,64 +7,64 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % only clear cfg to avoid accidentally clearing other useful data -clear cfg flux +clear cfg flux; -%load mcxyz_skinvessel.mat +% load mcxyz_skinvessel.mat -cfg.vol=zeros(200,200,200); -cfg.shapes=['{"Shapes":[{"ZLayers":[[1,20,1],[21,32,4],[33,200,3]]},' ... - '{"Cylinder": {"Tag":2, "C0": [0,100.5,100.5], "C1": [200,100.5,100.5], "R": 20}}]}']; -cfg.unitinmm=0.005; -cfg.prop=[0.0000 0.0 1.0000 1 - 3.5640e-05 1.0000 1.0000 1.3700 - 23.0543 9.3985 0.9000 1.3700 - 0.0458 35.6541 0.9000 1.3700 - 1.6572 37.5940 0.9000 1.3700]; +cfg.vol = zeros(200, 200, 200); +cfg.shapes = ['{"Shapes":[{"ZLayers":[[1,20,1],[21,32,4],[33,200,3]]},' ... + '{"Cylinder": {"Tag":2, "C0": [0,100.5,100.5], "C1": [200,100.5,100.5], "R": 20}}]}']; +cfg.unitinmm = 0.005; +cfg.prop = [0.0000 0.0 1.0000 1 + 3.5640e-05 1.0000 1.0000 1.3700 + 23.0543 9.3985 0.9000 1.3700 + 0.0458 35.6541 0.9000 1.3700 + 1.6572 37.5940 0.9000 1.3700]; -cfg.nphoton=1e8; -cfg.issrcfrom0=1; -cfg.srcpos=[100 100 20]; -cfg.tstart=0; -cfg.tend=5e-8; -cfg.tstep=5e-8; -cfg.srcdir=[0 0 1]; -cfg.srctype='disk'; -cfg.srcparam1=[0.3/cfg.unitinmm 0 0 0]; -cfg.isreflect=0; -cfg.autopilot=1; -cfg.gpuid=1; -cfg.debuglevel='P'; +cfg.nphoton = 1e8; +cfg.issrcfrom0 = 1; +cfg.srcpos = [100 100 20]; +cfg.tstart = 0; +cfg.tend = 5e-8; +cfg.tstep = 5e-8; +cfg.srcdir = [0 0 1]; +cfg.srctype = 'disk'; +cfg.srcparam1 = [0.3 / cfg.unitinmm 0 0 0]; +cfg.isreflect = 0; +cfg.autopilot = 1; +cfg.gpuid = 1; +cfg.debuglevel = 'P'; -%cfg.outputtype='energy'; -cfg.outputtype='flux'; -flux=mcxlab(cfg); +% cfg.outputtype='energy'; +cfg.outputtype = 'flux'; +flux = mcxlab(cfg); % convert mcx solution to mcxyz's output % 'energy': mcx outputs normalized energy deposition, must convert % it to normalized energy density (1/cm^3) as in mcxyz -% 'flux': cfg.tstep is used in mcx's fluence normalization, must +% 'flux': cfg.tstep is used in mcx's fluence normalization, must % undo 100 converts 1/mm^2 from mcx output to 1/cm^2 as in mcxyz -if(strcmp(cfg.outputtype,'energy')) - mcxdata=flux.data/((cfg.unitinmm/10)^3); +if (strcmp(cfg.outputtype, 'energy')) + mcxdata = flux.data / ((cfg.unitinmm / 10)^3); else - mcxdata=flux.data*100; + mcxdata = flux.data * 100; end -if(strcmp(cfg.outputtype,'flux')) - mcxdata=mcxdata*cfg.tstep; +if (strcmp(cfg.outputtype, 'flux')) + mcxdata = mcxdata * cfg.tstep; end figure; -dim=size(cfg.vol); -yi=((1:dim(2))-floor(dim(2)/2))*cfg.unitinmm; -zi=(1:dim(3))*cfg.unitinmm; +dim = size(cfg.vol); +yi = ((1:dim(2)) - floor(dim(2) / 2)) * cfg.unitinmm; +zi = (1:dim(3)) * cfg.unitinmm; -imagesc(yi,zi,log10(abs(squeeze(mcxdata(100,:,:))))') +imagesc(yi, zi, log10(abs(squeeze(mcxdata(100, :, :))))'); axis equal; colormap(jet); -colorbar -if(strcmp(cfg.outputtype,'energy')) - set(gca,'clim',[-2.4429 4.7581]) +colorbar; +if (strcmp(cfg.outputtype, 'energy')) + set(gca, 'clim', [-2.4429 4.7581]); else - set(gca,'clim',[0.5 2.8]) + set(gca, 'clim', [0.5 2.8]); end diff --git a/mcxlab/examples/demo_multisrc.m b/mcxlab/examples/demo_multisrc.m index 6b4f4614..e4080e88 100644 --- a/mcxlab/examples/demo_multisrc.m +++ b/mcxlab/examples/demo_multisrc.m @@ -28,71 +28,71 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % only clear cfg to avoid accidentally clearing other useful data -clear cfg cfgs +clear cfg cfgs; -cfg.nphoton=1e7; -cfg.vol=uint8(ones(60,60,40)); -cfg.srctype='planar'; +cfg.nphoton = 1e7; +cfg.vol = uint8(ones(60, 60, 40)); +cfg.srctype = 'planar'; -Rs=20; -delta=pi/4; +Rs = 20; +delta = pi / 4; -ang=0:delta:(2*pi-delta); -rotmat2d=[cos(delta), -sin(delta); sin(delta), cos(delta)]; -offset2d=[30 30]; +ang = 0:delta:(2 * pi - delta); +rotmat2d = [cos(delta), -sin(delta); sin(delta), cos(delta)]; +offset2d = [30 30]; % first create an array of planar sources by rotating around origin % the 4th element of srcpos sets the initial weight -cfg.srcpos=repmat([Rs, 0, 0, 1], length(ang), 1); +cfg.srcpos = repmat([Rs, 0, 0, 1], length(ang), 1); % the 4th element of srcdir sets the focal length (positive: convergent) -cfg.srcdir=repmat([-0.5, 0, sqrt(3)/2, 20], length(ang), 1); -cfg.srcparam1=repmat([-8,3,0,0], length(ang), 1); -cfg.srcparam2=repmat([3,3,0,0], length(ang), 1); - -for i=2:length(ang) - cfg.srcpos(i,1:2)=(rotmat2d*cfg.srcpos(i-1,1:2)')'; - cfg.srcdir(i,1:2)=(rotmat2d*cfg.srcdir(i-1,1:2)')'; - cfg.srcparam1(i,1:2)=(rotmat2d*cfg.srcparam1(i-1,1:2)')'; - cfg.srcparam2(i,1:2)=(rotmat2d*cfg.srcparam2(i-1,1:2)')'; +cfg.srcdir = repmat([-0.5, 0, sqrt(3) / 2, 20], length(ang), 1); +cfg.srcparam1 = repmat([-8, 3, 0, 0], length(ang), 1); +cfg.srcparam2 = repmat([3, 3, 0, 0], length(ang), 1); + +for i = 2:length(ang) + cfg.srcpos(i, 1:2) = (rotmat2d * cfg.srcpos(i - 1, 1:2)')'; + cfg.srcdir(i, 1:2) = (rotmat2d * cfg.srcdir(i - 1, 1:2)')'; + cfg.srcparam1(i, 1:2) = (rotmat2d * cfg.srcparam1(i - 1, 1:2)')'; + cfg.srcparam2(i, 1:2) = (rotmat2d * cfg.srcparam2(i - 1, 1:2)')'; end % translate the circular array to the desired offset -cfg.srcpos(:,1)=cfg.srcpos(:,1)+offset2d(1); -cfg.srcpos(:,2)=cfg.srcpos(:,2)+offset2d(2); +cfg.srcpos(:, 1) = cfg.srcpos(:, 1) + offset2d(1); +cfg.srcpos(:, 2) = cfg.srcpos(:, 2) + offset2d(2); % manually add the 9th source to the center -cfg.srcpos(end+1, :)=[offset2d(1)-Rs/4,offset2d(2)-Rs/4,0,4]; % initial weight is 4 -cfg.srcdir(end+1, :)=[0, 0 1 0]; -cfg.srcparam1(end+1, :)=[Rs/2,0,0,0]; -cfg.srcparam2(end+1, :)=[0,Rs/2,0,0]; +cfg.srcpos(end + 1, :) = [offset2d(1) - Rs / 4, offset2d(2) - Rs / 4, 0, 4]; % initial weight is 4 +cfg.srcdir(end + 1, :) = [0, 0 1 0]; +cfg.srcparam1(end + 1, :) = [Rs / 2, 0, 0, 0]; +cfg.srcparam2(end + 1, :) = [0, Rs / 2, 0, 0]; -cfg.gpuid=1; +cfg.gpuid = 1; % cfg.gpuid='11'; % use two GPUs together -cfg.autopilot=1; -cfg.prop=[0 0 1 1;0.005 0.2 0 1.37]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-9; +cfg.autopilot = 1; +cfg.prop = [0 0 1 1; 0.005 0.2 0 1.37]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-9; -flux=mcxlab(cfg); +flux = mcxlab(cfg); mcxplotvol(log10(flux.data)); %% setting cfg.srcid to a positive number 1,2,3,.. specifies which src to simulate -cfg.srcid=8; +cfg.srcid = 8; -flux=mcxlab(cfg); +flux = mcxlab(cfg); mcxplotvol(log10(flux.data)); %% setting cfg.srcid to -1, solution of each src is stored separately -cfg.srcid=-1; +cfg.srcid = -1; -flux=mcxlab(cfg); +flux = mcxlab(cfg); % use up-down button to shift between different sources, there are 9 of % them diff --git a/mcxlab/examples/demo_photon_sharing.m b/mcxlab/examples/demo_photon_sharing.m index b7052060..97d775fd 100644 --- a/mcxlab/examples/demo_photon_sharing.m +++ b/mcxlab/examples/demo_photon_sharing.m @@ -1,76 +1,78 @@ % only clear cfg to avoid accidentally clearing other useful data clear cfg; -mcximg=[0 1 1 0 0 0 0 0 1 1 0 -0 0 0 1 1 0 1 1 0 0 0 -0 0 0 0 0 1 0 0 0 0 0 -0 0 0 1 1 0 1 1 0 0 0 -0 1 1 0 0 0 0 0 1 1 0 -0 0 0 0 0 0 0 0 0 0 0 -0 0 1 0 0 0 0 0 1 0 0 -0 1 0 0 0 0 0 0 0 1 0 -0 1 0 0 0 0 0 0 0 1 0 -0 1 0 0 0 0 0 0 0 1 0 -0 0 1 1 1 1 1 1 1 0 0 -0 0 0 0 0 0 0 0 0 0 0 -0 1 1 1 1 1 1 1 1 1 0 -0 0 0 1 0 0 0 0 0 0 0 -0 0 0 0 1 1 0 0 0 0 0 -0 0 0 1 0 0 0 0 0 0 0 -0 1 1 1 1 1 1 1 1 1 0 -0 0 0 0 0 0 0 0 0 0 0]; +mcximg = [0 1 1 0 0 0 0 0 1 1 0 + 0 0 0 1 1 0 1 1 0 0 0 + 0 0 0 0 0 1 0 0 0 0 0 + 0 0 0 1 1 0 1 1 0 0 0 + 0 1 1 0 0 0 0 0 1 1 0 + 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 1 0 0 + 0 1 0 0 0 0 0 0 0 1 0 + 0 1 0 0 0 0 0 0 0 1 0 + 0 1 0 0 0 0 0 0 0 1 0 + 0 0 1 1 1 1 1 1 1 0 0 + 0 0 0 0 0 0 0 0 0 0 0 + 0 1 1 1 1 1 1 1 1 1 0 + 0 0 0 1 0 0 0 0 0 0 0 + 0 0 0 0 1 1 0 0 0 0 0 + 0 0 0 1 0 0 0 0 0 0 0 + 0 1 1 1 1 1 1 1 1 1 0 + 0 0 0 0 0 0 0 0 0 0 0]; -cfg.nphoton=1e7; -cfg.vol=uint8(ones(60,60,60)); -cfg.vol(:,:,1)=0; -cfg.issaveref=1; -cfg.srctype='pattern'; -cfg.srcpattern=permute(reshape(mcximg,[6,3,size(mcximg,2)]),[2 1 3]); -cfg.srcnum=3; -cfg.srcpos=[0 0 0]; -cfg.issrcfrom0=1; -cfg.srcdir=[0 0 1]; -cfg.srcparam1=[60 0 0 size(cfg.srcpattern,2)]; -cfg.srcparam2=[0 60 0 size(cfg.srcpattern,3)]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-9; -cfg.voidtime=0; -cfg.gpuid=1; -cfg.autopilot=1; -cfg.prop=[0 0 1 1;0.005 1 0.8 1.37]; -cfg.seed=99999; +cfg.nphoton = 1e7; +cfg.vol = uint8(ones(60, 60, 60)); +cfg.vol(:, :, 1) = 0; +cfg.issaveref = 1; +cfg.srctype = 'pattern'; +cfg.srcpattern = permute(reshape(mcximg, [6, 3, size(mcximg, 2)]), [2 1 3]); +cfg.srcnum = 3; +cfg.srcpos = [0 0 0]; +cfg.issrcfrom0 = 1; +cfg.srcdir = [0 0 1]; +cfg.srcparam1 = [60 0 0 size(cfg.srcpattern, 2)]; +cfg.srcparam2 = [0 60 0 size(cfg.srcpattern, 3)]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-9; +cfg.voidtime = 0; +cfg.gpuid = 1; +cfg.autopilot = 1; +cfg.prop = [0 0 1 1; 0.005 1 0.8 1.37]; +cfg.seed = 99999; % when photon sharing is used, the detpt.w0 output of detected photon stores the % 1-D index of the pixel within a 2D pattern (col-major, starting from 0) % where the photon was initially launched. using detpt.w0, one can look up % the initial launch weight of each photon in all patterns -cfg.detpos=[25 30 0 2]; -cfg.savedetflag='dpw'; +cfg.detpos = [25 30 0 2]; +cfg.savedetflag = 'dpw'; -[flux, detpt]=mcxlab(cfg); +[flux, detpt] = mcxlab(cfg); -fcw=flux.data*cfg.tstep; -for i=1:3 - subplot(1,3,i); - hs=slice(log10(abs(double(fcw(:,:,:,i)))),1,1,2); - view([1 1 1]) - set(hs,'linestyle','none'); - axis equal; colorbar - title(sprintf('pattern #%d',i)); +fcw = flux.data * cfg.tstep; +for i = 1:3 + subplot(1, 3, i); + hs = slice(log10(abs(double(fcw(:, :, :, i)))), 1, 1, 2); + view([1 1 1]); + set(hs, 'linestyle', 'none'); + axis equal; + colorbar; + title(sprintf('pattern #%d', i)); end figure; -fcw=flux.dref*cfg.tstep; -for i=1:3 - subplot(1,3,i); - hs=slice(abs(double(fcw(:,:,:,i))),[],[],1); - view([1 1 1]) - set(hs,'linestyle','none'); - axis equal; colorbar - title(sprintf('pattern #%d',i)); +fcw = flux.dref * cfg.tstep; +for i = 1:3 + subplot(1, 3, i); + hs = slice(abs(double(fcw(:, :, :, i))), [], [], 1); + view([1 1 1]); + set(hs, 'linestyle', 'none'); + axis equal; + colorbar; + title(sprintf('pattern #%d', i)); end figure; -hist(double(detpt.w0)) +hist(double(detpt.w0)); xlabel('1D pixel index of the launch position'); diff --git a/mcxlab/examples/demo_polarized_photon.m b/mcxlab/examples/demo_polarized_photon.m index 908d3a84..1893c933 100644 --- a/mcxlab/examples/demo_polarized_photon.m +++ b/mcxlab/examples/demo_polarized_photon.m @@ -8,103 +8,103 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % only clear cfg to avoid accidentally clearing other useful data -clear cfg +clear cfg; %% simulation configurations % domain bounding box -dim=[100,100,12]; -cfg.vol=ones(dim); +dim = [100, 100, 12]; +cfg.vol = ones(dim); % add spherical inclusions -c=[60,60,6]; % center -r=5; % radius -[yi,xi,zi]=meshgrid(0.5:dim(1,1)-0.5, 0.5:dim(1,2)-0.5, 0.5:dim(1,3)-0.5); -dist_sq=(xi-c(1,1)).^2+(yi-c(1,2)).^2+(zi-c(1,3)).^2; -cfg.vol(dist_sq15) & za(:)>-10)=nan; -phi_ana((xa(:)<-12 | xa(:)>12) & za(:)>0)=nan; +[phi_ana, xa, ya, za] = sphdiffusionslab(0, 0, dim, -22:0.8:22, 0, -30:0.8:10, ana); +% save demo_sphbox.mat phi_ana xa ya za +% load demo_sphbox.mat +phi_ana((xa(:) < -15 | xa(:) > 15) & za(:) > -10) = nan; +phi_ana((xa(:) < -12 | xa(:) > 12) & za(:) > 0) = nan; %% plotting the results -figure +figure; subplot(121); -contourf(log10(squeeze(sum(f1.data(:,30,:,:),4))'),clines); +contourf(log10(squeeze(sum(f1.data(:, 30, :, :), 4))'), clines); hold on; -c=contourc(squeeze(double(cfg.vol(:,30,:))),1); -contour(xa+30.5,za+31,log10(abs(phi_ana/cfg.tstep)),clines,'color',[0.7 0.7 0.7],'linewidth',2); -plot(c(1,2:end),c(2,2:end),'b--') +c = contourc(squeeze(double(cfg.vol(:, 30, :))), 1); +contour(xa + 30.5, za + 31, log10(abs(phi_ana / cfg.tstep)), clines, 'color', [0.7 0.7 0.7], 'linewidth', 2); +plot(c(1, 2:end), c(2, 2:end), 'b--'); axis equal; colorbar('NorthOutside'); title('simulation with 1x1x1 mm resolution'); subplot(122); -[xx,yy]=meshgrid(0.5:0.5:dim/2,0.5:0.5:dim/2); -contourf(xx,yy,log10(squeeze(sum(f2.data(:,60,:,:),4))'),clines); +[xx, yy] = meshgrid(0.5:0.5:dim / 2, 0.5:0.5:dim / 2); +contourf(xx, yy, log10(squeeze(sum(f2.data(:, 60, :, :), 4))'), clines); hold on; -contour(xa+30,za+30.5,log10(abs(phi_ana/cfg2x.tstep)),clines,'color',[0.7 0.7 0.7],'linewidth',2); -c=contourc(squeeze(double(cfg2x.vol(:,60,:))),1); -plot(c(1,2:end)/2,c(2,2:end)/2,'b--') +contour(xa + 30, za + 30.5, log10(abs(phi_ana / cfg2x.tstep)), clines, 'color', [0.7 0.7 0.7], 'linewidth', 2); +c = contourc(squeeze(double(cfg2x.vol(:, 60, :))), 1); +plot(c(1, 2:end) / 2, c(2, 2:end) / 2, 'b--'); axis equal; colorbar('NorthOutside'); title('simulation with 0.5x0.5x0.5 mm resolution'); diff --git a/mcxlab/examples/demo_validation_homogeneous.m b/mcxlab/examples/demo_validation_homogeneous.m index 6343c60d..6057d2c9 100644 --- a/mcxlab/examples/demo_validation_homogeneous.m +++ b/mcxlab/examples/demo_validation_homogeneous.m @@ -1,20 +1,20 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % MCXLAB - Monte Carlo eXtreme for MATLAB/Octave by Qianqina Fang % -% In this example, we validate MCXLAB with a homogeneous medium in a +% In this example, we validate MCXLAB with a homogeneous medium in a % cubic domain. This is exactly the example shown in Fig.5 of Fang2009. % % You can also use the alternative optical properties that has a high g % value to observe the similarity between the two scattering/g configurations. % -% [Fang2009] Qianqian Fang and David A. Boas, "Monte Carlo simulation -% of photon migration in 3D turbid media accelerated by graphics processing +% [Fang2009] Qianqian Fang and David A. Boas, "Monte Carlo simulation +% of photon migration in 3D turbid media accelerated by graphics processing % units," Opt. Express 17, 20178-20190 (2009) % % This file is part of Monte Carlo eXtreme (MCX) URL:http://mcx.sf.net %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -if(exist('tddiffusion','file')~=2 || exist('cwdiffusion','file')~=2) +if (exist('tddiffusion', 'file') ~= 2 || exist('cwdiffusion', 'file') ~= 2) error(sprintf('Scripts "tddiffusion.m" and "cwdiffusion.m" were not found.\nThis demo requires you to add the "mcx/utils" directory first.')); end @@ -23,145 +23,145 @@ %% preparing the input data % set seed to make the simulation repeatible -cfg.seed=hex2dec('623F9A9E'); +cfg.seed = hex2dec('623F9A9E'); -cfg.nphoton=3e7; +cfg.nphoton = 3e7; % define a 1cm radius sphere within a 6x6x6 cm box -dim=60; -cfg.vol=ones(dim,dim,dim); -cfg.vol=uint8(cfg.vol); +dim = 60; +cfg.vol = ones(dim, dim, dim); +cfg.vol = uint8(cfg.vol); % define the source position -cfg.srcpos=[dim/2,dim/2,1]; -cfg.srcdir=[0 0 1]; +cfg.srcpos = [dim / 2, dim / 2, 1]; +cfg.srcdir = [0 0 1]; % define optical properties, format: [mua(1/mm) mus(1/mm) g n] -cfg.prop=[0 0 1 1 % medium 0: the environment - 0.005 1 0.01 1.0]; % medium 1: the cube +cfg.prop = [0 0 1 1 % medium 0: the environment + 0.005 1 0.01 1.0]; % medium 1: the cube % medium 1a: an alternative that has the same mus'=mus*(1-g) as medium 1. % use medium 1a can significantly reduce racing -%cfg.prop(2,:)=[0.005 10.1 0.9 1.0]; +% cfg.prop(2,:)=[0.005 10.1 0.9 1.0]; % time-domain simulation parameters -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=1e-10; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 1e-10; % GPU thread configuration -cfg.autopilot=1; -cfg.gpuid=1; +cfg.autopilot = 1; +cfg.gpuid = 1; -cfg.isreflect=0; % disable reflection at exterior boundary +cfg.isreflect = 0; % disable reflection at exterior boundary %% running simulation without boundary reflection fprintf('running simulation ... this takes about 6 seconds on a GTX 470\n'); tic; -f1=mcxlab(cfg); +f1 = mcxlab(cfg); toc; -f1=f1.data; +f1 = f1.data; %% running simulation with boundary reflection -cfg.prop(2,4)=1.37; -cfg.isreflect=1; % enable reflection at exterior boundary +cfg.prop(2, 4) = 1.37; +cfg.isreflect = 1; % enable reflection at exterior boundary fprintf('running simulation ... this takes about 11 seconds on a GTX 470\n'); tic; -f2=mcxlab(cfg); +f2 = mcxlab(cfg); toc; -f2=f2.data; +f2 = f2.data; %% plotting the results %% plotting TPSF at voxel [30 14 9] -figure +figure; subplot(221); hold on; -c0=299792458000; -detpos=[30 14 9]; % choose a point inside the domain +c0 = 299792458000; +detpos = [30 14 9]; % choose a point inside the domain -twin=cfg.tstart+cfg.tstep/2:cfg.tstep:cfg.tend; -semilogy(twin*1e9,tddiffusion(cfg.prop(2,1), cfg.prop(2,2)*(1-cfg.prop(2,3)), c0, 0, cfg.srcpos, detpos+1, twin),'r'); -semilogy(twin*1e9,squeeze(f1(detpos(1),detpos(2),detpos(3),:)),'o'); +twin = cfg.tstart + cfg.tstep / 2:cfg.tstep:cfg.tend; +semilogy(twin * 1e9, tddiffusion(cfg.prop(2, 1), cfg.prop(2, 2) * (1 - cfg.prop(2, 3)), c0, 0, cfg.srcpos, detpos + 1, twin), 'r'); +semilogy(twin * 1e9, squeeze(f1(detpos(1), detpos(2), detpos(3), :)), 'o'); -semilogy(twin*1e9,tddiffusion(cfg.prop(2,1), cfg.prop(2,2)*(1-cfg.prop(2,3)), c0/1.37, 0.493, cfg.srcpos, detpos, twin),'r--'); -semilogy(twin*1e9,squeeze(f2(detpos(1),detpos(2),detpos(3),:)),'+'); +semilogy(twin * 1e9, tddiffusion(cfg.prop(2, 1), cfg.prop(2, 2) * (1 - cfg.prop(2, 3)), c0 / 1.37, 0.493, cfg.srcpos, detpos, twin), 'r--'); +semilogy(twin * 1e9, squeeze(f2(detpos(1), detpos(2), detpos(3), :)), '+'); -set(gca,'ylim',[1 10^8.5]); +set(gca, 'ylim', [1 10^8.5]); -legend('Diffusion (no reflection)','MCX (no reflection)','Diffusion (with reflection)','MCX (with reflection)'); +legend('Diffusion (no reflection)', 'MCX (no reflection)', 'Diffusion (with reflection)', 'MCX (with reflection)'); legend boxoff; -set(gca,'yscale','log'); -xlabel('time (ns)') -ylabel('Fluence rate in 1/(mm^2 s)') +set(gca, 'yscale', 'log'); +xlabel('time (ns)'); +ylabel('Fluence rate in 1/(mm^2 s)'); box on; %% plotting spatial decay profile along line y=30 && z=0 subplot(222); hold on; -cwf1=sum(f1,4); -cwf2=sum(f2,4); +cwf1 = sum(f1, 4); +cwf2 = sum(f2, 4); -srcpos=[0 0 0]; -detpos=[0.5+(0:29)', 0.5*ones(30,1),0.5*ones(30,1)]; +srcpos = [0 0 0]; +detpos = [0.5 + (0:29)', 0.5 * ones(30, 1), 0.5 * ones(30, 1)]; -phicw=cwdiffusion(cfg.prop(2,1), cfg.prop(2,2)*(1-cfg.prop(2,3)), 0, srcpos, detpos); -phimcx=cwf1(30,:,1); -phicwb=cwdiffusion(cfg.prop(2,1), cfg.prop(2,2)*(1-cfg.prop(2,3)), 0.493, srcpos, detpos); -phimcxb=cwf2(30,:,1); +phicw = cwdiffusion(cfg.prop(2, 1), cfg.prop(2, 2) * (1 - cfg.prop(2, 3)), 0, srcpos, detpos); +phimcx = cwf1(30, :, 1); +phicwb = cwdiffusion(cfg.prop(2, 1), cfg.prop(2, 2) * (1 - cfg.prop(2, 3)), 0.493, srcpos, detpos); +phimcxb = cwf2(30, :, 1); -h=semilogy(1:30, phicw, 'r-', 1:30, phimcx(30:59)*cfg.tstep, 'o', 1:30, ... - phicwb, 'r--', 1:30, phimcxb(30:59)*cfg.tstep, 'b+'); +h = semilogy(1:30, phicw, 'r-', 1:30, phimcx(30:59) * cfg.tstep, 'o', 1:30, ... + phicwb, 'r--', 1:30, phimcxb(30:59) * cfg.tstep, 'b+'); box on; -set(gca,'yscale','log') +set(gca, 'yscale', 'log'); -legend('Diffusion (no reflection)','MCX (no reflection)','Diffusion (with reflection)','MCX(with reflection)'); +legend('Diffusion (no reflection)', 'MCX (no reflection)', 'Diffusion (with reflection)', 'MCX(with reflection)'); legend boxoff; -xlabel('x (mm)') -ylabel('Fluence rate in 1/(mm^2 s)') +xlabel('x (mm)'); +ylabel('Fluence rate in 1/(mm^2 s)'); %% plotting the cross-cut view along y=30 subplot(223); hold on; clines = -1.5:-0.5:-4; -srcpos=cfg.srcpos-0.5; -[xi,yi]=meshgrid(0.5:59.5,0.5:59.5); -detpos=[xi(:) 30*ones(size(xi(:))) yi(:)]; -phicw=reshape(cwdiffusion(cfg.prop(2,1), cfg.prop(2,2)*(1-cfg.prop(2,3)), 0, srcpos, detpos),size(xi)); - -[c h2]=contour(xi,yi, log10(max(squeeze(phicw),1e-8)), clines, 'k-' ); -[c h1]=contour(log10(max(squeeze(cwf1(:,30,:)*cfg.tstep)',1e-8)), clines, 'k:' ); -legend('Diffusion','MCX') +srcpos = cfg.srcpos - 0.5; +[xi, yi] = meshgrid(0.5:59.5, 0.5:59.5); +detpos = [xi(:) 30 * ones(size(xi(:))) yi(:)]; +phicw = reshape(cwdiffusion(cfg.prop(2, 1), cfg.prop(2, 2) * (1 - cfg.prop(2, 3)), 0, srcpos, detpos), size(xi)); + +[c h2] = contour(xi, yi, log10(max(squeeze(phicw), 1e-8)), clines, 'k-'); +[c h1] = contour(log10(max(squeeze(cwf1(:, 30, :) * cfg.tstep)', 1e-8)), clines, 'k:'); +legend('Diffusion', 'MCX'); legend boxoff; box on; -xlabel('x (mm)') -ylabel('z (mm)') +xlabel('x (mm)'); +ylabel('z (mm)'); %% plotting the temporal evolution at the cross-cut along y=30 subplot(224); hold on; -twin=5e-11:1e-10:5e-9; -Reff=0; +twin = 5e-11:1e-10:5e-9; +Reff = 0; -srcpos=[29.5 29.5 0]; -[xi,yi]=meshgrid(0.5:59.5,0.5:59.5); +srcpos = [29.5 29.5 0]; +[xi, yi] = meshgrid(0.5:59.5, 0.5:59.5); -detpos=[xi(:) 29.5*ones(size(xi(:))) yi(:)]; -for i=1:length(twin) - phitd(:,:,i)=reshape(tddiffusion(cfg.prop(2,1), cfg.prop(2,2)*(1-cfg.prop(2,3)),c0,Reff,srcpos,detpos,twin(i)),size(xi)); +detpos = [xi(:) 29.5 * ones(size(xi(:))) yi(:)]; +for i = 1:length(twin) + phitd(:, :, i) = reshape(tddiffusion(cfg.prop(2, 1), cfg.prop(2, 2) * (1 - cfg.prop(2, 3)), c0, Reff, srcpos, detpos, twin(i)), size(xi)); end -for i=1:5:21 - halfmax=max(max(phitd(:,:,i)))/2; - [c h2]=contour(xi, yi,max(squeeze(phitd(:,:,i)),1e-12),[halfmax halfmax], 'k-'); - halfmax=max(max(f1(:,30,:,i)))/2; - [c h2]=contour(max(squeeze(f1(:,30,:,i))',1e-12),[halfmax halfmax], 'k:'); +for i = 1:5:21 + halfmax = max(max(phitd(:, :, i))) / 2; + [c h2] = contour(xi, yi, max(squeeze(phitd(:, :, i)), 1e-12), [halfmax halfmax], 'k-'); + halfmax = max(max(f1(:, 30, :, i))) / 2; + [c h2] = contour(max(squeeze(f1(:, 30, :, i))', 1e-12), [halfmax halfmax], 'k:'); end -legend('Diffusion','MCX') +legend('Diffusion', 'MCX'); legend boxoff; box on; -xlabel('x (mm)') -ylabel('z (mm)') +xlabel('x (mm)'); +ylabel('z (mm)'); diff --git a/mcxlab/examples/mcx_gpu_benchmarks.m b/mcxlab/examples/mcx_gpu_benchmarks.m index 71a41be2..dfbb8b13 100644 --- a/mcxlab/examples/mcx_gpu_benchmarks.m +++ b/mcxlab/examples/mcx_gpu_benchmarks.m @@ -7,128 +7,128 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % only clear cfg to avoid accidentally clearing other useful data -clear cfg +clear cfg; -gpuinfo=mcxlab('gpuinfo'); +gpuinfo = mcxlab('gpuinfo'); -cfg.gpuid=1; % gpuid can be an integer 1-N to specify the n-th GPU - % or it can be a string containing only '0's and '1's. - % exp: if gpuid='1010', it means the 1st and 3rd GPU are both used. +cfg.gpuid = 1; % gpuid can be an integer 1-N to specify the n-th GPU +% or it can be a string containing only '0's and '1's. +% exp: if gpuid='1010', it means the 1st and 3rd GPU are both used. -%cfg.gpuid='111'; % on wazu, GPU#1,2,3 are 980Ti, 590 Core1 and Core 2 -%cfg.workload=[90,10,10]; % workload distribution between the 3 GPUs +% cfg.gpuid='111'; % on wazu, GPU#1,2,3 are 980Ti, 590 Core1 and Core 2 +% cfg.workload=[90,10,10]; % workload distribution between the 3 GPUs -gpuid=cfg.gpuid; +gpuid = cfg.gpuid; -if(ischar(gpuid) && regexp(gpuid,'^[01]+$')) - gpuid=char(gpuid)-'0'; - lastdev=find(gpuid,1,'last'); - if(lastdev>length(gpuinfo)) +if (ischar(gpuid) && regexp(gpuid, '^[01]+$')) + gpuid = char(gpuid) - '0'; + lastdev = find(gpuid, 1, 'last'); + if (lastdev > length(gpuinfo)) error('you specified a non-existant GPU'); end - gpuid=gpuid(1:lastdev); -elseif(isnumeric(gpuid) && gpuid>0) - gpuid=[zeros(1,gpuid-1) 1]; + gpuid = gpuid(1:lastdev); +elseif (isnumeric(gpuid) && gpuid > 0) + gpuid = [zeros(1, gpuid - 1) 1]; else error('the specified GPU id is invalid'); end -dates=datestr(now,'yyyy-mm-dd HH:MM:SS'); -mcxbenchmark=struct('date',dates,'gpu',gpuinfo(gpuid==1)); +dates = datestr(now, 'yyyy-mm-dd HH:MM:SS'); +mcxbenchmark = struct('date', dates, 'gpu', gpuinfo(gpuid == 1)); try - hbar=waitbar(0,'Running benchmarks #1'); + hbar = waitbar(0, 'Running benchmarks #1'); catch - hbar=[]; + hbar = []; end -count=0; - -cfg.nphoton=1e8; -cfg.vol=uint8(ones(60,60,60)); -cfg.srcpos=[29 29 0]; -cfg.srcdir=[0 0 1]; -cfg.issrcfrom0=1; -cfg.autopilot=1; -cfg.prop=[0 0 1 1;0.005 1 0.01 1.37;0.002 5.0 0.9, 1.0]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-9; -cfg.seed=29012392; -cfg.detpos=[29 19 0 1;29 39 0 1;19 29 0 1;39 29 0 1]; -cfg.isreflect=0; +count = 0; + +cfg.nphoton = 1e8; +cfg.vol = uint8(ones(60, 60, 60)); +cfg.srcpos = [29 29 0]; +cfg.srcdir = [0 0 1]; +cfg.issrcfrom0 = 1; +cfg.autopilot = 1; +cfg.prop = [0 0 1 1; 0.005 1 0.01 1.37; 0.002 5.0 0.9, 1.0]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-9; +cfg.seed = 29012392; +cfg.detpos = [29 19 0 1; 29 39 0 1; 19 29 0 1; 39 29 0 1]; +cfg.isreflect = 0; % calculate the flux distribution with the given config -speed=zeros(3); +speed = zeros(3); -for i=1:size(speed,1) - [flux, detps]=mcxlab(cfg); - if(abs(flux.stat.energyabs/flux.stat.energytot-0.1769)>0.005 || ... - abs(flux.stat.energytot-flux.stat.nphoton)>10) - flux.stat +for i = 1:size(speed, 1) + [flux, detps] = mcxlab(cfg); + if (abs(flux.stat.energyabs / flux.stat.energytot - 0.1769) > 0.005 || ... + abs(flux.stat.energytot - flux.stat.nphoton) > 10) + flux.stat; error('output absorption fraction is incorrect'); end - count=count+1; - if(~isempty(hbar)) - waitbar(count/9,hbar,'Running benchmarks #1'); + count = count + 1; + if (~isempty(hbar)) + waitbar(count / 9, hbar, 'Running benchmarks #1'); end - speed(i,1)=flux.stat.nphoton/flux.stat.runtime; + speed(i, 1) = flux.stat.nphoton / flux.stat.runtime; end -mcxbenchmark.benchmark1.stat=flux.stat; +mcxbenchmark.benchmark1.stat = flux.stat; -if(~isempty(hbar)) - waitbar(count/9,hbar,'Running benchmarks #2'); +if (~isempty(hbar)) + waitbar(count / 9, hbar, 'Running benchmarks #2'); end -cfg.shapes='{"Shapes":[{"Sphere":{"Tag":2, "O":[30,30,30],"R":15}}]}'; -cfg.isreflect=1; +cfg.shapes = '{"Shapes":[{"Sphere":{"Tag":2, "O":[30,30,30],"R":15}}]}'; +cfg.isreflect = 1; -for i=1:size(speed,1) - [flux, detps]=mcxlab(cfg); - if(abs(flux.stat.energyabs/flux.stat.energytot-0.2701)>0.005|| ... - abs(flux.stat.energytot-flux.stat.nphoton)>10) - flux.stat +for i = 1:size(speed, 1) + [flux, detps] = mcxlab(cfg); + if (abs(flux.stat.energyabs / flux.stat.energytot - 0.2701) > 0.005 || ... + abs(flux.stat.energytot - flux.stat.nphoton) > 10) + flux.stat; error('output absorption fraction is incorrect'); end - count=count+1; - if(~isempty(hbar)) - waitbar(count/9,hbar,'Running benchmarks #2'); + count = count + 1; + if (~isempty(hbar)) + waitbar(count / 9, hbar, 'Running benchmarks #2'); end - speed(i,2)=flux.stat.nphoton/flux.stat.runtime; + speed(i, 2) = flux.stat.nphoton / flux.stat.runtime; end -mcxbenchmark.benchmark2.stat=flux.stat; +mcxbenchmark.benchmark2.stat = flux.stat; -if(~isempty(hbar)) - waitbar(count/9,hbar,'Running benchmarks #3'); +if (~isempty(hbar)) + waitbar(count / 9, hbar, 'Running benchmarks #3'); end -cfg=rmfield(cfg,'shapes'); -cfg.srctype='planar'; -cfg.srcparam1=[40 0 0 0]; -cfg.srcparam2=[0 40 0 0]; -cfg.srcpos=[10 10 -10]; +cfg = rmfield(cfg, 'shapes'); +cfg.srctype = 'planar'; +cfg.srcparam1 = [40 0 0 0]; +cfg.srcparam2 = [0 40 0 0]; +cfg.srcpos = [10 10 -10]; -for i=1:size(speed,1) - [flux, detps]=mcxlab(cfg); - if(abs(flux.stat.energyabs/flux.stat.energytot-0.2551)>0.005) - flux.stat +for i = 1:size(speed, 1) + [flux, detps] = mcxlab(cfg); + if (abs(flux.stat.energyabs / flux.stat.energytot - 0.2551) > 0.005) + flux.stat; error('output absorption fraction is incorrect'); end - count=count+1; - if(~isempty(hbar)) - waitbar(count/9,hbar,'Running benchmarks #3'); + count = count + 1; + if (~isempty(hbar)) + waitbar(count / 9, hbar, 'Running benchmarks #3'); end - speed(i,3)=flux.stat.nphoton/flux.stat.runtime; + speed(i, 3) = flux.stat.nphoton / flux.stat.runtime; end -mcxbenchmark.benchmark3.stat=flux.stat; +mcxbenchmark.benchmark3.stat = flux.stat; -speed=mean(speed); +speed = mean(speed); -for i=1:length(speed) - mcxbenchmark.(sprintf('benchmark%d',i)).speed=speed(i); +for i = 1:length(speed) + mcxbenchmark.(sprintf('benchmark%d', i)).speed = speed(i); end -mcxbenchmark.speedsum=sum(speed); +mcxbenchmark.speedsum = sum(speed); -if(~isempty(hbar)) +if (~isempty(hbar)) delete(hbar); end diff --git a/mcxlab/examples/mcx_gpu_contest.m b/mcxlab/examples/mcx_gpu_contest.m index 137c9275..e1c37e06 100644 --- a/mcxlab/examples/mcx_gpu_contest.m +++ b/mcxlab/examples/mcx_gpu_contest.m @@ -8,39 +8,39 @@ %% ask user's basic information -if(exist('savejson','file')~=2) +if (exist('savejson', 'file') ~= 2) error('this example requires savejson.m. please download it from https://github.com/fangq/jsonlab'); end prompt = {sprintf(['Please answer all below questions. Your public name can be your ' ... - 'name or Internet name. Please also give your computer a name to ' ... - 'distinguish your submission from different machines.\n\n' ... - 'Your full name: (will not publish)']),'Email: (will not publish)',... - 'Your public name:','Institution:','Machine name:','Comment: (optional)'}; + 'name or Internet name. Please also give your computer a name to ' ... + 'distinguish your submission from different machines.\n\n' ... + 'Your full name: (will not publish)']), 'Email: (will not publish)', ... + 'Your public name:', 'Institution:', 'Machine name:', 'Comment: (optional)'}; dlg_title = 'MCX GPU Contest Submission'; num_lines = 1; -defaultans = {'','','','','',''}; +defaultans = {'', '', '', '', '', ''}; -if(exist('contest_info.mat','file')) +if (exist('contest_info.mat', 'file')) load contest_info.mat; end -mcxuser = inputdlg(prompt,dlg_title,num_lines,defaultans); +mcxuser = inputdlg(prompt, dlg_title, num_lines, defaultans); -if(isempty(mcxuser)) - return; +if (isempty(mcxuser)) + return end -while(isempty(mcxuser{1}) || isempty(mcxuser{2}) || isempty(mcxuser{3}) || isempty(mcxuser{4}) || isempty(mcxuser{5})) - hw=errordlg('missing required information'); +while (isempty(mcxuser{1}) || isempty(mcxuser{2}) || isempty(mcxuser{3}) || isempty(mcxuser{4}) || isempty(mcxuser{5})) + hw = errordlg('missing required information'); uiwait(hw); - mcxuser = inputdlg(prompt,dlg_title,num_lines,mcxuser); - if(isempty(mcxuser)) + mcxuser = inputdlg(prompt, dlg_title, num_lines, mcxuser); + if (isempty(mcxuser)) error('user aborted submission.'); end end -defaultans=mcxuser; +defaultans = mcxuser; try save contest_info.mat defaultans; % save the filled data to be load in the future to save time catch @@ -48,45 +48,45 @@ %% run the built-in benchmarks -choice = questdlg('Do you want to run the speed benchmarks? this may take a few minutes','Start Test','Yes','No','Yes'); -if(isempty(choice) || strcmp(choice,'No')) - return; +choice = questdlg('Do you want to run the speed benchmarks? this may take a few minutes', 'Start Test', 'Yes', 'No', 'Yes'); +if (isempty(choice) || strcmp(choice, 'No')) + return end -mcx_gpu_benchmarks +mcx_gpu_benchmarks; %% generate benchmark report -mcxbenchmark.version=1; -mcxbenchmark.mcxversion='$Date:: $'; -mcxbenchmark.userinfo=struct('name',mcxuser{1},'email',mcxuser{2},'nickname',mcxuser{3},... - 'institution',mcxuser{4},'machine',mcxuser{5},'comment',mcxuser{6}); +mcxbenchmark.version = 1; +mcxbenchmark.mcxversion = '$Date:: $'; +mcxbenchmark.userinfo = struct('name', mcxuser{1}, 'email', mcxuser{2}, 'nickname', mcxuser{3}, ... + 'institution', mcxuser{4}, 'machine', mcxuser{5}, 'comment', mcxuser{6}); -savejson(mcxbenchmark) +savejson(mcxbenchmark); -choice = questdlg(sprintf('Your benchmark score is %.0f. Press Yes to submit; No to cancel',mcxbenchmark.speedsum),... - 'Submission Confirmation','Yes','No','Yes'); -if(isempty(choice) || strcmp(choice,'No')) - return; +choice = questdlg(sprintf('Your benchmark score is %.0f. Press Yes to submit; No to cancel', mcxbenchmark.speedsum), ... + 'Submission Confirmation', 'Yes', 'No', 'Yes'); +if (isempty(choice) || strcmp(choice, 'No')) + return end %% submit the benchmark report to the web portal -gpustr=sprintf('%s/' ,mcxbenchmark.gpu(:).name); -gpustr=regexprep(gpustr,'GeForce\s*',''); -machinestr=sprintf('%s:/%s',mcxbenchmark.userinfo.machine,gpustr); +gpustr = sprintf('%s/', mcxbenchmark.gpu(:).name); +gpustr = regexprep(gpustr, 'GeForce\s*', ''); +machinestr = sprintf('%s:/%s', mcxbenchmark.userinfo.machine, gpustr); -submitstr={'name',urlencode(mcxbenchmark.userinfo.nickname), 'time',sprintf('%ld',round(8.64e4 * (now - datenum('1970', 'yyyy')))),... - 'ver',urlencode(mcxbenchmark.mcxversion(8:end-1)), 'b1', sprintf('%.2f',speed(1)), 'b2', sprintf('%.2f',speed(2)), ... - 'b3', sprintf('%.2f',speed(3)), 'score', sprintf('%.2f',mcxbenchmark.speedsum), ... - 'computer',urlencode(machinestr), 'report',urlencode(savejson(mcxbenchmark))}; +submitstr = {'name', urlencode(mcxbenchmark.userinfo.nickname), 'time', sprintf('%ld', round(8.64e4 * (now - datenum('1970', 'yyyy')))), ... + 'ver', urlencode(mcxbenchmark.mcxversion(8:end - 1)), 'b1', sprintf('%.2f', speed(1)), 'b2', sprintf('%.2f', speed(2)), ... + 'b3', sprintf('%.2f', speed(3)), 'score', sprintf('%.2f', mcxbenchmark.speedsum), ... + 'computer', urlencode(machinestr), 'report', urlencode(savejson(mcxbenchmark))}; -[s, status]=urlread('http://mcx.space/gpubench/gpucontest.cgi','post',submitstr); +[s, status] = urlread('http://mcx.space/gpubench/gpucontest.cgi', 'post', submitstr); pause(2); -if(isempty(s)) +if (isempty(s)) error('submission failed'); -elseif(strcmp(s,sprintf('SUCCESS\n'))) - hs=msgbox({'Submission is successful.','Please browse http://mcx.space/gpubench/ to see results.'},'Success','modal'); +elseif (strcmp(s, sprintf('SUCCESS\n'))) + hs = msgbox({'Submission is successful.', 'Please browse http://mcx.space/gpubench/ to see results.'}, 'Success', 'modal'); uiwait(hs); end diff --git a/mcxlab/mcxlab.m b/mcxlab/mcxlab.m index cf62e76c..20f3b5aa 100644 --- a/mcxlab/mcxlab.m +++ b/mcxlab/mcxlab.m @@ -1,11 +1,11 @@ -function varargout=mcxlab(varargin) +function varargout = mcxlab(varargin) % -%==================================================================== +% ==================================================================== % MCXLAB - Monte Carlo eXtreme (MCX) for MATLAB/GNU Octave -%-------------------------------------------------------------------- -%Copyright (c) 2011-2023 Qianqian Fang -% URL: http://mcx.space -%==================================================================== +% -------------------------------------------------------------------- +% Copyright (c) 2011-2024 Qianqian Fang +% URL: https://mcx.space +% ==================================================================== % % Format: % fluence=mcxlab(cfg); @@ -14,8 +14,8 @@ % [fluence,detphoton,vol,seed,trajectory]=mcxlab(cfg, option); % % Input: -% cfg: a struct, or struct array. Each element of cfg defines -% the parameters associated with a simulation. +% cfg: a struct, or struct array. Each element of cfg defines +% the parameters associated with a simulation. % if cfg='gpuinfo': return the supported GPUs and their parameters, % if cfg='version': return the version of MCXLAB as a string, % see sample script at the bottom @@ -32,7 +32,7 @@ % % cfg may contain the following fields: % -%== Required == +% == Required == % *cfg.nphoton: the total number of photons to be simulated (integer) % maximum supported value is 2^63-1 % *cfg.vol: a 3D array specifying the media index in the domain. @@ -65,7 +65,7 @@ % *cfg.tstart: starting time of the simulation (in seconds) % *cfg.tstep: time-gate width of the simulation (in seconds) % *cfg.tend: ending time of the simulation (in second) -% *cfg.srcpos: a 1 by 3 vector, the position of the source in grid unit; if a non-zero +% *cfg.srcpos: a 1 by 3 vector, the position of the source in grid unit; if a non-zero % 4th element is given, it specifies the initial weight of each photon packet % (or a multiplier in the cases of pattern/pattern3d sources); this initial weight % can be negative - the output fluence is expected to be linearly proportional @@ -83,9 +83,9 @@ % srcpos/srcdir support 3 or 4 columns, and srcparam1/srcparam2 support 4 columns. % If any of the 4 compnents present, they should have matching row number. % -%== MC simulation settings == +% == MC simulation settings == % cfg.seed: seed for the random number generator (integer) [0] -% if set to a uint8 array, the binary data in each column is used +% if set to a uint8 array, the binary data in each column is used % to seed a photon (i.e. the "replay" mode) % Example: % cfg.respin: repeat simulation for the given time (integer) [1] @@ -93,7 +93,7 @@ % cfg.isreflect: [1]-consider refractive index mismatch, 0-matched index % cfg.bc per-face boundary condition (BC), a strig of 6 letters (case insensitive) for % bounding box faces at -x,-y,-z,+x,+y,+z axes; -% overwrite cfg.isreflect if given. +% overwrite cfg.isreflect if given. % each letter can be one of the following: % '_': undefined, fallback to cfg.isreflect % 'r': like cfg.isreflect=1, Fresnel reflection BC @@ -103,7 +103,7 @@ % % in addition, cfg.bc can contain up to 12 characters, % with the 7-12 characters indicating bounding box -% facets -x,-y,-z,+x,+y,+z are used as a detector. The +% facets -x,-y,-z,+x,+y,+z are used as a detector. The % acceptable characters for digits 7-12 include % '0': this face is not used to detector photons % '1': this face is used to capture photons (if output detphoton) @@ -148,7 +148,7 @@ % cfg.gscatter: after a photon completes the specified number of % scattering events, mcx then ignores anisotropy g % and only performs isotropic scattering for speed [1e9] -% cfg.detphotons: detected photon data for replay. In the replay mode (cfg.seed +% cfg.detphotons: detected photon data for replay. In the replay mode (cfg.seed % is set as the 4th output of the baseline simulation), cfg.detphotons % should be set to the 2nd output (detphoton) of the baseline simulation % or detphoton.data subfield (as a 2D array). cfg.detphotons can use @@ -164,7 +164,7 @@ % mus prop(i,2); 2) if prop(i,3) < 1, polprop(i,3) will be % adjusted to achieve the target mus' prop(i,2)*(1-prop(i,3)) % -%== GPU settings == +% == GPU settings == % cfg.autopilot: 1-automatically set threads and blocks, [0]-use nthread/nblocksize % cfg.nblocksize: how many CUDA thread blocks to be used [64] % cfg.nthread: the total CUDA thread number [2048] @@ -174,14 +174,14 @@ % of 1s and 0s, it enables multiple GPUs. For example, '1101' % allows to use the 1st, 2nd and 4th GPUs together. % Example: -% cfg.workload an array denoting the relative loads of each selected GPU. +% cfg.workload an array denoting the relative loads of each selected GPU. % for example, [50,20,30] allocates 50%, 20% and 30% photons to the -% 3 selected GPUs, respectively; [10,10] evenly divides the load -% between 2 active GPUs. A simple load balancing strategy is to +% 3 selected GPUs, respectively; [10,10] evenly divides the load +% between 2 active GPUs. A simple load balancing strategy is to % use the GPU core counts as the weight. % cfg.isgpuinfo: 1-print GPU info, [0]-do not print % -%== Source-detector parameters == +% == Source-detector parameters == % cfg.detpos: an N by 4 array, each row specifying a detector: [x,y,z,radius] % cfg.maxdetphoton: maximum number of photons saved by the detectors [1000000] % cfg.srctype: source type, the parameters of the src are specified by cfg.srcparam{1,2} @@ -193,16 +193,16 @@ % 'hyperboloid' [*] - a one-sheeted hyperboloid gaussian beam, srcparam1(1) specifies the waist % radius (in voxels), srcparam1(2) specifies distance between launch plane and focus, % srcparam1(3) specifies rayleigh range -% 'planar' [*] - a 3D quadrilateral uniform planar source, with three corners specified +% 'planar' [*] - a 3D quadrilateral uniform planar source, with three corners specified % by srcpos, srcpos+srcparam1(1:3) and srcpos+srcparam2(1:3) % 'pattern' [*] - a 3D quadrilateral pattern illumination, same as above, except % srcparam1(4) and srcparam2(4) specify the pattern array x/y dimensions, -% and srcpattern is a floating-point pattern array, with values between [0-1]. -% if cfg.srcnum>1, srcpattern must be a floating-point array with +% and srcpattern is a floating-point pattern array, with values between [0-1]. +% if cfg.srcnum>1, srcpattern must be a floating-point array with % a dimension of [srcnum srcparam1(4) srcparam2(4)] % Example: % 'pattern3d' [*] - a 3D illumination pattern. srcparam1{x,y,z} defines the dimensions, -% and srcpattern is a floating-point pattern array, with values between [0-1]. +% and srcpattern is a floating-point pattern array, with values between [0-1]. % 'fourier' [*] - spatial frequency domain source, similar to 'planar', except % the integer parts of srcparam1(4) and srcparam2(4) represent % the x/y frequencies; the fraction part of srcparam1(4) multiplies @@ -211,7 +211,7 @@ % S=0.5*[1+M*cos(2*pi*(fx*x+fy*y)+phi0)], (0<=x,y,M<=1) % 'arcsine' - similar to isotropic, except the zenith angle is uniform % distribution, rather than a sine distribution. -% 'disk' [*] - a uniform disk source pointing along srcdir; the radius is +% 'disk' [*] - a uniform disk source pointing along srcdir; the radius is % set by srcparam1(1) (in grid unit); if srcparam1(2) is set to a non-zero % value, this source defines a ring (annulus) shaped source, with % srcparam1(2) denoting the inner circle's radius, here srcparam1(1)>=srcparam1(2) @@ -219,7 +219,7 @@ % of the ring is srcparam1(1) (in grid unit) and the inner radius is srcparam1(2); % srcparam1(3) and srcparam1(4) can optionally set the lower and upper angular % bound (in positive rad) of a ring sector if at least one of those is positive. -% 'fourierx' [*] - a general Fourier source, the parameters are +% 'fourierx' [*] - a general Fourier source, the parameters are % srcparam1: [v1x,v1y,v1z,|v2|], srcparam2: [kx,ky,phi0,M] % normalized vectors satisfy: srcdir cross v1=v2 % the phase shift is phi0*2*pi @@ -227,15 +227,15 @@ % srcparam1: [v1x,v1y,v1z,|v2|], srcparam2: [kx,ky,phix,phiy] % the phase shift is phi{x,y}*2*pi % 'zgaussian' - an angular gaussian beam, srcparam1(1) specifies the variance in the zenith angle -% 'line' - a line source, emitting from the line segment between -% cfg.srcpos and cfg.srcpos+cfg.srcparam(1:3), radiating +% 'line' - a line source, emitting from the line segment between +% cfg.srcpos and cfg.srcpos+cfg.srcparam(1:3), radiating % uniformly in the perpendicular direction -% 'slit' [*] - a colimated slit beam emitting from the line segment between -% cfg.srcpos and cfg.srcpos+cfg.srcparam(1:3), with the initial +% 'slit' [*] - a colimated slit beam emitting from the line segment between +% cfg.srcpos and cfg.srcpos+cfg.srcparam(1:3), with the initial % dir specified by cfg.srcdir % 'pencilarray' - a rectangular array of pencil beams. The srcparam1 and srcparam2 % are defined similarly to 'fourier', except that srcparam1(4) and srcparam2(4) -% are both integers, denoting the element counts in the x/y dimensions, respectively. +% are both integers, denoting the element counts in the x/y dimensions, respectively. % For exp., srcparam1=[10 0 0 4] and srcparam2[0 20 0 5] represent a 4x5 pencil beam array % spanning 10 grids in the x-axis and 20 grids in the y-axis (5-voxel spacing) % source types marked with [*] can be focused using the @@ -264,10 +264,10 @@ % -1 replay all detectors and save in separate volumes (output has 5 dimensions) % 0 replay all detectors and sum all Jacobians into one volume % a positive number: the index of the detector to replay and obtain Jacobians -% cfg.voidtime: for wide-field sources, [1]-start timer at launch, or 0-when entering +% cfg.voidtime: for wide-field sources, [1]-start timer at launch, or 0-when entering % the first non-zero voxel % -%== Output control == +% == Output control == % cfg.savedetflag: ['dp'] - a string (case insensitive) controlling the output detected photon data fields % 1 d output detector ID (1) % 2 s output partial scat. even counts (#media) @@ -284,21 +284,21 @@ % cfg.ismomentum: 1 to save photon momentum transfer,[0] not to save. % save as adding 'M' to cfg.savedetflag string % cfg.issaveref: [0]-save diffuse reflectance/transmittance in the non-zero voxels -% next to a boundary voxel. The reflectance data are stored as +% next to a boundary voxel. The reflectance data are stored as % negative values; must pad zeros next to boundaries % Example: see the demo script at the bottom % cfg.issave2pt: [1]-save volumetric output in the first output fluence.data; user can disable this output % by explicitly setting cfg.issave2pt=0, this way, even the first output fluence presents -% in mcxlab call, volume data will not be saved, this can speed up simulation when only +% in mcxlab call, volume data will not be saved, this can speed up simulation when only % detphoton is needed % cfg.issavedet: if the 2nd output is requested, this will be set to 1; in such case, user can force % setting it to 3 to enable early termination of simulation if the detected photon % buffer (length controlled by cfg.maxdetphoton) is filled; if the 2nd output is not % present, this will be set to 0 regardless user input. % cfg.outputtype: 'flux' - fluence-rate, (default value) -% 'fluence' - fluence integrated over each time gate, +% 'fluence' - fluence integrated over each time gate, % 'energy' - energy deposit per voxel -% 'jacobian' or 'wl' - mua Jacobian (replay mode), +% 'jacobian' or 'wl' - mua Jacobian (replay mode), % 'nscat' or 'wp' - weighted scattering counts for computing Jacobian for mus (replay mode) % 'wm' - weighted momentum transfer for a source/detector pair (replay mode) % 'rf' frequency-domain (FD/RF) mua Jacobian (replay mode), @@ -307,13 +307,13 @@ % and % cfg.session: a string for output file names (only used when no return variables) % -%== Debug == +% == Debug == % cfg.debuglevel: debug flag string (case insensitive), one or a combination of ['R','M','P','T'], no space % 'R': debug RNG, output fluence.data is filled with 0-1 random numbers % 'M': return photon trajectory data as the 5th output % 'P': show progress bar % 'T': save photon trajectory data only, as the 1st output, disable flux/detp/seeds outputs -% cfg.maxjumpdebug: [10000000|int] when trajectory is requested in the output, +% cfg.maxjumpdebug: [10000000|int] when trajectory is requested in the output, % use this parameter to set the maximum position stored. By default, % only the first 1e6 positions are stored. % @@ -321,18 +321,18 @@ % % Output: % fluence: a struct array, with a length equals to that of cfg. -% For each element of fluence, +% For each element of fluence, % fluence(i).data is a 4D array with -% dimensions specified by [size(vol) total-time-gates]. -% The content of the array is the normalized fluence at +% dimensions specified by [size(vol) total-time-gates]. +% The content of the array is the normalized fluence at % each voxel of each time-gate. % % when cfg.debuglevel contains 'T', fluence(i).data stores trajectory % output, see below % fluence(i).dref is a 4D array with the same dimension as fluence(i).data -% if cfg.issaveref is set to 1, containing only non-zero values in the +% if cfg.issaveref is set to 1, containing only non-zero values in the % layer of voxels immediately next to the non-zero voxels in cfg.vol, -% storing the normalized total diffuse reflectance (summation of the weights +% storing the normalized total diffuse reflectance (summation of the weights % of all escaped photon to the background regardless of their direction); % it is an empty array [] when if cfg.issaveref is 0. % fluence(i).stat is a structure storing additional information, including @@ -349,7 +349,7 @@ % detphoton.nscat: cummulative scattering event counts in each medium % detphoton.ppath: cummulative path lengths in each medium (partial pathlength) % one need to multiply cfg.unitinmm with ppath to convert it to mm. -% detphoton.mom: cummulative cos_theta for momentum transfer in each medium +% detphoton.mom: cummulative cos_theta for momentum transfer in each medium % detphoton.p or .v: exit position and direction, when cfg.issaveexit=1 % detphoton.w0: photon initial weight at launch time % detphoton.s: exit Stokes parameters for polarized photon @@ -363,7 +363,7 @@ % a byte array (uint8) for each detected photon. The column number % of seed equals that of detphoton. % trajectory: (optional), if given, mcxlab returns the trajectory data for -% each simulated photon. The output has 6 rows, the meanings are +% each simulated photon. The output has 6 rows, the meanings are % id: 1: index of the photon packet % pos: 2-4: x/y/z/ of each trajectory position % 5: current photon packet weight @@ -418,177 +418,176 @@ % try - defaultocl=evalin('base','USE_MCXCL'); + defaultocl = evalin('base', 'USE_MCXCL'); catch - defaultocl=0; + defaultocl = 0; end -useopencl=defaultocl; +useopencl = defaultocl; -if(nargin==2 && ischar(varargin{2})) - if(strcmp(varargin{2},'preview')) - [varargout{1:nargout}]=mcxpreview(varargin{1}); - return; - elseif(strcmp(varargin{2},'opencl')) - useopencl=1; +if (nargin == 2 && ischar(varargin{2})) + if (strcmp(varargin{2}, 'preview')) + [varargout{1:nargout}] = mcxpreview(varargin{1}); + return + elseif (strcmp(varargin{2}, 'opencl')) + useopencl = 1; end end -if(isstruct(varargin{1})) - for i=1:length(varargin{1}) - castlist={'srcpattern','srcpos','detpos','prop','workload','srcdir','srciquv'}; - for j=1:length(castlist) - if(isfield(varargin{1}(i),castlist{j})) - varargin{1}(i).(castlist{j})=double(varargin{1}(i).(castlist{j})); +if (isstruct(varargin{1})) + for i = 1:length(varargin{1}) + castlist = {'srcpattern', 'srcpos', 'detpos', 'prop', 'workload', 'srcdir', 'srciquv'}; + for j = 1:length(castlist) + if (isfield(varargin{1}(i), castlist{j})) + varargin{1}(i).(castlist{j}) = double(varargin{1}(i).(castlist{j})); end end - if (isfield(varargin{1}(i),'vol') && ndims(varargin{1}(i).vol)==4) - if((isa(varargin{1}(i).vol,'single') || isa(varargin{1}(i).vol,'double')) && isfield(varargin{1}(i),'unitinmm')) - varargin{1}(i).vol=varargin{1}(i).vol*varargin{1}(i).unitinmm; + if (isfield(varargin{1}(i), 'vol') && ndims(varargin{1}(i).vol) == 4) + if ((isa(varargin{1}(i).vol, 'single') || isa(varargin{1}(i).vol, 'double')) && isfield(varargin{1}(i), 'unitinmm')) + varargin{1}(i).vol = varargin{1}(i).vol * varargin{1}(i).unitinmm; end end - if (~isfield(varargin{1}(i),'tstart')) - varargin{1}(i).tstart=0; + if (~isfield(varargin{1}(i), 'tstart')) + varargin{1}(i).tstart = 0; end - if (~isfield(varargin{1}(i),'tend')) + if (~isfield(varargin{1}(i), 'tend')) error('you must define cfg.tend for the maximum time-of-flight of a photon in seconds'); end - if (~isfield(varargin{1}(i),'tstep')) - varargin{1}(i).tstep=varargin{1}(i).tend; + if (~isfield(varargin{1}(i), 'tstep')) + varargin{1}(i).tstep = varargin{1}(i).tend; end - if (~isfield(varargin{1}(i),'srcpos')) + if (~isfield(varargin{1}(i), 'srcpos')) error('you must define cfg.srcpos to defin the x/y/z position of the source in voxel unit'); end - if(isfield(varargin{1}(i),'detphotons') && isstruct(varargin{1}(i).detphotons)) - if(isfield(varargin{1}(i).detphotons,'data')) - varargin{1}(i).detphotons=varargin{1}(i).detphotons.data; + if (isfield(varargin{1}(i), 'detphotons') && isstruct(varargin{1}(i).detphotons)) + if (isfield(varargin{1}(i).detphotons, 'data')) + varargin{1}(i).detphotons = varargin{1}(i).detphotons.data; else - fulldetdata={'detid','nscat','ppath','mom','p','v','w0'}; - detfields=ismember(fulldetdata,fieldnames(varargin{1}(i).detphotons)); - detdata=[]; - for j=1:length(detfields) - if(detfields(j)) - val=typecast(varargin{1}(i).detphotons.(fulldetdata{j})(:),'single'); - detdata=[detdata reshape(val,size(varargin{1}(i).detphotons.(fulldetdata{j})))]; + fulldetdata = {'detid', 'nscat', 'ppath', 'mom', 'p', 'v', 'w0'}; + detfields = ismember(fulldetdata, fieldnames(varargin{1}(i).detphotons)); + detdata = []; + for j = 1:length(detfields) + if (detfields(j)) + val = typecast(varargin{1}(i).detphotons.(fulldetdata{j})(:), 'single'); + detdata = [detdata reshape(val, size(varargin{1}(i).detphotons.(fulldetdata{j})))]; end end - varargin{1}(i).detphotons=detdata'; - varargin{1}(i).savedetflag='dspmxvw'; - varargin{1}(i).savedetflag(detfields==0)=[]; + varargin{1}(i).detphotons = detdata'; + varargin{1}(i).savedetflag = 'dspmxvw'; + varargin{1}(i).savedetflag(detfields == 0) = []; end end end end - % detect [~,...]=mcxlab() in Octave. unfortunately matlab does not have isargout() -if(nargout>=1 && exist('isargout','builtin') && isargout(1)==0) - for i=1:length(varargin{1}) - varargin{1}(i).issave2pt=0; +if (nargout >= 1 && exist('isargout', 'builtin') && isargout(1) == 0) + for i = 1:length(varargin{1}) + varargin{1}(i).issave2pt = 0; end end -if(useopencl==0) - [varargout{1:max(1,nargout)}]=mcx(varargin{1}); +if (useopencl == 0) + [varargout{1:max(1, nargout)}] = mcx(varargin{1}); else - [varargout{1:max(1,nargout)}]=mcxcl(varargin{1}); + [varargout{1:max(1, nargout)}] = mcxcl(varargin{1}); end -if(nargin==0) - return; +if (nargin == 0) + return end -cfg=varargin{1}; +cfg = varargin{1}; -if(~ischar(cfg)) - for i=1:length(varargout{1}) - if(isfield(cfg(i),'srcnum') && cfg(i).srcnum>1) - dim=size(varargout{1}(i).data); - varargout{1}(i).data=reshape(varargout{1}(i).data,[cfg(i).srcnum, dim(1)/cfg(i).srcnum dim(2:end)]); - varargout{1}(i).data=permute(varargout{1}(i).data,[2:(length(dim)+1) 1]); - if(isfield(varargout{1}(i),'dref') && ~isempty(varargout{1}(i).dref)) - varargout{1}(i).dref=reshape(varargout{1}(i).dref,[cfg(i).srcnum, dim(1)/cfg(i).srcnum dim(2:end)]); - varargout{1}(i).dref=permute(varargout{1}(i).dref,[2:(length(dim)+1) 1]); +if (~ischar(cfg)) + for i = 1:length(varargout{1}) + if (isfield(cfg(i), 'srcnum') && cfg(i).srcnum > 1) + dim = size(varargout{1}(i).data); + varargout{1}(i).data = reshape(varargout{1}(i).data, [cfg(i).srcnum, dim(1) / cfg(i).srcnum dim(2:end)]); + varargout{1}(i).data = permute(varargout{1}(i).data, [2:(length(dim) + 1) 1]); + if (isfield(varargout{1}(i), 'dref') && ~isempty(varargout{1}(i).dref)) + varargout{1}(i).dref = reshape(varargout{1}(i).dref, [cfg(i).srcnum, dim(1) / cfg(i).srcnum dim(2:end)]); + varargout{1}(i).dref = permute(varargout{1}(i).dref, [2:(length(dim) + 1) 1]); end end end end -if(nargout>=2) - for i=1:length(varargout{2}) - if((~isfield(cfg(i),'savedetflag')) || ((isfield(cfg(i),'savedetflag')) && isempty(cfg(i).savedetflag))) - cfg(i).savedetflag='DP'; +if (nargout >= 2) + for i = 1:length(varargout{2}) + if ((~isfield(cfg(i), 'savedetflag')) || ((isfield(cfg(i), 'savedetflag')) && isempty(cfg(i).savedetflag))) + cfg(i).savedetflag = 'DP'; end - if(isfield(cfg(i),'issaveexit') && cfg(i).issaveexit) - cfg(i).savedetflag=[cfg(i).savedetflag,'XV']; + if (isfield(cfg(i), 'issaveexit') && cfg(i).issaveexit) + cfg(i).savedetflag = [cfg(i).savedetflag, 'XV']; end - if(isfield(cfg(i),'ismomentum') && cfg(i).ismomentum) - cfg(i).savedetflag=[cfg(i).savedetflag,'M']; + if (isfield(cfg(i), 'ismomentum') && cfg(i).ismomentum) + cfg(i).savedetflag = [cfg(i).savedetflag, 'M']; end - if(isfield(cfg(i),'polprop') && ~isempty(cfg(i).polprop)) - cfg(i).savedetflag=[cfg(i).savedetflag,'PVWI']; + if (isfield(cfg(i), 'polprop') && ~isempty(cfg(i).polprop)) + cfg(i).savedetflag = [cfg(i).savedetflag, 'PVWI']; else - cfg(i).savedetflag(regexp(cfg(i).savedetflag,'[Ii]'))=[]; + cfg(i).savedetflag(regexp(cfg(i).savedetflag, '[Ii]')) = []; end - if(ndims(cfg(i).vol)==4 && size(cfg(i).vol,1)~=8) - cfg(i).savedetflag=''; - if((isa(cfg(i).vol,'single') || isa(cfg(i).vol,'double')) && isfield(cfg(i),'unitinmm')) - cfg(i).vol=cfg(i).vol*cfg(i).unitinmm; + if (ndims(cfg(i).vol) == 4 && size(cfg(i).vol, 1) ~= 8) + cfg(i).savedetflag = ''; + if ((isa(cfg(i).vol, 'single') || isa(cfg(i).vol, 'double')) && isfield(cfg(i), 'unitinmm')) + cfg(i).vol = cfg(i).vol * cfg(i).unitinmm; end end - if((~isfield(cfg(i),'issaveexit') || cfg(i).issaveexit~=2)) - medianum=size(cfg(i).prop,1)-1; - detp=varargout{2}(i).data; - if(isempty(detp)) - continue; + if ((~isfield(cfg(i), 'issaveexit') || cfg(i).issaveexit ~= 2)) + medianum = size(cfg(i).prop, 1) - 1; + detp = varargout{2}(i).data; + if (isempty(detp)) + continue end - if(isfield(cfg(i),'polprop') && ~isempty(cfg(i).polprop)) - medianum=size(cfg(i).polprop,1); + if (isfield(cfg(i), 'polprop') && ~isempty(cfg(i).polprop)) + medianum = size(cfg(i).polprop, 1); end - flags={cfg(i).savedetflag}; - if(isfield(cfg(i),'issaveref')) - flags{end+1}=cfg(i).issaveref; + flags = {cfg(i).savedetflag}; + if (isfield(cfg(i), 'issaveref')) + flags{end + 1} = cfg(i).issaveref; end - if(isfield(cfg(i),'srcnum')) - flags{end+1}=cfg(i).srcnum; + if (isfield(cfg(i), 'srcnum')) + flags{end + 1} = cfg(i).srcnum; end - newdetp=mcxdetphoton(detp,medianum,flags{:}); - newdetp.prop=cfg(i).prop; - if(isfield(cfg(i),'polprop') && ~isempty(cfg(i).polprop)) && isfield(varargout{1}(i),'prop') - newdetp.prop(2:end,:)=varargout{1}(i).prop(:,2:end)'; + newdetp = mcxdetphoton(detp, medianum, flags{:}); + newdetp.prop = cfg(i).prop; + if (isfield(cfg(i), 'polprop') && ~isempty(cfg(i).polprop)) && isfield(varargout{1}(i), 'prop') + newdetp.prop(2:end, :) = varargout{1}(i).prop(:, 2:end)'; end - if(isfield(cfg(i),'unitinmm')) - newdetp.unitinmm=cfg(i).unitinmm; + if (isfield(cfg(i), 'unitinmm')) + newdetp.unitinmm = cfg(i).unitinmm; end - newdetp.data=detp; % enable this line for compatibility - newdetpstruct(i)=newdetp; + newdetp.data = detp; % enable this line for compatibility + newdetpstruct(i) = newdetp; else - newdetpstruct(i)=varargout{2}(i); + newdetpstruct(i) = varargout{2}(i); end end - if(exist('newdetpstruct','var')) - varargout{2}=newdetpstruct; + if (exist('newdetpstruct', 'var')) + varargout{2} = newdetpstruct; end end -if(nargout>=5 || (~isempty(cfg) && isstruct(cfg) && isfield(cfg, 'debuglevel') && ~isempty(regexp(cfg(1).debuglevel, '[tT]', 'once')))) - outputid=5; - if((isfield(cfg, 'debuglevel') && ~isempty(regexp(cfg(1).debuglevel, '[tT]', 'once')))) - outputid=1; +if (nargout >= 5 || (~isempty(cfg) && isstruct(cfg) && isfield(cfg, 'debuglevel') && ~isempty(regexp(cfg(1).debuglevel, '[tT]', 'once')))) + outputid = 5; + if ((isfield(cfg, 'debuglevel') && ~isempty(regexp(cfg(1).debuglevel, '[tT]', 'once')))) + outputid = 1; end - for i=1:length(varargout{outputid}) - data=varargout{outputid}.data; - if(isempty(data)) - continue; - end - traj.pos=data(2:4,:).'; - traj.id=typecast(data(1,:),'uint32').'; - [traj.id,idx]=sort(traj.id); - traj.pos=traj.pos(idx,:); - traj.data=[single(traj.id)' ; data(2:end,idx)]; - newtraj(i)=traj; + for i = 1:length(varargout{outputid}) + data = varargout{outputid}.data; + if (isempty(data)) + continue + end + traj.pos = data(2:4, :).'; + traj.id = typecast(data(1, :), 'uint32').'; + [traj.id, idx] = sort(traj.id); + traj.pos = traj.pos(idx, :); + traj.data = [single(traj.id)'; data(2:end, idx)]; + newtraj(i) = traj; end - if(exist('newtraj','var')) - varargout{outputid}=newtraj; + if (exist('newtraj', 'var')) + varargout{outputid} = newtraj; end end diff --git a/utils/cwdiffusion.m b/utils/cwdiffusion.m index 972d77fd..dbe6da04 100644 --- a/utils/cwdiffusion.m +++ b/utils/cwdiffusion.m @@ -1,4 +1,4 @@ -function [Phi r]= cwdiffusion(mua, musp, Reff, srcpos,detpos) +function [Phi r] = cwdiffusion(mua, musp, Reff, srcpos, detpos) % % [Phi r] = cwdiffusion(mua, musp, Reff, srcpos,detpos) % @@ -22,14 +22,14 @@ % see Boas2002, Haskell1994 % -D = 1/(3*(mua+musp)); -zb = (1+Reff)/(1-Reff)*2*D; +D = 1 / (3 * (mua + musp)); +zb = (1 + Reff) / (1 - Reff) * 2 * D; -z0 = 1/(musp+mua); -r=getdistance([srcpos(:,1:2) srcpos(:,3)+z0],detpos); -r2=getdistance([srcpos(:,1:2) srcpos(:,3)-z0-2*zb],detpos); +z0 = 1 / (musp + mua); +r = getdistance([srcpos(:, 1:2) srcpos(:, 3) + z0], detpos); +r2 = getdistance([srcpos(:, 1:2) srcpos(:, 3) - z0 - 2 * zb], detpos); -b=sqrt(3*mua*musp); +b = sqrt(3 * mua * musp); % unit of phi: 1/(mm^2) -Phi =1./(4*pi*D).*(exp(-b*r)./r - exp(-b*r2)./r2); +Phi = 1 ./ (4 * pi * D) .* (exp(-b * r) ./ r - exp(-b * r2) ./ r2); diff --git a/utils/cwfluencediffusion.m b/utils/cwfluencediffusion.m index a58914d1..ca8dbf2a 100644 --- a/utils/cwfluencediffusion.m +++ b/utils/cwfluencediffusion.m @@ -1,4 +1,4 @@ -function varargout=cwfluencediffusion(varargin) +function varargout = cwfluencediffusion(varargin) % % [Phi r]= cwfluencediffusion(mua, musp, Reff, srcpos,detpos) % @@ -12,4 +12,4 @@ % License: GPLv3, see http://mcx.sf.net for details % see Boas2002, Haskell1994 % -[varargout{1:nargout}]=cwdiffusion(varargin{:}); \ No newline at end of file +[varargout{1:nargout}] = cwdiffusion(varargin{:}); diff --git a/utils/cwfluxdiffusion.m b/utils/cwfluxdiffusion.m index 84f744ba..eb2691b4 100644 --- a/utils/cwfluxdiffusion.m +++ b/utils/cwfluxdiffusion.m @@ -1,4 +1,4 @@ -function [flux]= cwfluxdiffusion(mua, musp, Reff, srcpos, detpos) +function [flux] = cwfluxdiffusion(mua, musp, Reff, srcpos, detpos) % % [flux] = cwfluxdiffusion(mua, musp, n, srcpos, detpos) % @@ -20,13 +20,13 @@ % License: GPLv3, see http://mcx.sf.net for details % see Kienle1997 % - D = 1 / (3 * (mua + musp)); - z0 = 1 / (mua + musp); - zb = (1 + Reff) / (1 - Reff) * 2 * D; - mueff = sqrt(3 * mua * (mua + musp)); - r1 = getdistance([srcpos(:,1:2) srcpos(:,3) + z0],detpos); - r2 = getdistance([srcpos(:,1:2) srcpos(:,3) + z0 + 2 * zb],detpos); +D = 1 / (3 * (mua + musp)); +z0 = 1 / (mua + musp); +zb = (1 + Reff) / (1 - Reff) * 2 * D; +mueff = sqrt(3 * mua * (mua + musp)); +r1 = getdistance([srcpos(:, 1:2) srcpos(:, 3) + z0], detpos); +r2 = getdistance([srcpos(:, 1:2) srcpos(:, 3) + z0 + 2 * zb], detpos); - flux = 1 / (4 * pi) * (z0 * (mueff + 1 ./ r1) .* exp(-mueff .* r1) ./ r1.^2 + ... - (z0 + 2 * zb) * (mueff + 1 ./ r2) .* exp(-mueff .* r2) ./ r2.^2); % Eq. 6 of Kienle1997 -end \ No newline at end of file +flux = 1 / (4 * pi) * (z0 * (mueff + 1 ./ r1) .* exp(-mueff .* r1) ./ r1.^2 + ... + (z0 + 2 * zb) * (mueff + 1 ./ r2) .* exp(-mueff .* r2) ./ r2.^2); % Eq. 6 of Kienle1997 +end diff --git a/utils/getdistance.m b/utils/getdistance.m index 47b0c391..1dd7cc53 100644 --- a/utils/getdistance.m +++ b/utils/getdistance.m @@ -1,4 +1,4 @@ -function separation=getdistance(srcpos,detpos) +function separation = getdistance(srcpos, detpos) % separation=getdistance(srcpos,detpos) % % compute the source/detector separation from the positions @@ -17,10 +17,10 @@ % this file is part of Monte Carlo eXtreme (MCX) % License: GPLv3, see http://mcx.sf.net for details -srcnum=length(srcpos(:,1)); -detnum=length(detpos(:,1)); -for s=1:srcnum - for r=1:detnum - separation(r,s)=norm(srcpos(s,:)-detpos(r,:),'fro'); - end +srcnum = length(srcpos(:, 1)); +detnum = length(detpos(:, 1)); +for s = 1:srcnum + for r = 1:detnum + separation(r, s) = norm(srcpos(s, :) - detpos(r, :), 'fro'); + end end diff --git a/utils/image3i.m b/utils/image3i.m index 5285b689..3065a4c5 100644 --- a/utils/image3i.m +++ b/utils/image3i.m @@ -1,11 +1,11 @@ -function h = image3i(im,ij2xyz,handle, keepxyz) +function h = image3i(im, ij2xyz, handle, keepxyz) % Display a 2-D image in Matlab xyz 3-D space % h = image3i(C, IJ2XYZ, handle) % % C is an image, encoded with scalars or rgb-values, i.e. the dimensions of % C are either N x M or N x M x 3. Scalars correspond to indices in the -% current colormap and rgb-values should be within the closed -% interval [0,1]. Similar to the image command, image3i will treat scalars +% current colormap and rgb-values should be within the closed +% interval [0,1]. Similar to the image command, image3i will treat scalars % differently depending on if they are doubles or uint8/uint16. Doubles are % indexed starting at 1 and uint8/uint16 start at 0. By setting the % property CDataMapping for h, different behaviours can be obtained, e.g. @@ -26,12 +26,12 @@ % Thus IJ2XYZ = [ix jx cx;iy jy cy; iz jz cz; 0 0 1], where cx,cy and cz % encode the translation of the image. The ones and zeroes ensure that % the result of the transformation is also a homogeneous coordinate. Yes, -% you can skip that last row of IJ2XYZ and image3i will not care about +% you can skip that last row of IJ2XYZ and image3i will not care about % it. :-) % % The function returns a handle, h, which is a handle to a surf object. Use % this handle to e.g. modify the image, make it transparent or delete it. -% The handle can also be used as an optional argument to the image3i +% The handle can also be used as an optional argument to the image3i % command. In this case, the the image patch is recycled, which is an % efficient way of e.g. changing the image data or move the image to % another location. @@ -51,9 +51,9 @@ % axis ij; % axis image; % In the above example it _is_ important to hardcode the axis settings -% to compare image and image3i, otherwise Matlabs does some magic that make +% to compare image and image3i, otherwise Matlabs does some magic that make % them look different. -% +% % Some examples of use: % % %% Display an image with (1,1) located at (10,20,5). @@ -67,9 +67,9 @@ % %% Reuse the image h from the previous example, move (1,1) to (7,17,2). % %% This technique is useful in interactive applications. % h = image3i(C,[R t-3],h); axis equal -% % -% %% Display an image centered at (15,10,0), rotated 30 degrees ccw in the +% +% %% Display an image centered at (15,10,0), rotated 30 degrees ccw in the % %% image plane. % C = rand(8,4)*64; % a small random image % alpha = 30; % rotation, in ccw degrees @@ -86,70 +86,69 @@ % set(h,'FaceAlpha',0.25) % Make the image transparent % set(h,'EdgeColor','black'); % set(h,'LineStyle','-'); -% +% % SEE ALSO: imagesc3, surf % % Author: Anders Brun, anders@cb.uu.se (2008) % Hardcoded constants stepsize = 0.1; % Determines number of tiles in image. It is most efficient - % to set this to 1, but a higher number might render better - % graphics when the image is distorted a lot by the - % perspective mapping of the camera. All texture mapping is - % based on linear interpolation and does not take texture - % into account, at least it has been so in Matlab in the - % past. +% to set this to 1, but a higher number might render better +% graphics when the image is distorted a lot by the +% perspective mapping of the camera. All texture mapping is +% based on linear interpolation and does not take texture +% into account, at least it has been so in Matlab in the +% past. -if ndims(im) == 2 %Scalar mode - imsize = size(im); -elseif ndims(im) == 3 %RGB mode - imsize = size(im); - imsize = imsize(1:2); +if ndims(im) == 2 % Scalar mode + imsize = size(im); +elseif ndims(im) == 3 % RGB mode + imsize = size(im); + imsize = imsize(1:2); else - error('Only scalar and RGB images supported') + error('Only scalar and RGB images supported'); end -if(nargin>=4 && handle~=0 && keepxyz) - set(handle,'CData',im); - h = handle; - set(gcf,'renderer','opengl'); - return; +if (nargin >= 4 && handle ~= 0 && keepxyz) + set(handle, 'CData', im); + h = handle; + set(gcf, 'renderer', 'opengl'); + return end % Create the slice -[uu,vv] = ndgrid(0:stepsize:1, 0:stepsize:1); -% ij2xyz refers to voxel centers. Therefore we need to +[uu, vv] = ndgrid(0:stepsize:1, 0:stepsize:1); +% ij2xyz refers to voxel centers. Therefore we need to % add half a pixel to each size of the slice. -irange = [0.5 imsize(1)+0.5]; -jrange = [0.5 imsize(2)+0.5]; -% Create three 2D arrays giving the ijk coordinates for +irange = [0.5 imsize(1) + 0.5]; +jrange = [0.5 imsize(2) + 0.5]; +% Create three 2D arrays giving the ijk coordinates for % this slice. -iidx = irange(1) + uu*(irange(2)-irange(1)); -jidx = jrange(1) + vv*(jrange(2)-jrange(1)); +iidx = irange(1) + uu * (irange(2) - irange(1)); +jidx = jrange(1) + vv * (jrange(2) - jrange(1)); % Map these 2D ijk arrays to xyz -x = ij2xyz(1,1)*iidx + ij2xyz(1,2)*jidx + + ij2xyz(1,3); -y = ij2xyz(2,1)*iidx + ij2xyz(2,2)*jidx + + ij2xyz(2,3); -z = ij2xyz(3,1)*iidx + ij2xyz(3,2)*jidx + + ij2xyz(3,3); +x = ij2xyz(1, 1) * iidx + ij2xyz(1, 2) * jidx + +ij2xyz(1, 3); +y = ij2xyz(2, 1) * iidx + ij2xyz(2, 2) * jidx + +ij2xyz(2, 3); +z = ij2xyz(3, 1) * iidx + ij2xyz(3, 2) * jidx + +ij2xyz(3, 3); -if nargin<3 || handle == 0 - % Make a new surface - h = surface('XData',x,'YData',y,'ZData',z,... - 'CData', im,... - 'FaceColor','texturemap',... - 'EdgeColor','none',... - 'LineStyle','none',... - 'Marker','none',... - 'MarkerFaceColor','none',... - 'MarkerEdgeColor','none',... - 'CDataMapping','direct'); +if nargin < 3 || handle == 0 + % Make a new surface + h = surface('XData', x, 'YData', y, 'ZData', z, ... + 'CData', im, ... + 'FaceColor', 'texturemap', ... + 'EdgeColor', 'none', ... + 'LineStyle', 'none', ... + 'Marker', 'none', ... + 'MarkerFaceColor', 'none', ... + 'MarkerEdgeColor', 'none', ... + 'CDataMapping', 'direct'); else - % Reuse old surface - set(handle,'XData',x,'YData',y,'ZData',z,'CData',im); - h = handle; + % Reuse old surface + set(handle, 'XData', x, 'YData', y, 'ZData', z, 'CData', im); + h = handle; end % Just to be sure... -set(gcf,'renderer','opengl'); -%set(gcf,'renderer','zbuffer'); - +set(gcf, 'renderer', 'opengl'); +% set(gcf,'renderer','zbuffer'); diff --git a/utils/islicer.m b/utils/islicer.m index 5189d7b0..439beac4 100644 --- a/utils/islicer.m +++ b/utils/islicer.m @@ -1,4 +1,4 @@ -function h = islicer(vol,T, handles, keepxyz, varargin) +function h = islicer(vol, T, handles, keepxyz, varargin) % % h = islicer(vol); % or @@ -22,50 +22,46 @@ % if nargin < 2 - T = eye(4); + T = eye(4); end -if(nargin < 3) - handles=[0,0,0]; +if (nargin < 3) + handles = [0, 0, 0]; end -if(nargin < 4) - keepxyz=0; +if (nargin < 4) + keepxyz = 0; end -if(handles(1)==0) - h1 = slice3i(vol,T,1,round(size(vol,1)/2),handles(1), keepxyz); +if (handles(1) == 0) + h1 = slice3i(vol, T, 1, round(size(vol, 1) / 2), handles(1), keepxyz); else - h1 = slice3i(vol,T,1,round(min(min(get(handles(1),'xdata')))),handles(1), keepxyz); + h1 = slice3i(vol, T, 1, round(min(min(get(handles(1), 'xdata')))), handles(1), keepxyz); end -if(handles(2)==0) - h2 = slice3i(vol,T,2,round(size(vol,2)/2),handles(2), keepxyz); +if (handles(2) == 0) + h2 = slice3i(vol, T, 2, round(size(vol, 2) / 2), handles(2), keepxyz); else - h2 = slice3i(vol,T,2,round(min(min(get(handles(2),'ydata')))),handles(2), keepxyz); + h2 = slice3i(vol, T, 2, round(min(min(get(handles(2), 'ydata')))), handles(2), keepxyz); end -if(handles(3)==0) - h3 = slice3i(vol,T,3,round(size(vol,3)/2),handles(3), keepxyz); +if (handles(3) == 0) + h3 = slice3i(vol, T, 3, round(size(vol, 3) / 2), handles(3), keepxyz); else - h3 = slice3i(vol,T,3,round(min(min(get(handles(3),'zdata')))),handles(3), keepxyz); + h3 = slice3i(vol, T, 3, round(min(min(get(handles(3), 'zdata')))), handles(3), keepxyz); end -if(nargout>=1) - h = [h1,h2,h3]; +if (nargout >= 1) + h = [h1, h2, h3]; end -set([h1,h2,h3],'CDataMapping','scaled', varargin{:}); +set([h1, h2, h3], 'CDataMapping', 'scaled', varargin{:}); -%colormap(jet(64)); +% colormap(jet(64)); view(3); -if(all(handles==0)) - set(camlight,'Visible','on') +if (all(handles == 0)) + set(camlight, 'Visible', 'on'); end axis equal; - - - - \ No newline at end of file diff --git a/utils/json2mcx.m b/utils/json2mcx.m index 16546ccf..0f3dce5b 100644 --- a/utils/json2mcx.m +++ b/utils/json2mcx.m @@ -1,4 +1,4 @@ -function cfg=json2mcx(filename) +function cfg = json2mcx(filename) % % Format: % cfg=json2mcx(filename) @@ -11,12 +11,12 @@ % filename: the JSON input file % % Output: -% cfg: a struct defining the parameters associated with a simulation. +% cfg: a struct defining the parameters associated with a simulation. % Please run 'help mcxlab' or 'help mmclab' to see details. % % Dependency: -% this function depends on the savejson/loadjson functions from the -% Iso2Mesh toolbox (http://iso2mesh.sf.net) or JSONlab toolbox +% this function depends on the savejson/loadjson functions from the +% Iso2Mesh toolbox (http://iso2mesh.sf.net) or JSONlab toolbox % (http://iso2mesh.sf.net/jsonlab) % % This function is part of Monte Carlo eXtreme (MCX) URL: http://mcx.space @@ -24,137 +24,137 @@ % License: GNU General Public License version 3, please read LICENSE.txt for details % -if(ischar(filename)) - json=loadjson(filename); -elseif(isstruct(filename)) - json=filename; +if (ischar(filename)) + json = loadjson(filename); +elseif (isstruct(filename)) + json = filename; else error('first input is not supported'); end %% define the optodes: sources and detectors -cfg=struct(); -if(isfield(json,'Optode')) - if(isfield(json.Optode,'Source')) - cfg=copycfg(cfg,'srcpos',json.Optode.Source,'Pos'); - cfg=copycfg(cfg,'srcdir',json.Optode.Source,'Dir'); - if(isfield(cfg,'srcdir')) - cfg.srcdir(1:3)=cfg.srcdir(1:3)/norm(cfg.srcdir(1:3)); +cfg = struct(); +if (isfield(json, 'Optode')) + if (isfield(json.Optode, 'Source')) + cfg = copycfg(cfg, 'srcpos', json.Optode.Source, 'Pos'); + cfg = copycfg(cfg, 'srcdir', json.Optode.Source, 'Dir'); + if (isfield(cfg, 'srcdir')) + cfg.srcdir(1:3) = cfg.srcdir(1:3) / norm(cfg.srcdir(1:3)); + end + cfg = copycfg(cfg, 'srcparam1', json.Optode.Source, 'Param1'); + cfg = copycfg(cfg, 'srcparam2', json.Optode.Source, 'Param2'); + cfg = copycfg(cfg, 'srctype', json.Optode.Source, 'Type'); + cfg = copycfg(cfg, 'srcnum', json.Optode.Source, 'SrcNum'); + if (isfield(json.Optode.Source, 'Pattern')) + nz = jsonopt('Nz', 1, Optode.Source.Pattern); + cfg.srcpattern = reshape(Optode.Source.Pattern.Data, ... + [Optode.Source.Pattern.Nx, Optode.Source.Pattern.Ny, nz]); + end end - cfg=copycfg(cfg,'srcparam1',json.Optode.Source,'Param1'); - cfg=copycfg(cfg,'srcparam2',json.Optode.Source,'Param2'); - cfg=copycfg(cfg,'srctype',json.Optode.Source,'Type'); - cfg=copycfg(cfg,'srcnum',json.Optode.Source,'SrcNum'); - if(isfield(json.Optode.Source,'Pattern')) - nz=jsonopt('Nz',1,Optode.Source.Pattern); - cfg.srcpattern=reshape(Optode.Source.Pattern.Data,... - [Optode.Source.Pattern.Nx,Optode.Source.Pattern.Ny,nz]); + if (isfield(json.Optode, 'Detector') && ~isempty(json.Optode.Detector)) + if (iscell(json.Optode.Detector)) + json.Optode.Detector = cell2mat(json.Optode.Detector); + end + cfg.detpos = cell2mat(struct2cell(json.Optode.Detector')'); end - end - if(isfield(json.Optode,'Detector') && ~isempty(json.Optode.Detector)) - if(iscell(json.Optode.Detector)) - json.Optode.Detector=cell2mat(json.Optode.Detector); - end - cfg.detpos=cell2mat(struct2cell(json.Optode.Detector')'); - end end %% define the domain and optical properties -cfg=copycfg(cfg,'issrcfrom0',json.Domain,'OriginType'); -cfg=copycfg(cfg,'unitinmm',json.Domain,'LengthUnit'); +cfg = copycfg(cfg, 'issrcfrom0', json.Domain, 'OriginType'); +cfg = copycfg(cfg, 'unitinmm', json.Domain, 'LengthUnit'); -if(iscell(json.Domain.Media)) - json.Domain.Media=cell2mat(json.Domain.Media); +if (iscell(json.Domain.Media)) + json.Domain.Media = cell2mat(json.Domain.Media); end -cfg.prop=squeeze(cell2mat(struct2cell(json.Domain.Media)))'; +cfg.prop = squeeze(cell2mat(struct2cell(json.Domain.Media)))'; -if(isfield(json,'Shapes')) - cfg.shapes=savejson('Shapes',json.Shapes); +if (isfield(json, 'Shapes')) + cfg.shapes = savejson('Shapes', json.Shapes); end -if(isfield(json,'Domain') && isfield(json.Domain,'VolumeFile')) - [fpath, fname, fext]=fileparts(json.Domain.VolumeFile); - switch(fext) +if (isfield(json, 'Domain') && isfield(json.Domain, 'VolumeFile')) + [fpath, fname, fext] = fileparts(json.Domain.VolumeFile); + switch (fext) case '.json' - if(isfield(json.Domain,'Dim')) - cfg.vol=uint8(zeros(json.Domain.Dim)); + if (isfield(json.Domain, 'Dim')) + cfg.vol = uint8(zeros(json.Domain.Dim)); end - cfg.shapes=savejson('',loadjson(json.Domain.VolumeFile)); + cfg.shapes = savejson('', loadjson(json.Domain.VolumeFile)); case '.bin' - bytelen=1; - mediaclass='uint8'; - if(isfield(json.Domain,'MediaFormat')) - idx=find(ismember({'byte','short','integer','muamus_float',... - 'mua_float','muamus_half','asgn_byte','muamus_short','svmc','asgn_float'},... - lower(json.Domain.MediaFormat))); - if(idx) - typebyte=[1,2,4,8,4,4,4,4,8,16]; - typenames={'uint8','uint16','uint32','single','single','uint16','uint8','uint16','uint8','single'}; - bytelen=typebyte(idx); - mediaclass=typenames{idx}; + bytelen = 1; + mediaclass = 'uint8'; + if (isfield(json.Domain, 'MediaFormat')) + idx = find(ismember({'byte', 'short', 'integer', 'muamus_float', ... + 'mua_float', 'muamus_half', 'asgn_byte', 'muamus_short', 'svmc', 'asgn_float'}, ... + lower(json.Domain.MediaFormat))); + if (idx) + typebyte = [1, 2, 4, 8, 4, 4, 4, 4, 8, 16]; + typenames = {'uint8', 'uint16', 'uint32', 'single', 'single', 'uint16', 'uint8', 'uint16', 'uint8', 'single'}; + bytelen = typebyte(idx); + mediaclass = typenames{idx}; else - error('incorrect Domain.MediaFormat setting') + error('incorrect Domain.MediaFormat setting'); end end - cfg.vol=loadmc2(json.Domain.VolumeFile,[bytelen, json.Domain.Dim],'uchar=>uchar'); - cfg.vol=typecast(cfg.vol(:),mediaclass); - cfg.vol=reshape(cfg.vol,[length(cfg.vol)/prod(json.Domain.Dim), json.Domain.Dim]); - if(size(cfg.vol,1)==1) - if(exist('idx','var') && idx~=5) - cfg.vol=squeeze(cfg.vol); + cfg.vol = loadmc2(json.Domain.VolumeFile, [bytelen, json.Domain.Dim], 'uchar=>uchar'); + cfg.vol = typecast(cfg.vol(:), mediaclass); + cfg.vol = reshape(cfg.vol, [length(cfg.vol) / prod(json.Domain.Dim), json.Domain.Dim]); + if (size(cfg.vol, 1) == 1) + if (exist('idx', 'var') && idx ~= 5) + cfg.vol = squeeze(cfg.vol); end end case '.nii' - cfg.vol=mcxloadnii(json.Domain.VolumeFile); + cfg.vol = mcxloadnii(json.Domain.VolumeFile); end -elseif(~isfield(cfg,'shapes')) - cfg.vol=uint8(zeros(60,60,60)); +elseif (~isfield(cfg, 'shapes')) + cfg.vol = uint8(zeros(60, 60, 60)); end %% define the simulation session flags -cfg=copycfg(cfg,'session',json.Session,'ID'); -cfg=copycfg(cfg,'isreflect',json.Session,'DoMismatch'); -cfg=copycfg(cfg,'issave2pt',json.Session,'DoSaveVolume'); -cfg=copycfg(cfg,'issavedet',json.Session,'DoPartialPath'); -cfg=copycfg(cfg,'issaveexit',json.Session,'DoSaveExit'); -cfg=copycfg(cfg,'issaveseed',json.Session,'DoSaveSeed'); -cfg=copycfg(cfg,'isnormalize',json.Session,'DoNormalize'); -cfg=copycfg(cfg,'outputformat',json.Session,'OutputFormat'); -cfg=copycfg(cfg,'outputtype',json.Session,'OutputType'); -if(length(cfg.outputtype)==1) - otypemap=struct('x', 'flux', 'f', 'fluence', 'e', 'energy', 'j', 'jacobian', 'p', 'nscat', 'm', 'wm', 'r', 'rf', 'l', 'length'); - if(~isfield(otypemap, cfg.outputtype)) +cfg = copycfg(cfg, 'session', json.Session, 'ID'); +cfg = copycfg(cfg, 'isreflect', json.Session, 'DoMismatch'); +cfg = copycfg(cfg, 'issave2pt', json.Session, 'DoSaveVolume'); +cfg = copycfg(cfg, 'issavedet', json.Session, 'DoPartialPath'); +cfg = copycfg(cfg, 'issaveexit', json.Session, 'DoSaveExit'); +cfg = copycfg(cfg, 'issaveseed', json.Session, 'DoSaveSeed'); +cfg = copycfg(cfg, 'isnormalize', json.Session, 'DoNormalize'); +cfg = copycfg(cfg, 'outputformat', json.Session, 'OutputFormat'); +cfg = copycfg(cfg, 'outputtype', json.Session, 'OutputType'); +if (length(cfg.outputtype) == 1) + otypemap = struct('x', 'flux', 'f', 'fluence', 'e', 'energy', 'j', 'jacobian', 'p', 'nscat', 'm', 'wm', 'r', 'rf', 'l', 'length'); + if (~isfield(otypemap, cfg.outputtype)) error('output type %s is not supported', cfg.outputtype); end - cfg.outputtype=otypemap.(cfg.outputtype); + cfg.outputtype = otypemap.(cfg.outputtype); end -cfg=copycfg(cfg,'debuglevel',json.Session,'Debug'); -cfg=copycfg(cfg,'autopilot',json.Session,'DoAutoThread'); -cfg=copycfg(cfg,'autopilot',json.Session,'DoAutoThread'); -cfg=copycfg(cfg,'seed',json.Session,'RNGSeed'); -if(isfield(cfg,'seed') && ischar(cfg.seed) && ~isempty(regexp(cfg.seed,'\.mch$','match'))) - [data, header, cfg.seed]=loadmch(cfg.seed); +cfg = copycfg(cfg, 'debuglevel', json.Session, 'Debug'); +cfg = copycfg(cfg, 'autopilot', json.Session, 'DoAutoThread'); +cfg = copycfg(cfg, 'autopilot', json.Session, 'DoAutoThread'); +cfg = copycfg(cfg, 'seed', json.Session, 'RNGSeed'); +if (isfield(cfg, 'seed') && ischar(cfg.seed) && ~isempty(regexp(cfg.seed, '\.mch$', 'match'))) + [data, header, cfg.seed] = loadmch(cfg.seed); end -cfg=copycfg(cfg,'nphoton',json.Session,'Photons'); -cfg=copycfg(cfg,'rootpath',json.Session,'RootPath'); +cfg = copycfg(cfg, 'nphoton', json.Session, 'Photons'); +cfg = copycfg(cfg, 'rootpath', json.Session, 'RootPath'); %% define the forward simulation settings -if(isfield(json,'Forward')) - cfg.tstart=json.Forward.T0; - cfg=copycfg(cfg,'tstart',json.Forward,'T0'); - cfg=copycfg(cfg,'tend',json.Forward,'T1'); - cfg=copycfg(cfg,'tstep',json.Forward,'Dt'); +if (isfield(json, 'Forward')) + cfg.tstart = json.Forward.T0; + cfg = copycfg(cfg, 'tstart', json.Forward, 'T0'); + cfg = copycfg(cfg, 'tend', json.Forward, 'T1'); + cfg = copycfg(cfg, 'tstep', json.Forward, 'Dt'); end -function outdata=copycfg(cfg,name,outroot,outfield,defaultval) -if(nargin>=5 && ~isfield(outroot,outfield)) - outroot.(outfield)=defaultval; +function outdata = copycfg(cfg, name, outroot, outfield, defaultval) +if (nargin >= 5 && ~isfield(outroot, outfield)) + outroot.(outfield) = defaultval; end -if(isfield(outroot,outfield)) - cfg.(name)=outroot.(outfield); +if (isfield(outroot, outfield)) + cfg.(name) = outroot.(outfield); end -outdata=cfg; +outdata = cfg; diff --git a/utils/loadmc2.m b/utils/loadmc2.m index b43959de..95aee6a8 100644 --- a/utils/loadmc2.m +++ b/utils/loadmc2.m @@ -1,4 +1,4 @@ -function [data, dref]=loadmc2(fname,dim,format,offset) +function [data, dref] = loadmc2(fname, dim, format, offset) % % data=loadmc2(fname,dim,format) % or @@ -17,35 +17,35 @@ % data: the output MCX solution data array, in the % same dimension specified by dim % dref(optional): diffuse reflectance at the surface of the domain. -% if this output is not given while diffuse reflectance -% is recorded, dref is shown as the negative values in +% if this output is not given while diffuse reflectance +% is recorded, dref is shown as the negative values in % the data output. % % this file is part of Monte Carlo eXtreme (MCX) % License: GPLv3, see http://mcx.sf.net for details % -if(nargin==2) - format='float'; +if (nargin == 2) + format = 'float'; end -fid=fopen(fname,'rb'); +fid = fopen(fname, 'rb'); -if(fid==0) +if (fid == 0) error('can not open the specified file'); end -if(nargin>3) - fseek(fid,offset,'bof'); +if (nargin > 3) + fseek(fid, offset, 'bof'); end -data=fread(fid,inf,format); +data = fread(fid, inf, format); fclose(fid); -data=reshape(data,dim); +data = reshape(data, dim); -if(nargout>1) - dref=-data; - dref(dref<0)=0; - data(data<0)=0; +if (nargout > 1) + dref = -data; + dref(dref < 0) = 0; + data(data < 0) = 0; end diff --git a/utils/loadmch.m b/utils/loadmch.m index ccf00709..89269fe1 100644 --- a/utils/loadmch.m +++ b/utils/loadmch.m @@ -1,4 +1,4 @@ -function [data, headerstruct, photonseed]=loadmch(fname,format,endian) +function [data, headerstruct, photonseed] = loadmch(fname, format, endian) % % [data, header]=loadmch(fname,format,endian) % @@ -13,8 +13,8 @@ % % output: % data: the output detected photon data array -% data has at least M*2+2 columns (M=header.medium), the first column is the -% ID of the detector; columns 2 to M+1 store the number of +% data has at least M*2+2 columns (M=header.medium), the first column is the +% ID of the detector; columns 2 to M+1 store the number of % scattering events for every tissue region; the following M % columns are the partial path lengths (in mm) for each medium type; % the last column is the initial weight at launch time of each detecetd @@ -30,8 +30,8 @@ % [version,medianum,detnum,recordnum,totalphoton,detectedphoton, % savedphoton,lengthunit,seedbyte,normalizer,respin,srcnum,savedetflag,totalsource] % photonseed: (optional) if the mch file contains a seed section, this -% returns the seed data for each detected photon. Each row of -% photonseed is a byte array, which can be used to initialize a +% returns the seed data for each detected photon. Each row of +% photonseed is a byte array, which can be used to initialize a % seeded simulation. Note that the seed is RNG specific. You must use % the an identical RNG to utilize these seeds for a new simulation. % @@ -39,86 +39,88 @@ % License: GPLv3, see http://mcx.sf.net for details % -if(nargin==1) - format='float32=>float32'; +if (nargin == 1) + format = 'float32=>float32'; end -if(nargin<3) - endian='ieee-le'; +if (nargin < 3) + endian = 'ieee-le'; end -fid=fopen(fname,'rb',endian); +fid = fopen(fname, 'rb', endian); -data=[]; -header=[]; -photonseed=[]; +data = []; +header = []; +photonseed = []; -while(~feof(fid)) - magicheader=fread(fid,4,'char'); - if(strcmp(char(magicheader(:))','MCXH')~=1) - if(isempty(header)) - fclose(fid); - error('can not find a MCX history data block'); - end - break; - end - hd=fread(fid,7,'uint'); % version, maxmedia, detnum, colcount, totalphoton, detected, savedphoton - if(hd(1)~=1) error('version higher than 1 is not supported'); end - unitmm=fread(fid,1,'float32'); - seedbyte=fread(fid,1,'uint'); - normalizer=fread(fid,1,'float32'); - respin=fread(fid,1,'int'); - srcnum=fread(fid,1,'uint'); - savedetflag=fread(fid,1,'uint'); - totalsource=fread(fid,1,'uint'); - junk=fread(fid,1,'uint'); +while (~feof(fid)) + magicheader = fread(fid, 4, 'char'); + if (strcmp(char(magicheader(:))', 'MCXH') ~= 1) + if (isempty(header)) + fclose(fid); + error('can not find a MCX history data block'); + end + break + end + hd = fread(fid, 7, 'uint'); % version, maxmedia, detnum, colcount, totalphoton, detected, savedphoton + if (hd(1) ~= 1) + error('version higher than 1 is not supported'); + end + unitmm = fread(fid, 1, 'float32'); + seedbyte = fread(fid, 1, 'uint'); + normalizer = fread(fid, 1, 'float32'); + respin = fread(fid, 1, 'int'); + srcnum = fread(fid, 1, 'uint'); + savedetflag = fread(fid, 1, 'uint'); + totalsource = fread(fid, 1, 'uint'); + junk = fread(fid, 1, 'uint'); - detflag=dec2bin(bitand(savedetflag,(2^8-1)))-'0'; - if(strcmp(endian,'ieee-le')) - detflag=fliplr(detflag); + detflag = dec2bin(bitand(savedetflag, (2^8 - 1))) - '0'; + if (strcmp(endian, 'ieee-le')) + detflag = fliplr(detflag); end - datalen=[1 hd(2) hd(2) hd(2) 3 3 1 4]; - datlen=detflag.*datalen(1:length(detflag)); + datalen = [1 hd(2) hd(2) hd(2) 3 3 1 4]; + datlen = detflag .* datalen(1:length(detflag)); - dat=fread(fid,hd(7)*hd(4),format); - dat=reshape(dat,[hd(4),hd(7)])'; - if(savedetflag && length(detflag)>2 && detflag(3)>0) - dat(:,sum(datlen(1:2))+1:sum(datlen(1:3)))=dat(:,sum(datlen(1:2))+1:sum(datlen(1:3)))*unitmm; - elseif(savedetflag==0) - dat(:,2+hd(2):(1+2*hd(2)))=dat(:,2+hd(2):(1+2*hd(2)))*unitmm; + dat = fread(fid, hd(7) * hd(4), format); + dat = reshape(dat, [hd(4), hd(7)])'; + if (savedetflag && length(detflag) > 2 && detflag(3) > 0) + dat(:, sum(datlen(1:2)) + 1:sum(datlen(1:3))) = dat(:, sum(datlen(1:2)) + 1:sum(datlen(1:3))) * unitmm; + elseif (savedetflag == 0) + dat(:, 2 + hd(2):(1 + 2 * hd(2))) = dat(:, 2 + hd(2):(1 + 2 * hd(2))) * unitmm; end - data=[data;dat]; - if(seedbyte>0) - try - seeds=fread(fid,hd(7)*seedbyte,'uchar'); - seeds=reshape(seeds,[seedbyte,hd(7)])'; - photonseed=[photonseed;seeds]; - catch - seedbyte=0; - warning('photon seed section is not found'); - end + data = [data; dat]; + if (seedbyte > 0) + try + seeds = fread(fid, hd(7) * seedbyte, 'uchar'); + seeds = reshape(seeds, [seedbyte, hd(7)])'; + photonseed = [photonseed; seeds]; + catch + seedbyte = 0; + warning('photon seed section is not found'); end - if(respin>1) - hd(5)=hd(5)*respin; - end - if(isempty(header)) - header=[hd;unitmm]'; - else - if(any(header([1:4 8])~=[hd([1:4])' unitmm])) - error('loadmch can only load data generated from a single session'); - else - header(5:7)=header(5:7)+hd(5:7)'; - end - end + end + if (respin > 1) + hd(5) = hd(5) * respin; + end + if (isempty(header)) + header = [hd; unitmm]'; + else + if (any(header([1:4 8]) ~= [hd([1:4])' unitmm])) + error('loadmch can only load data generated from a single session'); + else + header(5:7) = header(5:7) + hd(5:7)'; + end + end end fclose(fid); -if(nargout>=2) - headerstruct=struct('version',header(1),'medianum',header(2),'detnum',header(3),... - 'recordnum',header(4),'totalphoton',header(5),... - 'detectedphoton',header(6),'savedphoton',header(7),... - 'lengthunit',header(8),'seedbyte',seedbyte,'normalizer',normalizer,... - 'respin',respin,'srcnum',srcnum,'savedetflag',savedetflag,'totalsource',totalsource); +if (nargout >= 2) + headerstruct = struct('version', header(1), 'medianum', header(2), 'detnum', header(3), ... + 'recordnum', header(4), 'totalphoton', header(5), ... + 'detectedphoton', header(6), 'savedphoton', header(7), ... + 'lengthunit', header(8), 'seedbyte', seedbyte, 'normalizer', normalizer, ... + 'respin', respin, 'srcnum', srcnum, 'savedetflag', savedetflag, 'totalsource', totalsource); end diff --git a/utils/mcx2json.m b/utils/mcx2json.m index 522cbc56..2985c204 100644 --- a/utils/mcx2json.m +++ b/utils/mcx2json.m @@ -1,4 +1,4 @@ -function mcx2json(cfg,filestub) +function mcx2json(cfg, filestub) % % Format: % mcx2json(cfg,filestub) @@ -8,7 +8,7 @@ function mcx2json(cfg,filestub) % Author: Qianqian Fang % % Input: -% cfg: a struct defining the parameters associated with a simulation. +% cfg: a struct defining the parameters associated with a simulation. % Please run 'help mcxlab' or 'help mmclab' to see the details. % mcxpreview supports the cfg input for both mcxlab and mmclab. % filestub: the filestub is the name stub for all output files,including @@ -18,8 +18,8 @@ function mcx2json(cfg,filestub) % filestub_pattern.bin: the domain shape file if cfg.pattern is defined % % Dependency: -% this function depends on the savejson/saveubjson functions from the -% Iso2Mesh toolbox (http://iso2mesh.sf.net) or JSONlab toolbox +% this function depends on the savejson/saveubjson functions from the +% Iso2Mesh toolbox (http://iso2mesh.sf.net) or JSONlab toolbox % (http://iso2mesh.sf.net/jsonlab) % % This function is part of Monte Carlo eXtreme (MCX) URL: http://mcx.space @@ -27,164 +27,163 @@ function mcx2json(cfg,filestub) % License: GNU General Public License version 3, please read LICENSE.txt for details % -[fpath, fname, fext]=fileparts(filestub); -filestub=fullfile(fpath,fname); +[fpath, fname, fext] = fileparts(filestub); +filestub = fullfile(fpath, fname); %% define the optodes: sources and detectors -Optode.Source=struct(); -Optode.Source=copycfg(cfg,'srcpos',Optode.Source,'Pos'); -Optode.Source=copycfg(cfg,'srcdir',Optode.Source,'Dir'); -Optode.Source=copycfg(cfg,'srciquv',Optode.Source,'IQUV'); -Optode.Source=copycfg(cfg,'srcparam1',Optode.Source,'Param1'); -Optode.Source=copycfg(cfg,'srcparam2',Optode.Source,'Param2'); -Optode.Source=copycfg(cfg,'srctype',Optode.Source,'Type'); -Optode.Source=copycfg(cfg,'srcnum',Optode.Source,'SrcNum'); -Optode.Source=copycfg(cfg,'lambda',Optode.Source,'WaveLength'); - -if(isfield(cfg,'detpos') && ~isempty(cfg.detpos)) - Optode.Detector=struct(); - Optode.Detector=cell2struct(mat2cell(cfg.detpos, ones(1,size(cfg.detpos,1)),[3 1]), {'Pos','R'} ,2); - Optode.Detector=Optode.Detector(:)'; - if(length(Optode.Detector)==1) - Optode.Detector={Optode.Detector}; +Optode.Source = struct(); +Optode.Source = copycfg(cfg, 'srcpos', Optode.Source, 'Pos'); +Optode.Source = copycfg(cfg, 'srcdir', Optode.Source, 'Dir'); +Optode.Source = copycfg(cfg, 'srciquv', Optode.Source, 'IQUV'); +Optode.Source = copycfg(cfg, 'srcparam1', Optode.Source, 'Param1'); +Optode.Source = copycfg(cfg, 'srcparam2', Optode.Source, 'Param2'); +Optode.Source = copycfg(cfg, 'srctype', Optode.Source, 'Type'); +Optode.Source = copycfg(cfg, 'srcnum', Optode.Source, 'SrcNum'); +Optode.Source = copycfg(cfg, 'lambda', Optode.Source, 'WaveLength'); + +if (isfield(cfg, 'detpos') && ~isempty(cfg.detpos)) + Optode.Detector = struct(); + Optode.Detector = cell2struct(mat2cell(cfg.detpos, ones(1, size(cfg.detpos, 1)), [3 1]), {'Pos', 'R'}, 2); + Optode.Detector = Optode.Detector(:)'; + if (length(Optode.Detector) == 1) + Optode.Detector = {Optode.Detector}; end end -if(isfield(cfg,'srcpattern') && ~isempty(cfg.srcpattern)) - Optode.Source.Pattern=single(cfg.srcpattern); +if (isfield(cfg, 'srcpattern') && ~isempty(cfg.srcpattern)) + Optode.Source.Pattern = single(cfg.srcpattern); end %% define the domain and optical properties -Domain=struct(); -Domain=copycfg(cfg,'issrcfrom0',Domain,'OriginType',0); -Domain=copycfg(cfg,'unitinmm',Domain,'LengthUnit'); -Domain=copycfg(cfg,'invcdf',Domain,'InverseCDF'); -Domain=copycfg(cfg,'angleinvcdf',Domain,'AngleInverseCDF'); +Domain = struct(); +Domain = copycfg(cfg, 'issrcfrom0', Domain, 'OriginType', 0); +Domain = copycfg(cfg, 'unitinmm', Domain, 'LengthUnit'); +Domain = copycfg(cfg, 'invcdf', Domain, 'InverseCDF'); +Domain = copycfg(cfg, 'angleinvcdf', Domain, 'AngleInverseCDF'); -Domain.Media=cell2struct(num2cell(cfg.prop), {'mua','mus','g','n'} ,2)'; +Domain.Media = cell2struct(num2cell(cfg.prop), {'mua', 'mus', 'g', 'n'}, 2)'; -if(isfield(cfg,'polprop') && ~isempty(cfg.polprop)) - Domain.MieScatter=cell2struct(num2cell(cfg.polprop), {'mua','radius','rho','nsph','nmed'}, 2)'; +if (isfield(cfg, 'polprop') && ~isempty(cfg.polprop)) + Domain.MieScatter = cell2struct(num2cell(cfg.polprop), {'mua', 'radius', 'rho', 'nsph', 'nmed'}, 2)'; end -if(isfield(cfg,'shapes') && ischar(cfg.shapes)) - Shapes=loadjson(cfg.shapes); - Shapes=Shapes.Shapes; +if (isfield(cfg, 'shapes') && ischar(cfg.shapes)) + Shapes = loadjson(cfg.shapes); + Shapes = Shapes.Shapes; end -if(isfield(cfg,'vol') && ~isempty(cfg.vol) && ~isfield(Domain,'VolumeFile')) - switch(class(cfg.vol)) - case {'uint8','int8'} - Domain.MediaFormat='byte'; - if(ndims(cfg.vol)==4 && size(cfg.vol,1)==4) - Domain.MediaFormat='asgn_byte'; - elseif(ndims(cfg.vol)==4 && size(cfg.vol,1)==8) - cfg.vol=reshape(typecast(uint8(cfg.vol(:)),'uint64'),size(cfg.vol,2,3,4)); - Domain.MediaFormat='svmc'; +if (isfield(cfg, 'vol') && ~isempty(cfg.vol) && ~isfield(Domain, 'VolumeFile')) + switch (class(cfg.vol)) + case {'uint8', 'int8'} + Domain.MediaFormat = 'byte'; + if (ndims(cfg.vol) == 4 && size(cfg.vol, 1) == 4) + Domain.MediaFormat = 'asgn_byte'; + elseif (ndims(cfg.vol) == 4 && size(cfg.vol, 1) == 8) + cfg.vol = reshape(typecast(uint8(cfg.vol(:)), 'uint64'), size(cfg.vol, 2, 3, 4)); + Domain.MediaFormat = 'svmc'; end - case {'uint16','int16'} - Domain.MediaFormat='short'; - if(ndims(cfg.vol)==4 && size(cfg.vol,1)==2) - Domain.MediaFormat='muamus_short'; + case {'uint16', 'int16'} + Domain.MediaFormat = 'short'; + if (ndims(cfg.vol) == 4 && size(cfg.vol, 1) == 2) + Domain.MediaFormat = 'muamus_short'; end - case {'uint32','int32'} - Domain.MediaFormat='integer'; - case {'single','double'} - if(isa(cfg.vol,'double')) - cfg.vol=single(cfg.vol); + case {'uint32', 'int32'} + Domain.MediaFormat = 'integer'; + case {'single', 'double'} + if (isa(cfg.vol, 'double')) + cfg.vol = single(cfg.vol); end - if(all(mod(cfg.vol(:),1) == 0)) - if(max(cfg.vol(:))<256) - Domain.MediaFormat='byte'; - cfg.vol=uint8(cfg.vol); + if (all(mod(cfg.vol(:), 1) == 0)) + if (max(cfg.vol(:)) < 256) + Domain.MediaFormat = 'byte'; + cfg.vol = uint8(cfg.vol); else - Domain.MediaFormat='integer'; - cfg.vol=uint32(cfg.vol); + Domain.MediaFormat = 'integer'; + cfg.vol = uint32(cfg.vol); end - elseif(ndims(cfg.vol)==4) - if(size(cfg.vol,1))==1 - Domain.MediaFormat='mua_float'; - elseif(size(cfg.vol,1)==2) - Domain.MediaFormat='muamus_float'; - elseif(size(cfg.vol,1)==4) - Domain.MediaFormat='asgn_float'; + elseif (ndims(cfg.vol) == 4) + if (size(cfg.vol, 1)) == 1 + Domain.MediaFormat = 'mua_float'; + elseif (size(cfg.vol, 1) == 2) + Domain.MediaFormat = 'muamus_float'; + elseif (size(cfg.vol, 1) == 4) + Domain.MediaFormat = 'asgn_float'; end end otherwise error('cfg.vol has format that is not supported'); end - Domain.Dim=size(cfg.vol); - if(length(Domain.Dim)==4) - Domain.Dim(1)=[]; + Domain.Dim = size(cfg.vol); + if (length(Domain.Dim) == 4) + Domain.Dim(1) = []; end - if(exist('Shapes','var')) - Domain.VolumeFile=[filestub '_vol.bin']; - fid=fopen(Domain.VolumeFile,'wb'); - fwrite(fid,cfg.vol,class(cfg.vol)); + if (exist('Shapes', 'var')) + Domain.VolumeFile = [filestub '_vol.bin']; + fid = fopen(Domain.VolumeFile, 'wb'); + fwrite(fid, cfg.vol, class(cfg.vol)); fclose(fid); else - Domain.VolumeFile=''; - Shapes=cfg.vol; - if(ndims(Shapes)==4 && size(Shapes,1)>1) - Shapes=permute(Shapes, [2 3 4 1]); + Domain.VolumeFile = ''; + Shapes = cfg.vol; + if (ndims(Shapes) == 4 && size(Shapes, 1) > 1) + Shapes = permute(Shapes, [2 3 4 1]); end end end %% define the simulation session flags -Session.ID=filestub; -Session=copycfg(cfg,'isreflect',Session,'DoMismatch'); -Session=copycfg(cfg,'issave2pt',Session,'DoSaveVolume'); -Session=copycfg(cfg,'issavedet',Session,'DoPartialPath'); -Session=copycfg(cfg,'issaveexit',Session,'DoSaveExit'); -Session=copycfg(cfg,'issaveseed',Session,'DoSaveSeed'); -Session=copycfg(cfg,'isnormalize',Session,'DoNormalize'); -Session=copycfg(cfg,'outputformat',Session,'OutputFormat'); -Session=copycfg(cfg,'outputtype',Session,'OutputType'); -Session=copycfg(cfg,'debuglevel',Session,'Debug'); -Session=copycfg(cfg,'autopilot',Session,'DoAutoThread'); -Session=copycfg(cfg,'maxdetphoton',Session,'MaxDetPhoton'); -Session=copycfg(cfg,'bc',Session,'BCFlags'); - -if(isfield(cfg,'savedetflag') && ~isempty(cfg.savedetflag) && ischar(cfg.savedetflag)) - cfg.savedetflag=upper(cfg.savedetflag); +Session.ID = filestub; +Session = copycfg(cfg, 'isreflect', Session, 'DoMismatch'); +Session = copycfg(cfg, 'issave2pt', Session, 'DoSaveVolume'); +Session = copycfg(cfg, 'issavedet', Session, 'DoPartialPath'); +Session = copycfg(cfg, 'issaveexit', Session, 'DoSaveExit'); +Session = copycfg(cfg, 'issaveseed', Session, 'DoSaveSeed'); +Session = copycfg(cfg, 'isnormalize', Session, 'DoNormalize'); +Session = copycfg(cfg, 'outputformat', Session, 'OutputFormat'); +Session = copycfg(cfg, 'outputtype', Session, 'OutputType'); +Session = copycfg(cfg, 'debuglevel', Session, 'Debug'); +Session = copycfg(cfg, 'autopilot', Session, 'DoAutoThread'); +Session = copycfg(cfg, 'maxdetphoton', Session, 'MaxDetPhoton'); +Session = copycfg(cfg, 'bc', Session, 'BCFlags'); + +if (isfield(cfg, 'savedetflag') && ~isempty(cfg.savedetflag) && ischar(cfg.savedetflag)) + cfg.savedetflag = upper(cfg.savedetflag); end -Session=copycfg(cfg,'savedetflag',Session,'SaveDataMask'); +Session = copycfg(cfg, 'savedetflag', Session, 'SaveDataMask'); -if(isfield(cfg,'seed') && numel(cfg.seed)==1) - Session.RNGSeed=cfg.seed; +if (isfield(cfg, 'seed') && numel(cfg.seed) == 1) + Session.RNGSeed = cfg.seed; end -Session=copycfg(cfg,'nphoton',Session,'Photons'); -Session=copycfg(cfg,'minenergy',Session,'MinEnergy'); -Session=copycfg(cfg,'rootpath',Session,'RootPath'); +Session = copycfg(cfg, 'nphoton', Session, 'Photons'); +Session = copycfg(cfg, 'minenergy', Session, 'MinEnergy'); +Session = copycfg(cfg, 'rootpath', Session, 'RootPath'); %% define the forward simulation settings -Forward.T0=cfg.tstart; -Forward.T1=cfg.tend; -Forward.Dt=cfg.tstep; +Forward.T0 = cfg.tstart; +Forward.T1 = cfg.tend; +Forward.Dt = cfg.tstep; %% assemble the complete input, save to a JSON or UBJSON input file -mcxsession=struct('Session', Session, 'Forward', Forward, 'Optode',Optode, 'Domain', Domain); -if(exist('Shapes','var')) - mcxsession.Shapes=Shapes; +mcxsession = struct('Session', Session, 'Forward', Forward, 'Optode', Optode, 'Domain', Domain); +if (exist('Shapes', 'var')) + mcxsession.Shapes = Shapes; end -if(strcmp(fext,'ubj')) - saveubjson('',mcxsession,[filestub,'.ubj']); +if (strcmp(fext, 'ubj')) + saveubjson('', mcxsession, [filestub, '.ubj']); else - savejson('',mcxsession,'filename',[filestub,'.json'],'compression','zlib'); + savejson('', mcxsession, 'filename', [filestub, '.json'], 'compression', 'zlib'); end - -function outdata=copycfg(cfg,name,outroot,outfield,defaultval) -if(nargin>=5) - outroot.(outfield)=defaultval; +function outdata = copycfg(cfg, name, outroot, outfield, defaultval) +if (nargin >= 5) + outroot.(outfield) = defaultval; end -if(isfield(cfg,name)) - outroot.(outfield)=cfg.(name); +if (isfield(cfg, name)) + outroot.(outfield) = cfg.(name); end -outdata=outroot; +outdata = outroot; diff --git a/utils/mcxcreate.m b/utils/mcxcreate.m index ad276f96..36ada95e 100644 --- a/utils/mcxcreate.m +++ b/utils/mcxcreate.m @@ -1,4 +1,4 @@ -function cfg=mcxcreate(benchname,varargin) +function cfg = mcxcreate(benchname, varargin) % % Format: % list=mcxcreate @@ -11,7 +11,7 @@ % % Input: % benchname (optional): a string to specify the name of the benchmark -% +% % Output: % cfg: a struct defining the parameters associated with a simulation. If % no input, this function returns a list of supported benchmarks. @@ -26,78 +26,78 @@ % License: GNU General Public License version 3, please read LICENSE.txt for details % -mcxbench.cube60=struct(... - 'nphoton',1e6,... - 'vol',uint8(ones(60,60,60)),... - 'srctype','pencil','srcpos',[29 29 0],'srcdir',[0 0 1],... - 'prop',[0 0 1 1;0.005 1 0.01 1.37],... - 'tstart',0,'tend',5e-9,'tstep',5e-9,.... - 'isreflect',0,'seed',1648335518,'issrcfrom0',1,... - 'detpos',[29,19,0,1;29,39,0,1;19,29,0,1;39,29,0,1]); +mcxbench.cube60 = struct( ... + 'nphoton', 1e6, ... + 'vol', uint8(ones(60, 60, 60)), ... + 'srctype', 'pencil', 'srcpos', [29 29 0], 'srcdir', [0 0 1], ... + 'prop', [0 0 1 1; 0.005 1 0.01 1.37], ... + 'tstart', 0, 'tend', 5e-9, 'tstep', 5e-9, .... + 'isreflect', 0, 'seed', 1648335518, 'issrcfrom0', 1, ... + 'detpos', [29, 19, 0, 1; 29, 39, 0, 1; 19, 29, 0, 1; 39, 29, 0, 1]); -mcxbench.cube60b=mcxbench.cube60; -mcxbench.cube60b.isreflect=1; +mcxbench.cube60b = mcxbench.cube60; +mcxbench.cube60b.isreflect = 1; -mcxbench.cube60planar=mcxbench.cube60b; -mcxbench.cube60planar.srctype='planar'; -mcxbench.cube60planar.srcpos=[10.0, 10.0, -10.0]; -mcxbench.cube60planar.srcparam1=[40.0, 0.0, 0.0, 0.0]; -mcxbench.cube60planar.srcparam2=[0.0, 40.0, 0.0, 0.0]; +mcxbench.cube60planar = mcxbench.cube60b; +mcxbench.cube60planar.srctype = 'planar'; +mcxbench.cube60planar.srcpos = [10.0, 10.0, -10.0]; +mcxbench.cube60planar.srcparam1 = [40.0, 0.0, 0.0, 0.0]; +mcxbench.cube60planar.srcparam2 = [0.0, 40.0, 0.0, 0.0]; -mcxbench.skinvessel=struct(... - 'nphoton',1e6,... - 'vol',uint8(ones(200,200,200)),... - 'srctype','disk','srcpos',[100 100 20],'srcdir',[0 0 1],... - 'srcparam1',[60 0 0 0],'unitinmm',0.005,... - 'prop',[0 0 1 1;3.564e-05 1 1 1.37;... - 23.05426549 9.398496241 0.9 1.37;... - 0.04584957865 35.65405549 0.9 1.37;... - 1.657237447 37.59398496 0.9 1.37],... - 'tstart',0,'tend',5e-8,'tstep',5e-8,.... - 'isreflect',0,'seed',1648335518,'issrcfrom0',1); -mcxbench.skinvessel.shapes=['{"Shapes":[{"ZLayers":[[1,20,1],[21,32,4],[33,200,3]]},' ... - '{"Cylinder": {"Tag":2, "C0": [0,100.5,100.5], "C1": [200,100.5,100.5], "R": 20}}]}']; +mcxbench.skinvessel = struct( ... + 'nphoton', 1e6, ... + 'vol', uint8(ones(200, 200, 200)), ... + 'srctype', 'disk', 'srcpos', [100 100 20], 'srcdir', [0 0 1], ... + 'srcparam1', [60 0 0 0], 'unitinmm', 0.005, ... + 'prop', [0 0 1 1; 3.564e-05 1 1 1.37; ... + 23.05426549 9.398496241 0.9 1.37; ... + 0.04584957865 35.65405549 0.9 1.37; ... + 1.657237447 37.59398496 0.9 1.37], ... + 'tstart', 0, 'tend', 5e-8, 'tstep', 5e-8, .... + 'isreflect', 0, 'seed', 1648335518, 'issrcfrom0', 1); +mcxbench.skinvessel.shapes = ['{"Shapes":[{"ZLayers":[[1,20,1],[21,32,4],[33,200,3]]},' ... + '{"Cylinder": {"Tag":2, "C0": [0,100.5,100.5], "C1": [200,100.5,100.5], "R": 20}}]}']; -mcxbench.sphshell=struct(... - 'nphoton',1e6,... - 'vol',uint8(ones(60,60,60)),... - 'srctype','pencil','srcpos',[30 30.1 0],'srcdir',[0 0 1],... - 'prop',[0 0 1 1;... - 0.02 7 0.89 1.37;... - 0.004 0.009 0.89 1.37;... - 0.02 9.0 0.89 1.37;... - 0.05 0.0 1.00 1.37],... - 'tstart',0,'tend',5e-9,'tstep',5e-9,.... - 'isreflect',1,'seed',1648335518,'issrcfrom0',1); -mcxbench.sphshell.shapes=['{"Shapes":[{"Grid":{"Tag":1,"Size":[60,60,60]}},'... - '{"Sphere":{"Tag":2,"O":[30,30,30],"R":25}},'... - '{"Sphere":{"Tag":3,"O":[30,30,30],"R":23}},'... - '{"Sphere":{"Tag":4,"O":[30,30,30],"R":10}}]}']; -mcxbench.sphshell.detpos=mcxbench.cube60.detpos; +mcxbench.sphshell = struct( ... + 'nphoton', 1e6, ... + 'vol', uint8(ones(60, 60, 60)), ... + 'srctype', 'pencil', 'srcpos', [30 30.1 0], 'srcdir', [0 0 1], ... + 'prop', [0 0 1 1; ... + 0.02 7 0.89 1.37; ... + 0.004 0.009 0.89 1.37; ... + 0.02 9.0 0.89 1.37; ... + 0.05 0.0 1.00 1.37], ... + 'tstart', 0, 'tend', 5e-9, 'tstep', 5e-9, .... + 'isreflect', 1, 'seed', 1648335518, 'issrcfrom0', 1); +mcxbench.sphshell.shapes = ['{"Shapes":[{"Grid":{"Tag":1,"Size":[60,60,60]}},'... + '{"Sphere":{"Tag":2,"O":[30,30,30],"R":25}},'... + '{"Sphere":{"Tag":3,"O":[30,30,30],"R":23}},'... + '{"Sphere":{"Tag":4,"O":[30,30,30],"R":10}}]}']; +mcxbench.sphshell.detpos = mcxbench.cube60.detpos; -mcxbench.spherebox=struct(... - 'nphoton',1e6,... - 'vol',uint8(ones(60,60,60)),... - 'srcpos',[29.5, 29.5 0],'srcdir',[0 0 1],... - 'prop',[0 0 1 1;... - 0.002 1 0.01 1.37;... - 0.05 5 0.9 1.37],... - 'tstart',0,'tend',5e-9,'tstep',1e-10,.... - 'isreflect',0,'seed',1648335518,'issrcfrom0',1); -mcxbench.spherebox.shapes=['{"Shapes":[{"Grid":{"Tag":1,"Size":[60,60,60]}},'... - '{"Sphere":{"Tag":2,"O":[30,30,30],"R":10}}]}']; +mcxbench.spherebox = struct( ... + 'nphoton', 1e6, ... + 'vol', uint8(ones(60, 60, 60)), ... + 'srcpos', [29.5, 29.5 0], 'srcdir', [0 0 1], ... + 'prop', [0 0 1 1; ... + 0.002 1 0.01 1.37; ... + 0.05 5 0.9 1.37], ... + 'tstart', 0, 'tend', 5e-9, 'tstep', 1e-10, .... + 'isreflect', 0, 'seed', 1648335518, 'issrcfrom0', 1); +mcxbench.spherebox.shapes = ['{"Shapes":[{"Grid":{"Tag":1,"Size":[60,60,60]}},'... + '{"Sphere":{"Tag":2,"O":[30,30,30],"R":10}}]}']; -if(nargin==0) - cfg=fieldnames(mcxbench); - return; +if (nargin == 0) + cfg = fieldnames(mcxbench); + return end -if(isfield(mcxbench,benchname)) - cfg=mcxbench.(benchname); - if(~isempty(varargin)) - for i=1:2:length(varargin) - if(ischar(varargin{i}) && i+1<=length(varargin)) - cfg.(lower(varargin{i}))=varargin{i+1}; +if (isfield(mcxbench, benchname)) + cfg = mcxbench.(benchname); + if (~isempty(varargin)) + for i = 1:2:length(varargin) + if (ischar(varargin{i}) && i + 1 <= length(varargin)) + cfg.(lower(varargin{i})) = varargin{i + 1}; else error('input must be in the form of ...,''name'',value,... pairs or structs'); end @@ -105,4 +105,4 @@ end else error('benchmark name is not supported'); -end \ No newline at end of file +end diff --git a/utils/mcxcwdref.m b/utils/mcxcwdref.m index 4c4c3d17..ca0dc002 100644 --- a/utils/mcxcwdref.m +++ b/utils/mcxcwdref.m @@ -3,12 +3,12 @@ % [dref] = mcxcwdref(detp, cfg) % % Compute CW diffuse reflectance from MC detected photon profiles -% +% % author: Shijie Yan (yan.shiji northeastern.edu) % % input: % detp: profiles of detected photons -% cfg: a struct, or struct array. Each element of cfg defines +% cfg: a struct, or struct array. Each element of cfg defines % the parameters associated with a MC simulation. % % output: @@ -18,16 +18,16 @@ % License: GPLv3, see http://mcx.sf.net for details % see Yao2018 % - unitinmm=1; - if(isfield(cfg,'unitinmm')) - unitinmm=cfg.unitinmm; - end - detweight = mcxdetweight(detp, cfg.prop); - detnum = length(unique(detp.detid)); - detweightsum = zeros(detnum, 1); - for i = 1 : length(detp.detid) - detweightsum(detp.detid(i)) = detweightsum(detp.detid(i)) + detweight(i); - end - area = pi * (cfg.detpos(:,4)*unitinmm).^2; - dref = detweightsum ./ area / cfg.nphoton; % Eq.12 of photon replay paper[Yao2018] -end \ No newline at end of file +unitinmm = 1; +if (isfield(cfg, 'unitinmm')) + unitinmm = cfg.unitinmm; +end +detweight = mcxdetweight(detp, cfg.prop); +detnum = length(unique(detp.detid)); +detweightsum = zeros(detnum, 1); +for i = 1:length(detp.detid) + detweightsum(detp.detid(i)) = detweightsum(detp.detid(i)) + detweight(i); +end +area = pi * (cfg.detpos(:, 4) * unitinmm).^2; +dref = detweightsum ./ area / cfg.nphoton; % Eq.12 of photon replay paper[Yao2018] +end diff --git a/utils/mcxdcsg1.m b/utils/mcxdcsg1.m index 841b731a..107d4ba3 100644 --- a/utils/mcxdcsg1.m +++ b/utils/mcxdcsg1.m @@ -1,4 +1,4 @@ -function [tau,g1]=mcxdcsg1(detps,tau, disp_model, DV, lambda, format, varargin) +function [tau, g1] = mcxdcsg1(detps, tau, disp_model, DV, lambda, format, varargin) % % [tau,g1]=mcxdcsg1(detps,tau, disp_model, DV, lambda, format) % @@ -9,7 +9,7 @@ % % input: % detps: the file name of the output .mch file or the 2nd output from mcxlab -% tau: correlation times at which to compute g1 +% tau: correlation times at which to compute g1 % (default: 1e-7 to 1e-1 seconds, log equidistant) % disp_model: displacement model ('brownian', 'random_flow', ) % (default: brownian, see further explanation below) @@ -18,89 +18,96 @@ % (default: 1e-7 mm^2/s, see further explanation below) % lambda: wavelenght of light used in nm % (default: 785) -% format: the format used to save the .mch file +% format: the format used to save the .mch file % (default: 'float') % % output: % % tau: correlation times at which g1 was computed provided for -% convenience (copied from input if set, otherwise +% convenience (copied from input if set, otherwise % outputs default) % g1: field auto-correlation curves, one for each detector % % The displacement model indicates the formula used to compute the root % mean square displacement of scattering particles during a given delay -% -% brownian: RMS= 6 * DV * tau; +% +% brownian: RMS= 6 * DV * tau; % DV(displacement variable)=Db (brownian diffusion coeff) -% random_flow: RMS= DV^2 * tau^2; +% random_flow: RMS= DV^2 * tau^2; % DV = V (first moment of velocity distribution) % : any string other than 'brownian' or 'random_flow' will % be evaluate as is using Matlab evalf, make sure it uses % 'DV' as the flow related independent variable, tau is -% indexed as tau(J). Any additional parameters can be +% indexed as tau(J). Any additional parameters can be % sent via "varargin" % % This file is part of Mesh-Based Monte Carlo % License: GPLv3, see http://mcx.space for details % -if nargin<6, format='float'; end -if nargin<5, lambda=785; end -if nargin<4, DV=1e-7; end -if nargin<3, disp_model='brownian'; end -if nargin<2, tau=logspace(-7,-1,200); end +if nargin < 6 + format = 'float'; +end +if nargin < 5 + lambda = 785; +end +if nargin < 4 + DV = 1e-7; +end +if nargin < 3 + disp_model = 'brownian'; +end +if nargin < 2 + tau = logspace(-7, -1, 200); +end -if(ischar(detps)) - [mch_data,mch_header]=loadmch(detps,format); - [fpath,fname,fext]=fileparts(detps); +if (ischar(detps)) + [mch_data, mch_header] = loadmch(detps, format); + [fpath, fname, fext] = fileparts(detps); - cfg=loadjson([fpath filesep fname '.json']); - prop=cell2mat(cfg.Domain.Media) - mua=cell2mat({prop.mua}); - mua=mua(2:end); - n=cell2mat({prop.n}); - n=n(2:end); - medianum=length(mua)-1; - detps=struct('detid',mch_data(1,:)'); - detps.ppath=mch_data(3:2+medianum,:)'; - if(size(mch_data,1)>=2*medianum+2) - detps.mom=mch_data(medianum+3:2*medianum+2,:)'; - end + cfg = loadjson([fpath filesep fname '.json']); + prop = cell2mat(cfg.Domain.Media); + mua = cell2mat({prop.mua}); + mua = mua(2:end); + n = cell2mat({prop.n}); + n = n(2:end); + medianum = length(mua) - 1; + detps = struct('detid', mch_data(1, :)'); + detps.ppath = mch_data(3:2 + medianum, :)'; + if (size(mch_data, 1) >= 2 * medianum + 2) + detps.mom = mch_data(medianum + 3:2 * medianum + 2, :)'; + end else - mua=detps.prop(2:end,1)'; - n=detps.prop(2:end,4)'; + mua = detps.prop(2:end, 1)'; + n = detps.prop(2:end, 4)'; end -if(~isfield(detps,'mom')) - error('No momentum transfer data are found, please rerun your simulation and set cfg.ismomentum=1.'); +if (~isfield(detps, 'mom')) + error('No momentum transfer data are found, please rerun your simulation and set cfg.ismomentum=1.'); end -if strcmp(disp_model,'brownian'), - disp_str='rmsdisp=6*DV.*tau(J);'; -elseif strcmp(disp_model,'random_flow'), - disp_str='rmsdisp=DV.^2.*tau(J).^2;'; -else - disp_str=['rmsdisp=' disp_model ';']; +if strcmp(disp_model, 'brownian') + disp_str = 'rmsdisp=6*DV.*tau(J);'; +elseif strcmp(disp_model, 'random_flow') + disp_str = 'rmsdisp=DV.^2.*tau(J).^2;'; +else + disp_str = ['rmsdisp=' disp_model ';']; end -k0=2*pi*n/(lambda*1e-6); +k0 = 2 * pi * n / (lambda * 1e-6); -detlist=sort(unique(detps.detid)); -g1=zeros(max(detlist),length(tau)); +detlist = sort(unique(detps.detid)); +g1 = zeros(max(detlist), length(tau)); -for detid=1:length(detlist) - I=detlist(detid); - idx= find(detps.detid==I); - fprintf('Processing detector %.0f: %.0f photons\n',I,length(idx)); +for detid = 1:length(detlist) + I = detlist(detid); + idx = find(detps.detid == I); + fprintf('Processing detector %.0f: %.0f photons\n', I, length(idx)); - for J=1:length(tau), + for J = 1:length(tau) eval(disp_str); - g1(I,J)=sum(exp(-(k0.^2.*rmsdisp/3)*detps.mom'-mua*detps.ppath')); + g1(I, J) = sum(exp(-(k0.^2 .* rmsdisp / 3) * detps.mom' - mua * detps.ppath')); end - g1_norm=sum(exp(-mua*detps.ppath')); - g1(I,:)=g1(I,:)./g1_norm; + g1_norm = sum(exp(-mua * detps.ppath')); + g1(I, :) = g1(I, :) ./ g1_norm; end - - - diff --git a/utils/mcxdetphoton.m b/utils/mcxdetphoton.m index c904ff1d..c93893e3 100644 --- a/utils/mcxdetphoton.m +++ b/utils/mcxdetphoton.m @@ -1,4 +1,4 @@ -function newdetp=mcxdetphoton(detp, medianum, savedetflag, issaveref, srcnum) +function newdetp = mcxdetphoton(detp, medianum, savedetflag, issaveref, srcnum) % % newdetp=mcxdetphoton(detp, medianum, savedetflag) % newdetp=mcxdetphoton(detp, medianum, savedetflag, issaveref, srcnum) @@ -31,52 +31,52 @@ % License: GPLv3, see http://mcx.space/ for details % -c0=1; -len=1; -if(regexp(savedetflag,'[dD]')) - if(nargin>3 && issaveref>1) - newdetp.w0=detp(1,:)'; +c0 = 1; +len = 1; +if (regexp(savedetflag, '[dD]')) + if (nargin > 3 && issaveref > 1) + newdetp.w0 = detp(1, :)'; else - newdetp.detid=int32(detp(1,:))'; - if(any(newdetp.detid>65535)) - newdetp.srcid=bitshift(newdetp.detid,-16); - newdetp.detid=bitand(newdetp.detid,int32(hex2dec('ffff'))); + newdetp.detid = int32(detp(1, :))'; + if (any(newdetp.detid > 65535)) + newdetp.srcid = bitshift(newdetp.detid, -16); + newdetp.detid = bitand(newdetp.detid, int32(hex2dec('ffff'))); end end - c0=2; + c0 = 2; end -len=medianum; -if(regexp(savedetflag,'[sS]')) - newdetp.nscat=int32(detp(c0:(c0+len-1),:))'; % 1st medianum block is num of scattering - c0=c0+len; +len = medianum; +if (regexp(savedetflag, '[sS]')) + newdetp.nscat = int32(detp(c0:(c0 + len - 1), :))'; % 1st medianum block is num of scattering + c0 = c0 + len; end -if(regexp(savedetflag,'[pP]')) - newdetp.ppath=detp(c0:(c0+len-1),:)';% 2nd medianum block is partial path - c0=c0+len; +if (regexp(savedetflag, '[pP]')) + newdetp.ppath = detp(c0:(c0 + len - 1), :)'; % 2nd medianum block is partial path + c0 = c0 + len; end -if(regexp(savedetflag,'[mM]')) - newdetp.mom=detp(c0:(c0+len-1),:)'; % 3rd medianum block is the momentum transfer - c0=c0+len; +if (regexp(savedetflag, '[mM]')) + newdetp.mom = detp(c0:(c0 + len - 1), :)'; % 3rd medianum block is the momentum transfer + c0 = c0 + len; end -len=3; -if(regexp(savedetflag,'[xX]')) - newdetp.p=detp(c0:(c0+len-1),:)'; %columns 7-5 from the right store the exit positions - c0=c0+len; +len = 3; +if (regexp(savedetflag, '[xX]')) + newdetp.p = detp(c0:(c0 + len - 1), :)'; % columns 7-5 from the right store the exit positions + c0 = c0 + len; end -if(regexp(savedetflag,'[vV]')) - newdetp.v=detp(c0:(c0+len-1),:)'; %columns 4-2 from the right store the exit dirs - c0=c0+len; +if (regexp(savedetflag, '[vV]')) + newdetp.v = detp(c0:(c0 + len - 1), :)'; % columns 4-2 from the right store the exit dirs + c0 = c0 + len; end -if(regexp(savedetflag,'[wW]')) - len=1; - newdetp.w0=detp(c0:(c0+len-1),:)'; % last column is the initial packet weight - if(nargin>4 && srcnum>1) - newdetp.w0=typecast(newdetp.w0,'uint32'); +if (regexp(savedetflag, '[wW]')) + len = 1; + newdetp.w0 = detp(c0:(c0 + len - 1), :)'; % last column is the initial packet weight + if (nargin > 4 && srcnum > 1) + newdetp.w0 = typecast(newdetp.w0, 'uint32'); end - c0=c0+len; + c0 = c0 + len; +end +if (regexp(savedetflag, '[iI]')) + len = 4; + newdetp.s = detp(c0:(c0 + len - 1), :)'; + c0 = c0 + len; end -if(regexp(savedetflag,'[iI]')) - len=4; - newdetp.s=detp(c0:(c0+len-1),:)'; - c0=c0+len; -end \ No newline at end of file diff --git a/utils/mcxdettime.m b/utils/mcxdettime.m index b58e7cc2..dfa37ee3 100644 --- a/utils/mcxdettime.m +++ b/utils/mcxdettime.m @@ -1,17 +1,17 @@ -function dett=mcxdettime(detp,prop,unitinmm) +function dett = mcxdettime(detp, prop, unitinmm) % % dett=mcxdettime(detp,prop,unitinmm) % -% Recalculate the detected photon time using partial path data and +% Recalculate the detected photon time using partial path data and % optical properties (for perturbation Monte Carlo or detector readings) % % author: Qianqian Fang (q.fang neu.edu) -% Ruoyang Yao (yaor rpi.edu) +% Ruoyang Yao (yaor rpi.edu) % % input: % detp: the 2nd output from mcxlab. detp must be a struct % prop: optical property list, as defined in the cfg.prop field of mcxlab's input -% unitinmm: voxel edge-length in mm, should use cfg.unitinmm used to generate detp; +% unitinmm: voxel edge-length in mm, should use cfg.unitinmm used to generate detp; % if ignored, assume to be 1 (mm) % % output: @@ -22,33 +22,33 @@ % License: GPLv3, see http://mcx.space/ for details % -R_C0 = 3.335640951981520e-12; % inverse of light speed in vacuum +R_C0 = 3.335640951981520e-12; % inverse of light speed in vacuum -if(nargin<3) - if(isfield(detp,'unitinmm')) - unitinmm=detp.unitinmm; +if (nargin < 3) + if (isfield(detp, 'unitinmm')) + unitinmm = detp.unitinmm; else - unitinmm=1; + unitinmm = 1; end end -if(nargin<2) - if(isfield(detp,'prop')) - prop=detp.prop; +if (nargin < 2) + if (isfield(detp, 'prop')) + prop = detp.prop; else error('must provide input "prop"'); end end -medianum=size(prop,1); -if(medianum<=1) +medianum = size(prop, 1); +if (medianum <= 1) error('empty property list'); end -if(isstruct(detp)) - dett=zeros(size(detp.ppath,1),1); - for i=1:medianum-1 - dett=dett+prop(i+1,4)*detp.ppath(:,i)*R_C0*unitinmm; +if (isstruct(detp)) + dett = zeros(size(detp.ppath, 1), 1); + for i = 1:medianum - 1 + dett = dett + prop(i + 1, 4) * detp.ppath(:, i) * R_C0 * unitinmm; end else error('the first input must be a struct with a subfield named "ppath"'); diff --git a/utils/mcxdettpsf.m b/utils/mcxdettpsf.m index 20d69a94..ea171aea 100644 --- a/utils/mcxdettpsf.m +++ b/utils/mcxdettpsf.m @@ -1,4 +1,4 @@ -function tpsf = mcxdettpsf(detp,detnum,prop,time) +function tpsf = mcxdettpsf(detp, detnum, prop, time) % % tpsf=mcxdettpsf(detp,detnum,prop,time) % @@ -6,7 +6,7 @@ % given the partial path data, optical properties, and distribution of time bins % % author: Qianqian Fang (q.fang neu.edu) -% Ruoyang Yao (yaor rpi.edu) +% Ruoyang Yao (yaor rpi.edu) % % input: % detp: the 2nd output from mcxlab. detp must be a struct with detid and ppath subfields @@ -23,25 +23,25 @@ % % select the photon data of the specified detector -detp.ppath=detp.ppath(detp.detid==detnum,:); -detp.detid=detp.detid(detp.detid==detnum); +detp.ppath = detp.ppath(detp.detid == detnum, :); +detp.detid = detp.detid(detp.detid == detnum); % calculate the detected photon weight and arrival time -replayweight=mcxdetweight(detp,prop); -replaytime=mcxdettime(detp,prop); +replayweight = mcxdetweight(detp, prop); +replaytime = mcxdettime(detp, prop); % define temporal point spread function vector -nTG = round((time(2)-time(1))/time(3)); % maximum time gate number -tpsf = zeros(nTG,1); +nTG = round((time(2) - time(1)) / time(3)); % maximum time gate number +tpsf = zeros(nTG, 1); % calculate the time bin, make sure not to exceed the boundary -ntg = ceil((replaytime-time(1))/time(3)); -ntg(ntg<1)=1; -ntg(ntg>nTG)=nTG; +ntg = ceil((replaytime - time(1)) / time(3)); +ntg(ntg < 1) = 1; +ntg(ntg > nTG) = nTG; % add each photon weight to corresponding time bin -for i=1:length(replayweight) - tpsf(ntg(i)) = tpsf(ntg(i))+replayweight(i); +for i = 1:length(replayweight) + tpsf(ntg(i)) = tpsf(ntg(i)) + replayweight(i); end end diff --git a/utils/mcxdetweight.m b/utils/mcxdetweight.m index 2b24fb79..66508a84 100644 --- a/utils/mcxdetweight.m +++ b/utils/mcxdetweight.m @@ -1,16 +1,16 @@ -function detw=mcxdetweight(detp,prop,unitinmm) +function detw = mcxdetweight(detp, prop, unitinmm) % % detw=mcxdetweight(detp,prop,unitinmm) % -% Recalculate the detected photon weight using partial path data and +% Recalculate the detected photon weight using partial path data and % optical properties (for perturbation Monte Carlo or detector readings) % % author: Qianqian Fang (q.fang neu.edu) % % input: -% detp: the 2nd output from mcxlab. detp must a struct +% detp: the 2nd output from mcxlab. detp must a struct % prop: optical property list, as defined in the cfg.prop field of mcxlab's input -% unitinmm: voxel edge-length in mm, should use cfg.unitinmm used to generate detp; +% unitinmm: voxel edge-length in mm, should use cfg.unitinmm used to generate detp; % if ignored, assume to be 1 (mm) % % output: @@ -21,35 +21,35 @@ % License: GPLv3, see http://mcx.space/ for details % -if(nargin<2) - if(isfield(detp,'prop')) - prop=detp.prop; +if (nargin < 2) + if (isfield(detp, 'prop')) + prop = detp.prop; else error('must provide input "prop"'); end end -medianum=size(prop,1); -if(medianum<=1) +medianum = size(prop, 1); +if (medianum <= 1) error('empty property list'); end -if(nargin<3) - if(isfield(detp,'unitinmm')) - unitinmm=detp.unitinmm; +if (nargin < 3) + if (isfield(detp, 'unitinmm')) + unitinmm = detp.unitinmm; else - unitinmm=1; + unitinmm = 1; end end -if(isstruct(detp)) - if(~isfield(detp,'w0')) - detw=ones(size(detp.ppath,1),1); +if (isstruct(detp)) + if (~isfield(detp, 'w0')) + detw = ones(size(detp.ppath, 1), 1); else - detw=detp.w0; + detw = detp.w0; end - for i=1:medianum-1 - detw=detw.*exp(-prop(i+1,1)*detp.ppath(:,i)*unitinmm); + for i = 1:medianum - 1 + detw = detw .* exp(-prop(i + 1, 1) * detp.ppath(:, i) * unitinmm); end else error('the first input must be a struct with a subfield named "ppath"'); diff --git a/utils/mcxfluence2energy.m b/utils/mcxfluence2energy.m index f703c08c..3bc7f19f 100644 --- a/utils/mcxfluence2energy.m +++ b/utils/mcxfluence2energy.m @@ -1,4 +1,4 @@ -function output=mcxfluence2energy(flux,vol,prop,tstep) +function output = mcxfluence2energy(flux, vol, prop, tstep) % % output=mcxfluence2energy(flux,cfg) % or @@ -14,7 +14,7 @@ % or, you can use % vol: if cfg is not given, user must provide the volume, i.e. cfg.vol, and % prop: the property list, i.e. cfg.prop, as well as -% tstep: the time-step of the +% tstep: the time-step of the % output: % output: if cfg.output is 'flux', the output is the energy deposition (1/mm^3) % if cfg.output is 'energy', the output is the fluence rate (1/mm^2) @@ -24,30 +24,30 @@ % License: GPLv3, see http://mcx.space/ for details % -data=flux; +data = flux; -if(nargin>=1 && isstruct(flux) && isfield(flux,'data')) - data=flux.data; +if (nargin >= 1 && isstruct(flux) && isfield(flux, 'data')) + data = flux.data; end -if(nargin==2 && isstruct(vol) && isfield(vol,'vol') && isfield(vol,'prop')) - cfg=vol; - vol=cfg.vol; - prop=cfg.prop; - tstep=cfg.tstep; - if(isfield(cfg,'outputtype') && strcmp(cfg.outputtype,'fluence')) - data=data./tstep; +if (nargin == 2 && isstruct(vol) && isfield(vol, 'vol') && isfield(vol, 'prop')) + cfg = vol; + vol = cfg.vol; + prop = cfg.prop; + tstep = cfg.tstep; + if (isfield(cfg, 'outputtype') && strcmp(cfg.outputtype, 'fluence')) + data = data ./ tstep; end else error('must provide cfg, or vol/prop as inputs'); end -mua=prop(:,1); -mua=repmat(mua(vol+1),1,1,1,size(flux.data,4)); -if(exist('cfg','var') && isfield(cfg,'outputtype') && strcmp(cfg.outputtype,'energy')) - data(mua==0)=0; - mua(mua==0)=1; - output=data./(tstep*mua); +mua = prop(:, 1); +mua = repmat(mua(vol + 1), 1, 1, 1, size(flux.data, 4)); +if (exist('cfg', 'var') && isfield(cfg, 'outputtype') && strcmp(cfg.outputtype, 'energy')) + data(mua == 0) = 0; + mua(mua == 0) = 1; + output = data ./ (tstep * mua); else % otherwise, assume input is fluence rate - output=data*(tstep).*mua; -end \ No newline at end of file + output = data * (tstep) .* mua; +end diff --git a/utils/mcxloadfile.m b/utils/mcxloadfile.m index 30b0f8a5..68919221 100644 --- a/utils/mcxloadfile.m +++ b/utils/mcxloadfile.m @@ -1,4 +1,4 @@ -function [data, header]=mcxloadfile(fname,varargin) +function [data, header] = mcxloadfile(fname, varargin) % % [data, header]=mcxloadfile(fname) % or @@ -21,20 +21,21 @@ % License: GPLv3, see http://mcx.sf.net for details % -[pathstr,name,ext] = fileparts(fname); +[pathstr, name, ext] = fileparts(fname); -if(strcmpi(ext,'.nii')) - nii=mcxloadnii(fname,varargin{:}); - data=nii.img; - header=nii.hdr; -elseif(strcmpi(ext,'.mc2')) - data=loadmc2(fname,varargin{:}); - data=log10(data); - header.dim=varargin{1}; - header.format=class(data); - header.scale='log10'; -elseif(strcmpi(ext,'.mch')) - [data, header]=loadmch(fname),varargin{:}; +if (strcmpi(ext, '.nii')) + nii = mcxloadnii(fname, varargin{:}); + data = nii.img; + header = nii.hdr; +elseif (strcmpi(ext, '.mc2')) + data = loadmc2(fname, varargin{:}); + data = log10(data); + header.dim = varargin{1}; + header.format = class(data); + header.scale = 'log10'; +elseif (strcmpi(ext, '.mch')) + [data, header] = loadmch(fname); + varargin{:}; else - data=loadmc2(fname,varargin{:}); + data = loadmc2(fname, varargin{:}); end diff --git a/utils/mcxloadnii.m b/utils/mcxloadnii.m index 96c2a485..40a69610 100644 --- a/utils/mcxloadnii.m +++ b/utils/mcxloadnii.m @@ -1,4 +1,4 @@ -function nii=mcxloadnii(filename) +function nii = mcxloadnii(filename) % % nii=mcxloadnii(filename) % @@ -31,120 +31,119 @@ % header = memmapfile(filename, ... - 'Offset', 0, ... - 'Writable', false, ... - 'Format', { ... - 'int32' [1 1] 'sizeof_hdr' ; %!< MUST be 348 % % int sizeof_hdr; % ... - 'int8' [1 10] 'data_type' ; %!< ++UNUSED++ % % char data_type[10]; % ... - 'int8' [1 18] 'db_name' ; %!< ++UNUSED++ % % char db_name[18]; % ... - 'int32' [1 1] 'extents' ; %!< ++UNUSED++ % % int extents; % ... - 'int16' [1 1] 'session_error' ; %!< ++UNUSED++ % % short session_error; % ... - 'int8' [1 1] 'regular' ; %!< ++UNUSED++ % % char regular; % ... - 'int8' [1 1] 'dim_info' ; %!< MRI slice ordering. % % char hkey_un0; % ... - 'uint16' [1 8] 'dim' ; %!< Data array dimensions.% % short dim[8]; % ... - 'single' [1 1] 'intent_p1' ; %!< 1st intent parameter. % % short unused8/9; % ... - 'single' [1 1] 'intent_p2' ; %!< 2nd intent parameter. % % short unused10/11; % ... - 'single' [1 1] 'intent_p3' ; %!< 3rd intent parameter. % % short unused12/13; % ... - 'int16' [1 1] 'intent_code' ; %!< NIFTI_INTENT_* code. % % short unused14; % ... - 'int16' [1 1] 'datatype' ; %!< Defines data type! % % short datatype; % ... - 'int16' [1 1] 'bitpix' ; %!< Number bits/voxel. % % short bitpix; % ... - 'int16' [1 1] 'slice_start' ; %!< First slice index. % % short dim_un0; % ... - 'single' [1 8] 'pixdim' ; %!< Grid spacings. % % float pixdim[8]; % ... - 'single' [1 1] 'vox_offset' ; %!< Offset into .nii file % % float vox_offset; % ... - 'single' [1 1] 'scl_slope' ; %!< Data scaling: slope. % % float funused1; % ... - 'single' [1 1] 'scl_inter' ; %!< Data scaling: offset. % % float funused2; % ... - 'int16' [1 1] 'slice_end' ; %!< Last slice index. % % float funused3; % ... - 'int8' [1 1] 'slice_code' ; %!< Slice timing order. % ... - 'int8' [1 1] 'xyzt_units' ; %!< Units of pixdim[1..4] % ... - 'single' [1 1] 'cal_max' ; %!< Max display intensity % % float cal_max; % ... - 'single' [1 1] 'cal_min' ; %!< Min display intensity % % float cal_min; % ... - 'single' [1 1] 'slice_duration'; %!< Time for 1 slice. % % float compressed; % ... - 'single' [1 1] 'toffset' ; %!< Time axis shift. % % float verified; % ... - 'int32' [1 1] 'glmax' ; %!< ++UNUSED++ % % int glmax; % ... - 'int32' [1 1] 'glmin' ; %!< ++UNUSED++ % % int glmin; % ... - 'int8' [1 80] 'descrip' ; %!< any text you like. % % char descrip[80]; % ... - 'int8' [1 24] 'aux_file' ; %!< auxiliary filename. % % char aux_file[24]; % ... - 'int16' [1 1] 'qform_code' ; %!< NIFTI_XFORM_* code. % %-- all ANALYZE 7.5 --- % ... - 'int16' [1 1] 'sform_code' ; %!< NIFTI_XFORM_* code. % %below here are replaced% ... - 'single' [1 1] 'quatern_b' ; %!< Quaternion b param. % ... - 'single' [1 1] 'quatern_c' ; %!< Quaternion c param. % ... - 'single' [1 1] 'quatern_d' ; %!< Quaternion d param. % ... - 'single' [1 1] 'qoffset_x' ; %!< Quaternion x shift. % ... - 'single' [1 1] 'qoffset_y' ; %!< Quaternion y shift. % ... - 'single' [1 1] 'qoffset_z' ; %!< Quaternion z shift. % ... - 'single' [1 4] 'srow_x' ; %!< 1st row affine transform. % ... - 'single' [1 4] 'srow_y' ; %!< 2nd row affine transform. % ... - 'single' [1 4] 'srow_z' ; %!< 3rd row affine transform. % ... - 'int8' [1 16] 'intent_name' ; %!< 'name' or meaning of data. % ... - 'int8' [1 4] 'magic' ; %!< MUST be "ni1\0" or "n+1\0". % ... - 'int8' [1 4] 'extension' %!< header extension % ... - }); + 'Offset', 0, ... + 'Writable', false, ... + 'Format', { ... + 'int32' [1 1] 'sizeof_hdr' % !< MUST be 348 % % int sizeof_hdr; % ... + 'int8' [1 10] 'data_type' % !< ++UNUSED++ % % char data_type[10]; % ... + 'int8' [1 18] 'db_name' % !< ++UNUSED++ % % char db_name[18]; % ... + 'int32' [1 1] 'extents' % !< ++UNUSED++ % % int extents; % ... + 'int16' [1 1] 'session_error' % !< ++UNUSED++ % % short session_error; % ... + 'int8' [1 1] 'regular' % !< ++UNUSED++ % % char regular; % ... + 'int8' [1 1] 'dim_info' % !< MRI slice ordering. % % char hkey_un0; % ... + 'uint16' [1 8] 'dim' % !< Data array dimensions.% % short dim[8]; % ... + 'single' [1 1] 'intent_p1' % !< 1st intent parameter. % % short unused8/9; % ... + 'single' [1 1] 'intent_p2' % !< 2nd intent parameter. % % short unused10/11; % ... + 'single' [1 1] 'intent_p3' % !< 3rd intent parameter. % % short unused12/13; % ... + 'int16' [1 1] 'intent_code' % !< NIFTI_INTENT_* code. % % short unused14; % ... + 'int16' [1 1] 'datatype' % !< Defines data type! % % short datatype; % ... + 'int16' [1 1] 'bitpix' % !< Number bits/voxel. % % short bitpix; % ... + 'int16' [1 1] 'slice_start' % !< First slice index. % % short dim_un0; % ... + 'single' [1 8] 'pixdim' % !< Grid spacings. % % float pixdim[8]; % ... + 'single' [1 1] 'vox_offset' % !< Offset into .nii file % % float vox_offset; % ... + 'single' [1 1] 'scl_slope' % !< Data scaling: slope. % % float funused1; % ... + 'single' [1 1] 'scl_inter' % !< Data scaling: offset. % % float funused2; % ... + 'int16' [1 1] 'slice_end' % !< Last slice index. % % float funused3; % ... + 'int8' [1 1] 'slice_code' % !< Slice timing order. % ... + 'int8' [1 1] 'xyzt_units' % !< Units of pixdim[1..4] % ... + 'single' [1 1] 'cal_max' % !< Max display intensity % % float cal_max; % ... + 'single' [1 1] 'cal_min' % !< Min display intensity % % float cal_min; % ... + 'single' [1 1] 'slice_duration' % !< Time for 1 slice. % % float compressed; % ... + 'single' [1 1] 'toffset' % !< Time axis shift. % % float verified; % ... + 'int32' [1 1] 'glmax' % !< ++UNUSED++ % % int glmax; % ... + 'int32' [1 1] 'glmin' % !< ++UNUSED++ % % int glmin; % ... + 'int8' [1 80] 'descrip' % !< any text you like. % % char descrip[80]; % ... + 'int8' [1 24] 'aux_file' % !< auxiliary filename. % % char aux_file[24]; % ... + 'int16' [1 1] 'qform_code' % !< NIFTI_XFORM_* code. % %-- all ANALYZE 7.5 --- % ... + 'int16' [1 1] 'sform_code' % !< NIFTI_XFORM_* code. % %below here are replaced% ... + 'single' [1 1] 'quatern_b' % !< Quaternion b param. % ... + 'single' [1 1] 'quatern_c' % !< Quaternion c param. % ... + 'single' [1 1] 'quatern_d' % !< Quaternion d param. % ... + 'single' [1 1] 'qoffset_x' % !< Quaternion x shift. % ... + 'single' [1 1] 'qoffset_y' % !< Quaternion y shift. % ... + 'single' [1 1] 'qoffset_z' % !< Quaternion z shift. % ... + 'single' [1 4] 'srow_x' % !< 1st row affine transform. % ... + 'single' [1 4] 'srow_y' % !< 2nd row affine transform. % ... + 'single' [1 4] 'srow_z' % !< 3rd row affine transform. % ... + 'int8' [1 16] 'intent_name' % !< 'name' or meaning of data. % ... + 'int8' [1 4] 'magic' % !< MUST be "ni1\0" or "n+1\0". % ... + 'int8' [1 4] 'extension' % !< header extension % ... + }); -nii.hdr=header.Data(1); - -type2byte=[ - 0 0 % unknown % - 1 0 % binary (1 bit/voxel) % - 2 1 % unsigned char (8 bits/voxel) % - 4 2 % signed short (16 bits/voxel) % - 8 4 % signed int (32 bits/voxel) % - 16 4 % float (32 bits/voxel) % - 32 8 % complex (64 bits/voxel) % - 64 8 % double (64 bits/voxel) % - 128 3 % RGB triple (24 bits/voxel) % - 255 0 % not very useful (?) % - 256 1 % signed char (8 bits) % - 512 2 % unsigned short (16 bits) % - 768 4 % unsigned int (32 bits) % - 1024 8 % long long (64 bits) % - 1280 8 % unsigned long long (64 bits) % - 1536 16 % long double (128 bits) % - 1792 16 % double pair (128 bits) % - 2048 32 % long double pair (256 bits) % - 2304 4 % 4 byte RGBA (32 bits/voxel) % -]; +nii.hdr = header.Data(1); -type2str={ - 'uint8' 0 % unknown % - 'uint8' 0 % binary (1 bit/voxel) % - 'uint8' 1 % unsigned char (8 bits/voxel) % - 'uint16' 1 % signed short (16 bits/voxel) % - 'int32' 1 % signed int (32 bits/voxel) % - 'float32' 1 % float (32 bits/voxel) % - 'float32' 2 % complex (64 bits/voxel) % - 'float64' 1 % double (64 bits/voxel) % - 'uint8' 3 % RGB triple (24 bits/voxel) % - 'uint8' 0 % not very useful (?) % - 'int8' 1 % signed char (8 bits) % - 'uint16' 1 % unsigned short (16 bits) % - 'uint32' 1 % unsigned int (32 bits) % - 'long' 1 % long long (64 bits) % - 'ulong' 1 % unsigned long long (64 bits) % - 'uint8' 16 % long double (128 bits) % - 'uint8' 16 % double pair (128 bits) % - 'uint8' 32 % long double pair (256 bits) % - 'uint8' 4 % 4 byte RGBA (32 bits/voxel) % -}; +type2byte = [ + 0 0 % unknown % + 1 0 % binary (1 bit/voxel) % + 2 1 % unsigned char (8 bits/voxel) % + 4 2 % signed short (16 bits/voxel) % + 8 4 % signed int (32 bits/voxel) % + 16 4 % float (32 bits/voxel) % + 32 8 % complex (64 bits/voxel) % + 64 8 % double (64 bits/voxel) % + 128 3 % RGB triple (24 bits/voxel) % + 255 0 % not very useful (?) % + 256 1 % signed char (8 bits) % + 512 2 % unsigned short (16 bits) % + 768 4 % unsigned int (32 bits) % + 1024 8 % long long (64 bits) % + 1280 8 % unsigned long long (64 bits) % + 1536 16 % long double (128 bits) % + 1792 16 % double pair (128 bits) % + 2048 32 % long double pair (256 bits) % + 2304 4 % 4 byte RGBA (32 bits/voxel) % + ]; -typeidx=find(type2byte(:,1)==nii.hdr.datatype); +type2str = { + 'uint8' 0 % unknown % + 'uint8' 0 % binary (1 bit/voxel) % + 'uint8' 1 % unsigned char (8 bits/voxel) % + 'uint16' 1 % signed short (16 bits/voxel) % + 'int32' 1 % signed int (32 bits/voxel) % + 'float32' 1 % float (32 bits/voxel) % + 'float32' 2 % complex (64 bits/voxel) % + 'float64' 1 % double (64 bits/voxel) % + 'uint8' 3 % RGB triple (24 bits/voxel) % + 'uint8' 0 % not very useful (?) % + 'int8' 1 % signed char (8 bits) % + 'uint16' 1 % unsigned short (16 bits) % + 'uint32' 1 % unsigned int (32 bits) % + 'long' 1 % long long (64 bits) % + 'ulong' 1 % unsigned long long (64 bits) % + 'uint8' 16 % long double (128 bits) % + 'uint8' 16 % double pair (128 bits) % + 'uint8' 32 % long double pair (256 bits) % + 'uint8' 4 % 4 byte RGBA (32 bits/voxel) % + }; -nii.datatype=type2str{typeidx,1}; -nii.datalen=type2str{typeidx,2}; -nii.voxelbyte=type2byte(typeidx,2); +typeidx = find(type2byte(:, 1) == nii.hdr.datatype); -if(type2byte(typeidx,2)==0) - nii.img=[]; - return; +nii.datatype = type2str{typeidx, 1}; +nii.datalen = type2str{typeidx, 2}; +nii.voxelbyte = type2byte(typeidx, 2); + +if (type2byte(typeidx, 2) == 0) + nii.img = []; + return end -if(type2str{typeidx,2}>1) - nii.hdr.dim=[nii.hdr.dim(1)+1 uint16(nii.datalen) nii.hdr.dim(2:end)]; +if (type2str{typeidx, 2} > 1) + nii.hdr.dim = [nii.hdr.dim(1) + 1 uint16(nii.datalen) nii.hdr.dim(2:end)]; end -fid=fopen(filename,'rb'); -fseek(fid,nii.hdr.vox_offset,'bof'); -nii.img=fread(fid,prod(nii.hdr.dim(2:nii.hdr.dim(1)+1)),[nii.datatype '=>' nii.datatype]); +fid = fopen(filename, 'rb'); +fseek(fid, nii.hdr.vox_offset, 'bof'); +nii.img = fread(fid, prod(nii.hdr.dim(2:nii.hdr.dim(1) + 1)), [nii.datatype '=>' nii.datatype]); fclose(fid); -nii.img=reshape(nii.img,nii.hdr.dim(2:nii.hdr.dim(1)+1)); - +nii.img = reshape(nii.img, nii.hdr.dim(2:nii.hdr.dim(1) + 1)); diff --git a/utils/mcxmeanpath.m b/utils/mcxmeanpath.m index b1112e4e..7a7297b5 100644 --- a/utils/mcxmeanpath.m +++ b/utils/mcxmeanpath.m @@ -1,4 +1,4 @@ -function avgpath=mcxmeanpath(detp,prop) +function avgpath = mcxmeanpath(detp, prop) % % avgpath=mcxmeanpath(detp,prop) % @@ -11,17 +11,17 @@ % prop: optical property list, as defined in the cfg.prop field of mcxlab's input % % output: -% avepath: the average pathlength for each tissue type +% avepath: the average pathlength for each tissue type % % this file is copied from Mesh-based Monte Carlo (MMC) % % License: GPLv3, see http://mcx.space/ for details % - if(isfield(detp,'unitinmm')) - unitinmm=detp.unitinmm; +if (isfield(detp, 'unitinmm')) + unitinmm = detp.unitinmm; else - unitinmm=1; + unitinmm = 1; end -detw=mcxdetweight(detp,prop); -avgpath=sum(detp.ppath.*unitinmm.*repmat(detw(:),1,size(detp.ppath,2))) / sum(detw(:)); +detw = mcxdetweight(detp, prop); +avgpath = sum(detp.ppath .* unitinmm .* repmat(detw(:), 1, size(detp.ppath, 2))) / sum(detw(:)); diff --git a/utils/mcxmeanscat.m b/utils/mcxmeanscat.m index fbe69b91..c2aca03e 100644 --- a/utils/mcxmeanscat.m +++ b/utils/mcxmeanscat.m @@ -1,4 +1,4 @@ -function avgnscat=mcxmeanscat(detp,prop) +function avgnscat = mcxmeanscat(detp, prop) % % avgnscat=mcxmeanscat(detp,prop) % @@ -11,12 +11,12 @@ % prop: optical property list, as defined in the cfg.prop field of mcxlab's input % % output: -% avgnscat: the average scattering event count for each tissue type +% avgnscat: the average scattering event count for each tissue type % % this file is copied from Mesh-based Monte Carlo (MMC) % % License: GPLv3, see http://mcx.space/ for details % -detw=mcxdetweight(detp,prop); -avgnscat=sum(double(detp.nscat).*repmat(detw(:),1,size(detp.nscat,2))) / sum(detw(:)); +detw = mcxdetweight(detp, prop); +avgnscat = sum(double(detp.nscat) .* repmat(detw(:), 1, size(detp.nscat, 2))) / sum(detw(:)); diff --git a/utils/mcxnuvoxel.m b/utils/mcxnuvoxel.m index 77cbe535..836f486b 100644 --- a/utils/mcxnuvoxel.m +++ b/utils/mcxnuvoxel.m @@ -1,4 +1,4 @@ -function [dbratio,uniqidx,bmask,nn,totalarea,iso]=mcxnuvoxel(vol, varargin) +function [dbratio, uniqidx, bmask, nn, totalarea, iso] = mcxnuvoxel(vol, varargin) % % Format: % newvol=mcxnuvoxel(vol) @@ -29,7 +29,7 @@ % are align with x/y/z/ axes. % % Output: -% dbratio: a vector of length as uniqidx, the approx. partial volume of +% dbratio: a vector of length as uniqidx, the approx. partial volume of % the higher-valued label in a mixed label voxel (between 0-1) % uniqidx: the 1-D index of all voxels that are made of mixed labels % bmask: an Nx2 array, where N is the length of uniqidx, with the 1st @@ -66,173 +66,172 @@ % %% parse user options -opt=varargin2struct(varargin{:}); -dodebug=jsonopt('debug',0,opt); -ksize=jsonopt('kernelsize',3,opt); -kstd=jsonopt('kernelstd',1,opt); -level=jsonopt('threshold',0.5,opt); -debugpatch=jsonopt('debugpatch',1,opt); -bmask=jsonopt('bmask',zeros(size(vol)),opt); -dosmooth=jsonopt('smoothing',1,opt); -curveonly=jsonopt('curveonly',1,opt); - -bmask2=zeros(size(vol)); +opt = varargin2struct(varargin{:}); +dodebug = jsonopt('debug', 0, opt); +ksize = jsonopt('kernelsize', 3, opt); +kstd = jsonopt('kernelstd', 1, opt); +level = jsonopt('threshold', 0.5, opt); +debugpatch = jsonopt('debugpatch', 1, opt); +bmask = jsonopt('bmask', zeros(size(vol)), opt); +dosmooth = jsonopt('smoothing', 1, opt); +curveonly = jsonopt('curveonly', 1, opt); + +bmask2 = zeros(size(vol)); %% read unique labels -labels=sort(unique(vol(:))); -labels(labels==0)=[]; +labels = sort(unique(vol(:))); +labels(labels == 0) = []; -if(length(labels)>255) +if (length(labels) > 255) error('MCX currently supports up to 255 labels for this function'); end %% loop over unique labels in ascending order -iso=struct('vertices',[],'faces',[]); +iso = struct('vertices', [], 'faces', []); -for i=1:length(labels) +for i = 1:length(labels) % convert each label into a binary mask, smooth it, then extract the % isosurface using marching cube algorithm (matlab builtin) - if(dosmooth) - volsmooth=smooth3(vol==labels(i),'g',ksize,kstd); + if (dosmooth) + volsmooth = smooth3(vol == labels(i), 'g', ksize, kstd); else - volsmooth=(vol>=labels(i)); + volsmooth = (vol >= labels(i)); end - fv0=isosurface(volsmooth,level); - if(isempty(fv0.vertices)) - continue; + fv0 = isosurface(volsmooth, level); + if (isempty(fv0.vertices)) + continue end % get the containing voxel linear id - c0=meshcentroid(fv0.vertices,fv0.faces); - voxid=sub2ind(size(vol),floor(c0(:,1))+1,floor(c0(:,2))+1,floor(c0(:,3))+1); + c0 = meshcentroid(fv0.vertices, fv0.faces); + voxid = sub2ind(size(vol), floor(c0(:, 1)) + 1, floor(c0(:, 2)) + 1, floor(c0(:, 3)) + 1); % identify unique voxels - uniqidx=unique(voxid); - bmask2(uniqidx)=labels(i); - + uniqidx = unique(voxid); + bmask2(uniqidx) = labels(i); + % find new boundary voxels that are not covered by previous levelsets - uniqidx=uniqidx(bmask(uniqidx)==0); - goodpatchidx=ismember(voxid,uniqidx); - + uniqidx = uniqidx(bmask(uniqidx) == 0); + goodpatchidx = ismember(voxid, uniqidx); + % merge surface patches located inside new boundary voxels - iso.faces=[iso.faces; size(iso.vertices,1)+fv0.faces(goodpatchidx==1,:)]; - iso.vertices=[iso.vertices; fv0.vertices]; - + iso.faces = [iso.faces; size(iso.vertices, 1) + fv0.faces(goodpatchidx == 1, :)]; + iso.vertices = [iso.vertices; fv0.vertices]; + % label those voxels as covered - bmask(uniqidx)=labels(i); + bmask(uniqidx) = labels(i); end %% handle uniform domains -if(isempty(iso.vertices)) - dbratio=[]; - uniqidx=[]; - nn=[]; - totalarea=[]; - return; +if (isempty(iso.vertices)) + dbratio = []; + uniqidx = []; + nn = []; + totalarea = []; + return end %% get the voxel mapping for the final combined isosurface -[iso.vertices,iso.faces]=removeisolatednode(iso.vertices,iso.faces); -c0=meshcentroid(iso.vertices,iso.faces); -voxid=sub2ind(size(vol),floor(c0(:,1))+1,floor(c0(:,2))+1,floor(c0(:,3))+1); -[uniqidx, vox2patch]=unique(voxid); - -[cc1,cc2]=histc(voxid,uniqidx); -cc=cc1(cc2); - -if(dodebug) - plotmesh(iso.vertices,iso.faces,'facealpha',0.4,'facecolor','b','edgealpha',0.2) - disp(max(iso.vertices)-min(iso.vertices)) +[iso.vertices, iso.faces] = removeisolatednode(iso.vertices, iso.faces); +c0 = meshcentroid(iso.vertices, iso.faces); +voxid = sub2ind(size(vol), floor(c0(:, 1)) + 1, floor(c0(:, 2)) + 1, floor(c0(:, 3)) + 1); +[uniqidx, vox2patch] = unique(voxid); + +[cc1, cc2] = histc(voxid, uniqidx); +cc = cc1(cc2); + +if (dodebug) + plotmesh(iso.vertices, iso.faces, 'facealpha', 0.4, 'facecolor', 'b', 'edgealpha', 0.2); + disp(max(iso.vertices) - min(iso.vertices)); end %% obtain the low and high labels in all mix-label voxels -bmask=[bmask(uniqidx),bmask2(uniqidx)]; -bmask(bmask(:,1)==bmask(:,2),2)=0; +bmask = [bmask(uniqidx), bmask2(uniqidx)]; +bmask(bmask(:, 1) == bmask(:, 2), 2) = 0; %% computing total area and normal vector for each boundary voxel -areas=elemvolume(iso.vertices,iso.faces); -normals=surfacenorm(iso.vertices,iso.faces); +areas = elemvolume(iso.vertices, iso.faces); +normals = surfacenorm(iso.vertices, iso.faces); -totalarea=zeros(size(vol)); -maxvid=max(voxid); -totalarea(1:maxvid)=accumarray(voxid,areas); % total areas of cross-sections in each boundary voxel -totalarea=totalarea(uniqidx); +totalarea = zeros(size(vol)); +maxvid = max(voxid); +totalarea(1:maxvid) = accumarray(voxid, areas); % total areas of cross-sections in each boundary voxel +totalarea = totalarea(uniqidx); %% creating weighted average surface patch normals per boundary voxel -nn=zeros([3 size(vol)]); -nn(1,1:maxvid)=accumarray(voxid,normals(:,1).*areas); % total normal_x of cross-sections in each boundary voxel -nn(2,1:maxvid)=accumarray(voxid,normals(:,2).*areas); % total normal_y of cross-sections in each boundary voxel -nn(3,1:maxvid)=accumarray(voxid,normals(:,3).*areas); % total normal_z of cross-sections in each boundary voxel -nnlen=sqrt(sum(nn.*nn,1)); -for i=1:3 - nn(i,voxid)=nn(i,voxid)./nnlen(voxid)'; +nn = zeros([3 size(vol)]); +nn(1, 1:maxvid) = accumarray(voxid, normals(:, 1) .* areas); % total normal_x of cross-sections in each boundary voxel +nn(2, 1:maxvid) = accumarray(voxid, normals(:, 2) .* areas); % total normal_y of cross-sections in each boundary voxel +nn(3, 1:maxvid) = accumarray(voxid, normals(:, 3) .* areas); % total normal_z of cross-sections in each boundary voxel +nnlen = sqrt(sum(nn .* nn, 1)); +for i = 1:3 + nn(i, voxid) = nn(i, voxid) ./ nnlen(voxid)'; end -nn=nn(:,uniqidx)'; +nn = nn(:, uniqidx)'; %% calculating distances between 8 nodes of the enclosing voxel and the % centroid of the surface patch -p0=[floor(c0(vox2patch,1)) floor(c0(vox2patch,2)) floor(c0(vox2patch,3))]; -p0=repmat(p0,1,8)+repmat([0 0 0 1 0 0 0 1 0 0 0 1 1 1 0 1 0 1 0 1 1 1 1 1],size(p0,1),1); - -pdiff=reshape(p0-repmat(c0(vox2patch,:),1,8), length(vox2patch), 3, 8); -pdiff=squeeze(sum(pdiff.*repmat(nn,[1,1,8]),2)); % pdiff=dr .* n: unique voxels x3 - -dbvox=zeros(size(pdiff,1),2); -[s1,s2]=find(pdiff>0); -dbvox(:,1)=accumarray(s1, pdiff(pdiff>0)); % summing positive distances -[s1,s2]=find(pdiff<0); -dbvox(:,2)=-accumarray(s1, pdiff(pdiff<0)); % dbvox: unique voxels x2, summing negative distances - -dbratio=dbvox(:,2)./(dbvox(:,1)+dbvox(:,2)); % dbratio: unique voxels - -%% remove x/y/z oriented -if(curveonly) - [ix,iy]=find(abs(nn)==1); - boxmask=zeros(size(vol)); - boxmask(uniqidx(ix))=1; - boxmask=smooth3(boxmask,'b',3); - boxmask=(boxmask>0); - ix=find(boxmask(uniqidx)==1); - - nn(ix,:)=[]; - dbratio(ix)=[]; - uniqidx(ix)=[]; - bmask(ix,:)=[]; - totalarea(ix)=[]; +p0 = [floor(c0(vox2patch, 1)) floor(c0(vox2patch, 2)) floor(c0(vox2patch, 3))]; +p0 = repmat(p0, 1, 8) + repmat([0 0 0 1 0 0 0 1 0 0 0 1 1 1 0 1 0 1 0 1 1 1 1 1], size(p0, 1), 1); + +pdiff = reshape(p0 - repmat(c0(vox2patch, :), 1, 8), length(vox2patch), 3, 8); +pdiff = squeeze(sum(pdiff .* repmat(nn, [1, 1, 8]), 2)); % pdiff=dr .* n: unique voxels x3 + +dbvox = zeros(size(pdiff, 1), 2); +[s1, s2] = find(pdiff > 0); +dbvox(:, 1) = accumarray(s1, pdiff(pdiff > 0)); % summing positive distances +[s1, s2] = find(pdiff < 0); +dbvox(:, 2) = -accumarray(s1, pdiff(pdiff < 0)); % dbvox: unique voxels x2, summing negative distances + +dbratio = dbvox(:, 2) ./ (dbvox(:, 1) + dbvox(:, 2)); % dbratio: unique voxels + +%% remove x/y/z oriented +if (curveonly) + [ix, iy] = find(abs(nn) == 1); + boxmask = zeros(size(vol)); + boxmask(uniqidx(ix)) = 1; + boxmask = smooth3(boxmask, 'b', 3); + boxmask = (boxmask > 0); + ix = find(boxmask(uniqidx) == 1); + + nn(ix, :) = []; + dbratio(ix) = []; + uniqidx(ix) = []; + bmask(ix, :) = []; + totalarea(ix) = []; end %% assemble the final volume -if(nargout==1) - newvol=zeros([7,size(vol)]); - newvol(1,uniqidx)=dbratio; - newvol(2:3,uniqidx)=bmask'; - newvol(4:6,uniqidx)=nn'; - newvol(7,uniqidx)=totalarea'; - dbratio=newvol; +if (nargout == 1) + newvol = zeros([7, size(vol)]); + newvol(1, uniqidx) = dbratio; + newvol(2:3, uniqidx) = bmask'; + newvol(4:6, uniqidx) = nn'; + newvol(7, uniqidx) = totalarea'; + dbratio = newvol; end %% plotting for verification -if(dodebug) +if (dodebug) figure; - pcidx=find(cc>1); % find 4-patch that blong to the same voxel (in patch idx) - pidx0=pcidx(debugpatch); % pick one such patch group to debug - idx1=voxid(pidx0); % find the corresponding voxel id idx1 for the patch pidx0 - patid=find(voxid==idx1); % these patches are within voxel linear id idx1 + pcidx = find(cc > 1); % find 4-patch that blong to the same voxel (in patch idx) + pidx0 = pcidx(debugpatch); % pick one such patch group to debug + idx1 = voxid(pidx0); % find the corresponding voxel id idx1 for the patch pidx0 + patid = find(voxid == idx1); % these patches are within voxel linear id idx1 - testmask=zeros(size(volsmooth)); - testmask(idx1)=1; - [no3,fc3]=binsurface(testmask,4); + testmask = zeros(size(volsmooth)); + testmask(idx1) = 1; + [no3, fc3] = binsurface(testmask, 4); figure; - plotmesh(no3,fc3,'facealpha',0.3,'facecolor','none') + plotmesh(no3, fc3, 'facealpha', 0.3, 'facecolor', 'none'); hold on; - plotmesh(iso.vertices,iso.faces(patid,:),'facealpha',0.3,'facecolor','b','edgealpha',0.2) - disp(nn(cc2(pidx0),:)) % normal in voxel id idx1 - plotmesh([c0(pidx0,:); c0(pidx0,:)+nn(cc2(pidx0),:)],'ro-'); % plot centroid of pidx0-th patch to the normal in voxel id idx1 - disp(dbratio(cc2(patid(1)))) % mix ratio of the selected voxel + plotmesh(iso.vertices, iso.faces(patid, :), 'facealpha', 0.3, 'facecolor', 'b', 'edgealpha', 0.2); + disp(nn(cc2(pidx0), :)); % normal in voxel id idx1 + plotmesh([c0(pidx0, :); c0(pidx0, :) + nn(cc2(pidx0), :)], 'ro-'); % plot centroid of pidx0-th patch to the normal in voxel id idx1 + disp(dbratio(cc2(patid(1)))); % mix ratio of the selected voxel end - diff --git a/utils/mcxplotphotons.m b/utils/mcxplotphotons.m index 5f8a3bb3..4e20a790 100644 --- a/utils/mcxplotphotons.m +++ b/utils/mcxplotphotons.m @@ -1,4 +1,4 @@ -function varargout=mcxplotphotons(traj,varargin) +function varargout = mcxplotphotons(traj, varargin) % % mcxplotphotons(traj) % or @@ -14,7 +14,7 @@ % traj.id: the photon index being recorded % traj.pos: the 3D position of the photon; for each photon, the % positions are stored in serial order -% traj.data: the combined output, in the form of +% traj.data: the combined output, in the form of % [id,pos,weight,reserved]' % % output: @@ -27,28 +27,28 @@ % License: GPLv3, see http://mcx.sf.net for details % -if(isstruct(traj) && ~isfield(traj, 'id') && isfield(traj, 'data')) - traj=struct('id',typecast(single(traj.data(1,:)'),'uint32'),'pos',traj.data(2:4,:)','weight',traj.data(5,:)', 'data', traj.data); +if (isstruct(traj) && ~isfield(traj, 'id') && isfield(traj, 'data')) + traj = struct('id', typecast(single(traj.data(1, :)'), 'uint32'), 'pos', traj.data(2:4, :)', 'weight', traj.data(5, :)', 'data', traj.data); end -if(~isstruct(traj) && size(traj,2)==6) - traj=struct('id',typecast(single(traj(:,1)),'uint32'),'pos',traj(:,2:4),'weight',traj(:,5)); +if (~isstruct(traj) && size(traj, 2) == 6) + traj = struct('id', typecast(single(traj(:, 1)), 'uint32'), 'pos', traj(:, 2:4), 'weight', traj(:, 5)); end -[newid, idx]=sort(traj.id); -lineend=(diff(newid)>0); -newidx=cumsum([0;lineend]+1); -newpos=nan(length(idx)+length(lineend),4); -newpos(newidx,1:3)=traj.pos(idx,:); -newpos(newidx,4)=traj.data(5,:)'; +[newid, idx] = sort(traj.id); +lineend = (diff(newid) > 0); +newidx = cumsum([0; lineend] + 1); +newpos = nan(length(idx) + length(lineend), 4); +newpos(newidx, 1:3) = traj.pos(idx, :); +newpos(newidx, 4) = traj.data(5, :)'; -if(~(length(varargin)==1 && strcmp(varargin{1},'noplot'))) - edgealpha = 1 - (1-(exist('OCTAVE_VERSION','builtin')~=0))*0.75; % octave 6 returns empty if edgealpha<1 - hg=patch(newpos(:,1),newpos(:,2),newpos(:,3),newpos(:,4), 'edgecolor', 'interp', 'edgealpha', edgealpha, varargin{:}); +if (~(length(varargin) == 1 && strcmp(varargin{1}, 'noplot'))) + edgealpha = 1 - (1 - (exist('OCTAVE_VERSION', 'builtin') ~= 0)) * 0.75; % octave 6 returns empty if edgealpha<1 + hg = patch(newpos(:, 1), newpos(:, 2), newpos(:, 3), newpos(:, 4), 'edgecolor', 'interp', 'edgealpha', edgealpha, varargin{:}); view(3); axis equal; else - hg=[]; + hg = []; end -output={struct('id',newid, 'pos',traj.pos(idx,:)), hg}; -[varargout{1:nargout}]=output{1:nargout}; +output = {struct('id', newid, 'pos', traj.pos(idx, :)), hg}; +[varargout{1:nargout}] = output{1:nargout}; diff --git a/utils/mcxplotshapes.m b/utils/mcxplotshapes.m index ad9bef8e..0d41b502 100644 --- a/utils/mcxplotshapes.m +++ b/utils/mcxplotshapes.m @@ -1,4 +1,4 @@ -function hseg=mcxplotshapes(jsonshape,gridsize,offset,hseg,voxelsize,varargin) +function hseg = mcxplotshapes(jsonshape, gridsize, offset, hseg, voxelsize, varargin) % % Format: % mcxplotshapes(jsonshapestr) @@ -33,119 +33,119 @@ % License: GNU General Public License version 3, please read LICENSE.txt for details % -if(nargin<4) - hseg=[]; +if (nargin < 4) + hseg = []; end -shapes=loadjson(jsonshape); -if(nargin<3) - offset=1; - if(nargin<2) - gridsize=[60 60 60]; +shapes = loadjson(jsonshape); +if (nargin < 3) + offset = 1; + if (nargin < 2) + gridsize = [60 60 60]; end end -isholdplot=ishold; +isholdplot = ishold; -orig=[0 0 0]+offset; -if(nargin<5) - voxelsize=1; +orig = [0 0 0] + offset; +if (nargin < 5) + voxelsize = 1; end rngstate = rand ('state'); -randseed=hex2dec('623F9A9E'); -rand('state',randseed); -surfcolors=rand(1024,3); +randseed = hex2dec('623F9A9E'); +rand('state', randseed); +surfcolors = rand(1024, 3); hold on; -if(isfield(shapes,'Shapes')) - for j=1:length(shapes.Shapes) - if(iscell(shapes.Shapes)) - shp=shapes.Shapes{j}; +if (isfield(shapes, 'Shapes')) + for j = 1:length(shapes.Shapes) + if (iscell(shapes.Shapes)) + shp = shapes.Shapes{j}; else - shp=shapes.Shapes(j); + shp = shapes.Shapes(j); end - sname=fieldnames(shp); - tag=1; - switch(sname{1}) - case {'Grid','Box','Subgrid'} - if(strcmp(sname{1},'Grid') && ~isempty(hseg)) + sname = fieldnames(shp); + tag = 1; + switch (sname{1}) + case {'Grid', 'Box', 'Subgrid'} + if (strcmp(sname{1}, 'Grid') && ~isempty(hseg)) delete(hseg); - hseg=[]; + hseg = []; end - obj=shp.(sname{1}); - if(isfield(obj,'Tag')) - tag=obj.Tag; + obj = shp.(sname{1}); + if (isfield(obj, 'Tag')) + tag = obj.Tag; end - gridsize=obj.Size; - [no,fc]=latticegrid([0 obj.Size(1)],[0 obj.Size(2)],[0 obj.Size(3)]); - hseg(end+1)=plotmesh(no*voxelsize,fc,'facealpha',0.3, 'linestyle', '-', 'facecolor','none', varargin{:}); + gridsize = obj.Size; + [no, fc] = latticegrid([0 obj.Size(1)], [0 obj.Size(2)], [0 obj.Size(3)]); + hseg(end + 1) = plotmesh(no * voxelsize, fc, 'facealpha', 0.3, 'linestyle', '-', 'facecolor', 'none', varargin{:}); case 'Sphere' - obj=shp.(sname{1}); - if(isfield(obj,'Tag')) - tag=obj.Tag; + obj = shp.(sname{1}); + if (isfield(obj, 'Tag')) + tag = obj.Tag; end - [sx,sy,sz]=sphere; - hseg(end+1)=surf(voxelsize*(sx*obj.R+(obj.O(1)+orig(1))), ... - voxelsize(sy*obj.R+(obj.O(2)+orig(2))), voxelsize(sz*obj.R+(obj.O(3)+orig(3))), ... - 'facealpha',0.3,'facecolor',surfcolors(tag+1,:),'linestyle','none'); + [sx, sy, sz] = sphere; + hseg(end + 1) = surf(voxelsize * (sx * obj.R + (obj.O(1) + orig(1))), ... + voxelsize(sy * obj.R + (obj.O(2) + orig(2))), voxelsize(sz * obj.R + (obj.O(3) + orig(3))), ... + 'facealpha', 0.3, 'facecolor', surfcolors(tag + 1, :), 'linestyle', 'none'); case 'Cylinder' - obj=shp.(sname{1}); - if(isfield(obj,'Tag')) - tag=obj.Tag; + obj = shp.(sname{1}); + if (isfield(obj, 'Tag')) + tag = obj.Tag; end - c0=obj.C0; - c1=obj.C1; - len=norm(c0-c1); + c0 = obj.C0; + c1 = obj.C1; + len = norm(c0 - c1); - [sx,sy,sz]=cylinder(obj.R); - sz=sz*len; - no=rotatevec3d([sx(:),sy(:),sz(:)],c1-c0); - sx=reshape(no(:,1),2,size(no,1)/2); - sy=reshape(no(:,2),2,size(no,1)/2); - sz=reshape(no(:,3),2,size(no,1)/2); - hseg(end+1)=surf(voxelsize*(sx+(c0(1)+orig(1))), ... - voxelsize*(sy+(c0(2)+orig(2))), voxelsize*(sz+(c0(3)+orig(3))), ... - 'facealpha',0.3,'facecolor',surfcolors(tag+1,:),'linestyle','none'); + [sx, sy, sz] = cylinder(obj.R); + sz = sz * len; + no = rotatevec3d([sx(:), sy(:), sz(:)], c1 - c0); + sx = reshape(no(:, 1), 2, size(no, 1) / 2); + sy = reshape(no(:, 2), 2, size(no, 1) / 2); + sz = reshape(no(:, 3), 2, size(no, 1) / 2); + hseg(end + 1) = surf(voxelsize * (sx + (c0(1) + orig(1))), ... + voxelsize * (sy + (c0(2) + orig(2))), voxelsize * (sz + (c0(3) + orig(3))), ... + 'facealpha', 0.3, 'facecolor', surfcolors(tag + 1, :), 'linestyle', 'none'); case 'Origin' - orig=voxelsize*shp.(sname{1}); - hseg(end+1)=plot3(orig(1),orig(2),orig(3),'m*'); - case {'XSlabs','YSlabs','ZSlabs'} - obj=shp.(sname{1}); - if(isfield(obj,'Tag')) - tag=obj.Tag; + orig = voxelsize * shp.(sname{1}); + hseg(end + 1) = plot3(orig(1), orig(2), orig(3), 'm*'); + case {'XSlabs', 'YSlabs', 'ZSlabs'} + obj = shp.(sname{1}); + if (isfield(obj, 'Tag')) + tag = obj.Tag; end - for k=1:size(obj.Bounds,1) - switch(sname{1}) + for k = 1:size(obj.Bounds, 1) + switch (sname{1}) case 'XSlabs' - [no,fc]=latticegrid([obj.Bounds(k,1) obj.Bounds(k,2)]+orig(1),[0 gridsize(2)],[0 gridsize(3)]); + [no, fc] = latticegrid([obj.Bounds(k, 1) obj.Bounds(k, 2)] + orig(1), [0 gridsize(2)], [0 gridsize(3)]); case 'YSlabs' - [no,fc]=latticegrid([0 gridsize(1)],[obj.Bounds(k,1) obj.Bounds(k,2)]+orig(2),[0 gridsize(3)]); + [no, fc] = latticegrid([0 gridsize(1)], [obj.Bounds(k, 1) obj.Bounds(k, 2)] + orig(2), [0 gridsize(3)]); case 'ZSlabs' - [no,fc]=latticegrid([0 gridsize(1)],[0 gridsize(2)],[obj.Bounds(k,1) obj.Bounds(k,2)]+orig(3)); + [no, fc] = latticegrid([0 gridsize(1)], [0 gridsize(2)], [obj.Bounds(k, 1) obj.Bounds(k, 2)] + orig(3)); end - hseg(end+1)=plotmesh(voxelsize*no,fc,'facealpha',0.3, 'linestyle', 'none', 'facecolor',surfcolors(tag+1,:), varargin{:}); + hseg(end + 1) = plotmesh(voxelsize * no, fc, 'facealpha', 0.3, 'linestyle', 'none', 'facecolor', surfcolors(tag + 1, :), varargin{:}); end - case {'XLayers','YLayers','ZLayers'} - obj=shp.(sname{1}); - if(~iscell(obj)) - obj=num2cell(obj,2); + case {'XLayers', 'YLayers', 'ZLayers'} + obj = shp.(sname{1}); + if (~iscell(obj)) + obj = num2cell(obj, 2); end - for k=1:length(obj) - tag=1; - if(length(obj{k})>=3) - tag=obj{k}(3); + for k = 1:length(obj) + tag = 1; + if (length(obj{k}) >= 3) + tag = obj{k}(3); end - switch(sname{1}) + switch (sname{1}) case 'XLayers' - [no,fc]=latticegrid([obj{k}(1)-1 obj{k}(2)]+orig(1)-1,[0 gridsize(2)],[0 gridsize(3)]); + [no, fc] = latticegrid([obj{k}(1) - 1 obj{k}(2)] + orig(1) - 1, [0 gridsize(2)], [0 gridsize(3)]); case 'YLayers' - [no,fc]=latticegrid([0 gridsize(1)],[obj{k}(1)-1 obj{k}(2)]+orig(2)-1,[0 gridsize(3)]); + [no, fc] = latticegrid([0 gridsize(1)], [obj{k}(1) - 1 obj{k}(2)] + orig(2) - 1, [0 gridsize(3)]); case 'ZLayers' - [no,fc]=latticegrid([0 gridsize(1)],[0 gridsize(2)],[obj{k}(1)-1 obj{k}(2)]+orig(3)-1); + [no, fc] = latticegrid([0 gridsize(1)], [0 gridsize(2)], [obj{k}(1) - 1 obj{k}(2)] + orig(3) - 1); end - hseg(end+1)=plotmesh(voxelsize*no,fc,'facealpha',0.3, 'linestyle', 'none', 'facecolor',surfcolors(tag+1,:), varargin{:}); + hseg(end + 1) = plotmesh(voxelsize * no, fc, 'facealpha', 0.3, 'linestyle', 'none', 'facecolor', surfcolors(tag + 1, :), varargin{:}); end otherwise error('unsupported shape constructs'); @@ -153,8 +153,8 @@ end end -if(~isholdplot) +if (~isholdplot) hold off; end -rand ('state',rngstate); +rand ('state', rngstate); diff --git a/utils/mcxplotvol.m b/utils/mcxplotvol.m index 1b92ff50..bc7a7fba 100644 --- a/utils/mcxplotvol.m +++ b/utils/mcxplotvol.m @@ -1,4 +1,4 @@ -function [dat, filename, handles, hfig]=mcxplotvol(varargin) +function [dat, filename, handles, hfig] = mcxplotvol(varargin) % % [dat, filename, handles]=mcxplotvol() % or @@ -26,92 +26,89 @@ % License: GPLv3, see http://mcx.sf.net for details % -if(nargin>=1) - if(ischar(varargin{1})) - fname=varargin{1}; - data=mcxloadfile(fname, varargin{2:end}); +if (nargin >= 1) + if (ischar(varargin{1})) + fname = varargin{1}; + data = mcxloadfile(fname, varargin{2:end}); else - fname=''; - data=varargin{1}; + fname = ''; + data = varargin{1}; end else - [fname pathname]=uigetfile( {'*.*'},'Pick a file'); - fname=fullfile(pathname, fname); - if(isempty(fname)) - return; + [fname pathname] = uigetfile({'*.*'}, 'Pick a file'); + fname = fullfile(pathname, fname); + if (isempty(fname)) + return end - [pathstr,name,ext] = fileparts(fname); - if(~strcmpi(ext,'.nii') && length(varargin)<=1) - prompt = {'Enter x-dimension:','Enter y-dimension:','Enter z-dimension:','Enter frame count:','Format:'}; + [pathstr, name, ext] = fileparts(fname); + if (~strcmpi(ext, '.nii') && length(varargin) <= 1) + prompt = {'Enter x-dimension:', 'Enter y-dimension:', 'Enter z-dimension:', 'Enter frame count:', 'Format:'}; dlg_title = 'Input'; num_lines = 1; - defaultans = {'','','','1','float32'}; - dim= inputdlg(prompt,dlg_title,num_lines,defaultans); - dataformat=dim{5}; - dim=cellfun(@(x) str2num(x), dim(1:4)); - data=mcxloadfile(fname, dim(:)',dataformat); + defaultans = {'', '', '', '1', 'float32'}; + dim = inputdlg(prompt, dlg_title, num_lines, defaultans); + dataformat = dim{5}; + dim = cellfun(@(x) str2num(x), dim(1:4)); + data = mcxloadfile(fname, dim(:)', dataformat); else - data=mcxloadfile(fname, varargin{2:end}); + data = mcxloadfile(fname, varargin{2:end}); end end -%if(ndims(squeeze(data))==4) +% if(ndims(squeeze(data))==4) % data=sum(squeeze(data),4); -%end +% end -if(nargout>=2) - filename=fname; -elseif(nargout>=1) - dat=data; +if (nargout >= 2) + filename = fname; +elseif (nargout >= 1) + dat = data; end -hfig=figure; +hfig = figure; -guidata=struct('filename',fname,'data',data,'frame',1); -guidata.handles=islicer(data(:,:,:,guidata.frame)); +guidata = struct('filename', fname, 'data', data, 'frame', 1); +guidata.handles = islicer(data(:, :, :, guidata.frame)); -set(hfig,'WindowKeyPressFcn',@changeframe) -set(hfig,'name',['MCX Viewer (mcxplotvol) ' fname]); -set(hfig,'NumberTitle','off'); -set(gca,'UserData',guidata); +set(hfig, 'WindowKeyPressFcn', @changeframe); +set(hfig, 'name', ['MCX Viewer (mcxplotvol) ' fname]); +set(hfig, 'NumberTitle', 'off'); +set(gca, 'UserData', guidata); +helpinfo = sprintf('Drag slice using left-btn to move slices; Click with mouse mid-btn to start rotation; Drag right-key up-down to change color level; Up-arrow key :next time-gate; Down-arrow key:prev time-gate'); -helpinfo=sprintf('Drag slice using left-btn to move slices; Click with mouse mid-btn to start rotation; Drag right-key up-down to change color level; Up-arrow key :next time-gate; Down-arrow key:prev time-gate'); +helpbtn = uicontrol('Parent', hfig, 'Style', 'pushbutton', 'String', 'Help', 'Units', 'points', 'Position', [10 10 50 20], 'Visible', 'on', 'Callback', @showhelp); -helpbtn=uicontrol('Parent',hfig,'Style','pushbutton','String','Help','Units','points','Position',[10 10 50 20],'Visible','on','Callback',@showhelp); +set(helpbtn, 'TooltipString', helpinfo); -set(helpbtn,'TooltipString',helpinfo); - - -xlabel(sprintf('x (frame=%d of %d)',1,size(data,4))); +xlabel(sprintf('x (frame=%d of %d)', 1, size(data, 4))); ylabel('y'); zlabel('z'); colorbar; +function changeframe(src, event) -function changeframe(src,event) - -guidata=get(gca,'UserData'); +guidata = get(gca, 'UserData'); -if(isempty(guidata) || ~isfield(guidata,'frame')) - return; +if (isempty(guidata) || ~isfield(guidata, 'frame')) + return end -newframe=-1; -switch(event.Key) +newframe = -1; +switch (event.Key) case 'uparrow' - newframe=min(guidata.frame+1,size(guidata.data,4)); + newframe = min(guidata.frame + 1, size(guidata.data, 4)); case 'downarrow' - newframe=max(guidata.frame-1,1); + newframe = max(guidata.frame - 1, 1); end -if(newframe>0 && newframe~=guidata.frame) - guidata.handles=islicer(guidata.data(:,:,:,newframe), eye(4), guidata.handles, 1); - xlabel(sprintf('x (frame=%d of %d)',newframe,size(guidata.data,4))); - guidata.frame=newframe; - set(gca,'UserData',guidata); +if (newframe > 0 && newframe ~= guidata.frame) + guidata.handles = islicer(guidata.data(:, :, :, newframe), eye(4), guidata.handles, 1); + xlabel(sprintf('x (frame=%d of %d)', newframe, size(guidata.data, 4))); + guidata.frame = newframe; + set(gca, 'UserData', guidata); end -function showhelp(source,event) -msgbox(get(source,'TooltipString'),'Help info'); +function showhelp(source, event) +msgbox(get(source, 'TooltipString'), 'Help info'); diff --git a/utils/mcxpreview.m b/utils/mcxpreview.m index 721590b9..3f878ba0 100644 --- a/utils/mcxpreview.m +++ b/utils/mcxpreview.m @@ -1,4 +1,4 @@ -function hs=mcxpreview(cfg, varargin) +function hs = mcxpreview(cfg, varargin) % % Format: % hs=mcxpreview(cfg); @@ -8,7 +8,7 @@ % Author: Qianqian Fang % % Input: -% cfg: a struct, or struct array. Each element of cfg defines +% cfg: a struct, or struct array. Each element of cfg defines % the parameters associated with a simulation. Please run % 'help mcxlab' or 'help mmclab' to see the details. % mcxpreview supports the cfg input for both mcxlab and mmclab. @@ -24,179 +24,179 @@ % License: GNU General Public License version 3, please read LICENSE.txt for details % -if(nargin==0) +if (nargin == 0) error('input field cfg must be defined'); end -if(~isstruct(cfg)) +if (~isstruct(cfg)) error('cfg must be a struct or struct array'); end -if(~exist('latticegrid','file')) +if (~exist('latticegrid', 'file')) error('you must install the iso2mesh toolbox from https://github.com/fangq/iso2mesh first'); end -len=length(cfg); -if(nargout>0) - hs=cell(len,1); +len = length(cfg); +if (nargout > 0) + hs = cell(len, 1); end rngstate = rand ('state'); -randseed=hex2dec('623F9A9E'); -rand('state',randseed); -surfcolors=rand(1024,3); -isholdplot=ishold; +randseed = hex2dec('623F9A9E'); +rand('state', randseed); +surfcolors = rand(1024, 3); +isholdplot = ishold; -for i=1:len - if(~isfield(cfg(i),'vol') && ~isfield(cfg(i),'node') && ~isfield(cfg(i),'shapes')) +for i = 1:len + if (~isfield(cfg(i), 'vol') && ~isfield(cfg(i), 'node') && ~isfield(cfg(i), 'shapes')) error('cfg.vol or cfg.node or cfg.shapes is missing'); end - if(i>1) + if (i > 1) figure; end hold on; - voxelsize=1; - if(isfield(cfg(i),'unitinmm')) - voxelsize=cfg(i).unitinmm; + voxelsize = 1; + if (isfield(cfg(i), 'unitinmm')) + voxelsize = cfg(i).unitinmm; end - offset=1; - if(isfield(cfg(i),'issrcfrom0') && cfg(i).issrcfrom0==1 || isfield(cfg(i),'node')) - offset=0; + offset = 1; + if (isfield(cfg(i), 'issrcfrom0') && cfg(i).issrcfrom0 == 1 || isfield(cfg(i), 'node')) + offset = 0; end - - hseg=[]; - if(isfield(cfg(i),'vol') && ~isfield(cfg(i),'node')) + + hseg = []; + if (isfield(cfg(i), 'vol') && ~isfield(cfg(i), 'node')) % render mcxlab voxelated domain - dim=size(cfg(i).vol); - if(ndims(cfg(i).vol)==4) % for spatially varying medium - dim=dim(2:end); - cfg(i).vol=ones(dim); + dim = size(cfg(i).vol); + if (ndims(cfg(i).vol) == 4) % for spatially varying medium + dim = dim(2:end); + cfg(i).vol = ones(dim); end - [bbxno,bbxfc]=latticegrid(0:dim(1):dim(1),0:dim(2):dim(2),0:dim(3):dim(3)); - hbbx=plotmesh((bbxno+offset)*voxelsize,bbxfc,'facecolor','none'); - - val=unique(cfg(i).vol(:)); - val(val==0)=[]; - padvol=zeros(dim+2); - padvol(2:end-1,2:end-1,2:end-1)=cfg(i).vol; - - if(length(val)>1) - hseg=zeros(length(val),1); - for id=1:length(val) - [no,fc]=binsurface(padvol==val(id)); - hseg(id)=plotmesh((no-1)*voxelsize,fc,'facealpha',0.3, 'linestyle', 'none', 'facecolor',surfcolors(val(id)+1,:), varargin{:}); + [bbxno, bbxfc] = latticegrid(0:dim(1):dim(1), 0:dim(2):dim(2), 0:dim(3):dim(3)); + hbbx = plotmesh((bbxno + offset) * voxelsize, bbxfc, 'facecolor', 'none'); + + val = unique(cfg(i).vol(:)); + val(val == 0) = []; + padvol = zeros(dim + 2); + padvol(2:end - 1, 2:end - 1, 2:end - 1) = cfg(i).vol; + + if (length(val) > 1) + hseg = zeros(length(val), 1); + for id = 1:length(val) + [no, fc] = binsurface(padvol == val(id)); + hseg(id) = plotmesh((no - 1) * voxelsize, fc, 'facealpha', 0.3, 'linestyle', 'none', 'facecolor', surfcolors(val(id) + 1, :), varargin{:}); end end - elseif(isfield(cfg(i),'node') && isfield(cfg(i),'elem')) + elseif (isfield(cfg(i), 'node') && isfield(cfg(i), 'elem')) % render mmclab mesh domain - elemtype=ones(size(cfg(i).elem,1),1); - if(isfield(cfg(i),'elemprop')) - elemtype=cfg(i).elemprop; + elemtype = ones(size(cfg(i).elem, 1), 1); + if (isfield(cfg(i), 'elemprop')) + elemtype = cfg(i).elemprop; else - if(size(cfg(i).elem,2)>4) - elemtype=cfg(i).elem(:,5); + if (size(cfg(i).elem, 2) > 4) + elemtype = cfg(i).elem(:, 5); end end - etypes=unique(elemtype); - no=cfg(i).node*voxelsize; - hseg=zeros(length(etypes),1); - for id=1:size(etypes,1) - hseg(id)=plotmesh(no,[],cfg(i).elem(elemtype==etypes(id),:),'facealpha',0.3, 'linestyle', 'none', 'facecolor',surfcolors(etypes(id)+1,:), varargin{:}); + etypes = unique(elemtype); + no = cfg(i).node * voxelsize; + hseg = zeros(length(etypes), 1); + for id = 1:size(etypes, 1) + hseg(id) = plotmesh(no, [], cfg(i).elem(elemtype == etypes(id), :), 'facealpha', 0.3, 'linestyle', 'none', 'facecolor', surfcolors(etypes(id) + 1, :), varargin{:}); end end - if(isfield(cfg(i),'shapes')) - if(isfield(cfg(i),'vol')) - hseg=mcxplotshapes(cfg(i).shapes,size(cfg(i).vol),offset,hseg,voxelsize,varargin{:}); + if (isfield(cfg(i), 'shapes')) + if (isfield(cfg(i), 'vol')) + hseg = mcxplotshapes(cfg(i).shapes, size(cfg(i).vol), offset, hseg, voxelsize, varargin{:}); else - hseg=mcxplotshapes(cfg(i).shapes,[60,60,60],offset,hseg,voxelsize,varargin{:}); + hseg = mcxplotshapes(cfg(i).shapes, [60, 60, 60], offset, hseg, voxelsize, varargin{:}); end end % rendering source position and direction - if(~isfield(cfg(i),'srcpos') || ~isfield(cfg(i),'srcdir')) + if (~isfield(cfg(i), 'srcpos') || ~isfield(cfg(i), 'srcdir')) error('cfg.srcpos or cfg.srcdir is missing'); end - - cfg(i).srcpos=cfg(i).srcpos; - srcpos=cfg(i).srcpos*voxelsize; - hsrc=plotmesh(srcpos,'r*'); - srcvec=cfg(i).srcdir*10*voxelsize; - headsize=1e2; - if(isoctavemesh) - headsize=0.5; + + cfg(i).srcpos = cfg(i).srcpos; + srcpos = cfg(i).srcpos * voxelsize; + hsrc = plotmesh(srcpos, 'r*'); + srcvec = cfg(i).srcdir * 10 * voxelsize; + headsize = 1e2; + if (isoctavemesh) + headsize = 0.5; end - hdir=quiver3(srcpos(1),srcpos(2), srcpos(3), srcvec(1),srcvec(2),srcvec(3), 'linewidth',3, 'color', 'r', 'MaxHeadSize',headsize,'AutoScaleFactor',1, varargin{:}); + hdir = quiver3(srcpos(1), srcpos(2), srcpos(3), srcvec(1), srcvec(2), srcvec(3), 'linewidth', 3, 'color', 'r', 'MaxHeadSize', headsize, 'AutoScaleFactor', 1, varargin{:}); % rendering area-source aperature - hsrcarea=[]; - if(isfield(cfg(i),'srctype')) - if(strcmp(cfg(i).srctype,'disk') || strcmp(cfg(i).srctype,'gaussian') || strcmp(cfg(i).srctype,'zgaussian') || strcmp(cfg(i).srctype,'ring')) - if(~isfield(cfg(i),'srcparam1')) + hsrcarea = []; + if (isfield(cfg(i), 'srctype')) + if (strcmp(cfg(i).srctype, 'disk') || strcmp(cfg(i).srctype, 'gaussian') || strcmp(cfg(i).srctype, 'zgaussian') || strcmp(cfg(i).srctype, 'ring')) + if (~isfield(cfg(i), 'srcparam1')) error('cfg.srcparam1 is missing'); end - [ncyl,fcyl]=meshacylinder(srcpos,srcpos+cfg(i).srcdir(1:3)*1e-5,cfg(i).srcparam1(1)*voxelsize,0,0); - hsrcarea=plotmesh(ncyl,fcyl{end-1},'facecolor','r','linestyle','none'); - if(cfg(1).srcparam1(2) > 0) - [ncyl,fcyl]=meshacylinder(srcpos,srcpos+cfg(i).srcdir(1:3)*1e-5,cfg(i).srcparam1(2)*voxelsize,0,0); - hsrcarea=plotmesh(ncyl,fcyl{end-1},'facecolor','k','linestyle','none'); + [ncyl, fcyl] = meshacylinder(srcpos, srcpos + cfg(i).srcdir(1:3) * 1e-5, cfg(i).srcparam1(1) * voxelsize, 0, 0); + hsrcarea = plotmesh(ncyl, fcyl{end - 1}, 'facecolor', 'r', 'linestyle', 'none'); + if (cfg(1).srcparam1(2) > 0) + [ncyl, fcyl] = meshacylinder(srcpos, srcpos + cfg(i).srcdir(1:3) * 1e-5, cfg(i).srcparam1(2) * voxelsize, 0, 0); + hsrcarea = plotmesh(ncyl, fcyl{end - 1}, 'facecolor', 'k', 'linestyle', 'none'); end - elseif(strcmp(cfg(i).srctype,'planar') || strcmp(cfg(i).srctype,'pattern') || strcmp(cfg(i).srctype,'fourier') || ... - strcmp(cfg(i).srctype,'fourierx') || strcmp(cfg(i).srctype,'fourierx2d') || strcmp(cfg(i).srctype,'pencilarray')) - if(~isfield(cfg(i),'srcparam1') || ~isfield(cfg(i),'srcparam2')) + elseif (strcmp(cfg(i).srctype, 'planar') || strcmp(cfg(i).srctype, 'pattern') || strcmp(cfg(i).srctype, 'fourier') || ... + strcmp(cfg(i).srctype, 'fourierx') || strcmp(cfg(i).srctype, 'fourierx2d') || strcmp(cfg(i).srctype, 'pencilarray')) + if (~isfield(cfg(i), 'srcparam1') || ~isfield(cfg(i), 'srcparam2')) error('cfg.srcparam2 or cfg.srcparam2 is missing'); end - if(strcmp(cfg(i).srctype,'fourierx') || strcmp(cfg(i).srctype,'fourierx2d')) - vec2=cross(cfg(i).srcdir, cfg(i).srcparam1(1:3)*voxelsize); + if (strcmp(cfg(i).srctype, 'fourierx') || strcmp(cfg(i).srctype, 'fourierx2d')) + vec2 = cross(cfg(i).srcdir, cfg(i).srcparam1(1:3) * voxelsize); else - vec2=cfg(i).srcparam2(1:3)*voxelsize; + vec2 = cfg(i).srcparam2(1:3) * voxelsize; end - nrec=[0 0 0; cfg(i).srcparam1(1:3)*voxelsize; cfg(i).srcparam1(1:3)*voxelsize+vec2; vec2]; - hsrcarea=plotmesh(nrec+repmat(srcpos(:)',[4,1]), {[1 2 3 4 1]}); - elseif(strcmp(cfg(i).srctype,'pattern3d')) - dim=cfg(i).srcparam1(1:3); - [bbxno,bbxfc]=latticegrid(0:dim(1):dim(1),0:dim(2):dim(2),0:dim(3):dim(3)); - hbbx=plotmesh(((bbxno+repmat(cfg(i).srcpos(1:3),size(bbxno,1),1))+offset)*voxelsize,bbxfc,'facecolor','y','facealpha',0.3); - elseif(strcmp(cfg(i).srctype,'slit') || strcmp(cfg(i).srctype,'line')) - if(~isfield(cfg(i),'srcparam1')) + nrec = [0 0 0; cfg(i).srcparam1(1:3) * voxelsize; cfg(i).srcparam1(1:3) * voxelsize + vec2; vec2]; + hsrcarea = plotmesh(nrec + repmat(srcpos(:)', [4, 1]), {[1 2 3 4 1]}); + elseif (strcmp(cfg(i).srctype, 'pattern3d')) + dim = cfg(i).srcparam1(1:3); + [bbxno, bbxfc] = latticegrid(0:dim(1):dim(1), 0:dim(2):dim(2), 0:dim(3):dim(3)); + hbbx = plotmesh(((bbxno + repmat(cfg(i).srcpos(1:3), size(bbxno, 1), 1)) + offset) * voxelsize, bbxfc, 'facecolor', 'y', 'facealpha', 0.3); + elseif (strcmp(cfg(i).srctype, 'slit') || strcmp(cfg(i).srctype, 'line')) + if (~isfield(cfg(i), 'srcparam1')) error('cfg.srcparam1 is missing'); end - hsrcarea=plotmesh([srcpos(1:3); cfg(i).srcparam1(1:3)*voxelsize],[1 2],'linewidth',3,'color','r'); + hsrcarea = plotmesh([srcpos(1:3); cfg(i).srcparam1(1:3) * voxelsize], [1 2], 'linewidth', 3, 'color', 'r'); end end - + % rendering detectors - hdet=[]; - if(isfield(cfg(i),'detpos')) - hdet=zeros(size(cfg(i).detpos,1),1); - detpos=cfg(i).detpos(:,1:3)*voxelsize; - if(size(cfg(i).detpos,2)==4) - detpos(:,4)=cfg(i).detpos(:,4)*voxelsize; + hdet = []; + if (isfield(cfg(i), 'detpos')) + hdet = zeros(size(cfg(i).detpos, 1), 1); + detpos = cfg(i).detpos(:, 1:3) * voxelsize; + if (size(cfg(i).detpos, 2) == 4) + detpos(:, 4) = cfg(i).detpos(:, 4) * voxelsize; else - detpos(:,4)=1; + detpos(:, 4) = 1; end - for id=1:size(detpos,1) - [sx,sy,sz]=sphere; - hdet(id)=surf(sx*detpos(id,4)+(detpos(id,1)), ... - sy*detpos(id,4)+(detpos(id,2)), ... - sz*detpos(id,4)+(detpos(id,3)), ... - 'facealpha',0.3,'facecolor','g','linestyle','none'); + for id = 1:size(detpos, 1) + [sx, sy, sz] = sphere; + hdet(id) = surf(sx * detpos(id, 4) + (detpos(id, 1)), ... + sy * detpos(id, 4) + (detpos(id, 2)), ... + sz * detpos(id, 4) + (detpos(id, 3)), ... + 'facealpha', 0.3, 'facecolor', 'g', 'linestyle', 'none'); end end - + % combining all handles - if(nargout>0) - hs{i}=struct('bbx',hbbx, 'seg', hseg, 'src', hsrc, 'srcarrow', hdir, 'srcarea', hsrcarea, 'det', hdet); + if (nargout > 0) + hs{i} = struct('bbx', hbbx, 'seg', hseg, 'src', hsrc, 'srcarrow', hdir, 'srcarea', hsrcarea, 'det', hdet); end end -if(~isholdplot) +if (~isholdplot) hold off; end -rand ('state',rngstate); +rand ('state', rngstate); diff --git a/utils/mcxrfreplay.m b/utils/mcxrfreplay.m index bc7558a5..c723adde 100644 --- a/utils/mcxrfreplay.m +++ b/utils/mcxrfreplay.m @@ -1,4 +1,4 @@ -function [rfjac_lnA, rfjac_phase]=mcxrfreplay(cfg,f_mod,detp,seeds,detnums) +function [rfjac_lnA, rfjac_phase] = mcxrfreplay(cfg, f_mod, detp, seeds, detnums) % % [rfjac_lnA, rfjac_phase]=mcxrfreplay(cfg,f_mod,detp,seeds,detnums) % @@ -29,57 +29,56 @@ % License: GPLv3, see http://mcx.space/ for details % -if(nargin<5) +if (nargin < 5) error('you must provide all 5 required input parameters'); end -if(~isfield(cfg,'unitinmm')) +if (~isfield(cfg, 'unitinmm')) cfg.unitinmm = 1; end % Initialize the 4D arrays for collecting the Jacobians. The 4th dimension % corresponds to the detector index. -rfjac_lnA=zeros([size(cfg.vol),length(detnums)]); -rfjac_phase=zeros([size(cfg.vol),length(detnums)]); +rfjac_lnA = zeros([size(cfg.vol), length(detnums)]); +rfjac_phase = zeros([size(cfg.vol), length(detnums)]); % Collect Jacobians one detector index at a time. for d = detnums % MCXLAB REPLAY SETTINGS - clear cfg_jac - cfg_jac=cfg; - cfg_jac.seed=seeds.data; - cfg_jac.detphotons=detp.data; - cfg_jac.replaydet=d; - cfg_jac.outputtype='rf'; - cfg_jac.omega=2*pi*f_mod; % 100 MHz RF modulation - cfg_jac.isnormalized=0; % ! + clear cfg_jac; + cfg_jac = cfg; + cfg_jac.seed = seeds.data; + cfg_jac.detphotons = detp.data; + cfg_jac.replaydet = d; + cfg_jac.outputtype = 'rf'; + cfg_jac.omega = 2 * pi * f_mod; % 100 MHz RF modulation + cfg_jac.isnormalized = 0; % ! % REPLAY SIMULATION - [rfjac_d, detp_d, vol_d, seeds_d]=mcxlab(cfg_jac); - detw=mcxdetweight(detp_d,cfg_jac.prop,cfg_jac.unitinmm); % array with detected photon weights - dett=mcxdettime(detp_d,cfg_jac.prop,cfg_jac.unitinmm); % array with photon time-of-flights + [rfjac_d, detp_d, vol_d, seeds_d] = mcxlab(cfg_jac); + detw = mcxdetweight(detp_d, cfg_jac.prop, cfg_jac.unitinmm); % array with detected photon weights + dett = mcxdettime(detp_d, cfg_jac.prop, cfg_jac.unitinmm); % array with photon time-of-flights % FD MEASUREMENT ESTIMATES - X=dot(detw,cos((2*f_mod).*dett*pi)); - Y=dot(detw,sin((2*f_mod).*dett*pi)); - A=sqrt(X^2 + Y^2); % amplitude [a.u.] - phase=atan2(Y,X) + (double(atan2(Y,X)<0))*2*pi; % phase shift in [0,2*pi] [rad] - if A==0 - fprintf('MCX WARNING: No detected photons for detector %d.\n',d) - continue; + X = dot(detw, cos((2 * f_mod) .* dett * pi)); + Y = dot(detw, sin((2 * f_mod) .* dett * pi)); + A = sqrt(X^2 + Y^2); % amplitude [a.u.] + phase = atan2(Y, X) + (double(atan2(Y, X) < 0)) * 2 * pi; % phase shift in [0,2*pi] [rad] + if A == 0 + fprintf('MCX WARNING: No detected photons for detector %d.\n', d); + continue end % FD JACOBIANS % Compute the Jacobians with the rf replay feature. - rfjac_d=sum(rfjac_d.data,4); % sum over time instances - if cfg_jac.isnormalized==0 - rfjac_d=(cfg_jac.unitinmm).*rfjac_d; % correct units to [mm] + rfjac_d = sum(rfjac_d.data, 4); % sum over time instances + if cfg_jac.isnormalized == 0 + rfjac_d = (cfg_jac.unitinmm) .* rfjac_d; % correct units to [mm] end % Jacobians for X and Y wrt mua: - rfjac_X=rfjac_d(:,:,:,:,:,1); - rfjac_Y=rfjac_d(:,:,:,:,:,2); + rfjac_X = rfjac_d(:, :, :, :, :, 1); + rfjac_Y = rfjac_d(:, :, :, :, :, 2); % Jacobians for log-amplitude and phase shift wrt mua: - rfjac_lnA(:,:,:,d)=(1/(A^2)).*(X.*rfjac_X + Y.*rfjac_Y); - rfjac_phase(:,:,:,d)=(1/(A^2)).*(X.*rfjac_Y - Y.*rfjac_X); + rfjac_lnA(:, :, :, d) = (1 / (A^2)) .* (X .* rfjac_X + Y .* rfjac_Y); + rfjac_phase(:, :, :, d) = (1 / (A^2)) .* (X .* rfjac_Y - Y .* rfjac_X); end - diff --git a/utils/mcxsvmc.m b/utils/mcxsvmc.m index f75c08ce..26cab2bf 100644 --- a/utils/mcxsvmc.m +++ b/utils/mcxsvmc.m @@ -1,4 +1,4 @@ -function [bmask,uniqidx,nc,nn,totalarea,iso]=mcxsvmc(vol, varargin) +function [bmask, uniqidx, nc, nn, totalarea, iso] = mcxsvmc(vol, varargin) % % Format: % newvol=mcxsvmc(vol) @@ -34,7 +34,7 @@ % records the higher-valued label ID in a mixed label voxel % uniqidx: the 1-D index of all voxels that are made of mixed labels % nc: nc is a Nx3 array, where N is the length of uniqidx, representing -% the reference point of the intravoxel interface in a mixed label +% the reference point of the intravoxel interface in a mixed label % voxel % nn: nn is a Nx3 array, where N is the length of uniqidx, representing % the normalized normal vector in a mixed label voxel, pointing @@ -66,174 +66,173 @@ % %% parse user options -opt=varargin2struct(varargin{:}); -dodebug=jsonopt('debug',0,opt); -ksize=jsonopt('kernelsize',3,opt); -kstd=jsonopt('kernelstd',1,opt); -level=jsonopt('threshold',0.5,opt); -debugpatch=jsonopt('debugpatch',1,opt); -bmask=jsonopt('bmask',NaN(size(vol)),opt); -dosmooth=jsonopt('smoothing',1,opt); -curveonly=jsonopt('curveonly',1,opt); - -bmask2=zeros(size(vol)); +opt = varargin2struct(varargin{:}); +dodebug = jsonopt('debug', 0, opt); +ksize = jsonopt('kernelsize', 3, opt); +kstd = jsonopt('kernelstd', 1, opt); +level = jsonopt('threshold', 0.5, opt); +debugpatch = jsonopt('debugpatch', 1, opt); +bmask = jsonopt('bmask', NaN(size(vol)), opt); +dosmooth = jsonopt('smoothing', 1, opt); +curveonly = jsonopt('curveonly', 1, opt); + +bmask2 = zeros(size(vol)); %% read unique labels -labels=sort(unique(vol(:))); +labels = sort(unique(vol(:))); % labels(labels==0)=[]; -if(length(labels)>255) +if (length(labels) > 255) error('MCX currently supports up to 255 labels for this function'); end %% loop over unique labels in ascending order -iso=struct('vertices',[],'faces',[]); +iso = struct('vertices', [], 'faces', []); -for i=1:length(labels) +for i = 1:length(labels) % convert each label into a binary mask, smooth it, then extract the % isosurface using marching cube algorithm (matlab builtin) - if(dosmooth) - volsmooth=smooth3(double(vol==labels(i)),'g',ksize,kstd); + if (dosmooth) + volsmooth = smooth3(double(vol == labels(i)), 'g', ksize, kstd); else - volsmooth=(vol==labels(i)); + volsmooth = (vol == labels(i)); end - [xi,yi,zi]=ndgrid(1:size(volsmooth,1),1:size(volsmooth,2),1:size(volsmooth,3)); - fv0=isosurface(xi,yi,zi,volsmooth,level); - if(isempty(fv0.vertices)) - continue; + [xi, yi, zi] = ndgrid(1:size(volsmooth, 1), 1:size(volsmooth, 2), 1:size(volsmooth, 3)); + fv0 = isosurface(xi, yi, zi, volsmooth, level); + if (isempty(fv0.vertices)) + continue end % get the containing voxel linear id - c0=meshcentroid(fv0.vertices,fv0.faces); - voxid=sub2ind(size(vol),floor(c0(:,1))+1,floor(c0(:,2))+1,floor(c0(:,3))+1); + c0 = meshcentroid(fv0.vertices, fv0.faces); + voxid = sub2ind(size(vol), floor(c0(:, 1)) + 1, floor(c0(:, 2)) + 1, floor(c0(:, 3)) + 1); % identify unique voxels - uniqidx=unique(voxid); - bmask2(uniqidx)=labels(i); - + uniqidx = unique(voxid); + bmask2(uniqidx) = labels(i); + % find new boundary voxels that are not covered by previous levelsets - uniqidx=uniqidx(isnan(bmask(uniqidx))); - goodpatchidx=ismember(voxid,uniqidx); - + uniqidx = uniqidx(isnan(bmask(uniqidx))); + goodpatchidx = ismember(voxid, uniqidx); + % merge surface patches located inside new boundary voxels - iso.faces=[iso.faces; size(iso.vertices,1)+fv0.faces(goodpatchidx==1,:)]; - iso.vertices=[iso.vertices; fv0.vertices]; - + iso.faces = [iso.faces; size(iso.vertices, 1) + fv0.faces(goodpatchidx == 1, :)]; + iso.vertices = [iso.vertices; fv0.vertices]; + % label those voxels as covered - bmask(uniqidx)=labels(i); + bmask(uniqidx) = labels(i); end %% handle uniform domains -if(isempty(iso.vertices)) - uniqidx=[]; - nn=[]; - totalarea=[]; - return; +if (isempty(iso.vertices)) + uniqidx = []; + nn = []; + totalarea = []; + return end %% get the voxel mapping for the final combined isosurface -[iso.vertices,iso.faces]=removeisolatednode(iso.vertices,iso.faces); -c0=meshcentroid(iso.vertices,iso.faces); -voxid=sub2ind(size(vol),floor(c0(:,1))+1,floor(c0(:,2))+1,floor(c0(:,3))+1); -[uniqidx, vox2patch]=unique(voxid); - -[cc1,cc2]=histc(voxid,uniqidx); -cc=cc1(cc2); - -if(dodebug) - plotmesh(iso.vertices,iso.faces,'facealpha',0.4,'facecolor','b','edgealpha',0.2) - disp(max(iso.vertices)-min(iso.vertices)) +[iso.vertices, iso.faces] = removeisolatednode(iso.vertices, iso.faces); +c0 = meshcentroid(iso.vertices, iso.faces); +voxid = sub2ind(size(vol), floor(c0(:, 1)) + 1, floor(c0(:, 2)) + 1, floor(c0(:, 3)) + 1); +[uniqidx, vox2patch] = unique(voxid); + +[cc1, cc2] = histc(voxid, uniqidx); +cc = cc1(cc2); + +if (dodebug) + plotmesh(iso.vertices, iso.faces, 'facealpha', 0.4, 'facecolor', 'b', 'edgealpha', 0.2); + disp(max(iso.vertices) - min(iso.vertices)); end %% obtain the low and high labels in all mix-label voxels -bmask=[bmask(uniqidx),bmask2(uniqidx)]; -bmask(bmask(:,1)==bmask(:,2),2)=0; +bmask = [bmask(uniqidx), bmask2(uniqidx)]; +bmask(bmask(:, 1) == bmask(:, 2), 2) = 0; %% computing total area and normal vector for each boundary voxel -areas=elemvolume(iso.vertices,iso.faces); -normals=surfacenorm(iso.vertices,iso.faces); -centroids=meshcentroid(iso.vertices,iso.faces); +areas = elemvolume(iso.vertices, iso.faces); +normals = surfacenorm(iso.vertices, iso.faces); +centroids = meshcentroid(iso.vertices, iso.faces); -totalarea=zeros(size(vol)); -maxvid=max(voxid); -totalarea(1:maxvid)=accumarray(voxid,areas); % total areas of cross-sections in each boundary voxel +totalarea = zeros(size(vol)); +maxvid = max(voxid); +totalarea(1:maxvid) = accumarray(voxid, areas); % total areas of cross-sections in each boundary voxel % totalarea_unique=totalarea(uniqidx); %% compute weighted average surface centroid per boundary voxel; -nc=zeros([3 size(vol)]); -nc(1,1:maxvid)=accumarray(voxid,centroids(:,1).*areas); % total normal_x of cross-sections in each boundary voxel -nc(2,1:maxvid)=accumarray(voxid,centroids(:,2).*areas); % total normal_y of cross-sections in each boundary voxel -nc(3,1:maxvid)=accumarray(voxid,centroids(:,3).*areas); % total normal_z of cross-sections in each boundary voxel -for i=1:3 - nc(i,uniqidx)=nc(i,uniqidx)./totalarea(uniqidx)'; +nc = zeros([3 size(vol)]); +nc(1, 1:maxvid) = accumarray(voxid, centroids(:, 1) .* areas); % total normal_x of cross-sections in each boundary voxel +nc(2, 1:maxvid) = accumarray(voxid, centroids(:, 2) .* areas); % total normal_y of cross-sections in each boundary voxel +nc(3, 1:maxvid) = accumarray(voxid, centroids(:, 3) .* areas); % total normal_z of cross-sections in each boundary voxel +for i = 1:3 + nc(i, uniqidx) = nc(i, uniqidx) ./ totalarea(uniqidx)'; end -nc=nc(:,uniqidx)'; +nc = nc(:, uniqidx)'; %% creating weighted average surface patch normals per boundary voxel -nn=zeros([3 size(vol)]); -nn(1,1:maxvid)=accumarray(voxid,normals(:,1).*areas); % total normal_x of cross-sections in each boundary voxel -nn(2,1:maxvid)=accumarray(voxid,normals(:,2).*areas); % total normal_y of cross-sections in each boundary voxel -nn(3,1:maxvid)=accumarray(voxid,normals(:,3).*areas); % total normal_z of cross-sections in each boundary voxel -nnlen=sqrt(sum(nn.*nn,1)); -for i=1:3 - nn(i,uniqidx)=nn(i,uniqidx)./nnlen(uniqidx)'; +nn = zeros([3 size(vol)]); +nn(1, 1:maxvid) = accumarray(voxid, normals(:, 1) .* areas); % total normal_x of cross-sections in each boundary voxel +nn(2, 1:maxvid) = accumarray(voxid, normals(:, 2) .* areas); % total normal_y of cross-sections in each boundary voxel +nn(3, 1:maxvid) = accumarray(voxid, normals(:, 3) .* areas); % total normal_z of cross-sections in each boundary voxel +nnlen = sqrt(sum(nn .* nn, 1)); +for i = 1:3 + nn(i, uniqidx) = nn(i, uniqidx) ./ nnlen(uniqidx)'; end -nn=nn(:,uniqidx)'; - -%% remove x/y/z oriented -if(curveonly) - [ixc,iyc]=find((nc-floor(nc))<1e-6); - [ixn,iyn]=find(abs(nn)==1); - ix=intersect(ixc,ixn); - boxmask=zeros(size(vol)); - boxmask(uniqidx(ix))=1; - boxmask=smooth3(boxmask,'b',3); - boxmask=(boxmask>0); - ix=find(boxmask(uniqidx)==1); - - nn(ix,:)=[]; - nc(ix,:)=[]; - uniqidx(ix)=[]; - bmask(ix,:)=[]; - totalarea(ix)=[]; +nn = nn(:, uniqidx)'; + +%% remove x/y/z oriented +if (curveonly) + [ixc, iyc] = find((nc - floor(nc)) < 1e-6); + [ixn, iyn] = find(abs(nn) == 1); + ix = intersect(ixc, ixn); + boxmask = zeros(size(vol)); + boxmask(uniqidx(ix)) = 1; + boxmask = smooth3(boxmask, 'b', 3); + boxmask = (boxmask > 0); + ix = find(boxmask(uniqidx) == 1); + + nn(ix, :) = []; + nc(ix, :) = []; + uniqidx(ix) = []; + bmask(ix, :) = []; + totalarea(ix) = []; end %% discretize nn and nc vector components to 0-255 gray-scale numbers -nc=nc-floor(nc); -nc=floor(nc*255); -nn=min(floor((nn+1)*255/2),254); +nc = nc - floor(nc); +nc = floor(nc * 255); +nn = min(floor((nn + 1) * 255 / 2), 254); %% assemble the final volume -if(nargout==1) - newvol=zeros([8,size(vol)]); - newvol(1,:,:,:)=vol; - newvol(1:2,uniqidx)=bmask'; - newvol(3:5,uniqidx)=nc'; - newvol(6:8,uniqidx)=nn'; - bmask=newvol; +if (nargout == 1) + newvol = zeros([8, size(vol)]); + newvol(1, :, :, :) = vol; + newvol(1:2, uniqidx) = bmask'; + newvol(3:5, uniqidx) = nc'; + newvol(6:8, uniqidx) = nn'; + bmask = newvol; end %% plotting for verification -if(dodebug) +if (dodebug) figure; - pcidx=find(cc>1); % find 4-patch that blong to the same voxel (in patch idx) - pidx0=pcidx(debugpatch); % pick one such patch group to debug - idx1=voxid(pidx0); % find the corresponding voxel id idx1 for the patch pidx0 - patid=voxid==idx1; % these patches are within voxel linear id idx1 + pcidx = find(cc > 1); % find 4-patch that blong to the same voxel (in patch idx) + pidx0 = pcidx(debugpatch); % pick one such patch group to debug + idx1 = voxid(pidx0); % find the corresponding voxel id idx1 for the patch pidx0 + patid = voxid == idx1; % these patches are within voxel linear id idx1 - testmask=zeros(size(volsmooth)); - testmask(idx1)=1; - [no3,fc3]=binsurface(testmask,4); + testmask = zeros(size(volsmooth)); + testmask(idx1) = 1; + [no3, fc3] = binsurface(testmask, 4); figure; - plotmesh(no3,fc3,'facealpha',0.3,'facecolor','none') + plotmesh(no3, fc3, 'facealpha', 0.3, 'facecolor', 'none'); hold on; - plotmesh(iso.vertices,iso.faces(patid,:),'facealpha',0.3,'facecolor','b','edgealpha',0.2) - disp(nn(cc2(pidx0),:)) % normal in voxel id idx1 - plotmesh([c0(pidx0,:); c0(pidx0,:)+nn(cc2(pidx0),:)],'ro-'); % plot centroid of pidx0-th patch to the normal in voxel id idx1 + plotmesh(iso.vertices, iso.faces(patid, :), 'facealpha', 0.3, 'facecolor', 'b', 'edgealpha', 0.2); + disp(nn(cc2(pidx0), :)); % normal in voxel id idx1 + plotmesh([c0(pidx0, :); c0(pidx0, :) + nn(cc2(pidx0), :)], 'ro-'); % plot centroid of pidx0-th patch to the normal in voxel id idx1 end - diff --git a/utils/normalizemcx.m b/utils/normalizemcx.m index d443df81..775adf5a 100644 --- a/utils/normalizemcx.m +++ b/utils/normalizemcx.m @@ -1,12 +1,12 @@ -function phi=normalizemcx(data,mua,Vvox,dt,energyabsorbed,energytotal) +function phi = normalizemcx(data, mua, Vvox, dt, energyabsorbed, energytotal) % % phi=normalizemcx(data,mua,Vvox,dt,energyabsorbed,energytotal) -% +% % Normalization of fluence distributions from Monte-Carlo simulations % % author: Qianqian Fang (q.fang neu.edu) % -% input: +% input: % data: a 3D or 4D array for the raw output from MCX (probability) % mua: absorption coeff, with the same dimensions as data % Vvox: volume of a voxel (1/mm^3) @@ -17,15 +17,15 @@ % output: % phi: the fluence under a unitary source % -% For tMCimg output, set energyabsorbed to -1 and energytotal to +% For tMCimg output, set energyabsorbed to -1 and energytotal to % the total photon numbers % % This subroutine of part of Monte-Carlo eXtreme (mcx) package % -if(energyabsorbed<0) - energyabsorbed=energytotal+sum(data(find(data<0))); - data(find(data<0))=0; +if (energyabsorbed < 0) + energyabsorbed = energytotal + sum(data(find(data < 0))); + data(find(data < 0)) = 0; end -alpha=energyabsorbed/energytotal/(Vvox*sum(data(:).*mua(:)))/(dt); -phi=alpha*data; +alpha = energyabsorbed / energytotal / (Vvox * sum(data(:) .* mua(:))) / (dt); +phi = alpha * data; diff --git a/utils/rbgetreff.m b/utils/rbgetreff.m index c15cc862..df93befd 100644 --- a/utils/rbgetreff.m +++ b/utils/rbgetreff.m @@ -1,50 +1,50 @@ -function Reff = rbgetreff(n_in,n_out) -% -% Reff = rbgetreff(n_in,n_out) -% -% given refractive index of the diffuse medium, calculate the effective -% refractive index, defined as in Haskell 1994 paper. -% -% author: David Boas -% -% input: -% n_in: the refractive index n of the interior of the domain -% n_out: the refractive index n of the outside space -% -% output: -% Reff: effective reflection coefficient, see -% -% license: -% GPL version 3, see LICENSE_GPLv3.txt files for details -% -% original file name calcExtBnd -% this file was modified from the PMI toolbox -% -- this function is part of Redbird-m toolbox -% - -if(nargin==1) - n_out=1; -end - -oc = asin(1/n_in); -ostep = pi / 2000; - -o = 0:ostep:oc; - -cosop = (1-n_in^2 * sin(o).^2).^0.5; -coso = cos(o); -r_fres = 0.5 * ( (n_in*cosop-n_out*coso)./(n_in*cosop+n_out*coso) ).^2; -r_fres = r_fres + 0.5 * ( (n_in*coso-n_out*cosop)./(n_in*coso+n_out*cosop) ).^2; - -r_fres(ceil(oc/ostep):1000) = 1; - -o = 0:ostep:ostep*(length(r_fres)-1); -coso = cos(o); - -r_phi_int = 2 * sin(o) .* coso .* r_fres; -r_phi = sum(r_phi_int) / 1000 * pi/2; - -r_j_int = 3 * sin(o) .* coso.^2 .* r_fres; -r_j = sum(r_j_int) / 1000 * pi/2; - -Reff = (r_phi + r_j) / (2 - r_phi + r_j); +function Reff = rbgetreff(n_in, n_out) +% +% Reff = rbgetreff(n_in,n_out) +% +% given refractive index of the diffuse medium, calculate the effective +% refractive index, defined as in Haskell 1994 paper. +% +% author: David Boas +% +% input: +% n_in: the refractive index n of the interior of the domain +% n_out: the refractive index n of the outside space +% +% output: +% Reff: effective reflection coefficient, see +% +% license: +% GPL version 3, see LICENSE_GPLv3.txt files for details +% +% original file name calcExtBnd +% this file was modified from the PMI toolbox +% -- this function is part of Redbird-m toolbox +% + +if (nargin == 1) + n_out = 1; +end + +oc = asin(1 / n_in); +ostep = pi / 2000; + +o = 0:ostep:oc; + +cosop = (1 - n_in^2 * sin(o).^2).^0.5; +coso = cos(o); +r_fres = 0.5 * ((n_in * cosop - n_out * coso) ./ (n_in * cosop + n_out * coso)).^2; +r_fres = r_fres + 0.5 * ((n_in * coso - n_out * cosop) ./ (n_in * coso + n_out * cosop)).^2; + +r_fres(ceil(oc / ostep):1000) = 1; + +o = 0:ostep:ostep * (length(r_fres) - 1); +coso = cos(o); + +r_phi_int = 2 * sin(o) .* coso .* r_fres; +r_phi = sum(r_phi_int) / 1000 * pi / 2; + +r_j_int = 3 * sin(o) .* coso.^2 .* r_fres; +r_j = sum(r_j_int) / 1000 * pi / 2; + +Reff = (r_phi + r_j) / (2 - r_phi + r_j); diff --git a/utils/serialcorr.m b/utils/serialcorr.m index 7c3c4c79..661de267 100644 --- a/utils/serialcorr.m +++ b/utils/serialcorr.m @@ -1,4 +1,4 @@ -function report=serialcorr(randomseq,maxshift) +function report = serialcorr(randomseq, maxshift) % report=serialcorr(randomseq,maxshift) % % serial correlation function in a random sequence at a range of separations @@ -10,16 +10,16 @@ % maxshift: the maximum separation to test with % % output: -% report: the corr. coeff for the sequence between randomseq +% report: the corr. coeff for the sequence between randomseq % and randomseq(i:end) where i<=maxshift % % this file is part of Monte Carlo eXtreme (MCX) % License: GPLv3, see http://mcx.sf.net for details % see Boas2002, Heskell1996 -report=zeros(maxshift,2); -for i=1:maxshift - [r,p]=corrcoef(randomseq(1:end-i),randomseq(i+1:end)); - report(i,:)=[r(1,2),p(1,2)]; - fprintf(1,'test shift %d (r=%20.16f p=%20.16f)\n',i,r(1,2),p(1,2)); +report = zeros(maxshift, 2); +for i = 1:maxshift + [r, p] = corrcoef(randomseq(1:end - i), randomseq(i + 1:end)); + report(i, :) = [r(1, 2), p(1, 2)]; + fprintf(1, 'test shift %d (r=%20.16f p=%20.16f)\n', i, r(1, 2), p(1, 2)); end diff --git a/utils/slice3i.m b/utils/slice3i.m index 2c3c1066..692fe42b 100644 --- a/utils/slice3i.m +++ b/utils/slice3i.m @@ -1,6 +1,6 @@ function h = slice3i(vol, I2X, slicedim, sliceidx, handle, keepxyz) % Display a slice from a volume in 3-D -% h = slice3(vol, I2X, slicedim, sliceidx, handle) +% h = slice3(vol, I2X, slicedim, sliceidx, handle) % % Vol is either a scalar or RGB volume, e.g. N x M x K or N x M x K x 3. % I2X is a transformation matrix from volume coordinates to xyz 3-D world @@ -29,15 +29,15 @@ % % Modified by Qianqian Fang, q.fang at neu.edu % -% Features added: +% Features added: % 1) compatible with octave 4.0 or newer % 2) start 3D rotation by clicking/holding the middle mouse key % 3) adjust colormap levels by dragging with the right mouse key % 4) support 4-D data (up/down key to change frames) -% +% -if(nargin<6) - keepxyz=0; +if (nargin < 6) + keepxyz = 0; end try @@ -45,160 +45,155 @@ catch h = update_slice(vol, I2X, slicedim, sliceidx); end - + % set up gui gui.handle = h; gui.vol = vol; gui.I2X = I2X; gui.slicedim = slicedim; gui.sliceidx = sliceidx; -set(gui.handle,'ButtonDownFcn',@startmovit); +set(gui.handle, 'ButtonDownFcn', @startmovit); -set(h,'UserData',gui); +set(h, 'UserData', gui); -function stoprotate(src,hrot) -if strcmp(get(gcf,'SelectionType'), 'extend') +function stoprotate(src, hrot) +if strcmp(get(gcf, 'SelectionType'), 'extend') rotate3d off; end -function startmovit(src,evnt) +function startmovit(src, evnt) -if strcmp(get(gcf,'SelectionType'), 'extend') +if strcmp(get(gcf, 'SelectionType'), 'extend') rotate3d on; - return; + return end % Unpack gui object -gui = get(src,'UserData'); -%turn off mouse pointer -%set(gcf,'PointerShapeCData',nan(16,16)); -%set(gcf,'Pointer','custom'); +gui = get(src, 'UserData'); +% turn off mouse pointer +% set(gcf,'PointerShapeCData',nan(16,16)); +% set(gcf,'Pointer','custom'); thisfig = gcbf(); -gui.startray = get(gca,'CurrentPoint'); +gui.startray = get(gca, 'CurrentPoint'); gui.startidx = gui.sliceidx; -gui.p0=get(gcf,'currentpoint'); -gui.level0=size(colormap,1); - +gui.p0 = get(gcf, 'currentpoint'); +gui.level0 = size(colormap, 1); % Store gui object -set(src,'UserData',gui); -set(thisfig,'WindowButtonMotionFcn',@movit); -set(thisfig,'WindowButtonUpFcn',@stopmovit); -set(thisfig,'UserData',src); - +set(src, 'UserData', gui); +set(thisfig, 'WindowButtonMotionFcn', @movit); +set(thisfig, 'WindowButtonUpFcn', @stopmovit); +set(thisfig, 'UserData', src); -function movit(src,evnt) +function movit(src, evnt) % Unpack gui object -gui = get(get(gcf,'UserData'),'UserData'); +gui = get(get(gcf, 'UserData'), 'UserData'); % Some safetymeasures try -if isequal(gui.startray,[]) - return -end + if isequal(gui.startray, []) + return + end catch end -if strcmp(get(gcf,'SelectionType'), 'alt') - if(isempty(gui) || ~isfield(gui,'p0')) - return; +if strcmp(get(gcf, 'SelectionType'), 'alt') + if (isempty(gui) || ~isfield(gui, 'p0')) + return end - delta=get(gcf,'currentpoint')-gui.p0; - windim=get(gcf,'position'); - delta=delta./windim(3:4); - currentlevel=round(gui.level0+delta(2)/4*256); - if(currentlevel>256) - currentlevel=256; - elseif(currentlevel<8) - currentlevel=8; + delta = get(gcf, 'currentpoint') - gui.p0; + windim = get(gcf, 'position'); + delta = delta ./ windim(3:4); + currentlevel = round(gui.level0 + delta(2) / 4 * 256); + if (currentlevel > 256) + currentlevel = 256; + elseif (currentlevel < 8) + currentlevel = 8; end colormap(jet(currentlevel)); - return; + return end % Do "smart" positioning of the markers... -nowray = get(gca,'CurrentPoint'); +nowray = get(gca, 'CurrentPoint'); % Project rays on slice-axis -s = gui.I2X(1:3,gui.slicedim); -a = gui.startray(1,:)'; -b = gui.startray(2,:)'; +s = gui.I2X(1:3, gui.slicedim); +a = gui.startray(1, :)'; +b = gui.startray(2, :)'; -alphabeta = pinv([s'*s, -s'*(b-a);(b-a)'*s, -(b-a)'*(b-a)])*[s'*a, (b-a)'*a]'; -pstart = alphabeta(1)*s; +alphabeta = pinv([s' * s, -s' * (b - a); (b - a)' * s, -(b - a)' * (b - a)]) * [s' * a, (b - a)' * a]'; +pstart = alphabeta(1) * s; alphastart = alphabeta(1); -a = nowray(1,:)'; -b = nowray(2,:)'; -alphabeta = pinv([s'*s, -s'*(b-a);(b-a)'*s, -(b-a)'*(b-a)])*[s'*a, (b-a)'*a]'; -pnow = alphabeta(1)*s; +a = nowray(1, :)'; +b = nowray(2, :)'; +alphabeta = pinv([s' * s, -s' * (b - a); (b - a)' * s, -(b - a)' * (b - a)]) * [s' * a, (b - a)' * a]'; +pnow = alphabeta(1) * s; alphanow = alphabeta(1); -slicediff = alphanow-alphastart; +slicediff = alphanow - alphastart; -gui.sliceidx = gui.startidx+slicediff; -gui.sliceidx = min(max(1,gui.sliceidx),size(gui.vol,gui.slicedim)); +gui.sliceidx = gui.startidx + slicediff; +gui.sliceidx = min(max(1, gui.sliceidx), size(gui.vol, gui.slicedim)); update_slice(gui.vol, gui.I2X, gui.slicedim, gui.sliceidx, gui.handle); drawnow; % Store gui object -set(get(gcf,'UserData'),'UserData',gui); +set(get(gcf, 'UserData'), 'UserData', gui); - -function stopmovit(src,evnt) +function stopmovit(src, evnt) thisfig = gcbf(); -%set(gcf,'Pointer','arrow'); -set(thisfig,'WindowButtonUpFcn',''); -set(thisfig,'WindowButtonMotionFcn',''); -gui = get(get(gcf,'UserData'),'UserData'); +% set(gcf,'Pointer','arrow'); +set(thisfig, 'WindowButtonUpFcn', ''); +set(thisfig, 'WindowButtonMotionFcn', ''); +gui = get(get(gcf, 'UserData'), 'UserData'); gui.startray = []; -%gui.sliceidx = gui.nextsliceidx -set(get(gcf,'UserData'),'UserData',gui); -set(gcf,'UserData',[]); +% gui.sliceidx = gui.nextsliceidx +set(get(gcf, 'UserData'), 'UserData', gui); +set(gcf, 'UserData', []); drawnow; function h = update_slice(vol, I2X, slicedim, sliceidx, handle, keepxyz) -if(nargin<6) - keepxyz=0; +if (nargin < 6) + keepxyz = 0; end -if ndims(vol) == 3 %Scalar mode -elseif ndims(vol) == 4 %RGB mode - if(size(vol,4)>3) - gui = get(get(gcf,'UserData'),'UserData'); - if(~isempty(gui) && isfield(gui,'frame')) - vol=gui.vol(:,:,:,gui.frame); +if ndims(vol) == 3 % Scalar mode +elseif ndims(vol) == 4 % RGB mode + if (size(vol, 4) > 3) + gui = get(get(gcf, 'UserData'), 'UserData'); + if (~isempty(gui) && isfield(gui, 'frame')) + vol = gui.vol(:, :, :, gui.frame); else - vol=gui.vol(:,:,:,1); + vol = gui.vol(:, :, :, 1); end end else - error('Only scalar and RGB images supported') + error('Only scalar and RGB images supported'); end % Create the slice if slicedim == 3 % k - ij2xyz = I2X(:,[1 2]); - ij2xyz(:,3) = I2X*[0 0 sliceidx 1]'; - sliceim = squeeze(vol(:,:,round(sliceidx),:)); + ij2xyz = I2X(:, [1 2]); + ij2xyz(:, 3) = I2X * [0 0 sliceidx 1]'; + sliceim = squeeze(vol(:, :, round(sliceidx), :)); elseif slicedim == 2 % j - ij2xyz = I2X(:,[1 3]); - ij2xyz(:,3) = I2X*[0 sliceidx 0 1]'; - sliceim = squeeze(vol(:,round(sliceidx),:,:)); + ij2xyz = I2X(:, [1 3]); + ij2xyz(:, 3) = I2X * [0 sliceidx 0 1]'; + sliceim = squeeze(vol(:, round(sliceidx), :, :)); elseif slicedim == 1 % i - ij2xyz = I2X(:,[2 3]); - ij2xyz(:,3) = I2X*[sliceidx 0 0 1]'; - sliceim = squeeze(vol(round(sliceidx),:,:,:)); + ij2xyz = I2X(:, [2 3]); + ij2xyz(:, 3) = I2X * [sliceidx 0 0 1]'; + sliceim = squeeze(vol(round(sliceidx), :, :, :)); else - error('Slicedim should be 1, 2 or 3') + error('Slicedim should be 1, 2 or 3'); end - -if nargin<5 || handle == 0 - h = image3i(sliceim,ij2xyz); +if nargin < 5 || handle == 0 + h = image3i(sliceim, ij2xyz); else - h = image3i(sliceim,ij2xyz,handle, keepxyz); + h = image3i(sliceim, ij2xyz, handle, keepxyz); end - diff --git a/utils/tddiffusion.m b/utils/tddiffusion.m index 46bc2b91..d583aab0 100644 --- a/utils/tddiffusion.m +++ b/utils/tddiffusion.m @@ -1,7 +1,7 @@ -function Phi = tddiffusion(mua, musp, v, Reff, srcpos,detpos, t) +function Phi = tddiffusion(mua, musp, v, Reff, srcpos, detpos, t) % % Phi = tddiffusion(mua, musp, v, Reff, srcpos,detpos, t) -% +% % semi-infinite medium analytical solution to diffusion model % % author: Qianqian Fang (q.fang neu.edu) @@ -13,7 +13,7 @@ % Reff: the effective reflection coeff. % srcpos:array for the source positions (x,y,z) % detpos:array for the detector positions (x,y,z) -% t: a list of time in s at which to evaluate the +% t: a list of time in s at which to evaluate the % analytical diffusion solution % % output: @@ -24,14 +24,14 @@ % see Boas2002 % -D = 1/(3*(mua+musp)); -zb = (1+Reff)/(1-Reff)*2*D; +D = 1 / (3 * (mua + musp)); +zb = (1 + Reff) / (1 - Reff) * 2 * D; -z0 = 1/(musp+mua); -r=getdistance([srcpos(:,1:2) srcpos(:,3)+z0],detpos); -r2=getdistance([srcpos(:,1:2) srcpos(:,3)-z0-2*zb],detpos); +z0 = 1 / (musp + mua); +r = getdistance([srcpos(:, 1:2) srcpos(:, 3) + z0], detpos); +r2 = getdistance([srcpos(:, 1:2) srcpos(:, 3) - z0 - 2 * zb], detpos); -s=4*D*v*t; +s = 4 * D * v * t; % unit of phi: 1/(mm^2*s) -Phi =v./((s*pi).^(3/2)).*exp(-mua*v*t).*(exp(-(r.^2)./s) - exp(-(r2.^2)./s)); +Phi = v ./ ((s * pi).^(3 / 2)) .* exp(-mua * v * t) .* (exp(-(r.^2) ./ s) - exp(-(r2.^2) ./ s));