diff --git a/examples/colin27/createmesh.m b/examples/colin27/createmesh.m index d56cbf14..6e6bd390 100644 --- a/examples/colin27/createmesh.m +++ b/examples/colin27/createmesh.m @@ -1,11 +1,11 @@ -addpath('../../../matlab/'); +addpath('../../../matlab/'); -if(~exist('MMC_Collins_Atlas_Mesh_Version_2L.mat','file')) - f=websave('MMC_Collins_Atlas_Mesh_Version_2L.mat','https://github.com/fangq/Colin27BrainMesh/raw/master/MMC_Collins_Atlas_Mesh_Version_2L.mat'); - if(~exist('MMC_Collins_Atlas_Mesh_Version_2L.mat','file')) - warning('Please download Colin27 atlas mesh from https://github.com/fangq/Colin27BrainMesh/raw/master/MMC_Collins_Atlas_Mesh_Version_2L.mat') - end +if (~exist('MMC_Collins_Atlas_Mesh_Version_2L.mat', 'file')) + f = websave('MMC_Collins_Atlas_Mesh_Version_2L.mat', 'https://github.com/fangq/Colin27BrainMesh/raw/master/MMC_Collins_Atlas_Mesh_Version_2L.mat'); + if (~exist('MMC_Collins_Atlas_Mesh_Version_2L.mat', 'file')) + warning('Please download Colin27 atlas mesh from https://github.com/fangq/Colin27BrainMesh/raw/master/MMC_Collins_Atlas_Mesh_Version_2L.mat'); + end end -load MMC_Collins_Atlas_Mesh_Version_2L.mat -savemmcmesh('brain',node,elem); +load MMC_Collins_Atlas_Mesh_Version_2L.mat; +savemmcmesh('brain', node, elem); diff --git a/examples/dcs/createmesh.m b/examples/dcs/createmesh.m index a01194d3..b84a9bbf 100644 --- a/examples/dcs/createmesh.m +++ b/examples/dcs/createmesh.m @@ -1,10 +1,9 @@ -addpath ../../matlab -srcpos=[50.5 50.5 0]; +addpath ../../matlab; +srcpos = [50.5 50.5 0]; fprintf('Generating mesh...'); -[node,elem] = genT5mesh(0:4:100,0:4:100,0:4:80); +[node, elem] = genT5mesh(0:4:100, 0:4:100, 0:4:80); fprintf('done\nSaving mesh..'); -savemmcmesh('dcs',node(:,1:3),elem); % 4th column of node is label and confuses savemmcmesh volume calculation +savemmcmesh('dcs', node(:, 1:3), elem); % 4th column of node is label and confuses savemmcmesh volume calculation fprintf('done\nFinding element enclosing source: '); -eid=tsearchn(node(:,1:3),elem(:,1:4),srcpos); -fprintf('%d\n',eid); - +eid = tsearchn(node(:, 1:3), elem(:, 1:4), srcpos); +fprintf('%d\n', eid); diff --git a/examples/dcs/dcs_example.m b/examples/dcs/dcs_example.m index 899554c9..45f14540 100644 --- a/examples/dcs/dcs_example.m +++ b/examples/dcs/dcs_example.m @@ -1,38 +1,40 @@ addpath('../../matlab'); -Db=1e-7; % simulated brownian motion diffusion coefficient -sim_beta=0.4; +Db = 1e-7; % simulated brownian motion diffusion coefficient +sim_beta = 0.4; -mua=0.01; -mus=1; -g=0.01; -musp=mus*(1-g); -sdsep=15; -prob_scat_moving_scat=1; +mua = 0.01; +mus = 1; +g = 0.01; +musp = mus * (1 - g); +sdsep = 15; +prob_scat_moving_scat = 1; - -[tau,g1]=generate_g1('dcs.mch',logspace(-8,0,200),'brownian',Db); +[tau, g1] = generate_g1('dcs.mch', logspace(-8, 0, 200), 'brownian', Db); figure(1); -for I=1:4, - subplot(2,2,I); - semilogx(tau,g1(I,:),'.'); - x=fminsearch(@(x) dcs_g1_Db_fms(x,tau,g1(I,:),sdsep,mua,musp,prob_scat_moving_scat),[1e-5]); +for I = 1:4 + subplot(2, 2, I); + semilogx(tau, g1(I, :), '.'); + x = fminsearch(@(x) dcs_g1_Db_fms(x, tau, g1(I, :), sdsep, mua, musp, prob_scat_moving_scat), [1e-5]); hold on; - semilogx(tau,dcs_g1_Db(x,tau,sdsep,mua,musp,prob_scat_moving_scat),'r'); - xlabel('\tau (s)'); ylabel('g_1(\tau)');axis tight; - title(['Det ' num2str(I) ': fit Db: ' sprintf('%.2g',x) ' err: ' num2str((x-Db)/Db*100,'%.1f') '%']); + semilogx(tau, dcs_g1_Db(x, tau, sdsep, mua, musp, prob_scat_moving_scat), 'r'); + xlabel('\tau (s)'); + ylabel('g_1(\tau)'); + axis tight; + title(['Det ' num2str(I) ': fit Db: ' sprintf('%.2g', x) ' err: ' num2str((x - Db) / Db * 100, '%.1f') '%']); end -figure(2); -for I=1:4, - subplot(2,2,I); - g2=1+sim_beta*g1(I,:).^2; - semilogx(tau,g2,'.'); - x=fminsearch(@(x) dcs_g2_Db_fms(x,tau,g2,sdsep,mua,musp,prob_scat_moving_scat),[1e-5 0.5]); +figure(2); +for I = 1:4 + subplot(2, 2, I); + g2 = 1 + sim_beta * g1(I, :).^2; + semilogx(tau, g2, '.'); + x = fminsearch(@(x) dcs_g2_Db_fms(x, tau, g2, sdsep, mua, musp, prob_scat_moving_scat), [1e-5 0.5]); hold on; - semilogx(tau,dcs_g2_Db(x(1),tau,sdsep,mua,musp,prob_scat_moving_scat,x(2)),'r'); - xlabel('\tau (s)'); ylabel('g_2(\tau)');axis tight; - title(['Det ' num2str(I) ': fit Db: ' sprintf('%.2g',x(1)) ' err: ' num2str((x(1)-Db)/Db*100,'%.1f') '%']); + semilogx(tau, dcs_g2_Db(x(1), tau, sdsep, mua, musp, prob_scat_moving_scat, x(2)), 'r'); + xlabel('\tau (s)'); + ylabel('g_2(\tau)'); + axis tight; + title(['Det ' num2str(I) ': fit Db: ' sprintf('%.2g', x(1)) ' err: ' num2str((x(1) - Db) / Db * 100, '%.1f') '%']); end - diff --git a/examples/dcs/dcs_g1_Db.m b/examples/dcs/dcs_g1_Db.m index edcbec97..275f5199 100644 --- a/examples/dcs/dcs_g1_Db.m +++ b/examples/dcs/dcs_g1_Db.m @@ -1,16 +1,18 @@ -function result=dcs_g1_Db(Db,tau,sdsep,mu_a,mu_sp,alpha) -% +function result = dcs_g1_Db(Db, tau, sdsep, mu_a, mu_sp, alpha) +% % this function generates analytical auto-correlation decay for a semi- % infinite medium % % sdsep, mu_a and mu_sp units must be mm -zo=(mu_sp+mu_a)^-1; zb= 1.76/mu_sp; % this assumes n_tissue=1.35 -r1=(sdsep^2+zo^2)^(1/2); r2=(sdsep^2+(zo+2*zb)^2)^(1/2); -k0=2*pi*1.35/(785*1e-6); %wavelength=786e-6 mm! -kd=(3*mu_sp*mu_a+mu_sp^2*k0^2*alpha.*(6*Db.*tau)).^(1/2); -kd0=(3*mu_sp*mu_a).^(1/2); -fit_g1=exp(-kd.*r1)/r1-exp(-kd.*r2)/r2; -fit_g1_norm=exp(-kd0.*r1)/r1-exp(-kd0.*r2)/r2; +zo = (mu_sp + mu_a)^-1; +zb = 1.76 / mu_sp; % this assumes n_tissue=1.35 +r1 = (sdsep^2 + zo^2)^(1 / 2); +r2 = (sdsep^2 + (zo + 2 * zb)^2)^(1 / 2); +k0 = 2 * pi * 1.35 / (785 * 1e-6); % wavelength=786e-6 mm! +kd = (3 * mu_sp * mu_a + mu_sp^2 * k0^2 * alpha .* (6 * Db .* tau)).^(1 / 2); +kd0 = (3 * mu_sp * mu_a).^(1 / 2); +fit_g1 = exp(-kd .* r1) / r1 - exp(-kd .* r2) / r2; +fit_g1_norm = exp(-kd0 .* r1) / r1 - exp(-kd0 .* r2) / r2; -result=fit_g1/fit_g1_norm; \ No newline at end of file +result = fit_g1 / fit_g1_norm; diff --git a/examples/dcs/dcs_g1_Db_fms.m b/examples/dcs/dcs_g1_Db_fms.m index f25db66f..6ba34924 100644 --- a/examples/dcs/dcs_g1_Db_fms.m +++ b/examples/dcs/dcs_g1_Db_fms.m @@ -1,16 +1,18 @@ -function result=dcs_g1_Db_fms(Db,tau,g1,sdsep,mu_a,mu_sp,alpha) -% +function result = dcs_g1_Db_fms(Db, tau, g1, sdsep, mu_a, mu_sp, alpha) +% % this function generates analytical auto-correlation decay for a semi- % infinite medium, and computes the rms error for fminsearch fitting % % sdsep, mu_a and mu_sp units must be mm -zo=(mu_sp+mu_a)^-1; zb= 1.76/mu_sp; % this assumes n_tissue=1.35 -r1=(sdsep^2+zo^2)^(1/2); r2=(sdsep^2+(zo+2*zb)^2)^(1/2); -k0=2*pi*1.35/(785*1e-6); %wavelength=786e-6 mm! -kd=(3*mu_sp*mu_a+mu_sp^2*k0^2*alpha.*(6*Db.*tau)).^(1/2); -kd0=(3*mu_sp*mu_a).^(1/2); -fit_g1=exp(-kd.*r1)/r1-exp(-kd.*r2)/r2; -fit_g1_norm=exp(-kd0.*r1)/r1-exp(-kd0.*r2)/r2; +zo = (mu_sp + mu_a)^-1; +zb = 1.76 / mu_sp; % this assumes n_tissue=1.35 +r1 = (sdsep^2 + zo^2)^(1 / 2); +r2 = (sdsep^2 + (zo + 2 * zb)^2)^(1 / 2); +k0 = 2 * pi * 1.35 / (785 * 1e-6); % wavelength=786e-6 mm! +kd = (3 * mu_sp * mu_a + mu_sp^2 * k0^2 * alpha .* (6 * Db .* tau)).^(1 / 2); +kd0 = (3 * mu_sp * mu_a).^(1 / 2); +fit_g1 = exp(-kd .* r1) / r1 - exp(-kd .* r2) / r2; +fit_g1_norm = exp(-kd0 .* r1) / r1 - exp(-kd0 .* r2) / r2; -result=sum((g1-fit_g1/fit_g1_norm).^2); \ No newline at end of file +result = sum((g1 - fit_g1 / fit_g1_norm).^2); diff --git a/examples/dcs/dcs_g2_Db.m b/examples/dcs/dcs_g2_Db.m index dd50b0a7..473bb9e4 100644 --- a/examples/dcs/dcs_g2_Db.m +++ b/examples/dcs/dcs_g2_Db.m @@ -1,19 +1,20 @@ -function g2=dcs_g2_Db(Db,tau,sdsep,mu_a,mu_sp,alpha,beta) -% +function g2 = dcs_g2_Db(Db, tau, sdsep, mu_a, mu_sp, alpha, beta) +% % this function generates analytical field auto-correlation decay for a semi- % infinite medium, then uses the Siegert relationship to derive the % intensity temporal auto-correlation decay assuming ergodicity % % sdsep, mu_a and mu_sp units must be mm -zo=(mu_sp+mu_a)^-1; zb= 1.76/mu_sp; % this assumes n_tissue=1.35 -r1=(sdsep^2+zo^2)^(1/2); r2=(sdsep^2+(zo+2*zb)^2)^(1/2); -k0=2*pi*1.35/(785*1e-6); %wavelength=786e-6 mm! -kd=(3*mu_sp*mu_a+mu_sp^2*k0^2*alpha.*(6*Db.*tau)).^(1/2); -kd0=(3*mu_sp*mu_a).^(1/2); -fit_g1=exp(-kd.*r1)/r1-exp(-kd.*r2)/r2; -fit_g1_norm=exp(-kd0.*r1)/r1-exp(-kd0.*r2)/r2; - -g1_norm=fit_g1/fit_g1_norm; -g2=1+beta*(g1_norm).^2; +zo = (mu_sp + mu_a)^-1; +zb = 1.76 / mu_sp; % this assumes n_tissue=1.35 +r1 = (sdsep^2 + zo^2)^(1 / 2); +r2 = (sdsep^2 + (zo + 2 * zb)^2)^(1 / 2); +k0 = 2 * pi * 1.35 / (785 * 1e-6); % wavelength=786e-6 mm! +kd = (3 * mu_sp * mu_a + mu_sp^2 * k0^2 * alpha .* (6 * Db .* tau)).^(1 / 2); +kd0 = (3 * mu_sp * mu_a).^(1 / 2); +fit_g1 = exp(-kd .* r1) / r1 - exp(-kd .* r2) / r2; +fit_g1_norm = exp(-kd0 .* r1) / r1 - exp(-kd0 .* r2) / r2; +g1_norm = fit_g1 / fit_g1_norm; +g2 = 1 + beta * (g1_norm).^2; diff --git a/examples/dcs/dcs_g2_Db_fms.m b/examples/dcs/dcs_g2_Db_fms.m index 3e8b3934..72d3aedb 100644 --- a/examples/dcs/dcs_g2_Db_fms.m +++ b/examples/dcs/dcs_g2_Db_fms.m @@ -1,23 +1,25 @@ -function result=dcs_g2_Db_fms(s,tau,g2,sdsep,mu_a,mu_sp,alpha) -% +function result = dcs_g2_Db_fms(s, tau, g2, sdsep, mu_a, mu_sp, alpha) +% % this function generates analytical field auto-correlation decay for a semi- % infinite medium, then uses the Siegert relationship to derive the % intensity temporal auto-correlation decay assuming ergodicity % % sdsep, mu_a and mu_sp units must be mm -Db=s(1); -beta=s(2); +Db = s(1); +beta = s(2); -zo=(mu_sp+mu_a)^-1; zb= 1.76/mu_sp; % this assumes n_tissue=1.35 -r1=(sdsep^2+zo^2)^(1/2); r2=(sdsep^2+(zo+2*zb)^2)^(1/2); -k0=2*pi*1.35/(785*1e-6); %wavelength=786e-6 mm! -kd=(3*mu_sp*mu_a+mu_sp^2*k0^2*alpha.*(6*Db.*tau)).^(1/2); -kd0=(3*mu_sp*mu_a).^(1/2); -fit_g1=exp(-kd.*r1)/r1-exp(-kd.*r2)/r2; -fit_g1_norm=exp(-kd0.*r1)/r1-exp(-kd0.*r2)/r2; +zo = (mu_sp + mu_a)^-1; +zb = 1.76 / mu_sp; % this assumes n_tissue=1.35 +r1 = (sdsep^2 + zo^2)^(1 / 2); +r2 = (sdsep^2 + (zo + 2 * zb)^2)^(1 / 2); +k0 = 2 * pi * 1.35 / (785 * 1e-6); % wavelength=786e-6 mm! +kd = (3 * mu_sp * mu_a + mu_sp^2 * k0^2 * alpha .* (6 * Db .* tau)).^(1 / 2); +kd0 = (3 * mu_sp * mu_a).^(1 / 2); +fit_g1 = exp(-kd .* r1) / r1 - exp(-kd .* r2) / r2; +fit_g1_norm = exp(-kd0 .* r1) / r1 - exp(-kd0 .* r2) / r2; -g1_norm=fit_g1/fit_g1_norm; -fit_g2=1+beta*(g1_norm).^2; +g1_norm = fit_g1 / fit_g1_norm; +fit_g2 = 1 + beta * (g1_norm).^2; -result=sum((g2-fit_g2).^2); +result = sum((g2 - fit_g2).^2); diff --git a/examples/mcxsph/createmcxbin.m b/examples/mcxsph/createmcxbin.m index b354e03c..487fcd8c 100644 --- a/examples/mcxsph/createmcxbin.m +++ b/examples/mcxsph/createmcxbin.m @@ -1,11 +1,11 @@ -dim=60; -[xi,yi,zi]=meshgrid(1:dim,1:dim,1:dim); -dist=(xi-30).^2+(yi-30).^2+(zi-30).^2; +dim = 60; +[xi, yi, zi] = meshgrid(1:dim, 1:dim, 1:dim); +dist = (xi - 30).^2 + (yi - 30).^2 + (zi - 30).^2; -v=zeros(size(xi)); -v(dist<100)=1; -v=v+1; +v = zeros(size(xi)); +v(dist < 100) = 1; +v = v + 1; -fid=fopen('spherebox.bin','wb'); -aa=fwrite(fid,v,'uchar'); +fid = fopen('spherebox.bin', 'wb'); +aa = fwrite(fid, v, 'uchar'); fclose(fid); diff --git a/examples/meshtest/createmesh.m b/examples/meshtest/createmesh.m index bdee2936..b3bd9c18 100644 --- a/examples/meshtest/createmesh.m +++ b/examples/meshtest/createmesh.m @@ -4,66 +4,64 @@ % preparation -% 1. you need to add the path to iso2mesh toolbox +% 1. you need to add the path to iso2mesh toolbox % addpath('/path/to/iso2mesh/toolbox/'); % 2. you need to add the path to MMC matlab folder -addpath('../../matlab') - +addpath('../../matlab'); % create a surface mesh for a 10mm radius sphere -[no,el]=meshasphere([30 30 30],10,1.0); - +[no, el] = meshasphere([30 30 30], 10, 1.0); % generate a coarse volumetric mesh from the sphere with an additional bounding box % the maximum element volume is 20 -ISO2MESH_SESSION='mmcmesh2_'; +ISO2MESH_SESSION = 'mmcmesh2_'; -srcpos=[30. 30. 0.]; -fixednodes=[30.,30.,0.05; 30 30 30]; -nodesize=[ones(size(no,1),1) ; 0.5; 3]; -nfull=[no;fixednodes]; -[node3,elem3,face3]=surf2mesh([nfull,nodesize],el,[0 0 0],[60.1 60.1 60.1],1,8,[30 30 30],[],[1.5 1.5 1.5 1.5 5 5 5 5]); -[node3,elem3]=sortmesh(srcpos,node3,elem3,1:4); -elem3(:,1:4)=meshreorient(node3,elem3(:,1:4)); -elem3(:,5)=elem3(:,5)+1; -savemmcmesh('mesh2',node3,elem3(:,1:5),[]); -eid3=tsearchn(node3,elem3(:,1:4),srcpos); +srcpos = [30. 30. 0.]; +fixednodes = [30., 30., 0.05; 30 30 30]; +nodesize = [ones(size(no, 1), 1); 0.5; 3]; +nfull = [no; fixednodes]; +[node3, elem3, face3] = surf2mesh([nfull, nodesize], el, [0 0 0], [60.1 60.1 60.1], 1, 8, [30 30 30], [], [1.5 1.5 1.5 1.5 5 5 5 5]); +[node3, elem3] = sortmesh(srcpos, node3, elem3, 1:4); +elem3(:, 1:4) = meshreorient(node3, elem3(:, 1:4)); +elem3(:, 5) = elem3(:, 5) + 1; +savemmcmesh('mesh2', node3, elem3(:, 1:5), []); +eid3 = tsearchn(node3, elem3(:, 1:4), srcpos); % generate a dense volumetric mesh from the sphere with an additional bounding box % the maximum element volume is 5 -ISO2MESH_SESSION='mmcmesh1_'; +ISO2MESH_SESSION = 'mmcmesh1_'; -nodesize=[1*ones(size(no,1),1) ; 1; 1]; -[node2,elem2,face2]=surf2mesh([nfull,nodesize],el,[0 0 0],[60.1 60.1 60.1],1,2,[30 30 30],[],[1 1 1 1 1 1 1 1]); -[node2,elem2]=sortmesh(srcpos,node2,elem2,1:4); -elem2(:,1:4)=meshreorient(node2,elem2(:,1:4)); -elem2(:,5)=elem2(:,5)+1; -savemmcmesh('mesh1',node2,elem2(:,1:5),[]); -eid2=tsearchn(node2,elem2(:,1:4),srcpos); +nodesize = [1 * ones(size(no, 1), 1); 1; 1]; +[node2, elem2, face2] = surf2mesh([nfull, nodesize], el, [0 0 0], [60.1 60.1 60.1], 1, 2, [30 30 30], [], [1 1 1 1 1 1 1 1]); +[node2, elem2] = sortmesh(srcpos, node2, elem2, 1:4); +elem2(:, 1:4) = meshreorient(node2, elem2(:, 1:4)); +elem2(:, 5) = elem2(:, 5) + 1; +savemmcmesh('mesh1', node2, elem2(:, 1:5), []); +eid2 = tsearchn(node2, elem2(:, 1:4), srcpos); % reduce the surface node numbers to 20% -ISO2MESH_SESSION='mmcmesh0_'; +ISO2MESH_SESSION = 'mmcmesh0_'; -%[no2,el2]=meshresample(no,el,0.2); +% [no2,el2]=meshresample(no,el,0.2); % using the coarse spherical surface, we generate a coarse volumetric % mesh with maximum volume of 10 -nodesize=[ones(size(no,1),1); 3]; -nfull=[no; 30 30 30]; -[node1,elem1,face1]=surf2mesh([nfull,nodesize],el,[0 0 0],[60.1 60.1 60.1],1,10,[30 30 30],[],[2 2 2 2 5 5 5 5]); -[node1,elem1]=sortmesh(srcpos,node1,elem1,1:4); -elem1(:,1:4)=meshreorient(node1,elem1(:,1:4)); -elem1(:,5)=elem1(:,5)+1; -savemmcmesh('mesh0',node1,elem1(:,1:5),[]); -eid1=tsearchn(node1,elem1(:,1:4),srcpos); +nodesize = [ones(size(no, 1), 1); 3]; +nfull = [no; 30 30 30]; +[node1, elem1, face1] = surf2mesh([nfull, nodesize], el, [0 0 0], [60.1 60.1 60.1], 1, 10, [30 30 30], [], [2 2 2 2 5 5 5 5]); +[node1, elem1] = sortmesh(srcpos, node1, elem1, 1:4); +elem1(:, 1:4) = meshreorient(node1, elem1(:, 1:4)); +elem1(:, 5) = elem1(:, 5) + 1; +savemmcmesh('mesh0', node1, elem1(:, 1:5), []); +eid1 = tsearchn(node1, elem1(:, 1:4), srcpos); -clear ISO2MESH_SESSION +clear ISO2MESH_SESSION; -fid=fopen('initial_elem.txt','wt'); -fprintf(fid,'mesh0: %d\nmesh1: %d\nmesh2: %d\n',eid1,eid2,eid3); +fid = fopen('initial_elem.txt', 'wt'); +fprintf(fid, 'mesh0: %d\nmesh1: %d\nmesh2: %d\n', eid1, eid2, eid3); fclose(fid); diff --git a/examples/meshtest/plotmmcsph.m b/examples/meshtest/plotmmcsph.m index 552c2ed3..0c4f5aa3 100644 --- a/examples/meshtest/plotmmcsph.m +++ b/examples/meshtest/plotmmcsph.m @@ -1,157 +1,156 @@ -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% add paths to the necessary toolboxes -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- -addpath('/space/kwafoo/2/users/fangq/Projects/mcx/utils/') -addpath('../../matlab') +addpath('/space/kwafoo/2/users/fangq/Projects/mcx/utils/'); +addpath('../../matlab'); -c0=299792458000; -t0=0; -dt=1e-10; -t1=5e-9; +c0 = 299792458000; +t0 = 0; +dt = 1e-10; +t1 = 5e-9; -twin=[t0+dt/2:dt:t1]; -gates=length(twin); -clines=[-1:0.5:8]-10; +twin = [t0 + dt / 2:dt:t1]; +gates = length(twin); +clines = [-1:0.5:8] - 10; -[xi,yi]=meshgrid(1:60,0:60); +[xi, yi] = meshgrid(1:60, 0:60); -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% load MCX results -%%----------------------------------------------------------------- -mcx=loadmc2('../mcxsph/spherebox.mc2', [60 60 60 gates]); -cwmcx=sum(mcx,4)*dt; +%% ----------------------------------------------------------------- +mcx = loadmc2('../mcxsph/spherebox.mc2', [60 60 60 gates]); +cwmcx = sum(mcx, 4) * dt; -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% 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; +[xcirc, ycirc] = cylinder(10, 200); +xcirc = xcirc(1, :) + 30; +ycirc = ycirc(1, :) + 30; % create the voxel-contour of the sphere for MCX -%dim=60; -%[xv,yv,zv]=meshgrid(1:dim,1:dim,1:dim); -%dist=(xv-30).^2+(yv-30).^2+(zv-30).^2; +% dim=60; +% [xv,yv,zv]=meshgrid(1:dim,1:dim,1:dim); +% dist=(xv-30).^2+(yv-30).^2+(zv-30).^2; -%vv=zeros(size(xv)); -%vv(dist<100)=1; +% vv=zeros(size(xv)); +% vv(dist<100)=1; -%c=contourc(squeeze(vv(:,30,:)),1); -%plot(c(1,2:end),c(2,2:end),'c--') +% c=contourc(squeeze(vv(:,30,:)),1); +% plot(c(1,2:end),c(2,2:end),'c--') -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% plot sphere 1 -%%----------------------------------------------------------------- -node1=readmmcnode('node_mesh0.dat'); -elem1=readmmcelem('elem_mesh0.dat'); -load mesh0.dat -mesh0=reshape(mesh0(:,end),[size(node1,1),length(mesh0)/size(node1,1)]); -s1=sum(mesh0,2)*dt; -[cutpos,cutvalue,facedata]=qmeshcut(elem1(:,1:4),node1,s1,[0 30 0; 0 30 1; 1 30 0]); -%patch('Vertices',cutpos,'Faces',facedata,'FaceVertexCData',log10(cutvalue),'FaceColor','interp','linestyle','none'); -%view([0 1 0]) - -vi=griddata(cutpos(:,1),cutpos(:,3),cutvalue,xi,yi); - -figure -hold on -[cc,hc]=contour(xa+30,za+31,log10(abs(phi_ana)),clines,'color',[0.7 0.7 0.7],'linewidth',2); -contour(log10(squeeze(abs(cwmcx(:,30,:)))'),clines,'b-') -contour(log10(abs(vi)),clines,'r:') -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','MMCM') +%% ----------------------------------------------------------------- +node1 = readmmcnode('node_mesh0.dat'); +elem1 = readmmcelem('elem_mesh0.dat'); +load mesh0.dat; +mesh0 = reshape(mesh0(:, end), [size(node1, 1), length(mesh0) / size(node1, 1)]); +s1 = sum(mesh0, 2) * dt; +[cutpos, cutvalue, facedata] = qmeshcut(elem1(:, 1:4), node1, s1, [0 30 0; 0 30 1; 1 30 0]); +% patch('Vertices',cutpos,'Faces',facedata,'FaceVertexCData',log10(cutvalue),'FaceColor','interp','linestyle','none'); +% view([0 1 0]) + +vi = griddata(cutpos(:, 1), cutpos(:, 3), cutvalue, xi, yi); + +figure; +hold on; +[cc, hc] = contour(xa + 30, za + 31, log10(abs(phi_ana)), clines, 'color', [0.7 0.7 0.7], 'linewidth', 2); +contour(log10(squeeze(abs(cwmcx(:, 30, :)))'), clines, 'b-'); +contour(log10(abs(vi)), clines, 'r:'); +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', 'MMCM'); legend boxoff; box on; -set(gcf,'PaperPositionMode','auto'); -print -depsc2 mesh0.eps +set(gcf, 'PaperPositionMode', 'auto'); +print -depsc2 mesh0.eps; -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% plot sphere 2 -%%----------------------------------------------------------------- - -node2=readmmcnode('node_mesh1.dat'); -elem2=readmmcelem('elem_mesh1.dat'); -load mesh1.dat -mesh1=reshape(mesh1(:,end),[size(node2,1),length(mesh1)/size(node2,1)]); -s2=sum(mesh1,2)*dt; -[cutpos,cutvalue,facedata]=qmeshcut(elem2(:,1:4),node2,s2,[0 30 0; 0 30 1; 1 30 0]); -%patch('Vertices',cutpos,'Faces',facedata,'FaceVertexCData',log10(cutvalue),'FaceColor','interp','linestyle','none'); -%view([0 1 0]) -vi=griddata(cutpos(:,1),cutpos(:,3),cutvalue,xi,yi); - -figure -hold on -[cc,hc]=contour(xa+30,za+31,log10(abs(phi_ana)),clines,'color',[0.7 0.7 0.7],'linewidth',2); -contour(log10(squeeze(abs(cwmcx(:,30,:)))'),clines,'b-') -contour(log10(abs(vi)),clines,'r:') -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','MMCM') +%% ----------------------------------------------------------------- + +node2 = readmmcnode('node_mesh1.dat'); +elem2 = readmmcelem('elem_mesh1.dat'); +load mesh1.dat; +mesh1 = reshape(mesh1(:, end), [size(node2, 1), length(mesh1) / size(node2, 1)]); +s2 = sum(mesh1, 2) * dt; +[cutpos, cutvalue, facedata] = qmeshcut(elem2(:, 1:4), node2, s2, [0 30 0; 0 30 1; 1 30 0]); +% patch('Vertices',cutpos,'Faces',facedata,'FaceVertexCData',log10(cutvalue),'FaceColor','interp','linestyle','none'); +% view([0 1 0]) +vi = griddata(cutpos(:, 1), cutpos(:, 3), cutvalue, xi, yi); + +figure; +hold on; +[cc, hc] = contour(xa + 30, za + 31, log10(abs(phi_ana)), clines, 'color', [0.7 0.7 0.7], 'linewidth', 2); +contour(log10(squeeze(abs(cwmcx(:, 30, :)))'), clines, 'b-'); +contour(log10(abs(vi)), clines, 'r:'); +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', 'MMCM'); legend boxoff; box on; -set(gcf,'PaperPositionMode','auto'); -print -depsc2 mesh1.eps +set(gcf, 'PaperPositionMode', 'auto'); +print -depsc2 mesh1.eps; -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% plot sphere 3 -%%----------------------------------------------------------------- - -node3=readmmcnode('node_mesh2.dat'); -elem3=readmmcelem('elem_mesh2.dat'); -load mesh2.dat -mesh2=reshape(mesh2(:,end),[size(node3,1),length(mesh2)/size(node3,1)]); -s3=sum(mesh2,2)*dt; -[cutpos,cutvalue,facedata]=qmeshcut(elem3(:,1:4),node3,s3,[0 29 0; 0 29 1; 1 29 0]); - -vi=griddata(cutpos(:,1),cutpos(:,3),cutvalue,xi,yi); - -figure -%patch('Vertices',cutpos,'Faces',facedata,'FaceVertexCData',log10(cutvalue),'FaceColor','interp','linestyle','none'); -%view([0 1 0]) -hold on -[cc,hc]=contour(xa+30,za+31,log10(abs(phi_ana)),clines,'color',[0.7 0.7 0.7],'linewidth',2); -contour(log10(squeeze(abs(cwmcx(:,30,:)))'),clines,'b-') -contour(log10(abs(vi)),clines,'r:') -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','MMCM') +%% ----------------------------------------------------------------- + +node3 = readmmcnode('node_mesh2.dat'); +elem3 = readmmcelem('elem_mesh2.dat'); +load mesh2.dat; +mesh2 = reshape(mesh2(:, end), [size(node3, 1), length(mesh2) / size(node3, 1)]); +s3 = sum(mesh2, 2) * dt; +[cutpos, cutvalue, facedata] = qmeshcut(elem3(:, 1:4), node3, s3, [0 29 0; 0 29 1; 1 29 0]); + +vi = griddata(cutpos(:, 1), cutpos(:, 3), cutvalue, xi, yi); + +figure; +% patch('Vertices',cutpos,'Faces',facedata,'FaceVertexCData',log10(cutvalue),'FaceColor','interp','linestyle','none'); +% view([0 1 0]) +hold on; +[cc, hc] = contour(xa + 30, za + 31, log10(abs(phi_ana)), clines, 'color', [0.7 0.7 0.7], 'linewidth', 2); +contour(log10(squeeze(abs(cwmcx(:, 30, :)))'), clines, 'b-'); +contour(log10(abs(vi)), clines, 'r:'); +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', 'MMCM'); legend boxoff; box on; -set(gcf,'PaperPositionMode','auto'); -print -depsc2 mesh2.eps - +set(gcf, 'PaperPositionMode', 'auto'); +print -depsc2 mesh2.eps; diff --git a/examples/misctest/bary_external.m b/examples/misctest/bary_external.m index 2ab4fb8c..5163f6e5 100644 --- a/examples/misctest/bary_external.m +++ b/examples/misctest/bary_external.m @@ -1,18 +1,17 @@ % test bary centric coordinates outside a tetrahedron -node=[0 0 0;1 0 0;0 1 0;0 0 1]; -elem=[1 2 3 4]; -tetramesh(elem,node); -view([60,30]); +node = [0 0 0; 1 0 0; 0 1 0; 0 0 1]; +elem = [1 2 3 4]; +tetramesh(elem, node); +view([60, 30]); hold on; -b1=[1/3,1/3,1/3,0]; -b2=[0 1/3 1/3 1/3]; -t=-2:0.1:2; +b1 = [1 / 3, 1 / 3, 1 / 3, 0]; +b2 = [0 1 / 3 1 / 3 1 / 3]; +t = -2:0.1:2; -for i=1:length(t) - pp=node'*(t(i)*b1+(1-t(i))*b2)'; - plot3(pp(1),pp(2),pp(3),'o'); - axis equal; - waitforbuttonpress; +for i = 1:length(t) + pp = node' * (t(i) * b1 + (1 - t(i)) * b2)'; + plot3(pp(1), pp(2), pp(3), 'o'); + axis equal; + waitforbuttonpress; end - diff --git a/examples/onecube/createmesh.m b/examples/onecube/createmesh.m index dd29d247..8cc41749 100644 --- a/examples/onecube/createmesh.m +++ b/examples/onecube/createmesh.m @@ -1,13 +1,12 @@ -sessionid='onecube'; +sessionid = 'onecube'; addpath('../../matlab/'); -[node,elem]=genT6mesh(0:1,0:1,0:1); -elem=sortrows(elem); -elem(:,1:4)=meshreorient(node,elem(:,1:4)); +[node, elem] = genT6mesh(0:1, 0:1, 0:1); +elem = sortrows(elem); +elem(:, 1:4) = meshreorient(node, elem(:, 1:4)); -node=node*10; - -srcpos=[2,8,0]; -savemmcmesh(sessionid,node,elem,[]); -eid=tsearchn(node,elem(:,1:4),srcpos) +node = node * 10; +srcpos = [2, 8, 0]; +savemmcmesh(sessionid, node, elem, []); +eid = tsearchn(node, elem(:, 1:4), srcpos); diff --git a/examples/onecube/plotmmcdebug.m b/examples/onecube/plotmmcdebug.m index 456993af..8d5c5bdb 100644 --- a/examples/onecube/plotmmcdebug.m +++ b/examples/onecube/plotmmcdebug.m @@ -1,26 +1,26 @@ addpath('../../matlab/'); -node=readmmcnode('node_onecube.dat'); -elem=readmmcelem('elem_onecube.dat'); +node = readmmcnode('node_onecube.dat'); +elem = readmmcelem('elem_onecube.dat'); -load ad.txt -load mov.txt -srcpos=[2 8 0]; +load ad.txt; +load mov.txt; +srcpos = [2 8 0]; -hh=tetramesh(elem(:,1:4),node); -set(hh,'facealpha',0.1) -hold on +hh = tetramesh(elem(:, 1:4), node); +set(hh, 'facealpha', 0.1); +hold on; -photonnum=max(mov(:,end-1)); -tracks=[]; -for i=0:photonnum - idx=find(mov(:,end-1)==i); - tracks=[tracks; [srcpos(1);mov(idx,2)],[srcpos(2);mov(idx,3)],[srcpos(3);mov(idx,4)]; nan nan nan]; +photonnum = max(mov(:, end - 1)); +tracks = []; +for i = 0:photonnum + idx = find(mov(:, end - 1) == i); + tracks = [tracks; [srcpos(1); mov(idx, 2)], [srcpos(2); mov(idx, 3)], [srcpos(3); mov(idx, 4)]; nan nan nan]; end -plot3(tracks(:,1),tracks(:,2),tracks(:,3),'.-'); -idx=find(mov(:,1)==0); -plot3(mov(idx,2),mov(idx,3),mov(idx,4),'ko'); +plot3(tracks(:, 1), tracks(:, 2), tracks(:, 3), '.-'); +idx = find(mov(:, 1) == 0); +plot3(mov(idx, 2), mov(idx, 3), mov(idx, 4), 'ko'); -idx=find(mov(:,1)==2); -plot3(mov(idx,2),mov(idx,3),mov(idx,4),'+'); +idx = find(mov(:, 1) == 2); +plot3(mov(idx, 2), mov(idx, 3), mov(idx, 4), '+'); -plot3(ad(:,1),ad(:,2),ad(:,3),'r.'); +plot3(ad(:, 1), ad(:, 2), ad(:, 3), 'r.'); diff --git a/examples/planar/addsource_digimouse.m b/examples/planar/addsource_digimouse.m index 5a59159c..ce5ee486 100644 --- a/examples/planar/addsource_digimouse.m +++ b/examples/planar/addsource_digimouse.m @@ -1,20 +1,20 @@ -if(~exist('Digimouse_Mesh_1L.mat','file')) - if(~exist('digimouse_mesh_version_1L.tar.gz','file')) - websave('digimouse_mesh_version_1L.tar.gz','http://downloads.sourceforge.net/project/mcx/mmc/Digimouse%20FEM%20Mesh/Version%201/digimouse_mesh_version_1L.tar.gz?r=http%3A%2F%2Fsourceforge.net%2Fprojects%2Fmcx%2Ffiles%2Fmmc%2FDigimouse%2520FEM%2520Mesh%2FVersion%25201%2F&ts=1450931781&use_mirror=skylineservers'); - end - if(~exist('digimouse_mesh_version_1L.tar','file')) - gunzip('digimouse_mesh_version_1L.tar.gz'); - end - if(~exist('digimouse_mesh/Digimouse_Mesh_1L.mat','file')) - untar('digimouse_mesh_version_1L.tar'); - movefile('digimouse_mesh/Digimouse_Mesh_1L.mat','./Digimouse_Mesh_1L.mat'); - end +if (~exist('Digimouse_Mesh_1L.mat', 'file')) + if (~exist('digimouse_mesh_version_1L.tar.gz', 'file')) + websave('digimouse_mesh_version_1L.tar.gz', 'http://downloads.sourceforge.net/project/mcx/mmc/Digimouse%20FEM%20Mesh/Version%201/digimouse_mesh_version_1L.tar.gz?r=http%3A%2F%2Fsourceforge.net%2Fprojects%2Fmcx%2Ffiles%2Fmmc%2FDigimouse%2520FEM%2520Mesh%2FVersion%25201%2F&ts=1450931781&use_mirror=skylineservers'); + end + if (~exist('digimouse_mesh_version_1L.tar', 'file')) + gunzip('digimouse_mesh_version_1L.tar.gz'); + end + if (~exist('digimouse_mesh/Digimouse_Mesh_1L.mat', 'file')) + untar('digimouse_mesh_version_1L.tar'); + movefile('digimouse_mesh/Digimouse_Mesh_1L.mat', './Digimouse_Mesh_1L.mat'); + end end load Digimouse_Mesh_1L; -elem(:,5)=1; +elem(:, 5) = 1; -cfg=struct('srctype','planar','srcpos',[15 50 25],'srcdir',[0 0 -1],... - 'srcparam1',[10 0 0 0],'srcparam2',[0 10 0 0]); +cfg = struct('srctype', 'planar', 'srcpos', [15 50 25], 'srcdir', [0 0 -1], ... + 'srcparam1', [10 0 0 0], 'srcparam2', [0 10 0 0]); -[newnode,newelem]=mmcaddsrc(node,elem,cfg); -savemmcmesh('digimouse',newnode,newelem); +[newnode, newelem] = mmcaddsrc(node, elem, cfg); +savemmcmesh('digimouse', newnode, newelem); diff --git a/examples/planar/plotresult.m b/examples/planar/plotresult.m index eac35157..98b1fa74 100644 --- a/examples/planar/plotresult.m +++ b/examples/planar/plotresult.m @@ -1,8 +1,7 @@ -figure -load enterpos.txt +figure; +load enterpos.txt; subplot(121); -plotmesh(enterpos(:,1:3),'.') -load exitpos.txt +plotmesh(enterpos(:, 1:3), '.'); +load exitpos.txt; subplot(122); -plotmesh(exitpos(:,1:3),'.') - +plotmesh(exitpos(:, 1:3), '.'); diff --git a/examples/reftest/createmesh.m b/examples/reftest/createmesh.m index 8513a128..6868beed 100644 --- a/examples/reftest/createmesh.m +++ b/examples/reftest/createmesh.m @@ -1,15 +1,14 @@ -sessionid='onecube'; +sessionid = 'onecube'; addpath('../../matlab/'); -[node,elem]=genT6mesh(0:1,0:1,0:1); -elem=sortrows(elem); -elem(:,1:4)=meshreorient(node,elem(:,1:4)); -elem(:,5)=1; +[node, elem] = genT6mesh(0:1, 0:1, 0:1); +elem = sortrows(elem); +elem(:, 1:4) = meshreorient(node, elem(:, 1:4)); +elem(:, 5) = 1; -node=node*10; - -srcpos=[2,8,0]; -eid=tsearchn(node,elem(:,1:4),srcpos) -elem(eid,5)=2; -savemmcmesh(sessionid,node,elem,[]); +node = node * 10; +srcpos = [2, 8, 0]; +eid = tsearchn(node, elem(:, 1:4), srcpos); +elem(eid, 5) = 2; +savemmcmesh(sessionid, node, elem, []); diff --git a/examples/reftest/plotmmcdebug.m b/examples/reftest/plotmmcdebug.m index f0c2a62b..d03409ab 100644 --- a/examples/reftest/plotmmcdebug.m +++ b/examples/reftest/plotmmcdebug.m @@ -1,26 +1,26 @@ addpath('../../matlab/'); -node=readmmcnode('node_onecube.dat'); -elem=readmmcelem('elem_onecube.dat'); +node = readmmcnode('node_onecube.dat'); +elem = readmmcelem('elem_onecube.dat'); -load ad.txt -load mov.txt +load ad.txt; +load mov.txt; figure; -hh=tetramesh(elem,node); -set(hh,'facealpha',0.1) -hold on -photonnum=max(mov(:,end-1)); -for i=0:photonnum - idx=find(mov(:,end-1)==i); - plot3(mov(idx,2),mov(idx,3),mov(idx,4),'.-'); +hh = tetramesh(elem, node); +set(hh, 'facealpha', 0.1); +hold on; +photonnum = max(mov(:, end - 1)); +for i = 0:photonnum + idx = find(mov(:, end - 1) == i); + plot3(mov(idx, 2), mov(idx, 3), mov(idx, 4), '.-'); end -idx=find(mov(:,1)==0); -plot3(mov(idx,2),mov(idx,3),mov(idx,4),'co'); +idx = find(mov(:, 1) == 0); +plot3(mov(idx, 2), mov(idx, 3), mov(idx, 4), 'co'); -idx=find(mov(:,1)==2); -plot3(mov(idx,2),mov(idx,3),mov(idx,4),'+'); +idx = find(mov(:, 1) == 2); +plot3(mov(idx, 2), mov(idx, 3), mov(idx, 4), '+'); -idx=find(mov(:,1)==3); -plot3(mov(idx,2),mov(idx,3),mov(idx,4),'co'); +idx = find(mov(:, 1) == 3); +plot3(mov(idx, 2), mov(idx, 3), mov(idx, 4), 'co'); -plot3(ad(:,1),ad(:,2),ad(:,3),'r.'); +plot3(ad(:, 1), ad(:, 2), ad(:, 3), 'r.'); diff --git a/examples/regression/exitangle/phantom.m b/examples/regression/exitangle/phantom.m index a37ac0e8..b971be2f 100644 --- a/examples/regression/exitangle/phantom.m +++ b/examples/regression/exitangle/phantom.m @@ -1,18 +1,18 @@ clear; -phantom_l=50; -phantom_w=40; -phantom_h=21; -bar_dis=16.8; -bar_h=11; -bar_c1=[(phantom_l-bar_dis)/2,bar_h]; -bar_c2=[(phantom_l+bar_dis)/2,bar_h]; +phantom_l = 50; +phantom_w = 40; +phantom_h = 21; +bar_dis = 16.8; +bar_h = 11; +bar_c1 = [(phantom_l - bar_dis) / 2, bar_h]; +bar_c2 = [(phantom_l + bar_dis) / 2, bar_h]; %% old mesh -[node,face,elem] = meshabox([0 0 0],[phantom_l phantom_w phantom_h],1.2,10); -elem(:,1:4) = meshreorient(node(:,1:3),elem(:,1:4)); -elem(:,5) = 1; -plotmesh(node,elem); +[node, face, elem] = meshabox([0 0 0], [phantom_l phantom_w phantom_h], 1.2, 10); +elem(:, 1:4) = meshreorient(node(:, 1:3), elem(:, 1:4)); +elem(:, 5) = 1; +plotmesh(node, elem); % savemmcmesh('tank',node,elem); @@ -22,10 +22,10 @@ source_dir = [0 0 -1]; param1 = [40 0 0 0]; param2 = [0 30 0 0]; -cfg=struct('srctype','planar','srcpos',source,'srcdir',source_dir,'srcparam1',param1,'srcparam2',param2); -source_domain = mmcsrcdomain(cfg,[min(node);max(node)]); +cfg = struct('srctype', 'planar', 'srcpos', source, 'srcdir', source_dir, 'srcparam1', param1, 'srcparam2', param2); +source_domain = mmcsrcdomain(cfg, [min(node); max(node)]); -[newnode,newelem] = mmcaddsrc(node,elem,source_domain); -plotmesh(newnode,newelem); +[newnode, newelem] = mmcaddsrc(node, elem, source_domain); +plotmesh(newnode, newelem); -savemmcmesh('tank',newnode,newelem); +savemmcmesh('tank', newnode, newelem); diff --git a/examples/regression/exitangle/testexitdir.m b/examples/regression/exitangle/testexitdir.m index 2317209a..23888900 100644 --- a/examples/regression/exitangle/testexitdir.m +++ b/examples/regression/exitangle/testexitdir.m @@ -1,7 +1,6 @@ -dat=loadmch('tank_planar.mch'); -dd=dat(:,7:9); -dl=sqrt(sum(dd.*dd,2)); +dat = loadmch('tank_planar.mch'); +dd = dat(:, 7:9); +dl = sqrt(sum(dd .* dd, 2)); % plot(dl) -find(sum(dd(:,1:2).*dd(:,1:2),2)<1e-5) - +find(sum(dd(:, 1:2) .* dd(:, 1:2), 2) < 1e-5); diff --git a/examples/replay/createmesh.m b/examples/replay/createmesh.m index b6e5d25b..0c87c426 100644 --- a/examples/replay/createmesh.m +++ b/examples/replay/createmesh.m @@ -1,8 +1,7 @@ - % you may also use meshgrid5 in iso2mesh 1.7.9 or newer % it is identical to genT5mesh -srcpos=[30.1 30.2 0.0]; -[node,elem]=genT6mesh(0:2:60,0:2:60,0:2:60); -e0=tsearchn(node,elem,srcpos) -savemmcmesh('replaytest',node,elem); +srcpos = [30.1 30.2 0.0]; +[node, elem] = genT6mesh(0:2:60, 0:2:60, 0:2:60); +e0 = tsearchn(node, elem, srcpos); +savemmcmesh('replaytest', node, elem); diff --git a/examples/replay/plotjacobian.m b/examples/replay/plotjacobian.m index e987af1a..5963687f 100644 --- a/examples/replay/plotjacobian.m +++ b/examples/replay/plotjacobian.m @@ -1,53 +1,53 @@ % verify the replay outcome and plot the Jacobian profile % the photons detected in the original run -[data1,header1]=loadmch('step1.mch'); -header1 +[data1, header1] = loadmch('step1.mch'); +header1; % the photons detected in the wl replay phase -[data2,header2]=loadmch('step2.mch'); -header2 +[data2, header2] = loadmch('step2.mch'); +header2; % the photons detected in the wp replay phase -[data3,header3]=loadmch('step3.mch'); -header3 +[data3, header3] = loadmch('step3.mch'); +header3; -data1=data1(data1(:,1)==1,:); +data1 = data1(data1(:, 1) == 1, :); % the two sets of captured photons should be identical -if(all(ismember(round(data1*1e10)*1e-10,round(data2*1e10)*1e-10,'rows')) && ... - all(ismember(round(data1*1e10)*1e-10,round(data2*1e10)*1e-10,'rows'))) - disp('replay is successful :-)'); +if (all(ismember(round(data1 * 1e10) * 1e-10, round(data2 * 1e10) * 1e-10, 'rows')) && ... + all(ismember(round(data1 * 1e10) * 1e-10, round(data2 * 1e10) * 1e-10, 'rows'))) + disp('replay is successful :-)'); else - disp('replay failed :-('); + disp('replay failed :-('); end % plot the wl profile -load step2.dat -[no,el]=readmmcmesh('replaytest'); +load step2.dat; +[no, el] = readmmcmesh('replaytest'); figure; -plotmesh([no,log10(step2(:,2))],el(:,1:4),'z=0.2','linestyle','none'); +plotmesh([no, log10(step2(:, 2))], el(:, 1:4), 'z=0.2', 'linestyle', 'none'); hold on; -plotmesh([no,log10(step2(:,2))],el(:,1:4),'x=30','linestyle','none'); -view(3) -set(gca,'xlim',[0 60]) -set(gca,'ylim',[0 60]) -set(gca,'zlim',[0 60]) -shading interp +plotmesh([no, log10(step2(:, 2))], el(:, 1:4), 'x=30', 'linestyle', 'none'); +view(3); +set(gca, 'xlim', [0 60]); +set(gca, 'ylim', [0 60]); +set(gca, 'zlim', [0 60]); +shading interp; % plot the wp profile -load step3.dat -[no,el]=readmmcmesh('replaytest'); +load step3.dat; +[no, el] = readmmcmesh('replaytest'); figure; -plotmesh([no,log10(step3(:,2))],el(:,1:4),'z=0.2','linestyle','none'); +plotmesh([no, log10(step3(:, 2))], el(:, 1:4), 'z=0.2', 'linestyle', 'none'); hold on; -plotmesh([no,log10(step3(:,2))],el(:,1:4),'x=30','linestyle','none'); -view(3) -set(gca,'xlim',[0 60]) -set(gca,'ylim',[0 60]) -set(gca,'zlim',[0 60]) -shading interp \ No newline at end of file +plotmesh([no, log10(step3(:, 2))], el(:, 1:4), 'x=30', 'linestyle', 'none'); +view(3); +set(gca, 'xlim', [0 60]); +set(gca, 'ylim', [0 60]); +set(gca, 'zlim', [0 60]); +shading interp; diff --git a/examples/replaywide/createmesh.m b/examples/replaywide/createmesh.m index cfd25784..7f48a06c 100644 --- a/examples/replaywide/createmesh.m +++ b/examples/replaywide/createmesh.m @@ -1,30 +1,29 @@ - %% original mesh -[node,face,elem]=meshabox([0 0 0],[60 60 20],2, 2); -elem(:,5)=1; +[node, face, elem] = meshabox([0 0 0], [60 60 20], 2, 2); +elem(:, 5) = 1; figure(1); -plotmesh(node,elem); +plotmesh(node, elem); %% extended source domain -srcdef=struct('srctype','planar','srcpos',[10,10,-2],'srcdir',[0 0 1],... - 'srcparam1',[40 0 0 40],'srcparam2',[0 40 0 40]); - -[newnode,newelem]=mmcaddsrc(node,elem,srcdef); +srcdef = struct('srctype', 'planar', 'srcpos', [10, 10, -2], 'srcdir', [0 0 1], ... + 'srcparam1', [40 0 0 40], 'srcparam2', [0 40 0 40]); + +[newnode, newelem] = mmcaddsrc(node, elem, srcdef); figure(2); -plotmesh(newnode,newelem); +plotmesh(newnode, newelem); %% extended detector domain -detdef=struct('srctype','planar','srcpos',[10,10,20.1],'srcdir',[0 0 -1],... - 'srcparam1',[40 0 0 40],'srcparam2',[0 40 0 40]); - -[newnode2,newelem2]=mmcadddet(newnode,newelem,detdef); +detdef = struct('srctype', 'planar', 'srcpos', [10, 10, 20.1], 'srcdir', [0 0 -1], ... + 'srcparam1', [40 0 0 40], 'srcparam2', [0 40 0 40]); + +[newnode2, newelem2] = mmcadddet(newnode, newelem, detdef); figure(3); -plotmesh(newnode2,newelem2); +plotmesh(newnode2, newelem2); -savemmcmesh('replaywide',newnode2,newelem2); \ No newline at end of file +savemmcmesh('replaywide', newnode2, newelem2); diff --git a/examples/replaywide/createpattern.m b/examples/replaywide/createpattern.m index cdcc37d5..472076d4 100644 --- a/examples/replaywide/createpattern.m +++ b/examples/replaywide/createpattern.m @@ -1,23 +1,22 @@ - % full field illumination pattern pat0 = ones(40); % pattern with left half dark pat1 = pat0; -pat1(1:20,:) = 0; +pat1(1:20, :) = 0; % pattern with top half dark pat2 = pat0; -pat2(:,1:20) = 0; +pat2(:, 1:20) = 0; -fid=fopen('pattern0.pat','wb','ieee-le'); -fwrite(fid,pat0','float'); +fid = fopen('pattern0.pat', 'wb', 'ieee-le'); +fwrite(fid, pat0', 'float'); fclose(fid); -fid=fopen('pattern1.pat','wb','ieee-le'); -fwrite(fid,pat1','float'); +fid = fopen('pattern1.pat', 'wb', 'ieee-le'); +fwrite(fid, pat1', 'float'); fclose(fid); -fid=fopen('pattern2.pat','wb','ieee-le'); -fwrite(fid,pat2','float'); -fclose(fid); \ No newline at end of file +fid = fopen('pattern2.pat', 'wb', 'ieee-le'); +fwrite(fid, pat2', 'float'); +fclose(fid); diff --git a/examples/replaywide/plotresults.m b/examples/replaywide/plotresults.m index df48e454..b5f2ab8e 100644 --- a/examples/replaywide/plotresults.m +++ b/examples/replaywide/plotresults.m @@ -1,15 +1,14 @@ +[node, face, elem] = meshabox([0 0 0], [60 60 20], 2, 2); -[node,face,elem]=meshabox([0 0 0],[60 60 20],2, 2); - -data1=load('replay1.dat'); -data2=load('replay2.dat'); -data3=load('replay3.dat'); +data1 = load('replay1.dat'); +data2 = load('replay2.dat'); +data3 = load('replay3.dat'); figure(1); -plotmesh([node,log(data1(1:end-7,2))],elem); +plotmesh([node, log(data1(1:end - 7, 2))], elem); figure(2); -plotmesh([node,log(data2(1:end-7,2))],elem); +plotmesh([node, log(data2(1:end - 7, 2))], elem); figure(3); -plotmesh([node,log(data3(1:end-7,2))],elem); \ No newline at end of file +plotmesh([node, log(data3(1:end - 7, 2))], elem); diff --git a/examples/sfdi2layer/createmesh.m b/examples/sfdi2layer/createmesh.m index 5c1ca78e..75da40c5 100644 --- a/examples/sfdi2layer/createmesh.m +++ b/examples/sfdi2layer/createmesh.m @@ -2,43 +2,45 @@ %% 2-layer mesh model -layercount=2; +layercount = 2; + +if (layercount == 2) + [node, face, c0] = latticegrid([0 60], [0 60], [0 25 30]); + c0(:, 4) = [2; 1]; % maximum element size for bottom (label 1) and top (label 2) layers -if(layercount==2) - [node,face,c0]=latticegrid([0 60],[0 60],[0 25 30]); - c0(:,4)=[2;1]; % maximum element size for bottom (label 1) and top (label 2) layers - % simulate the optical properties of skull and gray-matter of a human brain model % see http://mcx.sourceforge.net/cgi-bin/index.cgi?MMC/Colin27AtlasMesh - % cfg.prop=[0 0 1 1;0.02 9.0, 0.89 1.37;0.019 7.8 0.89 1.37]; + % cfg.prop=[0 0 1 1;0.02 9.0, 0.89 1.37;0.019 7.8 0.89 1.37]; else - [node,face,c0]=latticegrid([0 60],[0 60],[0 20 25 30]); % if you like a 3-layer model - c0(:,4)=[2;2;1]; - % cfg.prop=[0 0 1 1;0.02 9.0, 0.89 1.37;0.004 0.009, 0.89 1.37;0.019 7.8 0.89 1.37]; + [node, face, c0] = latticegrid([0 60], [0 60], [0 20 25 30]); % if you like a 3-layer model + c0(:, 4) = [2; 2; 1]; + % cfg.prop=[0 0 1 1;0.02 9.0, 0.89 1.37;0.004 0.009, 0.89 1.37;0.019 7.8 0.89 1.37]; end -[no,el]=surf2mesh(node,face,[],[],1,[],c0); +[no, el] = surf2mesh(node, face, [], [], 1, [], c0); -figure(1); plotmesh(no,el); -savemmcmesh('media',no,el); +figure(1); +plotmesh(no, el); +savemmcmesh('media', no, el); %% add source and retessellate mesh -cfg.srctype='fourier'; -cfg.srcpos=[10 10 35]; -kx=3; % wave number in the x-dir -ky=0; % wave number in the x-dir -xphase=pi/3; % phase offset in the x-dir, must < 2pi -yphase=0; % phase offset in the x-dir, must < 2pi -cfg.srcparam1=[40 0 0 kx+xphase/(2*pi)]; % 3 is k-number in x direction -cfg.srcparam2=[0 40 0 ky+yphase/(2*pi)]; -cfg.srcdir=[0 0 -1]; +cfg.srctype = 'fourier'; +cfg.srcpos = [10 10 35]; +kx = 3; % wave number in the x-dir +ky = 0; % wave number in the x-dir +xphase = pi / 3; % phase offset in the x-dir, must < 2pi +yphase = 0; % phase offset in the x-dir, must < 2pi +cfg.srcparam1 = [40 0 0 kx + xphase / (2 * pi)]; % 3 is k-number in x direction +cfg.srcparam2 = [0 40 0 ky + yphase / (2 * pi)]; +cfg.srcdir = [0 0 -1]; -srcdef=struct('srctype',cfg.srctype,'srcpos',cfg.srcpos,'srcdir',cfg.srcdir,... - 'srcparam1',cfg.srcparam1,'srcparam2',cfg.srcparam2); +srcdef = struct('srctype', cfg.srctype, 'srcpos', cfg.srcpos, 'srcdir', cfg.srcdir, ... + 'srcparam1', cfg.srcparam1, 'srcparam2', cfg.srcparam2); -[node,elem] = mmcaddsrc(no,el,mmcsrcdomain(srcdef,[min(no);max(no)])); +[node, elem] = mmcaddsrc(no, el, mmcsrcdomain(srcdef, [min(no); max(no)])); -figure(2); plotmesh(node,elem); +figure(2); +plotmesh(node, elem); % save the final re-tessellated mesh -savemmcmesh('sfdi',node,elem); +savemmcmesh('sfdi', node, elem); diff --git a/examples/sfdi2layer/plot_result.m b/examples/sfdi2layer/plot_result.m index a6d06bcb..7651d47c 100644 --- a/examples/sfdi2layer/plot_result.m +++ b/examples/sfdi2layer/plot_result.m @@ -1,17 +1,18 @@ % CW fluence data = load('sfdi.dat'); -data = reshape(data(:,2),[],50); -layercw = sum(data(1:end-3,:),2)*1e-10; +data = reshape(data(:, 2), [], 50); +layercw = sum(data(1:end - 3, :), 2) * 1e-10; % media mesh cfg.node = readmmcnode('node_media.dat'); cfg.elem = readmmcelem('elem_media.dat'); -cfg.elemprop=cfg.elem(:,5); +cfg.elemprop = cfg.elem(:, 5); % plot results hold on; -qmeshcut(cfg.elem(cfg.elemprop>0,1:4),cfg.node,log10(layercw),'y=30','linestyle','none'); view(3) -qmeshcut(cfg.elem(cfg.elemprop>0,1:4),cfg.node,log10(layercw),'z=27','linestyle','none'); +qmeshcut(cfg.elem(cfg.elemprop > 0, 1:4), cfg.node, log10(layercw), 'y=30', 'linestyle', 'none'); +view(3); +qmeshcut(cfg.elem(cfg.elemprop > 0, 1:4), cfg.node, log10(layercw), 'z=27', 'linestyle', 'none'); box on; -axis equal +axis equal; view(-56, 22); diff --git a/examples/sharing/createmesh.m b/examples/sharing/createmesh.m index 61678183..2fc68824 100644 --- a/examples/sharing/createmesh.m +++ b/examples/sharing/createmesh.m @@ -1,20 +1,19 @@ - %% original mesh -[node,face,elem]=meshabox([0 0 0],[60 60 20],2, 2); -elem(:,5)=1; +[node, face, elem] = meshabox([0 0 0], [60 60 20], 2, 2); +elem(:, 5) = 1; figure(1); -plotmesh(node,elem); +plotmesh(node, elem); %% extended source domain -srcdef=struct('srctype','planar','srcpos',[10,10,-2],'srcdir',[0 0 1],... - 'srcparam1',[40 0 0 40],'srcparam2',[0 40 0 40]); - -[newnode,newelem]=mmcaddsrc(node,elem,srcdef); +srcdef = struct('srctype', 'planar', 'srcpos', [10, 10, -2], 'srcdir', [0 0 1], ... + 'srcparam1', [40 0 0 40], 'srcparam2', [0 40 0 40]); + +[newnode, newelem] = mmcaddsrc(node, elem, srcdef); figure(2); -plotmesh(newnode,newelem); +plotmesh(newnode, newelem); -savemmcmesh('sharing',newnode,newelem); \ No newline at end of file +savemmcmesh('sharing', newnode, newelem); diff --git a/examples/sharing/createpattern.m b/examples/sharing/createpattern.m index 1bc3d599..32215e2b 100644 --- a/examples/sharing/createpattern.m +++ b/examples/sharing/createpattern.m @@ -1,28 +1,27 @@ - % full field illumination pattern pat0 = ones(40); % pattern with left half bright pat1 = zeros(40); -pat1(1:20,:) = 1; +pat1(1:20, :) = 1; % pattern with top half bright pat2 = zeros(40); -pat2(:,1:20) = 1; +pat2(:, 1:20) = 1; % pattern with bright square in the middle pat3 = zeros(40); -pat3(11:30,11:30) = 1; +pat3(11:30, 11:30) = 1; % pattern with a bright cross pat4 = zeros(40); -pat4(16:25,:) = 1; -pat4(:,16:25) = 1; +pat4(16:25, :) = 1; +pat4(:, 16:25) = 1; -fid=fopen('patterns.pat','wb','ieee-le'); -fwrite(fid,pat0','float'); -fwrite(fid,pat1','float'); -fwrite(fid,pat2','float'); -fwrite(fid,pat3','float'); -fwrite(fid,pat4','float'); -fclose(fid); \ No newline at end of file +fid = fopen('patterns.pat', 'wb', 'ieee-le'); +fwrite(fid, pat0', 'float'); +fwrite(fid, pat1', 'float'); +fwrite(fid, pat2', 'float'); +fwrite(fid, pat3', 'float'); +fwrite(fid, pat4', 'float'); +fclose(fid); diff --git a/examples/sharing/plotresults.m b/examples/sharing/plotresults.m index 8c1f19a5..c460f68d 100644 --- a/examples/sharing/plotresults.m +++ b/examples/sharing/plotresults.m @@ -1,43 +1,47 @@ - % [node,face,elem]=meshabox([0 0 0],[60 60 20],2, 2); nTG = 50; npat = 5; -rawdata=load('sharing.dat'); -data=reshape(rawdata(:,end),npat,[],nTG); -cwdata=squeeze(sum(data,3)); -cwdata=cwdata(:,1:end-3); +rawdata = load('sharing.dat'); +data = reshape(rawdata(:, end), npat, [], nTG); +cwdata = squeeze(sum(data, 3)); +cwdata = cwdata(:, 1:end - 3); %% plot results figure(); -subplot(1,3,1); title('pattern 1'); -plotmesh([node,(cwdata(1,:))'],elem,'linestyle','none'); -shading interp -axis off -view([0,0,-1]) - -subplot(2,3,2); title('pattern 2'); -plotmesh([node,(cwdata(2,:))'],elem,'linestyle','none'); -shading interp -axis off -view([0,0,-1]) - -subplot(2,3,3); title('pattern 3'); -plotmesh([node,(cwdata(3,:))'],elem,'linestyle','none'); -shading interp -axis off -view([0,0,-1]) - -subplot(2,3,5); title('pattern 4'); -plotmesh([node,(cwdata(4,:))'],elem,'linestyle','none'); -shading interp -axis off -view([0,0,-1]) - -subplot(2,3,6); title('pattern 5'); -plotmesh([node,(cwdata(5,:))'],elem,'linestyle','none'); -shading interp -axis off -view([0,0,-1]) \ No newline at end of file +subplot(1, 3, 1); +title('pattern 1'); +plotmesh([node, (cwdata(1, :))'], elem, 'linestyle', 'none'); +shading interp; +axis off; +view([0, 0, -1]); + +subplot(2, 3, 2); +title('pattern 2'); +plotmesh([node, (cwdata(2, :))'], elem, 'linestyle', 'none'); +shading interp; +axis off; +view([0, 0, -1]); + +subplot(2, 3, 3); +title('pattern 3'); +plotmesh([node, (cwdata(3, :))'], elem, 'linestyle', 'none'); +shading interp; +axis off; +view([0, 0, -1]); + +subplot(2, 3, 5); +title('pattern 4'); +plotmesh([node, (cwdata(4, :))'], elem, 'linestyle', 'none'); +shading interp; +axis off; +view([0, 0, -1]); + +subplot(2, 3, 6); +title('pattern 5'); +plotmesh([node, (cwdata(5, :))'], elem, 'linestyle', 'none'); +shading interp; +axis off; +view([0, 0, -1]); diff --git a/examples/skinvessel/createsession.m b/examples/skinvessel/createsession.m index 02a5c1e5..dcb0cd0b 100644 --- a/examples/skinvessel/createsession.m +++ b/examples/skinvessel/createsession.m @@ -1,80 +1,78 @@ %% create the skin-vessel benchmark mesh -[no,fc]=latticegrid([0 200],[0 200],[20 32 200]); % create a 3-layer tissue -no(end,:)=no(end,:)+1e-5; +[no, fc] = latticegrid([0 200], [0 200], [20 32 200]); % create a 3-layer tissue +no(end, :) = no(end, :) + 1e-5; -fc2=cell2mat(fc); -fc=[fc2(:,[1 2 3]); fc2(:,[1 3 4])]; +fc2 = cell2mat(fc); +fc = [fc2(:, [1 2 3]); fc2(:, [1 3 4])]; -[ncy,fcy]=meshacylinder([-1,99.5,99.5],[201,99.5,99.5],20,5); % add the vessel -[newnode,newelem]=surfboolean(no,fc,'first',ncy,fcy); % merge the two domains +[ncy, fcy] = meshacylinder([-1, 99.5, 99.5], [201, 99.5, 99.5], 20, 5); % add the vessel +[newnode, newelem] = surfboolean(no, fc, 'first', ncy, fcy); % merge the two domains -c0=[10,100,150,26]'; -seeds=[ones(4,2)*100, c0]; % define the regions by index +c0 = [10, 100, 150, 26]'; +seeds = [ones(4, 2) * 100, c0]; % define the regions by index -[cfg.node,cfg.elem]=s2m(newnode,newelem(:,1:3),1,30,'tetgen',seeds,[],'-YY -A'); % creating the merged mesh domain +[cfg.node, cfg.elem] = s2m(newnode, newelem(:, 1:3), 1, 30, 'tetgen', seeds, [], '-YY -A'); % creating the merged mesh domain -voxellen=0.005; -cfg.node=cfg.node*voxellen; -cfg.method='g'; +voxellen = 0.005; +cfg.node = cfg.node * voxellen; +cfg.method = 'g'; -figure; +figure; subplot(121); -plotmesh(cfg.node,cfg.elem); +plotmesh(cfg.node, cfg.elem); -cfg.elemprop=cfg.elem(:,5); -cfg.elem=cfg.elem(:,1:4); +cfg.elemprop = cfg.elem(:, 5); +cfg.elem = cfg.elem(:, 1:4); %% define other properties -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.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.srcpos=[100 100 -1]*voxellen; -cfg.srcdir=[0 0 1]; +cfg.srcpos = [100 100 -1] * voxellen; +cfg.srcdir = [0 0 1]; -cfg.tstart=0; -cfg.tend=5e-8; -cfg.tstep=5e-8; +cfg.tstart = 0; +cfg.tend = 5e-8; +cfg.tstep = 5e-8; % cfg.outputtype='energy'; %energy deposition in mmc varys with elem volume -cfg.outputtype='flux'; -cfg.minenergy=0.01; +cfg.outputtype = 'flux'; +cfg.minenergy = 0.01; -cfg.srctype='disk'; -cfg.srcparam1=[0.3 0 0 0]; +cfg.srctype = 'disk'; +cfg.srcparam1 = [0.3 0 0 0]; %% define wide-field disk source by extending the mesh to the widefield src -srcdef=struct('srctype',cfg.srctype,'srcpos',cfg.srcpos,'srcdir',cfg.srcdir,... - 'srcparam1',cfg.srcparam1,'srcparam2',[]); +srcdef = struct('srctype', cfg.srctype, 'srcpos', cfg.srcpos, 'srcdir', cfg.srcdir, ... + 'srcparam1', cfg.srcparam1, 'srcparam2', []); -[cfg.node,cfg.elem] = mmcaddsrc(cfg.node,[cfg.elem cfg.elemprop],... - mmcsrcdomain(srcdef,[min(cfg.node);max(cfg.node)])); +[cfg.node, cfg.elem] = mmcaddsrc(cfg.node, [cfg.elem cfg.elemprop], ... + mmcsrcdomain(srcdef, [min(cfg.node); max(cfg.node)])); - -cfg.elemprop=cfg.elem(:,5); -cfg.elem=cfg.elem(:,1:4); +cfg.elemprop = cfg.elem(:, 5); +cfg.elem = cfg.elem(:, 1:4); %% other simulation information -cfg.nphoton=1e7; -cfg.seed=1648335518; +cfg.nphoton = 1e7; +cfg.seed = 1648335518; -cfg.debuglevel='TP'; -cfg.isreflect=0; +cfg.debuglevel = 'TP'; +cfg.isreflect = 0; %% saving coarse mesh -mmc2json(cfg,'dmmc_skinvessel.json'); +mmc2json(cfg, 'dmmc_skinvessel.json'); %% regenerate the mesh using fine mesh -[cfg.node,cfg.elem]=s2m(newnode,newelem(:,1:3),1,30,'tetgen',seeds,[]); % creating the merged mesh domain -cfg.node=cfg.node*voxellen; -cfg.elemprop=cfg.elem(:,5); -cfg.elem=cfg.elem(:,1:4); - -[cfg.node,cfg.elem] = mmcaddsrc(cfg.node,[cfg.elem cfg.elemprop],... - mmcsrcdomain(srcdef,[min(cfg.node);max(cfg.node)])); +[cfg.node, cfg.elem] = s2m(newnode, newelem(:, 1:3), 1, 30, 'tetgen', seeds, []); % creating the merged mesh domain +cfg.node = cfg.node * voxellen; +cfg.elemprop = cfg.elem(:, 5); +cfg.elem = cfg.elem(:, 1:4); -mmc2json(cfg,'skinvessel.json'); +[cfg.node, cfg.elem] = mmcaddsrc(cfg.node, [cfg.elem cfg.elemprop], ... + mmcsrcdomain(srcdef, [min(cfg.node); max(cfg.node)])); +mmc2json(cfg, 'skinvessel.json'); diff --git a/examples/sphere/addsource_sphere.m b/examples/sphere/addsource_sphere.m index 267563c1..1b012e6c 100644 --- a/examples/sphere/addsource_sphere.m +++ b/examples/sphere/addsource_sphere.m @@ -1,13 +1,13 @@ -[node,face,elem]=meshasphere([0 0 0],24,1,2); -elem(:,5)=1; +[node, face, elem] = meshasphere([0 0 0], 24, 1, 2); +elem(:, 5) = 1; -cfg=struct('srctype','planar','srcpos',[-5 -5 25],'srcdir',[0 0 -1],... - 'srcparam1',[10 0 0 0],'srcparam2',[0 10 0 0]); -[newnode,newelem]=mmcaddsrc(node,elem,cfg); +cfg = struct('srctype', 'planar', 'srcpos', [-5 -5 25], 'srcdir', [0 0 -1], ... + 'srcparam1', [10 0 0 0], 'srcparam2', [0 10 0 0]); +[newnode, newelem] = mmcaddsrc(node, elem, cfg); -cfg=struct('srctype','planar','srcpos',[-30 -5 -5],'srcdir',[1 0 0],... - 'srcparam1',[0 10 0 0],'srcparam2',[0 0 10 0]); -[nodedet,elemdet]=mmcadddet(newnode,newelem,cfg); -plotmesh(nodedet,elemdet); +cfg = struct('srctype', 'planar', 'srcpos', [-30 -5 -5], 'srcdir', [1 0 0], ... + 'srcparam1', [0 10 0 0], 'srcparam2', [0 0 10 0]); +[nodedet, elemdet] = mmcadddet(newnode, newelem, cfg); +plotmesh(nodedet, elemdet); -savemmcmesh('sphere',nodedet,elemdet); +savemmcmesh('sphere', nodedet, elemdet); diff --git a/examples/sphere/plotresults.m b/examples/sphere/plotresults.m index 08ad85b9..426b02b8 100644 --- a/examples/sphere/plotresults.m +++ b/examples/sphere/plotresults.m @@ -1,13 +1,12 @@ -no=readmmcnode('node_sphere.dat'); -el=readmmcelem('elem_sphere.dat'); +no = readmmcnode('node_sphere.dat'); +el = readmmcelem('elem_sphere.dat'); load planar.dat; -vv=reshape(planar(:,2),size(no,1),size(planar,1)/size(no,1)); -vvv=sum(vv,2); -plotmesh([no,vvv],el(el(:,end)>0,1:4)) -ppl=loadmch('planar.mch'); -hold on -plotmesh(ppl(:,4:6),'r.'); % plot detected photon locations from a widefield detector -figure -plotmesh([no,log10(vvv)],el(el(:,end)>0,1:4),'x=0'); -shading interp - +vv = reshape(planar(:, 2), size(no, 1), size(planar, 1) / size(no, 1)); +vvv = sum(vv, 2); +plotmesh([no, vvv], el(el(:, end) > 0, 1:4)); +ppl = loadmch('planar.mch'); +hold on; +plotmesh(ppl(:, 4:6), 'r.'); % plot detected photon locations from a widefield detector +figure; +plotmesh([no, log10(vvv)], el(el(:, end) > 0, 1:4), 'x=0'); +shading interp; diff --git a/examples/sphshells/createsession.m b/examples/sphshells/createsession.m index a5df92f5..b32435e2 100644 --- a/examples/sphshells/createsession.m +++ b/examples/sphshells/createsession.m @@ -1,83 +1,83 @@ -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% validate DMMC with MMC in a heterogeneous cubic domain % (see DMMC paper Fig. 1) -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- % -% In this example, we validate the DMMC algorithm with MMC using a +% In this example, we validate the DMMC algorithm with MMC using a % heterogeneous cubic domain. We also compare the DMMC/MMC solution with % that of voxel-based MC (MCX). This simulation generates the results % shown in Fig. 1(c-e) in the paper. -% -%%----------------------------------------------------------------- +% +%% ----------------------------------------------------------------- % preparation -% 1. you need to add the path to iso2mesh toolbox +% 1. you need to add the path to iso2mesh toolbox % addpath('/path/to/iso2mesh/toolbox/'); % 2. you need to add the path to MMC matlab folder % addpath('../../matlab'); % create a surface mesh for a 10 mm radius sphere -[nsph_10,fsph_10]=meshasphere([30 30 30],10,1.0); -[nsph_10,fsph_10]=removeisolatednode(nsph_10,fsph_10); +[nsph_10, fsph_10] = meshasphere([30 30 30], 10, 1.0); +[nsph_10, fsph_10] = removeisolatednode(nsph_10, fsph_10); % create a surface mesh for a 23 mm radius sphere -[nsph_23,fsph_23]=meshasphere([30 30 30],23,2.0); -[nsph_23,fsph_23]=removeisolatednode(nsph_23,fsph_23); +[nsph_23, fsph_23] = meshasphere([30 30 30], 23, 2.0); +[nsph_23, fsph_23] = removeisolatednode(nsph_23, fsph_23); % create a surface mesh for a 25 mm radius sphere -[nsph_25,fsph_25]=meshasphere([30 30 30],25,2.0); -[nsph_25,fsph_25]=removeisolatednode(nsph_25,fsph_25); +[nsph_25, fsph_25] = meshasphere([30 30 30], 25, 2.0); +[nsph_25, fsph_25] = removeisolatednode(nsph_25, fsph_25); -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% create simulation parameters -%%----------------------------------------------------------------- -clear cfg - -cfg.nphoton=3e6; -cfg.seed=1648335518; -cfg.srcpos=[30,30.1,0]; -cfg.srcdir=[0 0 1]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-10; -cfg.prop=[0,0,1,1;0.02 7.0 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.0 1.37]; -cfg.debuglevel='TP'; -cfg.isreflect=1; - -cfgs=[cfg cfg]; - -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- +clear cfg; + +cfg.nphoton = 3e6; +cfg.seed = 1648335518; +cfg.srcpos = [30, 30.1, 0]; +cfg.srcdir = [0 0 1]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-10; +cfg.prop = [0, 0, 1, 1; 0.02 7.0 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.0 1.37]; +cfg.debuglevel = 'TP'; +cfg.isreflect = 1; + +cfgs = [cfg cfg]; + +%% ----------------------------------------------------------------- %% tetrahedral mesh generation -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- -% generate a coarse CDT volumetric mesh from triangular surfaces of +% generate a coarse CDT volumetric mesh from triangular surfaces of % three spheres with an additional bounding box for DMMC -ISO2MESH_SESSION='dmmc1_'; +ISO2MESH_SESSION = 'dmmc1_'; -[nbox,ebox]=meshgrid6(0:60:60,0:60:60,0:60:60); -fbox=volface(ebox); -[no,fc]=mergemesh(nsph_10,fsph_10,nsph_23,fsph_23,nsph_25,fsph_25,nbox,fbox); -[no,fc]=removeisolatednode(no,fc); +[nbox, ebox] = meshgrid6(0:60:60, 0:60:60, 0:60:60); +fbox = volface(ebox); +[no, fc] = mergemesh(nsph_10, fsph_10, nsph_23, fsph_23, nsph_25, fsph_25, nbox, fbox); +[no, fc] = removeisolatednode(no, fc); -ISO2MESH_TETGENOPT='-A -q -Y' -[cfgs(1).node,cfgs(1).elem]=surf2mesh(no,fc,[0 0 0],[60.1 60.1 60.1],1,100,[1 1 1;30 30 6;30 30 15;30 30 30]);%thin layer +ISO2MESH_TETGENOPT = '-A -q -Y'; +[cfgs(1).node, cfgs(1).elem] = surf2mesh(no, fc, [0 0 0], [60.1 60.1 60.1], 1, 100, [1 1 1; 30 30 6; 30 30 15; 30 30 30]); % thin layer % [cfgs(1).node,cfgs(1).elem]=surf2mesh(no,fc,[0 0 0],[60.1 60.1 60.1],1,100,[1 1 1;30 30 6;30 30 17;30 30 30]);%thick layer -cfgs(1).method='g'; +cfgs(1).method = 'g'; -% generate a refined volumetric mesh from triangular surfaces of +% generate a refined volumetric mesh from triangular surfaces of % three spheres with an additional bounding box for MMC -clear ISO2MESH_TETGENOPT -ISO2MESH_SESSION='dmmc2_'; - -[no,fc]=mergemesh(nsph_10,fsph_10,nsph_23,fsph_23,nsph_25,fsph_25); -[no,fc]=removeisolatednode(no,fc); -srcpos=cfgs(1).srcpos; -[cfgs(2).node,cfgs(2).elem,face2]=surf2mesh(no,fc,[0 0 0],[60 60 60],1,0.25,[1 1 1 0.1;30 30 6 0.1;30 30 17 0.1;30 30 30 0.1],[],[1 1 1 1 1 1 1 1]); -[cfgs(2).node,cfgs(2).elem]=sortmesh(srcpos,cfgs(2).node,cfgs(2).elem,1:4); -cfgs(2).method='s'; - -mmc2json(cfgs(1),'dmmc_sphshells.json'); -mmc2json(cfgs(2),'sphshells.json'); +clear ISO2MESH_TETGENOPT; +ISO2MESH_SESSION = 'dmmc2_'; + +[no, fc] = mergemesh(nsph_10, fsph_10, nsph_23, fsph_23, nsph_25, fsph_25); +[no, fc] = removeisolatednode(no, fc); +srcpos = cfgs(1).srcpos; +[cfgs(2).node, cfgs(2).elem, face2] = surf2mesh(no, fc, [0 0 0], [60 60 60], 1, 0.25, [1 1 1 0.1; 30 30 6 0.1; 30 30 17 0.1; 30 30 30 0.1], [], [1 1 1 1 1 1 1 1]); +[cfgs(2).node, cfgs(2).elem] = sortmesh(srcpos, cfgs(2).node, cfgs(2).elem, 1:4); +cfgs(2).method = 's'; + +mmc2json(cfgs(1), 'dmmc_sphshells.json'); +mmc2json(cfgs(2), 'sphshells.json'); diff --git a/examples/statnoise/createmesh.m b/examples/statnoise/createmesh.m index 5f1526e6..71c3de80 100644 --- a/examples/statnoise/createmesh.m +++ b/examples/statnoise/createmesh.m @@ -1,11 +1,10 @@ -sessionid='cube20'; +sessionid = 'cube20'; addpath('../../matlab/'); -[node,elem]=genT5mesh(0:1:20,0:1:20,0:1:20); +[node, elem] = genT5mesh(0:1:20, 0:1:20, 0:1:20); -elem(:,1:4)=meshreorient(node,elem(:,1:4)); - -srcpos=[10.1,10.2,0]; -savemmcmesh(sessionid,node,elem,[]); -eid=tsearchn(node,elem(:,1:4),srcpos) +elem(:, 1:4) = meshreorient(node, elem(:, 1:4)); +srcpos = [10.1, 10.2, 0]; +savemmcmesh(sessionid, node, elem, []); +eid = tsearchn(node, elem(:, 1:4), srcpos); diff --git a/examples/statnoise/plotstdhist.m b/examples/statnoise/plotstdhist.m deleted file mode 100644 index e6d2c0c0..00000000 --- a/examples/statnoise/plotstdhist.m +++ /dev/null @@ -1,27 +0,0 @@ -addpath('../../matlab/') -chpt=[1e4 1e5 1e6 1e7]; -no=readmmcnode('node_cube20.dat'); - -data=zeros(length(chpt),10,size(no,1)); -for i=1:length(chpt) - for j=1:10 - dd=load(sprintf('v_%d_%d.dat',j,chpt(i))); - data(i,j,:)=dd(:,end); - end -end - -%data=log10(data); -chpt=sqrt(chpt); - -figure; hold on; -sty={'bo-','ro-','ko-','co-','bo:','ro:'}; -pos=[10 10 0;10 10 5;10 10 10;10 10 15;10 5 5;10 5 10]; - -% plot trial numbers with Coefficient of Variation (100*std/mean) - -for i=1:size(pos,1) - idx=find(ismember(no,pos(i,:),'rows')); - plot(chpt,100*[std(data(1,:,idx)),std(data(2,:,idx)),std(data(3,:,idx)),std(data(4,:,idx))]./chpt ... % standard error - ./[mean(data(1,:,idx)),mean(data(2,:,idx)),mean(data(3,:,idx)),mean(data(4,:,idx))],sty{i}); -end -hold off; diff --git a/examples/validation/createmesh.m b/examples/validation/createmesh.m index 5031ee9e..44c7b600 100644 --- a/examples/validation/createmesh.m +++ b/examples/validation/createmesh.m @@ -1,11 +1,10 @@ -sessionid='cube'; +sessionid = 'cube'; addpath('../../matlab/'); -[node,elem]=genT5mesh(0:2:60,0:2:60,0:2:60); +[node, elem] = genT5mesh(0:2:60, 0:2:60, 0:2:60); -elem(:,1:4)=meshreorient(node,elem(:,1:4)); - -srcpos=[30.1,30.2,0]; -savemmcmesh(sessionid,node,elem,[]); -eid=tsearchn(node,elem(:,1:4),srcpos) +elem(:, 1:4) = meshreorient(node, elem(:, 1:4)); +srcpos = [30.1, 30.2, 0]; +savemmcmesh(sessionid, node, elem, []); +eid = tsearchn(node, elem(:, 1:4), srcpos); diff --git a/examples/validation/plotcuberes.m b/examples/validation/plotcuberes.m index 307efa48..b98e940f 100644 --- a/examples/validation/plotcuberes.m +++ b/examples/validation/plotcuberes.m @@ -1,82 +1,80 @@ -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% add paths to the necessary toolboxes -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- -%addpath('/Please/add/path/to/mcx/utils/') -addpath('../../matlab') +% addpath('/Please/add/path/to/mcx/utils/') +addpath('../../matlab'); -c0=299792458000; -t0=0; -dt=1e-10; -t1=5e-9; +c0 = 299792458000; +t0 = 0; +dt = 1e-10; +t1 = 5e-9; -twin=[t0+dt/2:dt:t1]; -gates=length(twin); +twin = [t0 + dt / 2:dt:t1]; +gates = length(twin); -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% load MCX results -%%----------------------------------------------------------------- -mcx=loadmc2('../mcxsph/box.mc2', [60 60 60 gates]); -cwmcx=sum(mcx,4); +%% ----------------------------------------------------------------- +mcx = loadmc2('../mcxsph/box.mc2', [60 60 60 gates]); +cwmcx = sum(mcx, 4); -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% load MMC results -%%----------------------------------------------------------------- -node=readmmcnode('node_cube.dat'); -elem=readmmcelem('elem_cube.dat'); +%% ----------------------------------------------------------------- +node = readmmcnode('node_cube.dat'); +elem = readmmcelem('elem_cube.dat'); -load cube.dat -cube=reshape(cube(:,end),[size(node,1),length(cube)/size(node,1)]); -cwcb=sum(cube,2); -[cutpos,cutvalue,facedata]=qmeshcut(elem(:,1:4),node,cwcb,[0 30.2 0; 0 30.2 1; 1 30.2 0]); +load cube.dat; +cube = reshape(cube(:, end), [size(node, 1), length(cube) / size(node, 1)]); +cwcb = sum(cube, 2); +[cutpos, cutvalue, facedata] = qmeshcut(elem(:, 1:4), node, cwcb, [0 30.2 0; 0 30.2 1; 1 30.2 0]); -[xi,yi]=meshgrid(0.5:60,0:60); -vi=griddata(cutpos(:,1),cutpos(:,3),cutvalue,xi,yi); +[xi, yi] = meshgrid(0.5:60, 0:60); +vi = griddata(cutpos(:, 1), cutpos(:, 3), cutvalue, xi, yi); -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% plot the time-domain TPSF at [30 14 10] -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- -figure +figure; -srcpos=[30 30 0]; -detpos=[30 14 10]; +srcpos = [30 30 0]; +detpos = [30 14 10]; -hold on -semilogy((1:gates)/10,tddiffusion(0.005, 1, c0, 0, srcpos, detpos,twin),'r'); -semilogy((1:gates)/10,squeeze(mcx(detpos(1),detpos(2),detpos(3),:)),'o'); -semilogy((1:gates)/10,squeeze(cube(find(node(:,1)==detpos(1) & node(:,2)==detpos(2) & node(:,3)==detpos(3)),:)),'+'); +hold on; +semilogy((1:gates) / 10, tddiffusion(0.005, 1, c0, 0, srcpos, detpos, twin), 'r'); +semilogy((1:gates) / 10, squeeze(mcx(detpos(1), detpos(2), detpos(3), :)), 'o'); +semilogy((1:gates) / 10, squeeze(cube(find(node(:, 1) == detpos(1) & node(:, 2) == detpos(2) & node(:, 3) == detpos(3)), :)), '+'); -set(gca,'fontsize',20) -xlabel('t (ns)') -ylabel('Fluence TPSF (1/mm^2)') -set(gca,'yscale','log') -legend('Diffusion','MCX','MMCM') +set(gca, 'fontsize', 20); +xlabel('t (ns)'); +ylabel('Fluence TPSF (1/mm^2)'); +set(gca, 'yscale', 'log'); +legend('Diffusion', 'MCX', 'MMCM'); legend boxoff; box on; -set(gcf,'PaperPositionMode','auto'); -saveas(gcf,'box_td.fig'); +set(gcf, 'PaperPositionMode', 'auto'); +saveas(gcf, 'box_td.fig'); - -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% generate a contour plot along y=30.2 -%%----------------------------------------------------------------- -figure - -hold on -contour(log10(squeeze(abs(cwmcx(:,30,:)))'),[-1:0.5:8],'b-') -contour(log10(abs(vi)),[-1:0.5:8],'r:') - -axis equal -set(gca,'xlim',[1 60]) -set(gca,'fontsize',20) -xlabel('x (mm)') -ylabel('z (mm)') -legend('MCX','MMCM') +%% ----------------------------------------------------------------- +figure; + +hold on; +contour(log10(squeeze(abs(cwmcx(:, 30, :)))'), [-1:0.5:8], 'b-'); +contour(log10(abs(vi)), [-1:0.5:8], 'r:'); + +axis equal; +set(gca, 'xlim', [1 60]); +set(gca, 'fontsize', 20); +xlabel('x (mm)'); +ylabel('z (mm)'); +legend('MCX', 'MMCM'); legend boxoff; box on; -set(gcf,'PaperPositionMode','auto'); -saveas(gcf,'box.fig'); - +set(gcf, 'PaperPositionMode', 'auto'); +saveas(gcf, 'box.fig'); diff --git a/examples/validation/tessmesh.m b/examples/validation/tessmesh.m index 56be4798..b2c02134 100644 --- a/examples/validation/tessmesh.m +++ b/examples/validation/tessmesh.m @@ -1,12 +1,11 @@ -sessionid='cube2'; +sessionid = 'cube2'; addpath('../../matlab/'); -[node,elem]=meshgrid6(0:60:60,0:60:60,0:60:60); +[node, elem] = meshgrid6(0:60:60, 0:60:60, 0:60:60); -elem(:,1:4)=meshreorient(node,elem(:,1:4)); - -srcpos=[30.1,30.2,0]; -savemmcmesh(sessionid,node,elem,[]); -eid=tsearchn(node,elem(:,1:4),srcpos) +elem(:, 1:4) = meshreorient(node, elem(:, 1:4)); +srcpos = [30.1, 30.2, 0]; +savemmcmesh(sessionid, node, elem, []); +eid = tsearchn(node, elem(:, 1:4), srcpos); diff --git a/examples/widedet/createmesh.m b/examples/widedet/createmesh.m index c246a992..83e9cb67 100644 --- a/examples/widedet/createmesh.m +++ b/examples/widedet/createmesh.m @@ -1,25 +1,24 @@ - %% original mesh -[node,face,c0]=latticegrid([0 60],[0 60],[0 5 10]); -c0(:,4)=[2;3]; % maximum element size for bottom (label 1) and top (label 2) layers -[node,elem]=surf2mesh(node,face,[],[],1,[],c0); +[node, face, c0] = latticegrid([0 60], [0 60], [0 5 10]); +c0(:, 4) = [2; 3]; % maximum element size for bottom (label 1) and top (label 2) layers +[node, elem] = surf2mesh(node, face, [], [], 1, [], c0); figure(1); -plotmesh(node,elem); +plotmesh(node, elem); srcpos = [25.0 35.0 10.0]; %% extended detector domain -detdef=struct('srctype','planar','srcpos',[10,10,-1],'srcdir',[0 0 1],... - 'srcparam1',[40 0 0 40],'srcparam2',[0 40 0 40]); - -[newnode,newelem]=mmcadddet(node,elem,detdef); +detdef = struct('srctype', 'planar', 'srcpos', [10, 10, -1], 'srcdir', [0 0 1], ... + 'srcparam1', [40 0 0 40], 'srcparam2', [0 40 0 40]); + +[newnode, newelem] = mmcadddet(node, elem, detdef); figure(2); -plotmesh(newnode,newelem); +plotmesh(newnode, newelem); -newelem(:,1:4)=meshreorient(newnode,newelem(:,1:4)); -eid=tsearchn(newnode,newelem(:,1:4),srcpos) -savemmcmesh('widedet',newnode,newelem); \ No newline at end of file +newelem(:, 1:4) = meshreorient(newnode, newelem(:, 1:4)); +eid = tsearchn(newnode, newelem(:, 1:4), srcpos); +savemmcmesh('widedet', newnode, newelem); diff --git a/examples/widedet/plot_results.m b/examples/widedet/plot_results.m index bac5dfbb..bc5c6854 100644 --- a/examples/widedet/plot_results.m +++ b/examples/widedet/plot_results.m @@ -1,16 +1,16 @@ - -nx = 40; ny=40; +nx = 40; +ny = 40; nTG = 50; -fd=fopen('widedet.img','rb','ieee-le'); -data = fread(fd,nx*nx*nTG,'float'); -data=reshape(data,[nx ny nTG]); +fd = fopen('widedet.img', 'rb', 'ieee-le'); +data = fread(fd, nx * nx * nTG, 'float'); +data = reshape(data, [nx ny nTG]); fclose(fd); -datacw=sum(data,3); +datacw = sum(data, 3); figure(1); imagesc(datacw'); axis equal; -xlim([0.5 nx+0.5]); +xlim([0.5 nx + 0.5]); xlabel('offsetx (mm)'); ylabel('offsety (mm)'); diff --git a/matlab/besselhprime.m b/matlab/besselhprime.m index aa26f1eb..3b2e6905 100644 --- a/matlab/besselhprime.m +++ b/matlab/besselhprime.m @@ -1,8 +1,8 @@ -function hp=besselhprime(n,k,z) +function hp = besselhprime(n, k, z) % % hp=besselhprime(n,k,z) % -% Hankel function first order derivative +% Hankel function first order derivative % % author: Qianqian Fang (q.fang neu.edu) % @@ -12,7 +12,7 @@ % z: input variable % % output: -% hn: Hankel function first order derivative +% hn: Hankel function first order derivative % % example: % hn=besselhprime(0,1,1) @@ -22,4 +22,4 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -hp=besselh(n-1,k,z)-n/z.*besselh(n,k,z); +hp = besselh(n - 1, k, z) - n / z .* besselh(n, k, z); diff --git a/matlab/besseljprime.m b/matlab/besseljprime.m index 788a07be..97551d9b 100644 --- a/matlab/besseljprime.m +++ b/matlab/besseljprime.m @@ -1,8 +1,8 @@ -function jp=besseljprime(n,z) +function jp = besseljprime(n, z) % % jp=besseljprime(n,z) % -% Bessel function (Bessel first kind) first order derivative +% Bessel function (Bessel first kind) first order derivative % % author: Qianqian Fang (q.fang neu.edu) % @@ -21,4 +21,4 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -jp=besselj(n-1,z)-n/z.*besselj(n,z); +jp = besselj(n - 1, z) - n / z .* besselj(n, z); diff --git a/matlab/besselyprime.m b/matlab/besselyprime.m index 071cf9c2..ca6172ee 100644 --- a/matlab/besselyprime.m +++ b/matlab/besselyprime.m @@ -1,8 +1,8 @@ -function yp=besselyprime(n,z) +function yp = besselyprime(n, z) % % yp=besselyprime(n,z) % -% Neumann function (Bessel second kind) first order derivative +% Neumann function (Bessel second kind) first order derivative % % author: Qianqian Fang (q.fang neu.edu) % @@ -11,7 +11,7 @@ % z: input variable % % output: -% yp: Neumann function (Bessel second kind) first order derivative +% yp: Neumann function (Bessel second kind) first order derivative % % example: % yp=besselyprime(0,1) @@ -21,5 +21,4 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % - -yp=bessely(n-1,z)-n/z.*bessely(n,z); +yp = bessely(n - 1, z) - n / z .* bessely(n, z); diff --git a/matlab/cart2sphorigin.m b/matlab/cart2sphorigin.m index f77b2050..8ef17a81 100644 --- a/matlab/cart2sphorigin.m +++ b/matlab/cart2sphorigin.m @@ -1,4 +1,4 @@ -function [T,P,R]=cart2sphorigin(xi,yi,zi,x0,y0,z0) +function [T, P, R] = cart2sphorigin(xi, yi, zi, x0, y0, z0) % % [T,P,R]=cart2sphorigin(xi,yi,zi,x0,y0,z0) % @@ -23,7 +23,7 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -xi=xi-x0; -yi=yi-y0; -zi=zi-z0; -[T,P,R]=cart2sph(xi(:),yi(:),zi(:)); +xi = xi - x0; +yi = yi - y0; +zi = zi - z0; +[T, P, R] = cart2sph(xi(:), yi(:), zi(:)); diff --git a/matlab/genT5mesh.m b/matlab/genT5mesh.m index cea9e973..9d966d7b 100644 --- a/matlab/genT5mesh.m +++ b/matlab/genT5mesh.m @@ -1,70 +1,72 @@ -function [vertices,tess]=genT5mesh(varargin) -% tess_lat: simplicial tessellation of a rectangular lattice -% usage: [tessellation,vertices]=genT5mesh(v1,v2,v3,...) -% -% arguments: input -% v1,v2,v3,... - numeric vectors defining the lattice in -% each dimension. -% Each vector must be of length >= 1 -% -% arguments: (output) -% vertices - factorial lattice created from (v1,v2,v3,...) -% Each row of this array is one node in the lattice -% tess - integer array defining simplexes as references to -% rows of "vertices". - -% dimension of the lattice -n = length(varargin); -if(n~=3) error('only works for 3D case!'); end - -for i=1:n - v=varargin{i}; - if(mod(length(v),2)==0) - varargin{i}=linspace(v(1),v(end),length(v)+1); - end -end - -% create a single n-d hypercube -% list of vertices of the cube itself - -cube8=... -[1 4 5 13;1 2 5 11;1 10 11 13;11 13 14 5;11 13 1 5;... - 2 3 5 11;3 5 6 15;15 11 12 3;15 11 14 5;11 15 3 5;... - 4 5 7 13;5 7 8 17;16 17 13 7;13 17 14 5;5 7 17 13;... - 5 6 9 15;5 8 9 17;17 18 15 9;17 15 14 5;17 15 5 9;... - 10 13 11 19;13 11 14 23;22 19 23 13;19 23 20 11;13 11 19 23;... - 11 12 15 21;11 15 14 23;23 21 20 11;23 24 21 15;23 21 11 15;... - 16 13 17 25;13 17 14 23;25 26 23 17;25 22 23 13;13 17 25 23;... - 17 18 15 27;17 15 14 23;26 27 23 17;27 23 24 15;23 27 17 15]'; - -% build the complete lattice -nodecount = cellfun('length',varargin); -if any(nodecount<2) - error 'Each dimension must be of size 2 or more.' -end -vertices = lattice(varargin{:}); - -[ix,iy,iz]=meshgrid(1:2:nodecount(1)-2,1:2:nodecount(2)-2,1:2:nodecount(3)-2); -ind=sub2ind(nodecount,ix(:),iy(:),iz(:)); - -nodeshift=[0 1 2 nodecount(1) nodecount(1)+1 nodecount(1)+2 ... -2*nodecount(1) 2*nodecount(1)+1 2*nodecount(1)+2]; -nodeshift=[nodeshift,nodeshift+nodecount(1)*nodecount(2),nodeshift+2*nodecount(1)*nodecount(2)]; - -nc=length(ind); -tess=zeros(nc*40,4); -for i=1:nc - tess((1:40)+(i-1)*40,:)=reshape(nodeshift(cube8(:)),4,40)'+ind(i); -end - -% ======== subfunction ======== -function g = lattice(varargin) -% generate a factorial lattice in n variables -n=nargin; -sizes = cellfun('length',varargin); -c=cell(1,n); -[c{1:n}]=ndgrid(varargin{:}); -g=zeros(prod(sizes),n); -for i=1:n - g(:,i)=c{i}(:); -end +function [vertices, tess] = genT5mesh(varargin) +% tess_lat: simplicial tessellation of a rectangular lattice +% usage: [tessellation,vertices]=genT5mesh(v1,v2,v3,...) +% +% arguments: input +% v1,v2,v3,... - numeric vectors defining the lattice in +% each dimension. +% Each vector must be of length >= 1 +% +% arguments: (output) +% vertices - factorial lattice created from (v1,v2,v3,...) +% Each row of this array is one node in the lattice +% tess - integer array defining simplexes as references to +% rows of "vertices". + +% dimension of the lattice +n = length(varargin); +if (n ~= 3) + error('only works for 3D case!'); +end + +for i = 1:n + v = varargin{i}; + if (mod(length(v), 2) == 0) + varargin{i} = linspace(v(1), v(end), length(v) + 1); + end +end + +% create a single n-d hypercube +% list of vertices of the cube itself + +cube8 = ... + [1 4 5 13; 1 2 5 11; 1 10 11 13; 11 13 14 5; 11 13 1 5; ... + 2 3 5 11; 3 5 6 15; 15 11 12 3; 15 11 14 5; 11 15 3 5; ... + 4 5 7 13; 5 7 8 17; 16 17 13 7; 13 17 14 5; 5 7 17 13; ... + 5 6 9 15; 5 8 9 17; 17 18 15 9; 17 15 14 5; 17 15 5 9; ... + 10 13 11 19; 13 11 14 23; 22 19 23 13; 19 23 20 11; 13 11 19 23; ... + 11 12 15 21; 11 15 14 23; 23 21 20 11; 23 24 21 15; 23 21 11 15; ... + 16 13 17 25; 13 17 14 23; 25 26 23 17; 25 22 23 13; 13 17 25 23; ... + 17 18 15 27; 17 15 14 23; 26 27 23 17; 27 23 24 15; 23 27 17 15]'; + +% build the complete lattice +nodecount = cellfun('length', varargin); +if any(nodecount < 2) + error 'Each dimension must be of size 2 or more.'; +end +vertices = lattice(varargin{:}); + +[ix, iy, iz] = meshgrid(1:2:nodecount(1) - 2, 1:2:nodecount(2) - 2, 1:2:nodecount(3) - 2); +ind = sub2ind(nodecount, ix(:), iy(:), iz(:)); + +nodeshift = [0 1 2 nodecount(1) nodecount(1) + 1 nodecount(1) + 2 ... + 2 * nodecount(1) 2 * nodecount(1) + 1 2 * nodecount(1) + 2]; +nodeshift = [nodeshift, nodeshift + nodecount(1) * nodecount(2), nodeshift + 2 * nodecount(1) * nodecount(2)]; + +nc = length(ind); +tess = zeros(nc * 40, 4); +for i = 1:nc + tess((1:40) + (i - 1) * 40, :) = reshape(nodeshift(cube8(:)), 4, 40)' + ind(i); +end + +% ======== subfunction ======== +function g = lattice(varargin) +% generate a factorial lattice in n variables +n = nargin; +sizes = cellfun('length', varargin); +c = cell(1, n); +[c{1:n}] = ndgrid(varargin{:}); +g = zeros(prod(sizes), n); +for i = 1:n + g(:, i) = c{i}(:); +end diff --git a/matlab/genT6mesh.m b/matlab/genT6mesh.m index a5fa9190..6e41a04d 100644 --- a/matlab/genT6mesh.m +++ b/matlab/genT6mesh.m @@ -1,67 +1,67 @@ -function [vertices,tess]=genT6mesh(varargin) -% tess_lat: simplicial tessellation of a rectangular lattice -% usage: [tessellation,vertices]=genT6mesh(v1,v2,v3,...) -% -% URL: http://www.mathkb.com/Uwe/Forum.aspx/matlab/50484/Constant-surfaces -% -% arguments: input -% v1,v2,v3,... - numeric vectors defining the lattice in -% each dimension. -% Each vector must be of length >= 1 -% -% arguments: (output) -% vertices - factorial lattice created from (v1,v2,v3,...) -% Each row of this array is one node in the lattice -% tess - integer array defining simplexes as references to -% rows of "vertices". - -% dimension of the lattice -n = length(varargin); - -% create a single n-d hypercube -% list of vertices of the cube itself -vhc=('1'==dec2bin(0:(2^n-1))); -% permutations of the integers 1:n -p=perms(1:n); -nt=factorial(n); -thc=zeros(nt,n+1); -for i=1:nt - thc(i,:)=find(all(diff(vhc(:,p(i,:)),[],2)>=0,2))'; -end - -% build the complete lattice -nodecount = cellfun('length',varargin); -if any(nodecount<2) - error 'Each dimension must be of size 2 or more.' -end -vertices = lattice(varargin{:}); - -% unrolled index into each hyper-rectangle in the lattice -ind = cell(1,n); -for i=1:n -ind{i} = 0:(nodecount(i)-2); -end -ind = lattice(ind{:}); -k = cumprod([1,nodecount(1:(end-1))]); -ind = 1+ind*k'; -nind = length(ind); - -offset=vhc*k'; -tess=zeros(nt*nind,n+1); -L=(1:nind)'; -for i=1:nt - tess(L,:)=repmat(ind,1,n+1)+repmat(offset(thc(i,:))',nind,1); -L=L+nind; -end - -% ======== subfunction ======== -function g = lattice(varargin) -% generate a factorial lattice in n variables -n=nargin; -sizes = cellfun('length',varargin); -c=cell(1,n); -[c{1:n}]=ndgrid(varargin{:}); -g=zeros(prod(sizes),n); -for i=1:n -g(:,i)=c{i}(:); -end +function [vertices, tess] = genT6mesh(varargin) +% tess_lat: simplicial tessellation of a rectangular lattice +% usage: [tessellation,vertices]=genT6mesh(v1,v2,v3,...) +% +% URL: http://www.mathkb.com/Uwe/Forum.aspx/matlab/50484/Constant-surfaces +% +% arguments: input +% v1,v2,v3,... - numeric vectors defining the lattice in +% each dimension. +% Each vector must be of length >= 1 +% +% arguments: (output) +% vertices - factorial lattice created from (v1,v2,v3,...) +% Each row of this array is one node in the lattice +% tess - integer array defining simplexes as references to +% rows of "vertices". + +% dimension of the lattice +n = length(varargin); + +% create a single n-d hypercube +% list of vertices of the cube itself +vhc = ('1' == dec2bin(0:(2^n - 1))); +% permutations of the integers 1:n +p = perms(1:n); +nt = factorial(n); +thc = zeros(nt, n + 1); +for i = 1:nt + thc(i, :) = find(all(diff(vhc(:, p(i, :)), [], 2) >= 0, 2))'; +end + +% build the complete lattice +nodecount = cellfun('length', varargin); +if any(nodecount < 2) + error 'Each dimension must be of size 2 or more.'; +end +vertices = lattice(varargin{:}); + +% unrolled index into each hyper-rectangle in the lattice +ind = cell(1, n); +for i = 1:n + ind{i} = 0:(nodecount(i) - 2); +end +ind = lattice(ind{:}); +k = cumprod([1, nodecount(1:(end - 1))]); +ind = 1 + ind * k'; +nind = length(ind); + +offset = vhc * k'; +tess = zeros(nt * nind, n + 1); +L = (1:nind)'; +for i = 1:nt + tess(L, :) = repmat(ind, 1, n + 1) + repmat(offset(thc(i, :))', nind, 1); + L = L + nind; +end + +% ======== subfunction ======== +function g = lattice(varargin) +% generate a factorial lattice in n variables +n = nargin; +sizes = cellfun('length', varargin); +c = cell(1, n); +[c{1:n}] = ndgrid(varargin{:}); +g = zeros(prod(sizes), n); +for i = 1:n + g(:, i) = c{i}(:); +end diff --git a/matlab/generate_g1.m b/matlab/generate_g1.m index e1e145a8..0ba64473 100644 --- a/matlab/generate_g1.m +++ b/matlab/generate_g1.m @@ -1,4 +1,4 @@ -function [tau,g1]=generate_g1(fhist,tau, disp_model, DV, lambda, format, varargin) +function [tau, g1] = generate_g1(fhist, tau, disp_model, DV, lambda, format, varargin) % % [tau,g1]=generate_g1(fhist,tau, disp_model, DV, lambda, format) % @@ -8,8 +8,8 @@ % author: Stefan Carp (carp nmr.mgh.harvard.edu) % % input: -% fhist: the file name of the output .mch file -% tau: correlation times at which to compute g1 +% fhist: the file name of the output .mch file +% 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,77 +18,86 @@ % (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.sf.net 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 -[mch_data,mch_header]=loadmch(fhist,format); -temp=strfind(fhist,filesep); -if isempty(temp), fhist=[pwd filesep fhist]; end -temp=strfind(fhist,filesep); -lastslash=temp(end); -sim_label=fhist(lastslash+1:end-4); +[mch_data, mch_header] = loadmch(fhist, format); +temp = strfind(fhist, filesep); +if isempty(temp) + fhist = [pwd filesep fhist]; +end +temp = strfind(fhist, filesep); +lastslash = temp(end); +sim_label = fhist(lastslash + 1:end - 4); -[mua,mus,g,n]=load_mc_prop([fhist(1:lastslash) filesep 'prop_' sim_label '.dat']); +[mua, mus, g, n] = load_mc_prop([fhist(1:lastslash) filesep 'prop_' sim_label '.dat']); -if (mch_header.recordnum-2)~=(2*mch_header.medianum), +if (mch_header.recordnum - 2) ~= (2 * mch_header.medianum) fprintf('History file does not contain momentum transfer information \n'); - g1=-1; - return; + g1 = -1; + return 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); -g1=zeros(mch_header.detnum,length(tau)); +g1 = zeros(mch_header.detnum, length(tau)); -for I=1:mch_header.detnum, - idx= find(mch_data(:,1)==I); - fprintf('Processing detector %.0f: %.0f photons\n',I,length(idx)); +for I = 1:mch_header.detnum + idx = find(mch_data(:, 1) == 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)*mch_data(idx,(3+mch_header.medianum):end)'-mua*mch_data(idx,3:(3+mch_header.medianum-1))')); + g1(I, J) = sum(exp(-(k0.^2 .* rmsdisp / 3) * mch_data(idx, (3 + mch_header.medianum):end)' - mua * mch_data(idx, 3:(3 + mch_header.medianum - 1))')); end - g1_norm=sum(exp(-mua*mch_data(idx,3:(3+mch_header.medianum-1))')); - g1(I,:)=g1(I,:)./g1_norm; + g1_norm = sum(exp(-mua * mch_data(idx, 3:(3 + mch_header.medianum - 1))')); + g1(I, :) = g1(I, :) ./ g1_norm; end - - - diff --git a/matlab/load_mc_prop.m b/matlab/load_mc_prop.m index 43b1974a..f4c9a74f 100644 --- a/matlab/load_mc_prop.m +++ b/matlab/load_mc_prop.m @@ -1,27 +1,28 @@ -function [mua,mus,g,n]=load_mc_prop(fname) +function [mua, mus, g, n] = load_mc_prop(fname) % % [mua,mus,g,n]=load_mc_prop(fname) % -% Loads the absorption and scattering coefficients, as well as the +% Loads the absorption and scattering coefficients, as well as the % scattering anisotropy and index of refraction from the MMC optical % property file given as an argument -% +% % author: Stefan Carp (carp nmr.mgh.harvard.edu - -fid=fopen(fname,'r'); -if fid<0, - error('File %s not found\n',fname); +fid = fopen(fname, 'r'); +if fid < 0 + error('File %s not found\n', fname); end -mc_version=fscanf(fid,'%f',1); if mc_version>1, fprintf('WARNING: MMC version greater than 1\n'); end -num_tissues=fscanf(fid,'%f',1); - -for I=1:num_tissues, - tiss_ind=fscanf(fid,'%f',1); - mua(tiss_ind)=fscanf(fid,'%f',1); - mus(tiss_ind)=fscanf(fid,'%f',1); - g(tiss_ind)=fscanf(fid,'%f',1); - n(tiss_ind)=fscanf(fid,'%f',1); +mc_version = fscanf(fid, '%f', 1); +if mc_version > 1 + fprintf('WARNING: MMC version greater than 1\n'); end +num_tissues = fscanf(fid, '%f', 1); +for I = 1:num_tissues + tiss_ind = fscanf(fid, '%f', 1); + mua(tiss_ind) = fscanf(fid, '%f', 1); + mus(tiss_ind) = fscanf(fid, '%f', 1); + g(tiss_ind) = fscanf(fid, '%f', 1); + n(tiss_ind) = fscanf(fid, '%f', 1); +end diff --git a/matlab/loadmch.m b/matlab/loadmch.m index 2e988f43..92bfa92c 100644 --- a/matlab/loadmch.m +++ b/matlab/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 @@ -29,8 +29,8 @@ % [version,medianum,detnum,recordnum,totalphoton,detectedphoton, % savedphoton,lengthunit,seedbyte,normalizer,respin,srcnum,savedetflag] % 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. % @@ -38,81 +38,83 @@ % 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'); - junk=fread(fid,2,'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'); + junk = fread(fid, 2, 'uint'); - detflag=dec2bin(bitand(savedetflag,63))-'0'; - datalen=[1 hd(2) hd(2) hd(2) 3 3 1]; - datlen=detflag.*datalen(1:length(detflag)); + detflag = dec2bin(bitand(savedetflag, 63)) - '0'; + datalen = [1 hd(2) hd(2) hd(2) 3 3 1]; + 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); +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); end diff --git a/matlab/mmcadddet.m b/matlab/mmcadddet.m index 64ffa3ce..7a7cbc7d 100644 --- a/matlab/mmcadddet.m +++ b/matlab/mmcadddet.m @@ -1,4 +1,4 @@ -function varargout=mmcadddet(varargin) +function varargout = mmcadddet(varargin) % % [newnode,newelem]=mmcadddet(node,elem,det,opt) % or @@ -37,5 +37,4 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -[varargout{1:nargout}]=mmcaddsrc(varargin{:},'extcorelabel',-2,'KeepShape',1,'Expansion',1.0); - +[varargout{1:nargout}] = mmcaddsrc(varargin{:}, 'extcorelabel', -2, 'KeepShape', 1, 'Expansion', 1.0); diff --git a/matlab/mmcaddsrc.m b/matlab/mmcaddsrc.m index a7f60e79..a63cb173 100644 --- a/matlab/mmcaddsrc.m +++ b/matlab/mmcaddsrc.m @@ -1,4 +1,4 @@ -function [newnode,newelem]=mmcaddsrc(node,elem,src,varargin) +function [newnode, newelem] = mmcaddsrc(node, elem, src, varargin) % % [newnode,newelem]=mmcaddsrc(node,elem,src,opt) % or @@ -21,7 +21,7 @@ % the opt struct can be replaced by a list of 'param','value' pairs % % output: -% newnode: the node list of the modified mesh, by default, +% newnode: the node list of the modified mesh, by default, % newnode is a concatination of src at the end of node % newelem: the elem list of the modified mesh, by default, the elements % between the convex hull of the combined node/src and @@ -60,12 +60,12 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -opt=varargin2struct(varargin{:}); -if(~isfield(opt,'extcmdopt')) - opt.extcmdopt='-Y'; +opt = varargin2struct(varargin{:}); +if (~isfield(opt, 'extcmdopt')) + opt.extcmdopt = '-Y'; end -if(isstruct(src)) - src=mmcsrcdomain(src,[min(node);max(node)],opt); +if (isstruct(src)) + src = mmcsrcdomain(src, [min(node); max(node)], opt); end -opt.newnode=src; -[newnode,newelem]=meshrefine(node,elem,opt); +opt.newnode = src; +[newnode, newelem] = meshrefine(node, elem, opt); diff --git a/matlab/mmcdettime.m b/matlab/mmcdettime.m index b08d0e23..7a0bcf1d 100644 --- a/matlab/mmcdettime.m +++ b/matlab/mmcdettime.m @@ -1,17 +1,17 @@ -function dett=mmcdettime(detp,prop,unitinmm) +function dett = mmcdettime(detp, prop, unitinmm) % % dett=mmcdettime(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 mmclab. detp must be a struct % prop: optical property list, as defined in the cfg.prop field of mmclab'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://mmc.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/matlab/mmcdettpsf.m b/matlab/mmcdettpsf.m index 35d6c00c..79b2d49a 100644 --- a/matlab/mmcdettpsf.m +++ b/matlab/mmcdettpsf.m @@ -1,4 +1,4 @@ -function tpsf = mmcdettpsf(detp,detnum,prop,time) +function tpsf = mmcdettpsf(detp, detnum, prop, time) % % tpsf=mmcdettpsf(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 mmclab. detp must be a struct @@ -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=mmcdetweight(detp,prop); -replaytime=mmcdettime(detp,prop); +replayweight = mmcdetweight(detp, prop); +replaytime = mmcdettime(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/matlab/mmcdetweight.m b/matlab/mmcdetweight.m index f4838486..f65843fa 100644 --- a/matlab/mmcdetweight.m +++ b/matlab/mmcdetweight.m @@ -1,16 +1,16 @@ -function detw=mmcdetweight(detp,prop,unitinmm) +function detw = mmcdetweight(detp, prop, unitinmm) % % detw=mmcdetweight(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 mmclab. detp must a struct +% detp: the 2nd output from mmclab. detp must a struct % prop: optical property list, as defined in the cfg.prop field of mmclab'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://mmc.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/matlab/mmcjacobian.m b/matlab/mmcjacobian.m index aee4d562..79b9b68e 100644 --- a/matlab/mmcjacobian.m +++ b/matlab/mmcjacobian.m @@ -1,9 +1,9 @@ -function [Jmua, Jmus]=mmcjacobian(cfg,detp,seeds,detnum) +function [Jmua, Jmus] = mmcjacobian(cfg, detp, seeds, detnum) % % [Jmua, Jmus]=mmcjacobian(cfg,detp,seeds,detnum) (element based) % -% Generate time-domain Jacobians (sensitivity matrix) for absorption and scattering (mus) -% perturbation of a specified source-detector pair with configurations, detected photon +% Generate time-domain Jacobians (sensitivity matrix) for absorption and scattering (mus) +% perturbation of a specified source-detector pair with configurations, detected photon % seeds and detector readings from an initial MC simulation % % author: Ruoyang Yao (yaor rpi.edu) @@ -19,20 +19,20 @@ % Jmua: the Jacobian for absorption coefficient for a specified source-detector pair % also output Jmua as a by-product. % Jmus: (optional) the Jacobian for scattering perturbation of a specified source detector pair -% number of rows is the number of the mesh elements -% number of columns is the number of time gates +% number of rows is the number of the mesh elements +% number of columns is the number of time gates % % example: -% [cube,detp,ncfg,seeds]=mmclab(cfg); % initial MC simulation -% [Jmua,Jmus] = mmcjacobian(ncfg,detp,seeds,1); % generate scattering Jacobian of the first detector +% [cube,detp,ncfg,seeds]=mmclab(cfg); % initial MC simulation +% [Jmua,Jmus] = mmcjacobian(ncfg,detp,seeds,1); % generate scattering Jacobian of the first detector % % this file is part of Mesh-based Monte Carlo (MMC) % % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -if(nargout==1) - Jmua=mmcjmua(cfg,detp,seeds,detnum); -elseif(nargout==2) - [Jmus,Jmua]=mmcjmus(cfg,detp,seeds,detnum); +if (nargout == 1) + Jmua = mmcjmua(cfg, detp, seeds, detnum); +elseif (nargout == 2) + [Jmus, Jmua] = mmcjmus(cfg, detp, seeds, detnum); end diff --git a/matlab/mmcjmua.m b/matlab/mmcjmua.m index 8f2309a0..17ec8900 100644 --- a/matlab/mmcjmua.m +++ b/matlab/mmcjmua.m @@ -1,4 +1,4 @@ -function [Ja, newcfg]=mmcjmua(cfg,detp,seeds,detnum) +function [Ja, newcfg] = mmcjmua(cfg, detp, seeds, detnum) % % Ja=mmcjmua(cfg,detp,seeds,detnum) (element based) % @@ -11,18 +11,18 @@ % input: % cfg: the simulation configuration structure used for the initial MC simulation by mmclab % detp: detector readings from the initial MC simulation, must be a -% structure (supported after MMC v2016.4) +% structure (supported after MMC v2016.4) % seeds: detected photon seeds from the initial MC simulation % detnum: the detector number whose detected photons will be replayed % % output: % Ja: a Jacobian for absorption perturbation of the specified detector -% number of rows is the number of the mesh nodes or elements -% number of columns is the number of time gates +% number of rows is the number of the mesh nodes or elements +% number of columns is the number of time gates % % example: -% [cube,detp,ncfg,seeds]=mmclab(cfg); % initial MC simulation -% Jmua = mmcjmua(ncfg,detp,seeds,1); % generate absorption Jacobian of the first detector +% [cube,detp,ncfg,seeds]=mmclab(cfg); % initial MC simulation +% Jmua = mmcjmua(ncfg,detp,seeds,1); % generate absorption Jacobian of the first detector % % this file is part of Mesh-based Monte Carlo (MMC) % @@ -30,31 +30,31 @@ % % preprocessing of the mesh to get possible missing fields -newcfg=mmclab(cfg,'prep'); -%newcfg.basisorder=0; +newcfg = mmclab(cfg, 'prep'); +% newcfg.basisorder=0; % specify the detector number to replay -newcfg.replaydet=detnum; +newcfg.replaydet = detnum; % select the photon seeds and data of the specified detector -newcfg.seed=seeds.data(:,detp.detid==newcfg.replaydet); -detp.data=detp.data(:,detp.detid==newcfg.replaydet); +newcfg.seed = seeds.data(:, detp.detid == newcfg.replaydet); +detp.data = detp.data(:, detp.detid == newcfg.replaydet); % calculate the detected photon weight and arrival time -newcfg.replayweight=mmcdetweight(detp.data,newcfg.prop); -newcfg.replaytime=mmcdettime(detp.data,newcfg.prop); +newcfg.replayweight = mmcdetweight(detp.data, newcfg.prop); +newcfg.replaytime = mmcdettime(detp.data, newcfg.prop); % specify output type -newcfg.isnormalized=1; % should we leave this for users to decide? -newcfg.outputtype='wl'; +newcfg.isnormalized = 1; % should we leave this for users to decide? +newcfg.outputtype = 'wl'; % now replay detected photons -[jacob,detp1,newcfg]=mmclab(newcfg); +[jacob, detp1, newcfg] = mmclab(newcfg); % validate if the replay is successful -if(all(ismember(round(detp1.data'*1e10)*1e-10,round(detp.data'*1e10)*1e-10,'rows'))) - % disp('replay is successful :-)'); - Ja=-jacob.data; +if (all(ismember(round(detp1.data' * 1e10) * 1e-10, round(detp.data' * 1e10) * 1e-10, 'rows'))) + % disp('replay is successful :-)'); + Ja = -jacob.data; else - error('replay failed :-('); + error('replay failed :-('); end diff --git a/matlab/mmcjmus.m b/matlab/mmcjmus.m index bede7c4d..0fa3c9be 100644 --- a/matlab/mmcjmus.m +++ b/matlab/mmcjmus.m @@ -1,4 +1,4 @@ -function [Jmus, Jmua]=mmcjmus(cfg,detp,seeds,detnum) +function [Jmus, Jmua] = mmcjmus(cfg, detp, seeds, detnum) % % [Jmus, Jmua]=mmcjmus(cfg,detp,seeds,detnum) (element based) % @@ -16,57 +16,57 @@ % % output: % Jmus: the Jacobian for scattering perturbation of a specified source detector pair -% number of rows is the number of the mesh elements -% number of columns is the number of time gates +% number of rows is the number of the mesh elements +% number of columns is the number of time gates % Jmua: (optional) because calculating Jmus requires the Jacobian for mua, so one can % also output Jmua as a by-product. % % example: -% [cube,detp,ncfg,seeds]=mmclab(cfg); % initial MC simulation -% Jmus = mmcjmus(ncfg,detp,seeds,1); % generate scattering Jacobian of the first detector +% [cube,detp,ncfg,seeds]=mmclab(cfg); % initial MC simulation +% Jmus = mmcjmus(ncfg,detp,seeds,1); % generate scattering Jacobian of the first detector % % this file is part of Mesh-based Monte Carlo (MMC) % % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -[Jmua, newcfg]=mmcjmua(cfg,detp,seeds,detnum); +[Jmua, newcfg] = mmcjmua(cfg, detp, seeds, detnum); % specify output type 2 -newcfg.outputtype='wp'; +newcfg.outputtype = 'wp'; % replay detected photons for weighted partialpath -[jacob,detp2]=mmclab(newcfg); +[jacob, detp2] = mmclab(newcfg); % generate a map for scattering coefficient -elemp=newcfg.elemprop; -idx=find(elemp>0); -elemp(elemp<0)=0; -musmap0=newcfg.prop(elemp+1,2); +elemp = newcfg.elemprop; +idx = find(elemp > 0); +elemp(elemp < 0) = 0; +musmap0 = newcfg.prop(elemp + 1, 2); -if(newcfg.basisorder==1) - dim=4; - nodemus=zeros(size(newcfg.node,1),1); - nodevol=zeros(size(newcfg.node,1),1); - for i=1:length(idx) - nodemus(newcfg.elem(idx(i),1:dim))=nodemus(newcfg.elem(idx(i),1:dim))+newcfg.evol(idx(i))*musmap0(idx(i)); - nodevol(newcfg.elem(idx(i),1:dim))=nodevol(newcfg.elem(idx(i),1:dim))+newcfg.evol(idx(i)); +if (newcfg.basisorder == 1) + dim = 4; + nodemus = zeros(size(newcfg.node, 1), 1); + nodevol = zeros(size(newcfg.node, 1), 1); + for i = 1:length(idx) + nodemus(newcfg.elem(idx(i), 1:dim)) = nodemus(newcfg.elem(idx(i), 1:dim)) + newcfg.evol(idx(i)) * musmap0(idx(i)); + nodevol(newcfg.elem(idx(i), 1:dim)) = nodevol(newcfg.elem(idx(i), 1:dim)) + newcfg.evol(idx(i)); end - musmap=nodemus./nodevol; - musmap(isnan(musmap))=newcfg.prop(1,2); + musmap = nodemus ./ nodevol; + musmap(isnan(musmap)) = newcfg.prop(1, 2); else - musmap=musmap0; + musmap = musmap0; end % divide by local scattering coefficient -jacob.data=jacob.data./repmat(musmap(:),1,size(jacob.data,2)); -jacob.data(musmap<0)=0; +jacob.data = jacob.data ./ repmat(musmap(:), 1, size(jacob.data, 2)); +jacob.data(musmap < 0) = 0; % validate if the replay is successful -if(all(ismember(round(detp2.data'*1e10)*1e-10,round(detp.data'*1e10)*1e-10,'rows'))) - %disp('replay is successful :-)'); - Jmus=Jmua+jacob.data; +if (all(ismember(round(detp2.data' * 1e10) * 1e-10, round(detp.data' * 1e10) * 1e-10, 'rows'))) + % disp('replay is successful :-)'); + Jmus = Jmua + jacob.data; else - error('replay failed :-('); + error('replay failed :-('); end diff --git a/matlab/mmcmeanpath.m b/matlab/mmcmeanpath.m index b64933da..d58b473b 100644 --- a/matlab/mmcmeanpath.m +++ b/matlab/mmcmeanpath.m @@ -1,4 +1,4 @@ -function avgpath=mmcmeanpath(detp,prop) +function avgpath = mmcmeanpath(detp, prop) % % avgpath=mmcmeanpath(detp,prop) % @@ -11,12 +11,12 @@ % prop: optical property list, as defined in the cfg.prop field of mmclab's input % % output: -% avepath: the average pathlength for each tissue type +% avepath: the average pathlength for each tissue type % % this file is part of Mesh-based Monte Carlo (MMC) % % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -detw=mmcdetweight(detp,prop); -avgpath=sum(detp.ppath.*repmat(detw(:),1,size(detp.ppath,2))) / sum(detw(:)); +detw = mmcdetweight(detp, prop); +avgpath = sum(detp.ppath .* repmat(detw(:), 1, size(detp.ppath, 2))) / sum(detw(:)); diff --git a/matlab/mmcmeanscat.m b/matlab/mmcmeanscat.m index a0a30714..bda18160 100644 --- a/matlab/mmcmeanscat.m +++ b/matlab/mmcmeanscat.m @@ -1,4 +1,4 @@ -function avgnscat=mmcmeanscat(detp,prop) +function avgnscat = mmcmeanscat(detp, prop) % % avgnscat=mmcmeanscat(detp,prop) % @@ -11,12 +11,12 @@ % prop: optical property list, as defined in the cfg.prop field of mmclab'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 part of Mesh-based Monte Carlo (MMC) % % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -detw=mmcdetweight(detp,prop); -avgnscat=sum(detp.nscat.*repmat(detw(:),1,size(detp.ppath,2))) / sum(detw(:)); +detw = mmcdetweight(detp, prop); +avgnscat = sum(detp.nscat .* repmat(detw(:), 1, size(detp.ppath, 2))) / sum(detw(:)); diff --git a/matlab/mmcraytrace.m b/matlab/mmcraytrace.m index 9b563b96..dd355c75 100644 --- a/matlab/mmcraytrace.m +++ b/matlab/mmcraytrace.m @@ -1,4 +1,4 @@ -function [p,e0]=mmcraytrace(node,elem,p0,v0,e0) +function [p, e0] = mmcraytrace(node, elem, p0, v0, e0) % % [p,e0]=mmcraytrace(node,elem,p0,v0,e0) % @@ -22,53 +22,55 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -p=p0; -if(size(elem,2)==3) - face=elem; +p = p0; +if (size(elem, 2) == 3) + face = elem; else - face=volface(elem); + face = volface(elem); end -[t,u,v,idx]=raytrace(p0,v0,node,face); -if(isempty(idx)) +[t, u, v, idx] = raytrace(p0, v0, node, face); +if (isempty(idx)) error('ray does not intersect with the mesh'); else - t=t(idx); - if(e0=='>') - idx1=find(t>=0); - elseif(e0=='<') - idx1=find(t<=0); - elseif(isnan(e0) || e0=='-') - idx1=1:length(t); + t = t(idx); + if (e0 == '>') + idx1 = find(t >= 0); + elseif (e0 == '<') + idx1 = find(t <= 0); + elseif (isnan(e0) || e0 == '-') + idx1 = 1:length(t); else error('ray direction specifier is not recognized'); end - if(isempty(idx1)) + if (isempty(idx1)) error('no intersection is found along the ray direction'); end - t0=abs(t(idx1)); - [tmin,loc]=min(t0); - faceidx=idx(idx1(loc)); + t0 = abs(t(idx1)); + [tmin, loc] = min(t0); + faceidx = idx(idx1(loc)); % update source position - p=p0+t(idx1(loc))*v0; + p = p0 + t(idx1(loc)) * v0; - if(nargout<2) - return; + if (nargout < 2) + return end % find initial element id - if(size(elem,2)==3) - e0=faceidx; + if (size(elem, 2) == 3) + e0 = faceidx; else - felem=sort(face(faceidx,:)); - f=elem; - f=[f(:,[1,2,3]); - f(:,[2,1,4]); - f(:,[1,3,4]); - f(:,[2,4,3])]; - [tf,loc]=ismember(felem,sort(f,2),'rows'); - loc=mod(loc,size(elem,1)); - if(loc==0) loc=size(elem,1); end - e0=loc; + felem = sort(face(faceidx, :)); + f = elem; + f = [f(:, [1, 2, 3]) + f(:, [2, 1, 4]) + f(:, [1, 3, 4]) + f(:, [2, 4, 3])]; + [tf, loc] = ismember(felem, sort(f, 2), 'rows'); + loc = mod(loc, size(elem, 1)); + if (loc == 0) + loc = size(elem, 1); + end + e0 = loc; end end diff --git a/matlab/mmcsrcdomain.m b/matlab/mmcsrcdomain.m index f61428d8..50497031 100644 --- a/matlab/mmcsrcdomain.m +++ b/matlab/mmcsrcdomain.m @@ -1,8 +1,8 @@ -function [srcnode,srcface]=mmcsrcdomain(cfg,meshbbx,varargin) +function [srcnode, srcface] = mmcsrcdomain(cfg, meshbbx, varargin) % % [srcnode,srcface]=mmcsrcdomain(cfg) % -% Defining a source domain (for launching new photons) in the form of +% Defining a source domain (for launching new photons) in the form of % polyhedra based on an MMCLAB simulation configuration structure % % author: Qianqian Fang (q.fang neu.edu) @@ -38,67 +38,67 @@ % the launching domain should be slightly larger than the actual source % domain to avoid starting from an edge or vertex -opt=varargin2struct(varargin{:}); -expansion=jsonopt('Expansion',1.1,opt); -rotateangle=jsonopt('Rotate',0.0,opt); +opt = varargin2struct(varargin{:}); +expansion = jsonopt('Expansion', 1.1, opt); +rotateangle = jsonopt('Rotate', 0.0, opt); -if(~isstruct(cfg)) - error('input cfg must be a struct'); +if (~isstruct(cfg)) + error('input cfg must be a struct'); end -if(~isfield(cfg,'srcpos') || ~isfield(cfg,'srcdir') || ... - ~isfield(cfg,'srctype') ) +if (~isfield(cfg, 'srcpos') || ~isfield(cfg, 'srcdir') || ... + ~isfield(cfg, 'srctype')) error('you must at least define cfg.srcpos, cfg.srcdir, cfg.srctype'); end -if(strcmp(cfg.srctype,'isotropic')) - cfg.srcdir(1:3)=rand(1,3); - cfg.srcdir(1:3)=cfg.srcdir(1:3)/norm(cfg.srcdir(1:3)); +if (strcmp(cfg.srctype, 'isotropic')) + cfg.srcdir(1:3) = rand(1, 3); + cfg.srcdir(1:3) = cfg.srcdir(1:3) / norm(cfg.srcdir(1:3)); end -cfg.srcdir(1:3)=cfg.srcdir(1:3)/norm(cfg.srcdir(1:3)); -domainradius=min(meshbbx(2,:)-meshbbx(1,:))*0.25; -domaindiagnoal=norm(meshbbx(2,:)-meshbbx(1,:)); -if(strcmp(cfg.srctype,'pencil')) - warning(['for external pencil beams, you are highly recommended to set ' ... - 'cfg.e0=''>'', instead of using this script']); +cfg.srcdir(1:3) = cfg.srcdir(1:3) / norm(cfg.srcdir(1:3)); +domainradius = min(meshbbx(2, :) - meshbbx(1, :)) * 0.25; +domaindiagnoal = norm(meshbbx(2, :) - meshbbx(1, :)); +if (strcmp(cfg.srctype, 'pencil')) + warning(['for external pencil beams, you are highly recommended to set ' ... + 'cfg.e0=''>'', instead of using this script']); end -vperp=cross(cfg.srcdir(1:3),rand(1,3)); +vperp = cross(cfg.srcdir(1:3), rand(1, 3)); -if(strcmp(cfg.srctype,'pencil') || strcmp(cfg.srctype,'cone') || ... - strcmp(cfg.srctype,'zgaussian')|| strcmp(cfg.srctype,'isotropic') || strcmp(cfg.srctype,'arcsine')) - srcnode=orthdisk(cfg.srcpos,cfg.srcpos+cfg.srcdir(1:3),domainradius,3,vperp,rotateangle); - srcface=[1 2 3]; -elseif(strcmp(cfg.srctype,'gaussian')) - srcnode=orthdisk(cfg.srcpos,cfg.srcpos+cfg.srcdir(1:3),domaindiagnoal*0.5,3,vperp,rotateangle); - srcface=[1 2 3]; -elseif(strcmp(cfg.srctype,'line') || strcmp(cfg.srctype,'slit')) - v0=cfg.srcpos+cfg.srcparam1(1:3)*0.5; - srcnode=orthdisk(v0,v0+cfg.srcdir(1:3),norm(cfg.srcparam1(1:3))*expansion,3,cfg.srcparam1(1:3)); - srcface=[1 2 3]; -elseif(strcmp(cfg.srctype,'planar') || strcmp(cfg.srctype,'pattern') || ... - strcmp(cfg.srctype,'fourier') ||strcmp(cfg.srctype,'fourierx')||strcmp(cfg.srctype,'fourier2d')) - v0=cfg.srcpos(1:3); - v1=cfg.srcparam1(1:3); - v2=cfg.srcparam2(1:3); - if(strcmp(cfg.srctype,'fourierx')||strcmp(cfg.srctype,'fourier2d')) - v2=cross(v0,v1); +if (strcmp(cfg.srctype, 'pencil') || strcmp(cfg.srctype, 'cone') || ... + strcmp(cfg.srctype, 'zgaussian') || strcmp(cfg.srctype, 'isotropic') || strcmp(cfg.srctype, 'arcsine')) + srcnode = orthdisk(cfg.srcpos, cfg.srcpos + cfg.srcdir(1:3), domainradius, 3, vperp, rotateangle); + srcface = [1 2 3]; +elseif (strcmp(cfg.srctype, 'gaussian')) + srcnode = orthdisk(cfg.srcpos, cfg.srcpos + cfg.srcdir(1:3), domaindiagnoal * 0.5, 3, vperp, rotateangle); + srcface = [1 2 3]; +elseif (strcmp(cfg.srctype, 'line') || strcmp(cfg.srctype, 'slit')) + v0 = cfg.srcpos + cfg.srcparam1(1:3) * 0.5; + srcnode = orthdisk(v0, v0 + cfg.srcdir(1:3), norm(cfg.srcparam1(1:3)) * expansion, 3, cfg.srcparam1(1:3)); + srcface = [1 2 3]; +elseif (strcmp(cfg.srctype, 'planar') || strcmp(cfg.srctype, 'pattern') || ... + strcmp(cfg.srctype, 'fourier') || strcmp(cfg.srctype, 'fourierx') || strcmp(cfg.srctype, 'fourier2d')) + v0 = cfg.srcpos(1:3); + v1 = cfg.srcparam1(1:3); + v2 = cfg.srcparam2(1:3); + if (strcmp(cfg.srctype, 'fourierx') || strcmp(cfg.srctype, 'fourier2d')) + v2 = cross(v0, v1); end - voff1=(v1+v2)*0.5; - voff2=(v1-v2)*0.5; - if(jsonopt('KeepShape',0,opt)) - srcnode=[v0; v0+v1; v0+v1+v2; v0+v2]+[-voff1; voff2; voff1; -voff2]*(expansion-1.0); - srcface=[1 2 3;3 4 1]; + voff1 = (v1 + v2) * 0.5; + voff2 = (v1 - v2) * 0.5; + if (jsonopt('KeepShape', 0, opt)) + srcnode = [v0; v0 + v1; v0 + v1 + v2; v0 + v2] + [-voff1; voff2; voff1; -voff2] * (expansion - 1.0); + srcface = [1 2 3; 3 4 1]; else - srcnode=orthdisk(cfg.srcpos+voff1,cfg.srcpos+voff1+cfg.srcdir(1:3),(max(norm(voff1),norm(voff2)))*2.0*expansion,3,v1+v2,rotateangle); - srcface=[1 2 3]; + srcnode = orthdisk(cfg.srcpos + voff1, cfg.srcpos + voff1 + cfg.srcdir(1:3), (max(norm(voff1), norm(voff2))) * 2.0 * expansion, 3, v1 + v2, rotateangle); + srcface = [1 2 3]; end -elseif(strcmp(cfg.srctype,'disk')) - if(jsonopt('KeepShape',0,opt)) - srcnode=orthdisk(cfg.srcpos,cfg.srcpos+cfg.srcdir(1:3),cfg.srcparam1(1)*expansion,jsonopt('CircleDiv',100,opt)); - srcface=delaunay(srcnode(:,1),srcnode(:,2)); +elseif (strcmp(cfg.srctype, 'disk')) + if (jsonopt('KeepShape', 0, opt)) + srcnode = orthdisk(cfg.srcpos, cfg.srcpos + cfg.srcdir(1:3), cfg.srcparam1(1) * expansion, jsonopt('CircleDiv', 100, opt)); + srcface = delaunay(srcnode(:, 1), srcnode(:, 2)); else - srcnode=orthdisk(cfg.srcpos,cfg.srcpos+cfg.srcdir(1:3),(cfg.srcparam1(1)*2.0)*expansion,3,vperp,rotateangle); - srcface=[1 2 3]; + srcnode = orthdisk(cfg.srcpos, cfg.srcpos + cfg.srcdir(1:3), (cfg.srcparam1(1) * 2.0) * expansion, 3, vperp, rotateangle); + srcface = [1 2 3]; end else error(['source type not supported: ', cfg.srctype]); diff --git a/matlab/readmmcelem.m b/matlab/readmmcelem.m index c7ae7bf5..acc2aeb9 100644 --- a/matlab/readmmcelem.m +++ b/matlab/readmmcelem.m @@ -1,4 +1,4 @@ -function elem=readmmcelem(filename) +function elem = readmmcelem(filename) % % elem=readmmcelem(filename) % @@ -10,7 +10,7 @@ % filename: the file name to the element data file % % output: -% elem: the tetrahedral mesh element list +% elem: the tetrahedral mesh element list % % example: % elem=readmmcelem('elem_sph1.dat'); @@ -20,10 +20,10 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -fid=fopen(filename,'rt'); -[header,c]=fscanf(fid,'%d',2); -elem=fscanf(fid,'%d',[6 header(2)]); +fid = fopen(filename, 'rt'); +[header, c] = fscanf(fid, '%d', 2); +elem = fscanf(fid, '%d', [6 header(2)]); fclose(fid); -elem=elem'; -elem=elem(:,2:end); +elem = elem'; +elem = elem(:, 2:end); diff --git a/matlab/readmmcface.m b/matlab/readmmcface.m index f16c6938..e3e13391 100644 --- a/matlab/readmmcface.m +++ b/matlab/readmmcface.m @@ -1,4 +1,4 @@ -function face=readmmcface(filename) +function face = readmmcface(filename) % % face=readmmcface(filename) % @@ -10,7 +10,7 @@ % filename: the file name to the surface element data file % % output: -% face: the surface triangle element list +% face: the surface triangle element list % % example: % face=readmmcface('face_sph1.dat'); @@ -20,10 +20,10 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -fid=fopen(filename,'rt'); -[header,c]=fscanf(fid,'%d',2); -face=fscanf(fid,'%d',[5 header(2)]); +fid = fopen(filename, 'rt'); +[header, c] = fscanf(fid, '%d', 2); +face = fscanf(fid, '%d', [5 header(2)]); fclose(fid); -face=face'; -face=face(:,2:4); +face = face'; +face = face(:, 2:4); diff --git a/matlab/readmmcmesh.m b/matlab/readmmcmesh.m index 4e7b7b34..36133b42 100644 --- a/matlab/readmmcmesh.m +++ b/matlab/readmmcmesh.m @@ -1,33 +1,33 @@ -function varargout=readmmcmesh(key) -% -% [node elem]=readmmcmesh(key) -% -% Loading MMC node and element data files -% -% author: Qianqian Fang (q.fang neu.edu) -% -% input: -% key: the file name stub to the node coordinate file. The full -% file names are {node,elem}_key.dat -% -% output: -% node: the node coordinate list -% elem: the tetrahedra node index list -% -% example: -% [node elem]=readmmcmesh('sph1'); -% -% this file is part of Mesh-based Monte Carlo (MMC) -% -% License: GPLv3, see http://mcx.sf.net/mmc/ for details -% - -if(nargout>=1) - varargout{1}=readmmcnode(['node_',key,'.dat']); -end -if(nargout>=2) - varargout{2}=readmmcelem(['elem_',key,'.dat']); -end -if(nargout>=3) - varargout{3}=readmmcelem(['elem_',key,'.dat']); -end +function varargout = readmmcmesh(key) +% +% [node elem]=readmmcmesh(key) +% +% Loading MMC node and element data files +% +% author: Qianqian Fang (q.fang neu.edu) +% +% input: +% key: the file name stub to the node coordinate file. The full +% file names are {node,elem}_key.dat +% +% output: +% node: the node coordinate list +% elem: the tetrahedra node index list +% +% example: +% [node elem]=readmmcmesh('sph1'); +% +% this file is part of Mesh-based Monte Carlo (MMC) +% +% License: GPLv3, see http://mcx.sf.net/mmc/ for details +% + +if (nargout >= 1) + varargout{1} = readmmcnode(['node_', key, '.dat']); +end +if (nargout >= 2) + varargout{2} = readmmcelem(['elem_', key, '.dat']); +end +if (nargout >= 3) + varargout{3} = readmmcelem(['elem_', key, '.dat']); +end diff --git a/matlab/readmmcnode.m b/matlab/readmmcnode.m index cc71186a..07a602c6 100644 --- a/matlab/readmmcnode.m +++ b/matlab/readmmcnode.m @@ -1,29 +1,29 @@ -function node=readmmcnode(filename) -% -% node=readmmcnode(filename) -% -% Loading MMC node coordinates data file -% -% author: Qianqian Fang (q.fang neu.edu) -% -% input: -% filename: the file name to the node coordinate file -% -% output: -% node: the node coordinate list -% -% example: -% node=readmmcnode('node_sph1.dat'); -% -% this file is part of Mesh-based Monte Carlo (MMC) -% -% License: GPLv3, see http://mcx.sf.net/mmc/ for details -% - -fid=fopen(filename,'rt'); -hd=fscanf(fid,'%d',2); -node=fscanf(fid,'%d %e %e %e\n',hd(2)*4); -fclose(fid); - -node=reshape(node,[4,hd(2)])'; -node=node(:,2:4); +function node = readmmcnode(filename) +% +% node=readmmcnode(filename) +% +% Loading MMC node coordinates data file +% +% author: Qianqian Fang (q.fang neu.edu) +% +% input: +% filename: the file name to the node coordinate file +% +% output: +% node: the node coordinate list +% +% example: +% node=readmmcnode('node_sph1.dat'); +% +% this file is part of Mesh-based Monte Carlo (MMC) +% +% License: GPLv3, see http://mcx.sf.net/mmc/ for details +% + +fid = fopen(filename, 'rt'); +hd = fscanf(fid, '%d', 2); +node = fscanf(fid, '%d %e %e %e\n', hd(2) * 4); +fclose(fid); + +node = reshape(node, [4, hd(2)])'; +node = node(:, 2:4); diff --git a/matlab/savemmcmesh.m b/matlab/savemmcmesh.m index a27b66f3..c0757a1f 100644 --- a/matlab/savemmcmesh.m +++ b/matlab/savemmcmesh.m @@ -1,4 +1,4 @@ -function savemmcmesh(key,node,elem,varargin) +function savemmcmesh(key, node, elem, varargin) % % savemmcmesh(key,node,elem,face,evol,facenb) % savemmcmesh(key,node,elem,'face',face,'evol',evol,'facenb',facenb,'roi',roi) @@ -8,7 +8,7 @@ function savemmcmesh(key,node,elem,varargin) % author: Qianqian Fang (q.fang neu.edu) % % input: -% key: a string included in all exported mesh file names, the +% key: a string included in all exported mesh file names, the % format of the files are {node,elem,face,facenb,evol}_key.dat % node: a node coordinate list, 3 columns for x/y/z % elem: a tetrahedral element list @@ -27,78 +27,78 @@ function savemmcmesh(key,node,elem,varargin) % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -opt=varargin2struct(varargin{:}); +opt = varargin2struct(varargin{:}); -if(nargin<5 || isempty(jsonopt('evol',[],opt))) - evol=elemvolume(node,elem(:,1:4)); +if (nargin < 5 || isempty(jsonopt('evol', [], opt))) + evol = elemvolume(node, elem(:, 1:4)); end -if(~isempty(node)) - fid=fopen(['node_',key,'.dat'],'wt'); - fprintf(fid,'%d\t%d\n',1,size(node,1)); - fprintf(fid,'%d\t%16.8e\t%16.8e\t%16.8e\n',[1:length(node);node']); - fclose(fid); +if (~isempty(node)) + fid = fopen(['node_', key, '.dat'], 'wt'); + fprintf(fid, '%d\t%d\n', 1, size(node, 1)); + fprintf(fid, '%d\t%16.8e\t%16.8e\t%16.8e\n', [1:length(node); node']); + fclose(fid); end -if(~isempty(elem)) - elem(:,1:4)=meshreorient(node,elem(:,1:4)); +if (~isempty(elem)) + elem(:, 1:4) = meshreorient(node, elem(:, 1:4)); - fid=fopen(['elem_',key,'.dat'],'wt'); - fprintf(fid,'%d\t%d\n',1,size(elem,1)); - if(size(elem,2)==4) - fprintf(fid,'%d\t%d\t%d\t%d\t%d\t1\n', [1:length(elem);elem']); - elseif(size(elem,2)==5) - fprintf(fid,'%d\t%d\t%d\t%d\t%d\t%d\n',[1:length(elem);elem']); - else + fid = fopen(['elem_', key, '.dat'], 'wt'); + fprintf(fid, '%d\t%d\n', 1, size(elem, 1)); + if (size(elem, 2) == 4) + fprintf(fid, '%d\t%d\t%d\t%d\t%d\t1\n', [1:length(elem); elem']); + elseif (size(elem, 2) == 5) + fprintf(fid, '%d\t%d\t%d\t%d\t%d\t%d\n', [1:length(elem); elem']); + else + fclose(fid); + error('wrong elem input: must be 4 or 5 columns'); + end fclose(fid); - error('wrong elem input: must be 4 or 5 columns'); - end - fclose(fid); end -if(~isempty(jsonopt('facenb',[],opt))) - facenb=jsonopt('facenb',[],opt); +if (~isempty(jsonopt('facenb', [], opt))) + facenb = jsonopt('facenb', [], opt); end -if(nargin<6 || isempty(jsonopt('facenb',[],opt))) - facenb=faceneighbors(elem(:,1:4)); - if(nargin<4 || isempty(jsonopt('face',[],opt))) - face=faceneighbors(elem(:,1:4),'rowmajor'); - end +if (nargin < 6 || isempty(jsonopt('facenb', [], opt))) + facenb = faceneighbors(elem(:, 1:4)); + if (nargin < 4 || isempty(jsonopt('face', [], opt))) + face = faceneighbors(elem(:, 1:4), 'rowmajor'); + end end -if(~isempty(face)) - fid=fopen(['face_',key,'.dat'],'wt'); - fprintf(fid,'%d\t%d\n',1,size(face,1)); - if(size(face,2)==3) - fprintf(fid,'%d\t%d\t%d\t%d\t1\n',[1:length(face);face']); - elseif(size(face,2)==4) - fprintf(fid,'%d\t%d\t%d\t%d\t%d\n',[1:length(face);face']); - else +if (~isempty(face)) + fid = fopen(['face_', key, '.dat'], 'wt'); + fprintf(fid, '%d\t%d\n', 1, size(face, 1)); + if (size(face, 2) == 3) + fprintf(fid, '%d\t%d\t%d\t%d\t1\n', [1:length(face); face']); + elseif (size(face, 2) == 4) + fprintf(fid, '%d\t%d\t%d\t%d\t%d\n', [1:length(face); face']); + else + fclose(fid); + error('wrong face input: must be 3 or 4 columns'); + end fclose(fid); - error('wrong face input: must be 3 or 4 columns'); - end - fclose(fid); end -if(~isempty(evol)) - fid=fopen(['velem_' key '.dat'],'wt'); - fprintf(fid,'%d %d\n',1,size(elem,1)); - fprintf(fid,'%d %e\n',[(1:size(elem,1))',evol]'); - fclose(fid); +if (~isempty(evol)) + fid = fopen(['velem_' key '.dat'], 'wt'); + fprintf(fid, '%d %d\n', 1, size(elem, 1)); + fprintf(fid, '%d %e\n', [(1:size(elem, 1))', evol]'); + fclose(fid); end -if(~isempty(facenb)) - fid=fopen(['facenb_' key '.dat'],'wt'); - fprintf(fid,'%d %d\n',1,size(elem,1)); - fprintf(fid,'%d\t%d\t%d\t%d\n',facenb'); - fclose(fid); +if (~isempty(facenb)) + fid = fopen(['facenb_' key '.dat'], 'wt'); + fprintf(fid, '%d %d\n', 1, size(elem, 1)); + fprintf(fid, '%d\t%d\t%d\t%d\n', facenb'); + fclose(fid); end -roi=jsonopt('roi',[],opt); -if(~isempty(roi)) - fid=fopen(['roi_' key '.dat'],'wt'); - fprintf(fid,'%d %d\n',size(roi,2),size(roi,1)); - format=[repmat('%d\t',1,size(roi,2)) '\n']; - fprintf(fid,format,roi'); - fclose(fid); -end \ No newline at end of file +roi = jsonopt('roi', [], opt); +if (~isempty(roi)) + fid = fopen(['roi_' key '.dat'], 'wt'); + fprintf(fid, '%d %d\n', size(roi, 2), size(roi, 1)); + format = [repmat('%d\t', 1, size(roi, 2)) '\n']; + fprintf(fid, format, roi'); + fclose(fid); +end diff --git a/matlab/spbesselh.m b/matlab/spbesselh.m index 4960be33..f13841de 100644 --- a/matlab/spbesselh.m +++ b/matlab/spbesselh.m @@ -1,8 +1,8 @@ -function hn=spbesselh(n,k,z) +function hn = spbesselh(n, k, z) % % hn=spbesselhprime(n,k,z) % -% spherical Hankel function +% spherical Hankel function % % author: Qianqian Fang (q.fang neu.edu) % @@ -12,7 +12,7 @@ % z: input variable % % output: -% hn: spherical Hankel function +% hn: spherical Hankel function % % example: % hn=spbesselh(0,1,1) @@ -22,10 +22,10 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -if(k==1) - hn=spbesselj(n,z)+i*spbessely(n,z); -elseif(k==2) - hn=spbesselj(n,z)-i*spbessely(n,z); +if (k == 1) + hn = spbesselj(n, z) + i * spbessely(n, z); +elseif (k == 2) + hn = spbesselj(n, z) - i * spbessely(n, z); else error('wrong value for the second parameter'); end diff --git a/matlab/spbesselhprime.m b/matlab/spbesselhprime.m index 7e2e527c..5433908a 100644 --- a/matlab/spbesselhprime.m +++ b/matlab/spbesselhprime.m @@ -1,8 +1,8 @@ -function hn=spbesselhprime(n,k,z) +function hn = spbesselhprime(n, k, z) % % hn=spbesselhprime(n,k,z) % -% spherical Hankel function first order derivative +% spherical Hankel function first order derivative % % author: Qianqian Fang (q.fang neu.edu) % @@ -12,7 +12,7 @@ % z: input variable % % output: -% hn: spherical Hankel function first order derivative +% hn: spherical Hankel function first order derivative % % example: % hn=spbesselhprime(0,1,1) @@ -22,10 +22,10 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -if(k==1) - hn=spbesseljprime(n,z)+i*spbesselyprime(n,z); -elseif(k==2) - hn=spbesseljprime(n,z)-i*spbesselyprime(n,z); +if (k == 1) + hn = spbesseljprime(n, z) + i * spbesselyprime(n, z); +elseif (k == 2) + hn = spbesseljprime(n, z) - i * spbesselyprime(n, z); else error('wrong value for the second parameter'); end diff --git a/matlab/spbesselj.m b/matlab/spbesselj.m index 8e0fbaec..d450b6ce 100644 --- a/matlab/spbesselj.m +++ b/matlab/spbesselj.m @@ -1,4 +1,4 @@ -function jn=spbesselj(n,z) +function jn = spbesselj(n, z) % % jn=spbesselj(n,z) % @@ -21,4 +21,4 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -jn=besselj(n+1/2,z).*sqrt(pi./(2*z)); +jn = besselj(n + 1 / 2, z) .* sqrt(pi ./ (2 * z)); diff --git a/matlab/spbesseljprime.m b/matlab/spbesseljprime.m index 7a2d1358..dfc87049 100644 --- a/matlab/spbesseljprime.m +++ b/matlab/spbesseljprime.m @@ -1,4 +1,4 @@ -function jp=spbesseljprime(n,z) +function jp = spbesseljprime(n, z) % % jp=spbesseljprime(n,z) % @@ -21,4 +21,4 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -jp=besseljprime(n+1/2,z).*sqrt(pi/(2*z))-sqrt(pi/2)*besselj(n+1/2,z)./(2*z.*sqrt(z)); +jp = besseljprime(n + 1 / 2, z) .* sqrt(pi / (2 * z)) - sqrt(pi / 2) * besselj(n + 1 / 2, z) ./ (2 * z .* sqrt(z)); diff --git a/matlab/spbessely.m b/matlab/spbessely.m index 7698557e..3b8df5cf 100644 --- a/matlab/spbessely.m +++ b/matlab/spbessely.m @@ -1,8 +1,8 @@ -function yn=spbessely(n,z) +function yn = spbessely(n, z) % % yn=spbessely(n,z) % -% spherical Neumann function +% spherical Neumann function % % author: Qianqian Fang (q.fang neu.edu) % @@ -11,7 +11,7 @@ % z: input variable % % output: -% yn: spherical Neumann function first order derivative +% yn: spherical Neumann function first order derivative % % example: % yn=spbessely(0,1) @@ -21,4 +21,4 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -yn=bessely(n+1/2,z).*sqrt(pi./(2*z)); +yn = bessely(n + 1 / 2, z) .* sqrt(pi ./ (2 * z)); diff --git a/matlab/spbesselyprime.m b/matlab/spbesselyprime.m index 50620fc3..49927524 100644 --- a/matlab/spbesselyprime.m +++ b/matlab/spbesselyprime.m @@ -1,8 +1,8 @@ -function yp=spbesselyprime(n,z) +function yp = spbesselyprime(n, z) % % yp=spbesselyprime(n,z) % -% spherical Neumann function first order derivative +% spherical Neumann function first order derivative % % author: Qianqian Fang (q.fang neu.edu) % @@ -11,7 +11,7 @@ % z: input variable % % output: -% yp: spherical Neumann function first order derivative +% yp: spherical Neumann function first order derivative % % example: % yp=spbesselyprime(0,1) @@ -21,4 +21,4 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -yp=besselyprime(n+1/2,z).*sqrt(pi/(2*z))-sqrt(pi/2)*bessely(n+1/2,z)./(2*z.*sqrt(z)); +yp = besselyprime(n + 1 / 2, z) .* sqrt(pi / (2 * z)) - sqrt(pi / 2) * bessely(n + 1 / 2, z) ./ (2 * z .* sqrt(z)); diff --git a/matlab/spharmonic.m b/matlab/spharmonic.m index f6c6c140..b3f7a2eb 100644 --- a/matlab/spharmonic.m +++ b/matlab/spharmonic.m @@ -1,4 +1,4 @@ -function Y=spharmonic(l,m,theta,phi) +function Y = spharmonic(l, m, theta, phi) % % Y=spharmonic(l,m,theta,phi) % @@ -22,17 +22,17 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -coeff=1; -oldm=m; -if(m<0) - coeff=(-1)^m*prod(1:(l-m))/prod(1:(l+m)); - m=-m; +coeff = 1; +oldm = m; +if (m < 0) + coeff = (-1)^m * prod(1:(l - m)) / prod(1:(l + m)); + m = -m; end -Lmn=legendre(l,cos((theta(:))')); -if l~=0 - Lmn=squeeze(Lmn(m+1,:))'; +Lmn = legendre(l, cos((theta(:))')); +if l ~= 0 + Lmn = squeeze(Lmn(m + 1, :))'; end -Lmn=reshape(Lmn,size(theta)); -m=oldm; -Y=coeff*sqrt((2*l+1)*prod(1:(l-m))/(prod(1:(l+m))*4*pi)) ... - *Lmn.*exp(i*m*phi); +Lmn = reshape(Lmn, size(theta)); +m = oldm; +Y = coeff * sqrt((2 * l + 1) * prod(1:(l - m)) / (prod(1:(l + m)) * 4 * pi)) * ... + Lmn .* exp(i * m * phi); diff --git a/matlab/sphdiffAcoeff.m b/matlab/sphdiffAcoeff.m index 1cb330c6..9ccd42fa 100644 --- a/matlab/sphdiffAcoeff.m +++ b/matlab/sphdiffAcoeff.m @@ -1,4 +1,4 @@ -function A=sphdiffAcoeff(m,l,cfg) +function A = sphdiffAcoeff(m, l, cfg) % % A=sphdiffAcoeff(m,l,cfg) % @@ -22,14 +22,14 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -if((cfg.src(2)==pi | cfg.src(2)==0) & m~=0) - A=0; - return; +if ((cfg.src(2) == pi | cfg.src(2) == 0) & m ~= 0) + A = 0; + return end -x=cfg.kout*cfg.a; -y=cfg.kin*cfg.a; -Dout=cfg.Dout; -Din=cfg.Din; -A=-i*cfg.v*cfg.kout/Dout*spbesselh(l,1,cfg.kout*cfg.src(1))*conj(spharmonic(l,m,cfg.src(2),cfg.src(3)))... - *(Dout*x*spbesseljprime(l,x)*spbesselj(l,y)-Din*y*spbesselj(l,x)*spbesseljprime(l,y))... - /(Dout*x*spbesselhprime(l,1,x)*spbesselj(l,y)-Din*y*spbesselh(l,1,x)*spbesseljprime(l,y)); +x = cfg.kout * cfg.a; +y = cfg.kin * cfg.a; +Dout = cfg.Dout; +Din = cfg.Din; +A = -i * cfg.v * cfg.kout / Dout * spbesselh(l, 1, cfg.kout * cfg.src(1)) * conj(spharmonic(l, m, cfg.src(2), cfg.src(3))) * ... + (Dout * x * spbesseljprime(l, x) * spbesselj(l, y) - Din * y * spbesselj(l, x) * spbesseljprime(l, y)) / ... + (Dout * x * spbesselhprime(l, 1, x) * spbesselj(l, y) - Din * y * spbesselh(l, 1, x) * spbesseljprime(l, y)); diff --git a/matlab/sphdiffBcoeff.m b/matlab/sphdiffBcoeff.m index 473b0e09..9058c785 100644 --- a/matlab/sphdiffBcoeff.m +++ b/matlab/sphdiffBcoeff.m @@ -1,4 +1,4 @@ -function B=sphdiffBcoeff(m,l,cfg) +function B = sphdiffBcoeff(m, l, cfg) % % B=sphdiffBcoeff(m,l,cfg) % @@ -22,4 +22,4 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -B=i*sphdiffAcoeff(m,l,cfg); +B = i * sphdiffAcoeff(m, l, cfg); diff --git a/matlab/sphdiffCcoeff.m b/matlab/sphdiffCcoeff.m index c24a812d..ad082f39 100644 --- a/matlab/sphdiffCcoeff.m +++ b/matlab/sphdiffCcoeff.m @@ -1,4 +1,4 @@ -function C=sphdiffCcoeff(m,l,cfg) +function C = sphdiffCcoeff(m, l, cfg) % % C=sphdiffCcoeff(m,l,cfg) % @@ -22,14 +22,14 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -if((cfg.src(2)==pi | cfg.src(2)==0) & m~=0) - C=0; - return; +if ((cfg.src(2) == pi | cfg.src(2) == 0) & m ~= 0) + C = 0; + return end -x=cfg.kout*cfg.a; -y=cfg.kin*cfg.a; -Dout=cfg.Dout; -Din=cfg.Din; -C=-i*cfg.v*cfg.kout/Dout*spbesselh(l,1,cfg.kout*cfg.src(1))*conj(spharmonic(l,m,cfg.src(2),cfg.src(3)))... - *(Dout*x*spbesselh(l,1,x)*spbesseljprime(l,x)-Dout*x*spbesselhprime(l,1,x)*spbesselj(l,x))... - /(Dout*x*spbesselhprime(l,1,x)*spbesselj(l,y)-Din*y*spbesselh(l,1,x)*spbesseljprime(l,y)); +x = cfg.kout * cfg.a; +y = cfg.kin * cfg.a; +Dout = cfg.Dout; +Din = cfg.Din; +C = -i * cfg.v * cfg.kout / Dout * spbesselh(l, 1, cfg.kout * cfg.src(1)) * conj(spharmonic(l, m, cfg.src(2), cfg.src(3))) * ... + (Dout * x * spbesselh(l, 1, x) * spbesseljprime(l, x) - Dout * x * spbesselhprime(l, 1, x) * spbesselj(l, x)) / ... + (Dout * x * spbesselhprime(l, 1, x) * spbesselj(l, y) - Din * y * spbesselh(l, 1, x) * spbesseljprime(l, y)); diff --git a/matlab/sphdiffexterior.m b/matlab/sphdiffexterior.m index b7a9883b..d0e78977 100644 --- a/matlab/sphdiffexterior.m +++ b/matlab/sphdiffexterior.m @@ -1,4 +1,4 @@ -function res=sphdiffexterior(r,theta,phi,cfg) +function res = sphdiffexterior(r, theta, phi, cfg) % % res=sphdiffexterior(r,theta,phi,cfg) % @@ -8,7 +8,7 @@ % % input: % r,theta,phi: source position in spherical coordinates. -% cfg: the problem domain setup: +% cfg: the problem domain setup: % cfg.v: speed of light in vacuum (mm/s) % cfg.a: sphere radius (mm) % cfg.omua: background (outside) mua (1/mm) @@ -30,4 +30,4 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -res=sphdiffincident(r,theta,phi,cfg)+sphdiffscatter(r,theta,phi,cfg); +res = sphdiffincident(r, theta, phi, cfg) + sphdiffscatter(r, theta, phi, cfg); diff --git a/matlab/sphdiffincident.m b/matlab/sphdiffincident.m index be3f0b4a..1a52ec40 100644 --- a/matlab/sphdiffincident.m +++ b/matlab/sphdiffincident.m @@ -1,4 +1,4 @@ -function phi=sphdiffincident(r,theta,phi,cfg) +function phi = sphdiffincident(r, theta, phi, cfg) % % phi=sphdiffincident(r,theta,phi,cfg) % @@ -8,7 +8,7 @@ % % input: % r,theta,phi: source position in spherical coordinates. -% cfg: the problem domain setup: +% cfg: the problem domain setup: % cfg.v: speed of light in vacuum (mm/s) % cfg.a: sphere radius (mm) % cfg.omua: background (outside) mua (1/mm) @@ -31,10 +31,10 @@ % % matlab's theta and phi are defined differently -[xs,ys,zs] = sph2cart(cfg.src(3),pi/2-cfg.src(2),cfg.src(1)); -[x,y,z] = sph2cart(phi,pi/2-theta,r); -dist=sqrt((x-xs).*(x-xs)+(y-ys).*(y-ys)+(z-zs).*(z-zs)); -phi=cfg.v./(4*pi*cfg.Dout*dist).*exp(i*cfg.kout*dist); +[xs, ys, zs] = sph2cart(cfg.src(3), pi / 2 - cfg.src(2), cfg.src(1)); +[x, y, z] = sph2cart(phi, pi / 2 - theta, r); +dist = sqrt((x - xs) .* (x - xs) + (y - ys) .* (y - ys) + (z - zs) .* (z - zs)); +phi = cfg.v ./ (4 * pi * cfg.Dout * dist) .* exp(i * cfg.kout * dist); % if(isfield(cfg,'src2')) % [xs,ys,zs] = sph2cart(cfg.src2(3),pi/2-cfg.src2(2),cfg.src2(1)); diff --git a/matlab/sphdiffinterior.m b/matlab/sphdiffinterior.m index 0825be3b..0d145505 100644 --- a/matlab/sphdiffinterior.m +++ b/matlab/sphdiffinterior.m @@ -1,4 +1,4 @@ -function res=sphdiffinterior(r,theta,phi,cfg) +function res = sphdiffinterior(r, theta, phi, cfg) % % res=sphdiffinterior(r,theta,phi,cfg) % @@ -8,7 +8,7 @@ % % input: % r,theta,phi: source position in spherical coordinates. -% cfg: the problem domain setup: +% cfg: the problem domain setup: % cfg.v: speed of light in vacuum (mm/s) % cfg.a: sphere radius (mm) % cfg.omua: background (outside) mua (1/mm) @@ -30,9 +30,9 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -res=0; -for l=0:cfg.maxl - for m=-l:l - res=res+(sphdiffCcoeff(m,l,cfg).*spbesselj(l,cfg.kin*r)).*spharmonic(l,m,theta,phi); - end +res = 0; +for l = 0:cfg.maxl + for m = -l:l + res = res + (sphdiffCcoeff(m, l, cfg) .* spbesselj(l, cfg.kin * r)) .* spharmonic(l, m, theta, phi); + end end diff --git a/matlab/sphdiffscatter.m b/matlab/sphdiffscatter.m index cb377031..c81a3800 100644 --- a/matlab/sphdiffscatter.m +++ b/matlab/sphdiffscatter.m @@ -1,14 +1,14 @@ -function res=sphdiffscatter(r,theta,phi,cfg) +function res = sphdiffscatter(r, theta, phi, cfg) % % res=sphdiffscatter(r,theta,phi,cfg) % -% sphere exterior scattered field +% sphere exterior scattered field % % author: Qianqian Fang (q.fang neu.edu) % % input: % r,theta,phi: source position in spherical coordinates. -% cfg: the problem domain setup: +% cfg: the problem domain setup: % cfg.v: speed of light in vacuum (mm/s) % cfg.a: sphere radius (mm) % cfg.omua: background (outside) mua (1/mm) @@ -30,13 +30,13 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -%if(cfg.src(2) neu.edu) % % input: % xrange,yrange,zrange: a vector from where a grid will be created -% and the phi values will be calculated -% cfg: the problem domain setup: +% and the phi values will be calculated +% cfg: the problem domain setup: % cfg.v: speed of light in vacuum (mm/s) % cfg.a: sphere radius (mm) % cfg.omua: background (outside) mua (1/mm) @@ -32,64 +32,63 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % - -if(nargin<4) - cfg.v=299792458000; - cfg.a=10; - cfg.omua=0.002; - cfg.omusp=0.990; - cfg.imua=0.050; - cfg.imusp=0.500; - cfg.src=[30,pi,0]; - cfg.maxl=20; - cfg.omega=0; +if (nargin < 4) + cfg.v = 299792458000; + cfg.a = 10; + cfg.omua = 0.002; + cfg.omusp = 0.990; + cfg.imua = 0.050; + cfg.imusp = 0.500; + cfg.src = [30, pi, 0]; + cfg.maxl = 20; + cfg.omega = 0; end -cfg.Din=cfg.v/(3*cfg.imusp); -cfg.Dout=cfg.v/(3*cfg.omusp); -cfg.kin=sqrt((-cfg.v*cfg.imua+i*cfg.omega)/cfg.Din); -cfg.kout=sqrt((-cfg.v*cfg.omua+i*cfg.omega)/cfg.Dout); +cfg.Din = cfg.v / (3 * cfg.imusp); +cfg.Dout = cfg.v / (3 * cfg.omusp); +cfg.kin = sqrt((-cfg.v * cfg.imua + i * cfg.omega) / cfg.Din); +cfg.kout = sqrt((-cfg.v * cfg.omua + i * cfg.omega) / cfg.Dout); -[xi,yi,zi]=meshgrid(xrange,yrange,zrange); +[xi, yi, zi] = meshgrid(xrange, yrange, zrange); -[P,T,R]=cart2sph(xi(:),yi(:),zi(:)); % matlab's theta and phi are defined differently -T=pi/2-T; +[P, T, R] = cart2sph(xi(:), yi(:), zi(:)); % matlab's theta and phi are defined differently +T = pi / 2 - T; -idx=find(R>cfg.a); -res=zeros(length(R),1); -res(idx)=sphdiffexterior(R(idx),T(idx),P(idx),cfg); +idx = find(R > cfg.a); +res = zeros(length(R), 1); +res(idx) = sphdiffexterior(R(idx), T(idx), P(idx), cfg); -idx=find(R<=cfg.a); -res(idx)=sphdiffinterior(R(idx),T(idx),P(idx),cfg); +idx = find(R <= cfg.a); +res(idx) = sphdiffinterior(R(idx), T(idx), P(idx), cfg); -res=squeeze(reshape(res,size(xi))); -xi=squeeze(xi); -yi=squeeze(yi); -zi=squeeze(zi); +res = squeeze(reshape(res, size(xi))); +xi = squeeze(xi); +yi = squeeze(yi); +zi = squeeze(zi); -%%------------------------------------------------------- +%% ------------------------------------------------------- -function res=sphdiffexterior(r,theta,phi,cfg) -res=sphdiffincident(r,theta,phi,cfg)+sphdiffscatter(r,theta,phi,cfg); +function res = sphdiffexterior(r, theta, phi, cfg) +res = sphdiffincident(r, theta, phi, cfg) + sphdiffscatter(r, theta, phi, cfg); -%%------------------------------------------------------- +%% ------------------------------------------------------- -function res=sphdiffinterior(r,theta,phi,cfg) -res=0; -for l=0:cfg.maxl - for m=-l:l - res=res+(sphdiffCcoeff(m,l,cfg).*spbesselj(l,cfg.kin*r)).*spharmonic(l,m,theta,phi); - end +function res = sphdiffinterior(r, theta, phi, cfg) +res = 0; +for l = 0:cfg.maxl + for m = -l:l + res = res + (sphdiffCcoeff(m, l, cfg) .* spbesselj(l, cfg.kin * r)) .* spharmonic(l, m, theta, phi); + end end -%%------------------------------------------------------- +%% ------------------------------------------------------- -function phi=sphdiffincident(r,theta,phi,cfg) +function phi = sphdiffincident(r, theta, phi, cfg) % matlab's theta and phi are defined differently -[xs,ys,zs] = sph2cart(cfg.src(3),pi/2-cfg.src(2),cfg.src(1)); -[x,y,z] = sph2cart(phi,pi/2-theta,r); -dist=sqrt((x-xs).*(x-xs)+(y-ys).*(y-ys)+(z-zs).*(z-zs)); -phi=cfg.v./(4*pi*cfg.Dout*dist).*exp(i*cfg.kout*dist); +[xs, ys, zs] = sph2cart(cfg.src(3), pi / 2 - cfg.src(2), cfg.src(1)); +[x, y, z] = sph2cart(phi, pi / 2 - theta, r); +dist = sqrt((x - xs) .* (x - xs) + (y - ys) .* (y - ys) + (z - zs) .* (z - zs)); +phi = cfg.v ./ (4 * pi * cfg.Dout * dist) .* exp(i * cfg.kout * dist); % if(isfield(cfg,'src2')) % [xs,ys,zs] = sph2cart(cfg.src2(3),pi/2-cfg.src2(2),cfg.src2(1)); @@ -98,116 +97,113 @@ % phi=phi-cfg.v./(4*pi*cfg.Dout*dist).*exp(i*cfg.kout*dist); % end -%%------------------------------------------------------- +%% ------------------------------------------------------- -function res=sphdiffscatter(r,theta,phi,cfg) -res=zeros(size(r)); -for l=0:cfg.maxl - for m=-l:l - res=res+(sphdiffAcoeff(m,l,cfg)*spbesselj(l,cfg.kout*r)+sphdiffBcoeff(m,l,cfg)... - *spbessely(l,cfg.kout*r)).*spharmonic(l,m,theta,phi); - end +function res = sphdiffscatter(r, theta, phi, cfg) +res = zeros(size(r)); +for l = 0:cfg.maxl + for m = -l:l + res = res + (sphdiffAcoeff(m, l, cfg) * spbesselj(l, cfg.kout * r) + sphdiffBcoeff(m, l, cfg) * ... + spbessely(l, cfg.kout * r)) .* spharmonic(l, m, theta, phi); + end end -%%------------------------------------------------------- - -function A=sphdiffAcoeff(m,l,cfg) -x=cfg.kout*cfg.a; -y=cfg.kin*cfg.a; -Dout=cfg.Dout; -Din=cfg.Din; -A=-i*cfg.v*cfg.kout/Dout*spbesselh(l,1,cfg.kout*cfg.src(1))*conj(spharmonic(l,m,pi,0))... - *(Dout*x*spbesseljprime(l,x)*spbesselj(l,y)-Din*y*spbesselj(l,x)*spbesseljprime(l,y))... - /(Dout*x*spbesselhprime(l,1,x)*spbesselj(l,y)-Din*y*spbesselh(l,1,x)*spbesseljprime(l,y)); - -%%------------------------------------------------------- - -function B=sphdiffBcoeff(m,l,cfg) -B=i*sphdiffAcoeff(m,l,cfg); - -%%------------------------------------------------------- - -function C=sphdiffCcoeff(m,l,cfg) -x=cfg.kout*cfg.a; -y=cfg.kin*cfg.a; -Dout=cfg.Dout; -Din=cfg.Din; -C=-i*cfg.v*cfg.kout/Dout*spbesselh(l,1,cfg.kout*cfg.src(1))*conj(spharmonic(l,m,pi,0))... - *(Dout*x*spbesselh(l,1,x)*spbesseljprime(l,x)-Dout*x*spbesselhprime(l,1,x)*spbesselj(l,x))... - /(Dout*x*spbesselhprime(l,1,x)*spbesselj(l,y)-Din*y*spbesselh(l,1,x)*spbesseljprime(l,y)); - -%%------------------------------------------------------- - -function Y=spharmonic(l,m,theta,phi) -coeff=1; -oldm=m; -if(m<0) - coeff=(-1)^m*prod(1:(l-m))/prod(1:(l+m)); - m=-m; +%% ------------------------------------------------------- + +function A = sphdiffAcoeff(m, l, cfg) +x = cfg.kout * cfg.a; +y = cfg.kin * cfg.a; +Dout = cfg.Dout; +Din = cfg.Din; +A = -i * cfg.v * cfg.kout / Dout * spbesselh(l, 1, cfg.kout * cfg.src(1)) * conj(spharmonic(l, m, pi, 0)) * ... + (Dout * x * spbesseljprime(l, x) * spbesselj(l, y) - Din * y * spbesselj(l, x) * spbesseljprime(l, y)) / ... + (Dout * x * spbesselhprime(l, 1, x) * spbesselj(l, y) - Din * y * spbesselh(l, 1, x) * spbesseljprime(l, y)); + +%% ------------------------------------------------------- + +function B = sphdiffBcoeff(m, l, cfg) +B = i * sphdiffAcoeff(m, l, cfg); + +%% ------------------------------------------------------- + +function C = sphdiffCcoeff(m, l, cfg) +x = cfg.kout * cfg.a; +y = cfg.kin * cfg.a; +Dout = cfg.Dout; +Din = cfg.Din; +C = -i * cfg.v * cfg.kout / Dout * spbesselh(l, 1, cfg.kout * cfg.src(1)) * conj(spharmonic(l, m, pi, 0)) * ... + (Dout * x * spbesselh(l, 1, x) * spbesseljprime(l, x) - Dout * x * spbesselhprime(l, 1, x) * spbesselj(l, x)) / ... + (Dout * x * spbesselhprime(l, 1, x) * spbesselj(l, y) - Din * y * spbesselh(l, 1, x) * spbesseljprime(l, y)); + +%% ------------------------------------------------------- + +function Y = spharmonic(l, m, theta, phi) +coeff = 1; +oldm = m; +if (m < 0) + coeff = (-1)^m * prod(1:(l - m)) / prod(1:(l + m)); + m = -m; end -Lmn=legendre(l,cos(theta)); -if l~=0 - Lmn=squeeze(Lmn(m+1,:))'; +Lmn = legendre(l, cos(theta)); +if l ~= 0 + Lmn = squeeze(Lmn(m + 1, :))'; end -m=oldm; -Y=coeff*sqrt((2*l+1)*prod(1:(l-m))/(prod(1:(l+m))*4*pi)) ... - *Lmn.*exp(i*m*phi); +m = oldm; +Y = coeff * sqrt((2 * l + 1) * prod(1:(l - m)) / (prod(1:(l + m)) * 4 * pi)) * ... + Lmn .* exp(i * m * phi); -%%------------------------------------------------------- +%% ------------------------------------------------------- -function jn=spbesselj(n,z) -jn=besselj(n+1/2,z).*sqrt(pi./(2*z)); +function jn = spbesselj(n, z) +jn = besselj(n + 1 / 2, z) .* sqrt(pi ./ (2 * z)); -%%------------------------------------------------------- +%% ------------------------------------------------------- -function yn=spbessely(n,z) -yn=bessely(n+1/2,z).*sqrt(pi./(2*z)); +function yn = spbessely(n, z) +yn = bessely(n + 1 / 2, z) .* sqrt(pi ./ (2 * z)); -%%------------------------------------------------------- +%% ------------------------------------------------------- -function hn=spbesselh(n,k,z) -if(k==1) - hn=spbesselj(n,z)+i*spbessely(n,z); -elseif(k==2) - hn=spbesselj(n,z)-i*spbessely(n,z); +function hn = spbesselh(n, k, z) +if (k == 1) + hn = spbesselj(n, z) + i * spbessely(n, z); +elseif (k == 2) + hn = spbesselj(n, z) - i * spbessely(n, z); else error('wrong value for the second parameter'); end -%%------------------------------------------------------- +%% ------------------------------------------------------- -function jp=besseljprime(n,z) -jp=besselj(n-1,z)-n/z.*besselj(n,z); +function jp = besseljprime(n, z) +jp = besselj(n - 1, z) - n / z .* besselj(n, z); -%%------------------------------------------------------- +%% ------------------------------------------------------- -function yp=besselyprime(n,z) -yp=bessely(n-1,z)-n/z.*bessely(n,z); +function yp = besselyprime(n, z) +yp = bessely(n - 1, z) - n / z .* bessely(n, z); -%%------------------------------------------------------- +%% ------------------------------------------------------- -function hp=besselhprime(n,k,z) -hp=besselh(n-1,k,z)-n/z.*besselh(n,k,z); +function hp = besselhprime(n, k, z) +hp = besselh(n - 1, k, z) - n / z .* besselh(n, k, z); -%%------------------------------------------------------- +%% ------------------------------------------------------- -function jp=spbesseljprime(n,z) -jp=besseljprime(n+1/2,z).*sqrt(pi/(2*z))-sqrt(pi/2)*besselj(n+1/2,z)./(2*z.*sqrt(z)); +function jp = spbesseljprime(n, z) +jp = besseljprime(n + 1 / 2, z) .* sqrt(pi / (2 * z)) - sqrt(pi / 2) * besselj(n + 1 / 2, z) ./ (2 * z .* sqrt(z)); -%%------------------------------------------------------- +%% ------------------------------------------------------- -function yp=spbesselyprime(n,z) -yp=besselyprime(n+1/2,z).*sqrt(pi/(2*z))-sqrt(pi/2)*bessely(n+1/2,z)./(2*z.*sqrt(z)); +function yp = spbesselyprime(n, z) +yp = besselyprime(n + 1 / 2, z) .* sqrt(pi / (2 * z)) - sqrt(pi / 2) * bessely(n + 1 / 2, z) ./ (2 * z .* sqrt(z)); -%%------------------------------------------------------- +%% ------------------------------------------------------- -function hn=spbesselhprime(n,k,z) -if(k==1) - hn=spbesseljprime(n,z)+i*spbesselyprime(n,z); -elseif(k==2) - hn=spbesseljprime(n,z)-i*spbesselyprime(n,z); +function hn = spbesselhprime(n, k, z) +if (k == 1) + hn = spbesseljprime(n, z) + i * spbesselyprime(n, z); +elseif (k == 2) + hn = spbesseljprime(n, z) - i * spbesselyprime(n, z); else error('wrong value for the second parameter'); end - - - diff --git a/matlab/sphdiffusioninfinite.m b/matlab/sphdiffusioninfinite.m index a7caae66..647edc84 100644 --- a/matlab/sphdiffusioninfinite.m +++ b/matlab/sphdiffusioninfinite.m @@ -1,15 +1,15 @@ -function [res,xi,yi,zi]=sphdiffusioninfinite(xrange,yrange,zrange,cfg) +function [res, xi, yi, zi] = sphdiffusioninfinite(xrange, yrange, zrange, cfg) % % [res,xi,yi,zi]=sphdiffusioninfinite(xrange,yrange,zrange,cfg) % -% diffusion solution for a sphere inside the infinite homogeneous medium +% diffusion solution for a sphere inside the infinite homogeneous medium % % author: Qianqian Fang (q.fang neu.edu) % % input: % xrange,yrange,zrange: a vector from where a grid will be created -% and the phi values will be calculated -% cfg: the problem domain setup: +% and the phi values will be calculated +% cfg: the problem domain setup: % cfg.v: speed of light in vacuum (mm/s) % cfg.a: sphere radius (mm) % cfg.omua: background (outside) mua (1/mm) @@ -32,36 +32,36 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -if(nargin<4) - cfg.v=299792458000; - cfg.a=10; - cfg.omua=0.002; - cfg.omusp=0.990; - cfg.imua=0.050; - cfg.imusp=0.500; - cfg.src=[30,pi,0]; - cfg.maxl=20; - cfg.omega=0; +if (nargin < 4) + cfg.v = 299792458000; + cfg.a = 10; + cfg.omua = 0.002; + cfg.omusp = 0.990; + cfg.imua = 0.050; + cfg.imusp = 0.500; + cfg.src = [30, pi, 0]; + cfg.maxl = 20; + cfg.omega = 0; end -cfg.Din=cfg.v/(3*cfg.imusp); -cfg.Dout=cfg.v/(3*cfg.omusp); -cfg.kin=sqrt((-cfg.v*cfg.imua+i*cfg.omega)/cfg.Din); -cfg.kout=sqrt((-cfg.v*cfg.omua+i*cfg.omega)/cfg.Dout); +cfg.Din = cfg.v / (3 * cfg.imusp); +cfg.Dout = cfg.v / (3 * cfg.omusp); +cfg.kin = sqrt((-cfg.v * cfg.imua + i * cfg.omega) / cfg.Din); +cfg.kout = sqrt((-cfg.v * cfg.omua + i * cfg.omega) / cfg.Dout); -[xi,yi,zi]=meshgrid(xrange,yrange,zrange); +[xi, yi, zi] = meshgrid(xrange, yrange, zrange); -[P,T,R]=cart2sph(xi(:),yi(:),zi(:)); % matlab's theta and phi are defined differently -T=pi/2-T; +[P, T, R] = cart2sph(xi(:), yi(:), zi(:)); % matlab's theta and phi are defined differently +T = pi / 2 - T; -idx=find(R>cfg.a); -res=zeros(length(R),1); -res(idx)=sphdiffexterior(R(idx),T(idx),P(idx),cfg); +idx = find(R > cfg.a); +res = zeros(length(R), 1); +res(idx) = sphdiffexterior(R(idx), T(idx), P(idx), cfg); -idx=find(R<=cfg.a); -res(idx)=sphdiffinterior(R(idx),T(idx),P(idx),cfg); +idx = find(R <= cfg.a); +res(idx) = sphdiffinterior(R(idx), T(idx), P(idx), cfg); -res=squeeze(reshape(res,size(xi))); -xi=squeeze(xi); -yi=squeeze(yi); -zi=squeeze(zi); +res = squeeze(reshape(res, size(xi))); +xi = squeeze(xi); +yi = squeeze(yi); +zi = squeeze(zi); diff --git a/matlab/sphdiffusionscatteronly.m b/matlab/sphdiffusionscatteronly.m index 3386dd90..4e8647a7 100644 --- a/matlab/sphdiffusionscatteronly.m +++ b/matlab/sphdiffusionscatteronly.m @@ -1,4 +1,4 @@ -function [res,xi,yi,zi]=sphdiffusionscatteronly(xrange,yrange,zrange,cfg) +function [res, xi, yi, zi] = sphdiffusionscatteronly(xrange, yrange, zrange, cfg) % % [res,xi,yi,zi]=sphdiffusionscatteronly(xrange,yrange,zrange,cfg) % @@ -8,8 +8,8 @@ % % input: % xrange,yrange,zrange: a vector from where a grid will be created -% and the phi values will be calculated -% cfg: the problem domain setup: +% and the phi values will be calculated +% cfg: the problem domain setup: % cfg.v: speed of light in vacuum (mm/s) % cfg.a: sphere radius (mm) % cfg.omua: background (outside) mua (1/mm) @@ -32,33 +32,33 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -if(nargin<4) - cfg.v=299792458000; - cfg.a=10; - cfg.omua=0.002; - cfg.omusp=0.990; - cfg.imua=0.050; - cfg.imusp=0.500; - cfg.src=[30,pi,0]; - cfg.maxl=20; - cfg.omega=0; +if (nargin < 4) + cfg.v = 299792458000; + cfg.a = 10; + cfg.omua = 0.002; + cfg.omusp = 0.990; + cfg.imua = 0.050; + cfg.imusp = 0.500; + cfg.src = [30, pi, 0]; + cfg.maxl = 20; + cfg.omega = 0; end -cfg.Din=cfg.v/(3*cfg.imusp); -cfg.Dout=cfg.v/(3*cfg.omusp); -cfg.kin=sqrt((-cfg.v*cfg.imua+i*cfg.omega)/cfg.Din); -cfg.kout=sqrt((-cfg.v*cfg.omua+i*cfg.omega)/cfg.Dout); +cfg.Din = cfg.v / (3 * cfg.imusp); +cfg.Dout = cfg.v / (3 * cfg.omusp); +cfg.kin = sqrt((-cfg.v * cfg.imua + i * cfg.omega) / cfg.Din); +cfg.kout = sqrt((-cfg.v * cfg.omua + i * cfg.omega) / cfg.Dout); -[xi,yi,zi]=meshgrid(xrange,yrange,zrange); +[xi, yi, zi] = meshgrid(xrange, yrange, zrange); -[P,T,R]=cart2sph(xi(:),yi(:),zi(:)); % matlab's theta and phi are defined differently -T=pi/2-T; +[P, T, R] = cart2sph(xi(:), yi(:), zi(:)); % matlab's theta and phi are defined differently +T = pi / 2 - T; -idx=find(R>cfg.a); -res=zeros(length(R),1); -res(idx)=sphdiffscatter(R(idx),T(idx),P(idx),cfg); +idx = find(R > cfg.a); +res = zeros(length(R), 1); +res(idx) = sphdiffscatter(R(idx), T(idx), P(idx), cfg); -res=squeeze(reshape(res,size(xi))); -xi=squeeze(xi); -yi=squeeze(yi); -zi=squeeze(zi); +res = squeeze(reshape(res, size(xi))); +xi = squeeze(xi); +yi = squeeze(yi); +zi = squeeze(zi); diff --git a/matlab/sphdiffusionsemi.m b/matlab/sphdiffusionsemi.m index 2978c955..90993ce1 100644 --- a/matlab/sphdiffusionsemi.m +++ b/matlab/sphdiffusionsemi.m @@ -1,15 +1,15 @@ -function [res,xi,yi,zi] = sphdiffusionsemi(Reff,xrange,yrange,zrange,cfg) +function [res, xi, yi, zi] = sphdiffusionsemi(Reff, xrange, yrange, zrange, cfg) % % [res,xi,yi,zi]= sphdiffusionsemi(Reff,xrange,yrange,zrange,cfg) % -% diffusion solution for a sphere inside a semi-infinite homogeneous medium +% diffusion solution for a sphere inside a semi-infinite homogeneous medium % % author: Qianqian Fang (q.fang neu.edu) % % input: % Reff: the effective reflection coeff. % xrange,yrange,zrange: a vector from where a grid will be created -% and the phi values will be calculated +% and the phi values will be calculated % cfg: domain structure for internal/external parameters % cfg.v: speed of light in vacuum (mm/s) % cfg.a: sphere radius (mm) @@ -34,66 +34,65 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % - -if(nargin<5) - cfg.v=299792458000; % mm/s - cfg.a=10; % radius, mm - cfg.omua=0.002; % outside mua 1/mm - cfg.omusp=0.990; % outside mus' 1/mm - cfg.imua=0.050; - cfg.imusp=0.500; -% cfg.imua=0.002; -% cfg.imusp=0.990; - cfg.src=[30,pi,0]; - cfg.maxl=20; - cfg.omega=0; +if (nargin < 5) + cfg.v = 299792458000; % mm/s + cfg.a = 10; % radius, mm + cfg.omua = 0.002; % outside mua 1/mm + cfg.omusp = 0.990; % outside mus' 1/mm + cfg.imua = 0.050; + cfg.imusp = 0.500; + % cfg.imua=0.002; + % cfg.imusp=0.990; + cfg.src = [30, pi, 0]; + cfg.maxl = 20; + cfg.omega = 0; end -cfg.Din=cfg.v/(3*cfg.imusp); -cfg.Dout=cfg.v/(3*cfg.omusp); -cfg.kin=sqrt((-cfg.v*cfg.imua+i*cfg.omega)/cfg.Din); -cfg.kout=sqrt((-cfg.v*cfg.omua+i*cfg.omega)/cfg.Dout); -D = 1/(3*(cfg.omua+cfg.omusp)); +cfg.Din = cfg.v / (3 * cfg.imusp); +cfg.Dout = cfg.v / (3 * cfg.omusp); +cfg.kin = sqrt((-cfg.v * cfg.imua + i * cfg.omega) / cfg.Din); +cfg.kout = sqrt((-cfg.v * cfg.omua + i * cfg.omega) / cfg.Dout); +D = 1 / (3 * (cfg.omua + cfg.omusp)); -zb = (1+Reff)/(1-Reff)*2*D; +zb = (1 + Reff) / (1 - Reff) * 2 * D; -z0 = 1/(cfg.omusp+cfg.omua); +z0 = 1 / (cfg.omusp + cfg.omua); -src0=cfg.src; -cfg.src(1)=src0(1)-z0; +src0 = cfg.src; +cfg.src(1) = src0(1) - z0; % real source full field for the real sphere -[res,xi,yi,zi]=sphdiffusioninfinite(xrange,yrange,zrange,cfg); % S1,O1 +[res, xi, yi, zi] = sphdiffusioninfinite(xrange, yrange, zrange, cfg); % S1,O1 -cfg.src=src0; -cfg.src(2)=pi; -cfg.src(1)=src0(1)+z0+2*zb; +cfg.src = src0; +cfg.src(2) = pi; +cfg.src(1) = src0(1) + z0 + 2 * zb; % image source full field for the real sphere -res2=sphdiffusioninfinite(xrange,yrange,zrange,cfg); % S2,O1 +res2 = sphdiffusioninfinite(xrange, yrange, zrange, cfg); % S2,O1 -res=res-res2; +res = res - res2; -[P,T,R]=cart2sph(xi(:),yi(:),zi(:)); -T=pi/2-T; % matlab's theta and phi are defined differently -idx=find(R>cfg.a); +[P, T, R] = cart2sph(xi(:), yi(:), zi(:)); +T = pi / 2 - T; % matlab's theta and phi are defined differently +idx = find(R > cfg.a); -zrange=zrange+2*(src0(1)+zb); +zrange = zrange + 2 * (src0(1) + zb); -cfg.src=src0; -cfg.src(2)=0; -cfg.src(1)=src0(1)+z0+2*zb; +cfg.src = src0; +cfg.src(2) = 0; +cfg.src(1) = src0(1) + z0 + 2 * zb; % real source scattered field for the imaged sphere outside the real sphere -res2=sphdiffusionscatteronly(xrange,yrange,zrange,cfg); % S1,O2 +res2 = sphdiffusionscatteronly(xrange, yrange, zrange, cfg); % S1,O2 -res(idx)=res(idx)+res2(idx); +res(idx) = res(idx) + res2(idx); -cfg.src=src0; -cfg.src(2)=0; -cfg.src(1)=src0(1)-z0; +cfg.src = src0; +cfg.src(2) = 0; +cfg.src(1) = src0(1) - z0; % image source scattered field for the imaged sphere outside the real % sphere -res2=sphdiffusionscatteronly(xrange,yrange,zrange,cfg); % S2,O2 +res2 = sphdiffusionscatteronly(xrange, yrange, zrange, cfg); % S2,O2 -res(idx)=res(idx)-res2(idx); +res(idx) = res(idx) - res2(idx); % high order terms are ignored, for example, the Phi(S2,O2) scattered by % real sphere O1, or Phi(S1,O1) scatted by the mirrored sphere O2 etc @@ -129,4 +128,3 @@ % `......' % % - diff --git a/matlab/sphdiffusionslab.m b/matlab/sphdiffusionslab.m index 329ccd4f..fcdf36a3 100644 --- a/matlab/sphdiffusionslab.m +++ b/matlab/sphdiffusionslab.m @@ -1,15 +1,15 @@ -function [res,xi,yi,zi] = sphdiffusionslab(Reff1,Reff2,h,xrange,yrange,zrange,cfg) +function [res, xi, yi, zi] = sphdiffusionslab(Reff1, Reff2, h, xrange, yrange, zrange, cfg) % % [res,xi,yi,zi]= sphdiffusionslab(Reff,h,xrange,yrange,zrange,cfg) % -% diffusion solution for a sphere inside an infinite homogeneous slab +% diffusion solution for a sphere inside an infinite homogeneous slab % % author: Qianqian Fang (q.fang neu.edu) % % input: % Reff: the effective reflection coeff. % xrange,yrange,zrange: a vector from where a grid will be created -% and the phi values will be calculated +% and the phi values will be calculated % h: the height of the slab % cfg: domain structure for internal/external parameters % cfg.v: speed of light in vacuum (mm/s) @@ -35,80 +35,76 @@ % License: GPLv3, see http://mcx.sf.net/mmc/ for details % -if(nargin<7) - cfg.v=299792458000; % mm/s - cfg.a=10; % radius, mm - cfg.omua=0.002; % outside mua 1/mm - cfg.omusp=0.990; % outside mus' 1/mm - cfg.imua=0.050; - cfg.imusp=0.500; -% cfg.imua=0.002; -% cfg.imusp=0.990; - cfg.src=[30,pi,0]; - cfg.maxl=20; - cfg.omega=0; +if (nargin < 7) + cfg.v = 299792458000; % mm/s + cfg.a = 10; % radius, mm + cfg.omua = 0.002; % outside mua 1/mm + cfg.omusp = 0.990; % outside mus' 1/mm + cfg.imua = 0.050; + cfg.imusp = 0.500; + % cfg.imua=0.002; + % cfg.imusp=0.990; + cfg.src = [30, pi, 0]; + cfg.maxl = 20; + cfg.omega = 0; end -cfg.Din=cfg.v/(3*cfg.imusp); -cfg.Dout=cfg.v/(3*cfg.omusp); -cfg.kin=sqrt((-cfg.v*cfg.imua+i*cfg.omega)/cfg.Din); -cfg.kout=sqrt((-cfg.v*cfg.omua+i*cfg.omega)/cfg.Dout); -src0=cfg.src; +cfg.Din = cfg.v / (3 * cfg.imusp); +cfg.Dout = cfg.v / (3 * cfg.omusp); +cfg.kin = sqrt((-cfg.v * cfg.imua + i * cfg.omega) / cfg.Din); +cfg.kout = sqrt((-cfg.v * cfg.omua + i * cfg.omega) / cfg.Dout); +src0 = cfg.src; -[res,xi,yi,zi]=sphdiffusionsemi(Reff1,xrange,yrange,zrange,cfg); +[res, xi, yi, zi] = sphdiffusionsemi(Reff1, xrange, yrange, zrange, cfg); -D = 1/(3*(cfg.omua+cfg.omusp)); -zb = (1+Reff2)/(1-Reff2)*2*D; -z0 = 1/(cfg.omusp+cfg.omua); +D = 1 / (3 * (cfg.omua + cfg.omusp)); +zb = (1 + Reff2) / (1 - Reff2) * 2 * D; +z0 = 1 / (cfg.omusp + cfg.omua); -cfg.src=[2*h-src0(1)+2*zb-z0, pi-src0(2), src0(3)]; +cfg.src = [2 * h - src0(1) + 2 * zb - z0, pi - src0(2), src0(3)]; % image source at the upper interface full field for the real sphere -[res2,xi,yi,zi]=sphdiffusioninfinite(xrange,yrange,zrange,cfg); % S2,O1 +[res2, xi, yi, zi] = sphdiffusioninfinite(xrange, yrange, zrange, cfg); % S2,O1 -res=res-res2; +res = res - res2; -cfg.src=[2*h-src0(1)+2*zb-z0+2*(z0+zb), pi-src0(2), src0(3)]; +cfg.src = [2 * h - src0(1) + 2 * zb - z0 + 2 * (z0 + zb), pi - src0(2), src0(3)]; % image source at the upper interface full field for the real sphere -[res2,xi,yi,zi]=sphdiffusioninfinite(xrange,yrange,zrange,cfg); % S2,O1 +[res2, xi, yi, zi] = sphdiffusioninfinite(xrange, yrange, zrange, cfg); % S2,O1 -res=res+res2; +res = res + res2; +[P, T, R] = cart2sph(xi(:), yi(:), zi(:)); +T = pi / 2 - T; % matlab's theta and phi are defined differently +idx = find(R > cfg.a); -[P,T,R]=cart2sph(xi(:),yi(:),zi(:)); -T=pi/2-T; % matlab's theta and phi are defined differently -idx=find(R>cfg.a); - - -cfg.src=[2*h-src0(1)-z0, src0(2), src0(3)]; +cfg.src = [2 * h - src0(1) - z0, src0(2), src0(3)]; % real source scattered field for the imaged sphere outside the real sphere -res2=sphdiffusionscatteronly(xrange,yrange,zrange-2*(h-src0(1)+zb),cfg); % S1,O2 +res2 = sphdiffusionscatteronly(xrange, yrange, zrange - 2 * (h - src0(1) + zb), cfg); % S1,O2 -res(idx)=res(idx)+res2(idx); +res(idx) = res(idx) + res2(idx); -cfg.src=[2*h-src0(1)+2*zb+z0, src0(2), src0(3)]; +cfg.src = [2 * h - src0(1) + 2 * zb + z0, src0(2), src0(3)]; % image source scattered field for the imaged sphere outside the real % sphere -res2=sphdiffusionscatteronly(xrange,yrange,zrange-2*(h-src0(1)+zb),cfg); % S2,O2 - -res(idx)=res(idx)-res2(idx); +res2 = sphdiffusionscatteronly(xrange, yrange, zrange - 2 * (h - src0(1) + zb), cfg); % S2,O2 +res(idx) = res(idx) - res2(idx); % this translate the grid to the origin of the mirrored sphere -cfg.src=[src0(1)-z0, pi-src0(2), src0(3)]; +cfg.src = [src0(1) - z0, pi - src0(2), src0(3)]; % real source scattered field for the imaged sphere outside the real sphere -res2=sphdiffusionscatteronly(xrange,yrange,zrange-2*(h-src0(1)+zb),cfg); % S1,O2 +res2 = sphdiffusionscatteronly(xrange, yrange, zrange - 2 * (h - src0(1) + zb), cfg); % S1,O2 -res(idx)=res(idx)-res2(idx); +res(idx) = res(idx) - res2(idx); -cfg.src=[src0(1)+2*zb+z0, pi-src0(2), src0(3)]; +cfg.src = [src0(1) + 2 * zb + z0, pi - src0(2), src0(3)]; % image source scattered field for the imaged sphere outside the real % sphere -res2=sphdiffusionscatteronly(xrange,yrange,zrange-2*(h-src0(1)+zb),cfg); % S2,O2 - -res(idx)=res(idx)+res2(idx); +res2 = sphdiffusionscatteronly(xrange, yrange, zrange - 2 * (h - src0(1) + zb), cfg); % S2,O2 +res(idx) = res(idx) + res2(idx); % high order terms are ignored, for example, the Phi(S2,O2) scattered by % real sphere O1, or Phi(S1,O1) scatted by the mirrored sphere O2 etc diff --git a/mmclab/example/demo_compare_mmc_mcx.m b/mmclab/example/demo_compare_mmc_mcx.m index fc5ce3d3..64cc1341 100644 --- a/mmclab/example/demo_compare_mmc_mcx.m +++ b/mmclab/example/demo_compare_mmc_mcx.m @@ -1,166 +1,166 @@ -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% Comparing widefield MMC and MCX in a homogeneous cubic domain % (see MMC paper Fig. 2) -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- % % In this example, we compare MMC and MCX using both simple and % widefield sources. % % The cubic domain has a dimension of 60x60x60 mm with optical properties -% mua=0.001, mus=1, n=1.0 and g=0.01. The analytical solution for -% pencilbeam source can be computed by the cwdiffusion (for CW solution) +% mua=0.001, mus=1, n=1.0 and g=0.01. The analytical solution for +% pencilbeam source can be computed by the cwdiffusion (for CW solution) % and tddiffusion (for time-domain solutions) functions in the % package of Monte Carlo eXtreme (MCX) under the mcx/utils directory. % -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- -%addpath('/Please/add/path/to/mcx/utils/') +% addpath('/Please/add/path/to/mcx/utils/') addpath('../../matlab/'); addpath('../../mmclab/'); -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% run mmclab for the 60x60x60 homogeneous cubic domain -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- clear cfg; clear all; -planarsrc=1; % set to 1 to compare planar src, set to 0 for pencil beam -inclusion=1; % set to 1 to add an inclusion in the domain +planarsrc = 1; % set to 1 to compare planar src, set to 0 for pencil beam +inclusion = 1; % set to 1 to add an inclusion in the domain -cfg.nphoton=3e7; -cfg.seed=1648335518; -if(~inclusion) - [cfg.node,tmp,cfg.elem]=meshabox([0 0 0],[60 60 60], 2*sqrt(2), 2^3/6); - cfg.elemprop=ones(size(cfg.elem,1),1); - cfg.prop=[0 0 1 1;0.005 1.0 0.01 1.0]; +cfg.nphoton = 3e7; +cfg.seed = 1648335518; +if (~inclusion) + [cfg.node, tmp, cfg.elem] = meshabox([0 0 0], [60 60 60], 2 * sqrt(2), 2^3 / 6); + cfg.elemprop = ones(size(cfg.elem, 1), 1); + cfg.prop = [0 0 1 1; 0.005 1.0 0.01 1.0]; else - [node1,face1]=meshabox([0 0 0],[60 60 60], 2*sqrt(2), 2^3/6); - [node2,face2]=meshabox([20 20 20],[40 40 40], 2*sqrt(2), 2^3/6); - [node,face]=mergemesh(node1,face1,node2,face2); - [cfg.node,cfg.elem]=surf2mesh(node,face,[],[],1,2^3/6,[1 1 1;30 30 30],[],0); - cfg.elemprop=cfg.elem(:,5); - cfg.elem=cfg.elem(:,1:4); - cfg.prop=[0 0 1 1;0.005 1.0 0.01 1.0;0.01 0.2, 0.01 1.37]; + [node1, face1] = meshabox([0 0 0], [60 60 60], 2 * sqrt(2), 2^3 / 6); + [node2, face2] = meshabox([20 20 20], [40 40 40], 2 * sqrt(2), 2^3 / 6); + [node, face] = mergemesh(node1, face1, node2, face2); + [cfg.node, cfg.elem] = surf2mesh(node, face, [], [], 1, 2^3 / 6, [1 1 1; 30 30 30], [], 0); + cfg.elemprop = cfg.elem(:, 5); + cfg.elem = cfg.elem(:, 1:4); + cfg.prop = [0 0 1 1; 0.005 1.0 0.01 1.0; 0.01 0.2, 0.01 1.37]; end -cfg.srcpos=[30.1,30.2,0]; +cfg.srcpos = [30.1, 30.2, 0]; % cfg.srcdir=[0 0 1 -30]; % to test a diverging beam with a focus of -30 -cfg.srcdir=[0 0 1]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=1e-10; -cfg.debuglevel='TP'; -cfg.isreflect=1; -cfg.detpos=[0 30 30 2]; -cfg.method='elem'; +cfg.srcdir = [0 0 1]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 1e-10; +cfg.debuglevel = 'TP'; +cfg.isreflect = 1; +cfg.detpos = [0 30 30 2]; +cfg.method = 'elem'; % define wide-field planar source -if(planarsrc) % when planar src is used, re-tessellate the mesh - cfg.srctype='planar'; - cfg.srcpos=[10 10 -10]; - cfg.srcparam1=[40 0 0 0]; - cfg.srcparam2=[0 40 0 0]; +if (planarsrc) % when planar src is used, re-tessellate the mesh + cfg.srctype = 'planar'; + cfg.srcpos = [10 10 -10]; + cfg.srcparam1 = [40 0 0 0]; + cfg.srcparam2 = [0 40 0 0]; % the following block before "end" can be removed as mmclab % has this built-in - srcdef=struct('srctype',cfg.srctype,'srcpos',cfg.srcpos,'srcdir',cfg.srcdir,... - 'srcparam1',cfg.srcparam1,'srcparam2',cfg.srcparam2); - if(size(cfg.elem,2)==5) - cfg.elem=cfg.elem(:,1:4); + srcdef = struct('srctype', cfg.srctype, 'srcpos', cfg.srcpos, 'srcdir', cfg.srcdir, ... + 'srcparam1', cfg.srcparam1, 'srcparam2', cfg.srcparam2); + if (size(cfg.elem, 2) == 5) + cfg.elem = cfg.elem(:, 1:4); end - [cfg.node,cfg.elem] = mmcaddsrc(cfg.node,[cfg.elem cfg.elemprop],... - mmcsrcdomain(srcdef,[min(cfg.node);max(cfg.node)])); - cfg.elemprop=cfg.elem(:,5); - cfg.elem=cfg.elem(:,1:4); + [cfg.node, cfg.elem] = mmcaddsrc(cfg.node, [cfg.elem cfg.elemprop], ... + mmcsrcdomain(srcdef, [min(cfg.node); max(cfg.node)])); + cfg.elemprop = cfg.elem(:, 5); + cfg.elem = cfg.elem(:, 1:4); end -cfg=mmclab(cfg,'prep'); +cfg = mmclab(cfg, 'prep'); -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% run mmclab -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- -cube=mmclab(cfg); -%cube=mmclab(cfg,'sse'); % this is faster -cube=cube.data; +cube = mmclab(cfg); +% cube=mmclab(cfg,'sse'); % this is faster +cube = cube.data; -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% run mcxlab for the same domain -%%----------------------------------------------------------------- - -cfgx=cfg; -cfgx=rmfield(cfgx,{'node','elem','elemprop','debuglevel','facenb','evol','e0','isreoriented'}); -dim=60; -cfgx.vol=ones(dim,dim,dim); -cfgx.vol=uint8(cfgx.vol); -cfgx.faststep=0; -if(inclusion) - cfgx.vol(21:40,21:40,21:40)=2; +%% ----------------------------------------------------------------- + +cfgx = cfg; +cfgx = rmfield(cfgx, {'node', 'elem', 'elemprop', 'debuglevel', 'facenb', 'evol', 'e0', 'isreoriented'}); +dim = 60; +cfgx.vol = ones(dim, dim, dim); +cfgx.vol = uint8(cfgx.vol); +cfgx.faststep = 0; +if (inclusion) + cfgx.vol(21:40, 21:40, 21:40) = 2; end -cfgx.nphoton=numel(cfgx.vol)/size(cfg.node,1)*cfg.nphoton; % for mcx, nphoton - % needs to be bigger - % to match the noise - % of mmc -cfgx.autopilot=1; -cfgx.gpuid=1; -cfgx.issrcfrom0=1; % treating the lower-outer corner of the grid as [0 0 0] - %to match mmc - -cubex=mcxlab(cfgx); -cubex=cubex.data; - -%%----------------------------------------------------------------- +cfgx.nphoton = numel(cfgx.vol) / size(cfg.node, 1) * cfg.nphoton; % for mcx, nphoton +% needs to be bigger +% to match the noise +% of mmc +cfgx.autopilot = 1; +cfgx.gpuid = 1; +cfgx.issrcfrom0 = 1; % treating the lower-outer corner of the grid as [0 0 0] +% to match mmc + +cubex = mcxlab(cfgx); +cubex = cubex.data; + +%% ----------------------------------------------------------------- %% Make a cross-section -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- -c0=299792458000; +c0 = 299792458000; -twin=[cfg.tstart+cfg.tstep/2:cfg.tstep:cfg.tend]; -gates=length(twin); +twin = [cfg.tstart + cfg.tstep / 2:cfg.tstep:cfg.tend]; +gates = length(twin); -cwcb=sum(cube,2); -cwcbx=sum(cubex,4); +cwcb = sum(cube, 2); +cwcbx = sum(cubex, 4); -[cutpos,cutvalue,facedata]=qmeshcut(cfg.elem(:,1:4),cfg.node,cwcb,'y=30.5'); - % slice at y=30.5 to offset half - % grid to match mcx voxels +[cutpos, cutvalue, facedata] = qmeshcut(cfg.elem(:, 1:4), cfg.node, cwcb, 'y=30.5'); +% slice at y=30.5 to offset half +% grid to match mcx voxels -[xi,yi]=meshgrid(0.5:59.5,0.5:59.5); % interpolate mmc solution at - % half-grid because mcx's voxel - % readings are at the center of - % the voxels -vi=griddata(cutpos(:,1),cutpos(:,3),cutvalue,xi,yi); -vix=squeeze(cwcbx(:,30,:))'; +[xi, yi] = meshgrid(0.5:59.5, 0.5:59.5); % interpolate mmc solution at +% half-grid because mcx's voxel +% readings are at the center of +% the voxels +vi = griddata(cutpos(:, 1), cutpos(:, 3), cutvalue, xi, yi); +vix = squeeze(cwcbx(:, 30, :))'; -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% generate a contour plot along y=30.5 -%%----------------------------------------------------------------- -figure -hold on +%% ----------------------------------------------------------------- +figure; +hold on; clines = -1.5:-0.25:-8; -if(~planarsrc && ~inclusion) - srcs=[30.1,30.2,0]; - dets=[xi(:) 30.2*ones(size(xi(:))) yi(:)]; - phicw=reshape(cwdiffusion(0.005, 1.0, 0, srcs, dets),size(xi)); - contour(xi,yi, log10(max(squeeze(phicw),1e-8)), -1.5:-0.5:-4, 'k-' ); - % analytical is semi-infinite, only take the center part +if (~planarsrc && ~inclusion) + srcs = [30.1, 30.2, 0]; + dets = [xi(:) 30.2 * ones(size(xi(:))) yi(:)]; + phicw = reshape(cwdiffusion(0.005, 1.0, 0, srcs, dets), size(xi)); + contour(xi, yi, log10(max(squeeze(phicw), 1e-8)), -1.5:-0.5:-4, 'k-'); + % analytical is semi-infinite, only take the center part end -contour(xi,yi,log10(abs(vi*cfg.tstep)),clines,'r:') -contour(xi,yi,log10(abs(vix*cfg.tstep)),clines,'b--') +contour(xi, yi, log10(abs(vi * cfg.tstep)), clines, 'r:'); +contour(xi, yi, log10(abs(vix * cfg.tstep)), clines, 'b--'); -if(inclusion) - plot([20 20 40 40 20],[20 40 40 20 20],'k--'); +if (inclusion) + plot([20 20 40 40 20], [20 40 40 20 20], 'k--'); end -axis equal -set(gca,'xlim',[1 60]); -set(gca,'fontsize',20); +axis equal; +set(gca, 'xlim', [1 60]); +set(gca, 'fontsize', 20); xlabel('x (mm)'); ylabel('z (mm)'); -if(planarsrc || inclusion) - legend('MMC','MCX'); +if (planarsrc || inclusion) + legend('MMC', 'MCX'); else - legend('Diffusion','MMC','MCX'); + legend('Diffusion', 'MMC', 'MCX'); end legend boxoff; box on; diff --git a/mmclab/example/demo_dmmc_sphshells.m b/mmclab/example/demo_dmmc_sphshells.m index 8163663d..35a3e167 100644 --- a/mmclab/example/demo_dmmc_sphshells.m +++ b/mmclab/example/demo_dmmc_sphshells.m @@ -1,178 +1,178 @@ -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% validate DMMC with MMC in a heterogeneous cubic domain % (see DMMC paper Fig. 1) -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- % -% In this example, we validate the DMMC algorithm with MMC using a +% In this example, we validate the DMMC algorithm with MMC using a % heterogeneous cubic domain. We also compare the DMMC/MMC solution with % that of voxel-based MC (MCX). This simulation generates the results % shown in Fig. 1(c-e) in the paper. -% -%%----------------------------------------------------------------- +% +%% ----------------------------------------------------------------- % preparation -% 1. you need to add the path to iso2mesh toolbox +% 1. you need to add the path to iso2mesh toolbox % addpath('/path/to/iso2mesh/toolbox/'); % 2. you need to add the path to MMC matlab folder % addpath('../../matlab'); % create a surface mesh for a 10 mm radius sphere -[nsph_10,fsph_10]=meshasphere([30 30 30],10,1.0); -[nsph_10,fsph_10]=removeisolatednode(nsph_10,fsph_10); +[nsph_10, fsph_10] = meshasphere([30 30 30], 10, 1.0); +[nsph_10, fsph_10] = removeisolatednode(nsph_10, fsph_10); % create a surface mesh for a 23 mm radius sphere -[nsph_23,fsph_23]=meshasphere([30 30 30],23,2.0); -[nsph_23,fsph_23]=removeisolatednode(nsph_23,fsph_23); +[nsph_23, fsph_23] = meshasphere([30 30 30], 23, 2.0); +[nsph_23, fsph_23] = removeisolatednode(nsph_23, fsph_23); % create a surface mesh for a 25 mm radius sphere -[nsph_25,fsph_25]=meshasphere([30 30 30],25,2.0); -[nsph_25,fsph_25]=removeisolatednode(nsph_25,fsph_25); +[nsph_25, fsph_25] = meshasphere([30 30 30], 25, 2.0); +[nsph_25, fsph_25] = removeisolatednode(nsph_25, fsph_25); -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% create simulation parameters -%%----------------------------------------------------------------- -clear cfg - -cfg.nphoton=3e6; -cfg.seed=1648335518; -cfg.srcpos=[30.5,30.5,0]; -cfg.srcdir=[0 0 1]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-10; -cfg.prop=[0,0,1,1;0.02 7.0 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.0 1.37]; -cfg.debuglevel='TP'; -cfg.isreflect=1; - -cfgs=[cfg cfg]; - -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- +clear cfg; + +cfg.nphoton = 3e6; +cfg.seed = 1648335518; +cfg.srcpos = [30.5, 30.5, 0]; +cfg.srcdir = [0 0 1]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-10; +cfg.prop = [0, 0, 1, 1; 0.02 7.0 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.0 1.37]; +cfg.debuglevel = 'TP'; +cfg.isreflect = 1; + +cfgs = [cfg cfg]; + +%% ----------------------------------------------------------------- %% tetrahedral mesh generation -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- -% generate a coarse CDT volumetric mesh from triangular surfaces of +% generate a coarse CDT volumetric mesh from triangular surfaces of % three spheres with an additional bounding box for DMMC -ISO2MESH_SESSION='dmmc1_'; +ISO2MESH_SESSION = 'dmmc1_'; -[nbox,ebox]=meshgrid6(0:60:60,0:60:60,0:60:60); -fbox=volface(ebox); -[no,fc]=mergemesh(nsph_10,fsph_10,nsph_23,fsph_23,nsph_25,fsph_25,nbox,fbox); -[no,fc]=removeisolatednode(no,fc); +[nbox, ebox] = meshgrid6(0:60:60, 0:60:60, 0:60:60); +fbox = volface(ebox); +[no, fc] = mergemesh(nsph_10, fsph_10, nsph_23, fsph_23, nsph_25, fsph_25, nbox, fbox); +[no, fc] = removeisolatednode(no, fc); -ISO2MESH_TETGENOPT='-A -q -Y' -[cfgs(1).node,cfgs(1).elem]=surf2mesh(no,fc,[0 0 0],[60.1 60.1 60.1],1,100,[1 1 1;30 30 6;30 30 15;30 30 30]);%thin layer +ISO2MESH_TETGENOPT = '-A -q -Y'; +[cfgs(1).node, cfgs(1).elem] = surf2mesh(no, fc, [0 0 0], [60.1 60.1 60.1], 1, 100, [1 1 1; 30 30 6; 30 30 15; 30 30 30]); % thin layer % [cfgs(1).node,cfgs(1).elem]=surf2mesh(no,fc,[0 0 0],[60.1 60.1 60.1],1,100,[1 1 1;30 30 6;30 30 17;30 30 30]);%thick layer -cfgs(1).method='grid'; +cfgs(1).method = 'grid'; -% generate a refined volumetric mesh from triangular surfaces of +% generate a refined volumetric mesh from triangular surfaces of % three spheres with an additional bounding box for MMC -clear ISO2MESH_TETGENOPT -ISO2MESH_SESSION='dmmc2_'; +clear ISO2MESH_TETGENOPT; +ISO2MESH_SESSION = 'dmmc2_'; -[no,fc]=mergemesh(nsph_10,fsph_10,nsph_23,fsph_23,nsph_25,fsph_25); -[no,fc]=removeisolatednode(no,fc); -srcpos=[30.5 30.5 0.]; -[cfgs(2).node,cfgs(2).elem,face2]=surf2mesh(no,fc,[0 0 0],[60 60 60],1,0.25,[1 1 1 0.1;30 30 6 0.1;30 30 17 0.1;30 30 30 0.1],[],[1 1 1 1 1 1 1 1]); -[cfgs(2).node,cfgs(2).elem]=sortmesh(srcpos,cfgs(2).node,cfgs(2).elem,1:4); -cfgs(2).method='elem'; +[no, fc] = mergemesh(nsph_10, fsph_10, nsph_23, fsph_23, nsph_25, fsph_25); +[no, fc] = removeisolatednode(no, fc); +srcpos = [30.5 30.5 0.]; +[cfgs(2).node, cfgs(2).elem, face2] = surf2mesh(no, fc, [0 0 0], [60 60 60], 1, 0.25, [1 1 1 0.1; 30 30 6 0.1; 30 30 17 0.1; 30 30 30 0.1], [], [1 1 1 1 1 1 1 1]); +[cfgs(2).node, cfgs(2).elem] = sortmesh(srcpos, cfgs(2).node, cfgs(2).elem, 1:4); +cfgs(2).method = 'elem'; % % 3D view of the cross-section of the mesh: 'y>30' % figure;plotmesh(cfgs(1).node,cfgs(1).elem,'y>30');view(3); % figure;plotmesh(cfgs(2).node,cfgs(2).elem,'y>30');view(3); -phimmc=mmclab(cfgs); +phimmc = mmclab(cfgs); %% mcx clear cfg; % set seed to make the simulation repeatible -cfg.seed=hex2dec('623F9A9E'); +cfg.seed = hex2dec('623F9A9E'); -cfg.nphoton=1e8; +cfg.nphoton = 1e8; % define three spheres with radius=10 mm, 23 mm and 25 mm within a 60x60x60 mm box -dim=60; -[xi,yi,zi]=meshgrid(0.5:(dim-0.5),0.5:(dim-0.5),0.5:(dim-0.5)); -dist=(xi-30).^2+(yi-30).^2+(zi-30).^2; -cfg.vol=ones(size(xi)); -cfg.vol(dist<625)=2; -cfg.vol(dist<529)=3; -cfg.vol(dist<100)=4; -cfg.vol=uint8(cfg.vol); +dim = 60; +[xi, yi, zi] = meshgrid(0.5:(dim - 0.5), 0.5:(dim - 0.5), 0.5:(dim - 0.5)); +dist = (xi - 30).^2 + (yi - 30).^2 + (zi - 30).^2; +cfg.vol = ones(size(xi)); +cfg.vol(dist < 625) = 2; +cfg.vol(dist < 529) = 3; +cfg.vol(dist < 100) = 4; +cfg.vol = uint8(cfg.vol); % define the source position -cfg.srcpos=[30.5,30.5,0]; -cfg.srcdir=[0 0 1]; -cfg.issrcfrom0=1; +cfg.srcpos = [30.5, 30.5, 0]; +cfg.srcdir = [0 0 1]; +cfg.issrcfrom0 = 1; % format: [mua(1/mm) mus(1/mm) g n] -cfg.prop=[0,0,1,1;0.02 7.0 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.0 1.37]; +cfg.prop = [0, 0, 1, 1; 0.02 7.0 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.0 1.37]; % 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; -cfg.isreflect=1; % disable reflection at exterior boundaries -cfg.unitinmm=1; % resolution +cfg.isreflect = 1; % disable reflection at exterior boundaries +cfg.unitinmm = 1; % resolution %% running simulation with 1x1x1 mm input volume (60x60x60 grid) fprintf('running simulation ... this takes about 6 seconds on a GTX 470\n'); tic; -phimcx=mcxlab(cfg); +phimcx = mcxlab(cfg); toc; %% data visualization -%mcx -phi_mcx=sum(phimcx.data,4); -%mmc -[xx,yy]=meshgrid(0.5:59.5,0.5:59.5); -node1=cfgs(2).node; -elem1=cfgs(2).elem; -mesh0=phimmc(2).data; -s1=sum(mesh0,2); -[cutpos,cutvalue,facedata]=qmeshcut(elem1(:,1:4),node1,s1,[0 30.5 0; 0 30.5 1; 1 30.5 0]); -phi_mmc=griddata(cutpos(:,1),cutpos(:,3),cutvalue,xx,yy); -%dmmc -phi_dmmc=sum(phimmc(1).data,4); -phi_dmmc=phi_dmmc(1:60,1:60,1:60); +% mcx +phi_mcx = sum(phimcx.data, 4); +% mmc +[xx, yy] = meshgrid(0.5:59.5, 0.5:59.5); +node1 = cfgs(2).node; +elem1 = cfgs(2).elem; +mesh0 = phimmc(2).data; +s1 = sum(mesh0, 2); +[cutpos, cutvalue, facedata] = qmeshcut(elem1(:, 1:4), node1, s1, [0 30.5 0; 0 30.5 1; 1 30.5 0]); +phi_mmc = griddata(cutpos(:, 1), cutpos(:, 3), cutvalue, xx, yy); +% dmmc +phi_dmmc = sum(phimmc(1).data, 4); +phi_dmmc = phi_dmmc(1:60, 1:60, 1:60); figure; -clines=[-10:0.5:10]; -contourf(log10(abs(squeeze(phi_mmc))),clines,'linewidth',1.5); -hold on -contour(log10(abs(squeeze(phi_dmmc(:,31,:))')),clines,'linestyle','--','color','w','linewidth',1.5); -contour(log10(abs(squeeze(phi_mcx(:,31,:))')),clines,'linestyle','--','color',[0.9100 0.4100 0.1700],'linewidth',1.5); +clines = [-10:0.5:10]; +contourf(log10(abs(squeeze(phi_mmc))), clines, 'linewidth', 1.5); +hold on; +contour(log10(abs(squeeze(phi_dmmc(:, 31, :))')), clines, 'linestyle', '--', 'color', 'w', 'linewidth', 1.5); +contour(log10(abs(squeeze(phi_mcx(:, 31, :))')), clines, 'linestyle', '--', 'color', [0.9100 0.4100 0.1700], 'linewidth', 1.5); colorbar('EastOutside'); -%plot a dashed circle with radius of 10 -[xcirc,ycirc] = cylinder(10,200); -xcirc=xcirc(1,:)+30.5; -ycirc=ycirc(1,:)+30.5; -plot(xcirc,ycirc,'k--','linewidth',2); +% plot a dashed circle with radius of 10 +[xcirc, ycirc] = cylinder(10, 200); +xcirc = xcirc(1, :) + 30.5; +ycirc = ycirc(1, :) + 30.5; +plot(xcirc, ycirc, 'k--', 'linewidth', 2); -%plot a dashed circle with radius of 23 -[xcirc,ycirc] = cylinder(23,200); -xcirc=xcirc(1,:)+30.5; -ycirc=ycirc(1,:)+30.5; -plot(xcirc,ycirc,'k--','linewidth',2); +% plot a dashed circle with radius of 23 +[xcirc, ycirc] = cylinder(23, 200); +xcirc = xcirc(1, :) + 30.5; +ycirc = ycirc(1, :) + 30.5; +plot(xcirc, ycirc, 'k--', 'linewidth', 2); -%plot a dashed circle with radius of 25 -[xcirc,ycirc] = cylinder(25,200); -xcirc=xcirc(1,:)+30.5; -ycirc=ycirc(1,:)+30.5; -plot(xcirc,ycirc,'k--','linewidth',2); +% plot a dashed circle with radius of 25 +[xcirc, ycirc] = cylinder(25, 200); +xcirc = xcirc(1, :) + 30.5; +ycirc = ycirc(1, :) + 30.5; +plot(xcirc, ycirc, 'k--', 'linewidth', 2); axis equal; colormap; -lg=legend('MMC','DMMC','MCX','Location','northoutside','orientation','horizontal'); -set(lg,'Color',[0.5 0.5 0.5]); -set(lg,'box','on'); -set(gca,'fontsize',18); \ No newline at end of file +lg = legend('MMC', 'DMMC', 'MCX', 'Location', 'northoutside', 'orientation', 'horizontal'); +set(lg, 'Color', [0.5 0.5 0.5]); +set(lg, 'box', 'on'); +set(gca, 'fontsize', 18); diff --git a/mmclab/example/demo_dualmesh_output.m b/mmclab/example/demo_dualmesh_output.m index 16f1a628..c700044f 100644 --- a/mmclab/example/demo_dualmesh_output.m +++ b/mmclab/example/demo_dualmesh_output.m @@ -4,131 +4,131 @@ % preparation -% 1. you need to add the path to iso2mesh toolbox +% 1. you need to add the path to iso2mesh toolbox % addpath('/path/to/iso2mesh/toolbox/'); % 2. you need to add the path to MMC matlab folder -addpath('../../matlab') +addpath('../../matlab'); % create a surface mesh for a 10mm radius sphere -[nsph,fsph]=meshasphere([30 30 30],10,1.0); -[nsph,fsph]=removeisolatednode(nsph,fsph); +[nsph, fsph] = meshasphere([30 30 30], 10, 1.0); +[nsph, fsph] = removeisolatednode(nsph, fsph); %% create DMMC and MMC simulation parameters -clear cfg +clear cfg; -cfg.nphoton=1e7; -cfg.seed=1648335518; -cfg.srcpos=[30,30.001,0]; -cfg.srcdir=[0 0 1]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-10; -cfg.prop=[0 0 1 1;0.002 1.0 0.01 1.37;0.050 0 1 1.37]; -cfg.debuglevel='TP'; -cfg.isreflect=1; +cfg.nphoton = 1e7; +cfg.seed = 1648335518; +cfg.srcpos = [30, 30.001, 0]; +cfg.srcdir = [0 0 1]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-10; +cfg.prop = [0 0 1 1; 0.002 1.0 0.01 1.37; 0.050 0 1 1.37]; +cfg.debuglevel = 'TP'; +cfg.isreflect = 1; -cfgs=[cfg cfg]; +cfgs = [cfg cfg]; %% tetrahedral mesh generation % generate a coarse volumetric mesh from the sphere with an additional bounding box % the maximum element volume is 20 -ISO2MESH_SESSION='dmmc_'; +ISO2MESH_SESSION = 'dmmc_'; -[nbox,ebox]=meshgrid6(0:60:60,0:60:60,0:60:60); -fbox=volface(ebox); -[no,fc]=mergemesh(nbox,fbox,nsph,fsph); +[nbox, ebox] = meshgrid6(0:60:60, 0:60:60, 0:60:60); +fbox = volface(ebox); +[no, fc] = mergemesh(nbox, fbox, nsph, fsph); -ISO2MESH_TETGENOPT='-Y -A' -[cfgs(1).node,cfgs(1).elem]=surf2mesh(no,fc,[0 0 0],[60.1 60.1 60.1],1,100,[1,1,1;30 30 30]); -cfgs(1).method='grid'; +ISO2MESH_TETGENOPT = '-Y -A'; +[cfgs(1).node, cfgs(1).elem] = surf2mesh(no, fc, [0 0 0], [60.1 60.1 60.1], 1, 100, [1, 1, 1; 30 30 30]); +cfgs(1).method = 'grid'; -clear ISO2MESH_TETGENOPT -ISO2MESH_SESSION='mmc_'; +clear ISO2MESH_TETGENOPT; +ISO2MESH_SESSION = 'mmc_'; -[no,el]=meshasphere([30 30 30],10,1.0); -nodesize=[1*ones(size(no,1),1) ; 1; 1]; -srcpos=[30. 30.001 0.]; -fixednodes=[30.,30.,0.05; 30 30 30]; -nfull=[no;fixednodes]; -[cfgs(2).node,cfgs(2).elem,face2]=surf2mesh([nfull,nodesize],el,[0 0 0],[60.1 60.1 60.1],1,2,[30 30 30],[],[1 1 1 1 1 1 1 1]); -[cfgs(2).node,cfgs(2).elem]=sortmesh(srcpos,cfgs(2).node,cfgs(2).elem,1:4); -cfgs(2).elem(:,5)=cfgs(2).elem(:,5)+1; -cfgs(2).method='elem'; +[no, el] = meshasphere([30 30 30], 10, 1.0); +nodesize = [1 * ones(size(no, 1), 1); 1; 1]; +srcpos = [30. 30.001 0.]; +fixednodes = [30., 30., 0.05; 30 30 30]; +nfull = [no; fixednodes]; +[cfgs(2).node, cfgs(2).elem, face2] = surf2mesh([nfull, nodesize], el, [0 0 0], [60.1 60.1 60.1], 1, 2, [30 30 30], [], [1 1 1 1 1 1 1 1]); +[cfgs(2).node, cfgs(2).elem] = sortmesh(srcpos, cfgs(2).node, cfgs(2).elem, 1:4); +cfgs(2).elem(:, 5) = cfgs(2).elem(:, 5) + 1; +cfgs(2).method = 'elem'; %% running simulation with 1x1x1 mm input volume (60x60x60 grid) -phimmc=mmclab(cfgs); +phimmc = mmclab(cfgs); %% create MCX simulation parameters clear cfg; % 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; -[xi,yi,zi]=meshgrid(0.5:dim-0.5,0.5:dim-0.5,0.5:dim-0.5); -dist=(xi-30).^2+(yi-30).^2+(zi-30).^2; -cfg.vol=ones(size(xi)); -cfg.vol(dist<100)=2; -cfg.vol=uint8(cfg.vol); +dim = 60; +[xi, yi, zi] = meshgrid(0.5:dim - 0.5, 0.5:dim - 0.5, 0.5:dim - 0.5); +dist = (xi - 30).^2 + (yi - 30).^2 + (zi - 30).^2; +cfg.vol = ones(size(xi)); +cfg.vol(dist < 100) = 2; +cfg.vol = uint8(cfg.vol); % define the source position, same as DMMC/MMC -cfg.srcpos=[30,30.001,0]; -cfg.srcdir=[0 0 1]; -cfg.issrcfrom0=1; +cfg.srcpos = [30, 30.001, 0]; +cfg.srcdir = [0 0 1]; +cfg.issrcfrom0 = 1; % format: [mua(1/mm) mus(1/mm) g n] -cfg.prop=[0 0 1 1;0.002 1.0 0.01 1.37;0.050 0 1 1.37]; +cfg.prop = [0 0 1 1; 0.002 1.0 0.01 1.37; 0.050 0 1 1.37]; % 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; % enable reflection at exterior boundaries, same as DMMC/MMC -cfg.isreflect=1; +cfg.isreflect = 1; %% running simulation with 1x1x1 mm input volume (60x60x60 grid) fprintf('running MCX simulation ... this takes about 6 seconds on a GTX 470\n'); tic; -phimcx=mcxlab(cfg); +phimcx = mcxlab(cfg); toc; %% visualization: compare CW fluence maps produced by DMMC/MMC against that by MCX using contour lines -clines=-7:0.25:-1; -[xx,zz]=meshgrid(0.5:59.5,0.5:59.5); -node2=cfgs(2).node; -elem2=cfgs(2).elem; -flux_mmc=phimmc(2).data; -CWfluence_mmc=sum(flux_mmc,2)*cfg.tstep; -[cutpos,cutvalue,facedata]=qmeshcut(elem2(:,1:4),node2,CWfluence_mmc,[0 30.5 0; 0 30.5 1; 1 30.5 0]); - -CWfluence_mmc_grid=griddata(cutpos(:,1),cutpos(:,3),cutvalue,xx,zz); -CWfluence_dmmc=sum(phimmc(1).data,4)*cfg.tstep; -CWfluence_mcx=sum(phimcx.data,4)*cfg.tstep; +clines = -7:0.25:-1; +[xx, zz] = meshgrid(0.5:59.5, 0.5:59.5); +node2 = cfgs(2).node; +elem2 = cfgs(2).elem; +flux_mmc = phimmc(2).data; +CWfluence_mmc = sum(flux_mmc, 2) * cfg.tstep; +[cutpos, cutvalue, facedata] = qmeshcut(elem2(:, 1:4), node2, CWfluence_mmc, [0 30.5 0; 0 30.5 1; 1 30.5 0]); + +CWfluence_mmc_grid = griddata(cutpos(:, 1), cutpos(:, 3), cutvalue, xx, zz); +CWfluence_dmmc = sum(phimmc(1).data, 4) * cfg.tstep; +CWfluence_mcx = sum(phimcx.data, 4) * cfg.tstep; figure; -contourf(xx,zz,log10(abs(squeeze(CWfluence_mmc_grid))),clines); -hold on -contour(xx,zz,log10(abs(squeeze(CWfluence_dmmc(1:end-1,31,1:end-1))')),clines,'linestyle','--','color','w','linewidth',1.5); -contour(xx,zz,log10(abs(squeeze(CWfluence_mcx(:,31,:))')),clines,'linestyle','--','color',[0.9100 0.4100 0.1700],'linewidth',1.5); +contourf(xx, zz, log10(abs(squeeze(CWfluence_mmc_grid))), clines); +hold on; +contour(xx, zz, log10(abs(squeeze(CWfluence_dmmc(1:end - 1, 31, 1:end - 1))')), clines, 'linestyle', '--', 'color', 'w', 'linewidth', 1.5); +contour(xx, zz, log10(abs(squeeze(CWfluence_mcx(:, 31, :))')), clines, 'linestyle', '--', 'color', [0.9100 0.4100 0.1700], 'linewidth', 1.5); -[xcirc,ycirc] = cylinder(10,200); -xcirc=xcirc(1,:)+30; -ycirc=ycirc(1,:)+30; -plot(xcirc,ycirc,'k--','linewidth',2); +[xcirc, ycirc] = cylinder(10, 200); +xcirc = xcirc(1, :) + 30; +ycirc = ycirc(1, :) + 30; +plot(xcirc, ycirc, 'k--', 'linewidth', 2); axis equal; colormap; -set(gca,'fontsize',20); -lg=legend('MMC','DMMC','MCX'); -set(lg,'color','none'); -set(lg,'box','off'); +set(gca, 'fontsize', 20); +lg = legend('MMC', 'DMMC', 'MCX'); +set(lg, 'color', 'none'); +set(lg, 'box', 'off'); diff --git a/mmclab/example/demo_example_meshtest.m b/mmclab/example/demo_example_meshtest.m index 62bb6897..043247e8 100644 --- a/mmclab/example/demo_example_meshtest.m +++ b/mmclab/example/demo_example_meshtest.m @@ -4,7 +4,7 @@ % In this example, we validate MMCM algorithm using a sphere object % in a homogeneous cubic background. This simulation generates the results % shown in Fig. 3 in the paper. -% +% % The cubic domain has a dimension of 60x60x60 mm with optical properties % mua=0.002, mus=1, n=1.37 and g=0.01. A sphere is centered at [30 30 30]mm % with a radius of 10mm. The optical properties of the sphere is @@ -13,7 +13,7 @@ % sphdiffusionslab function in mmc/matlab/ directory (this has already % been done, the result for plane y=30 is saved in the % sphdiffsemiinf.mat file). -% +% % To validate MMCM, we generate an FE-mesh for the sphere and the cube. % Three meshes are tested: mesh0: a coarse FE mesh with only 10,000 nodes, % mesh1: a uniform dense FE mesh with 60000 nodes, and mesh2: a mesh @@ -24,212 +24,210 @@ % preparation -% 1. you need to add the path to iso2mesh toolbox +% 1. you need to add the path to iso2mesh toolbox % addpath('/path/to/iso2mesh/toolbox/'); % 2. you need to add the path to MMC matlab folder -addpath('../../matlab') - +addpath('../../matlab'); % create a surface mesh for a 10mm radius sphere -[no,el]=meshasphere([30 30 30],10,1.0); +[no, el] = meshasphere([30 30 30], 10, 1.0); -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% create the common parameters for all 3 simulations -%%----------------------------------------------------------------- -clear cfg - -cfg.nphoton=3e7; -cfg.seed=1648335518; -cfg.srcpos=[30.,30.,0]; -cfg.srcdir=[0 0 1]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=1e-10; -cfg.prop=[0 0 1 1;0.002 1.0 0.01 1.37;0.050 5.0 0.9 1.37]; -cfg.debuglevel='TP'; -cfg.isreflect=0; -cfg.method='elem'; - -cfg=[cfg cfg cfg]; - -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- +clear cfg; + +cfg.nphoton = 3e7; +cfg.seed = 1648335518; +cfg.srcpos = [30., 30., 0]; +cfg.srcdir = [0 0 1]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 1e-10; +cfg.prop = [0 0 1 1; 0.002 1.0 0.01 1.37; 0.050 5.0 0.9 1.37]; +cfg.debuglevel = 'TP'; +cfg.isreflect = 0; +cfg.method = 'elem'; + +cfg = [cfg cfg cfg]; + +%% ----------------------------------------------------------------- %% tetrahedral mesh generation -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- % generate a coarse volumetric mesh from the sphere with an additional bounding box % the maximum element volume is 20 -ISO2MESH_SESSION='mmcmesh2_'; +ISO2MESH_SESSION = 'mmcmesh2_'; -srcpos=[30. 30. 0.]; -fixednodes=[30.,30.,0.05; 30 30 30]; -nodesize=[ones(size(no,1),1) ; 0.5; 3]; -nfull=[no;fixednodes]; -[cfg(3).node,cfg(3).elem,face3]=surf2mesh([nfull,nodesize],el,[0 0 0],[60.1 60.1 60.1],1,8,[30 30 30],[],[1.5 1.5 1.5 1.5 5 5 5 5]); -[cfg(3).node,cfg(3).elem]=sortmesh(srcpos,cfg(3).node,cfg(3).elem,1:4); -cfg(3).elem(:,5)=cfg(3).elem(:,5)+1; +srcpos = [30. 30. 0.]; +fixednodes = [30., 30., 0.05; 30 30 30]; +nodesize = [ones(size(no, 1), 1); 0.5; 3]; +nfull = [no; fixednodes]; +[cfg(3).node, cfg(3).elem, face3] = surf2mesh([nfull, nodesize], el, [0 0 0], [60.1 60.1 60.1], 1, 8, [30 30 30], [], [1.5 1.5 1.5 1.5 5 5 5 5]); +[cfg(3).node, cfg(3).elem] = sortmesh(srcpos, cfg(3).node, cfg(3).elem, 1:4); +cfg(3).elem(:, 5) = cfg(3).elem(:, 5) + 1; % generate a dense volumetric mesh from the sphere with an additional bounding box % the maximum element volume is 5 -ISO2MESH_SESSION='mmcmesh1_'; +ISO2MESH_SESSION = 'mmcmesh1_'; -nodesize=[1*ones(size(no,1),1) ; 1; 1]; -[cfg(2).node,cfg(2).elem,face2]=surf2mesh([nfull,nodesize],el,[0 0 0],[60.1 60.1 60.1],1,2,[30 30 30],[],[1 1 1 1 1 1 1 1]); -[cfg(2).node,cfg(2).elem]=sortmesh(srcpos,cfg(2).node,cfg(2).elem,1:4); -cfg(2).elem(:,5)=cfg(2).elem(:,5)+1; +nodesize = [1 * ones(size(no, 1), 1); 1; 1]; +[cfg(2).node, cfg(2).elem, face2] = surf2mesh([nfull, nodesize], el, [0 0 0], [60.1 60.1 60.1], 1, 2, [30 30 30], [], [1 1 1 1 1 1 1 1]); +[cfg(2).node, cfg(2).elem] = sortmesh(srcpos, cfg(2).node, cfg(2).elem, 1:4); +cfg(2).elem(:, 5) = cfg(2).elem(:, 5) + 1; % reduce the surface node numbers to 20% -ISO2MESH_SESSION='mmcmesh0_'; +ISO2MESH_SESSION = 'mmcmesh0_'; % using the coarse spherical surface, we generate a coarse volumetric % mesh with maximum volume of 10 -nodesize=[ones(size(no,1),1); 3]; -nfull=[no; 30 30 30]; -[cfg(1).node,cfg(1).elem,face1]=surf2mesh([nfull,nodesize],el,[0 0 0],[60.1 60.1 60.1],1,10,[30 30 30],[],[2 2 2 2 5 5 5 5]); -[cfg(1).node,cfg(1).elem]=sortmesh(srcpos,cfg(1).node,cfg(1).elem,1:4); -cfg(1).elem(:,5)=cfg(1).elem(:,5)+1; - -clear ISO2MESH_SESSION +nodesize = [ones(size(no, 1), 1); 3]; +nfull = [no; 30 30 30]; +[cfg(1).node, cfg(1).elem, face1] = surf2mesh([nfull, nodesize], el, [0 0 0], [60.1 60.1 60.1], 1, 10, [30 30 30], [], [2 2 2 2 5 5 5 5]); +[cfg(1).node, cfg(1).elem] = sortmesh(srcpos, cfg(1).node, cfg(1).elem, 1:4); +cfg(1).elem(:, 5) = cfg(1).elem(:, 5) + 1; +clear ISO2MESH_SESSION; -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% running MMC simulations for all 3 cases -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- -flux=mmclab(cfg); +flux = mmclab(cfg); -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% plotting the results -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- -c0=299792458000; +c0 = 299792458000; -twin=[cfg(1).tstart+cfg(1).tstep/2:cfg(1).tstep:cfg(1).tend]; -gates=length(twin); -clines=[-1:0.5:8]-10; +twin = [cfg(1).tstart + cfg(1).tstep / 2:cfg(1).tstep:cfg(1).tend]; +gates = length(twin); +clines = [-1:0.5:8] - 10; -[xi,yi]=meshgrid(1:60,0:60); +[xi, yi] = meshgrid(1:60, 0:60); -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% 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 ../../examples/meshtest/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 ../../examples/meshtest/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; +[xcirc, ycirc] = cylinder(10, 200); +xcirc = xcirc(1, :) + 30; +ycirc = ycirc(1, :) + 30; % create the voxel-contour of the sphere for MCX -%dim=60; -%[xv,yv,zv]=meshgrid(1:dim,1:dim,1:dim); -%dist=(xv-30).^2+(yv-30).^2+(zv-30).^2; +% dim=60; +% [xv,yv,zv]=meshgrid(1:dim,1:dim,1:dim); +% dist=(xv-30).^2+(yv-30).^2+(zv-30).^2; -%vv=zeros(size(xv)); -%vv(dist<100)=1; +% vv=zeros(size(xv)); +% vv(dist<100)=1; -%c=contourc(squeeze(vv(:,30,:)),1); -%plot(c(1,2:end),c(2,2:end),'c--') +% c=contourc(squeeze(vv(:,30,:)),1); +% plot(c(1,2:end),c(2,2:end),'c--') -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% plot sphere 1 -%%----------------------------------------------------------------- -node1=cfg(1).node; -elem1=cfg(1).elem; -mesh0=flux(1).data; -s1=sum(mesh0,2)*cfg(1).tstep; -[cutpos,cutvalue,facedata]=qmeshcut(elem1(:,1:4),node1,s1,[0 30 0; 0 30 1; 1 30 0]); -%patch('Vertices',cutpos,'Faces',facedata,'FaceVertexCData',log10(cutvalue),'FaceColor','interp','linestyle','none'); -%view([0 1 0]) - -vi=griddata(cutpos(:,1),cutpos(:,3),cutvalue,xi,yi); - -figure -hold on -[cc,hc]=contour(xa+30,za+31,log10(abs(phi_ana)),clines,'color',[0.7 0.7 0.7],'linewidth',2); -contour(log10(abs(vi)),clines,'r:') -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','MMCM') +%% ----------------------------------------------------------------- +node1 = cfg(1).node; +elem1 = cfg(1).elem; +mesh0 = flux(1).data; +s1 = sum(mesh0, 2) * cfg(1).tstep; +[cutpos, cutvalue, facedata] = qmeshcut(elem1(:, 1:4), node1, s1, [0 30 0; 0 30 1; 1 30 0]); +% patch('Vertices',cutpos,'Faces',facedata,'FaceVertexCData',log10(cutvalue),'FaceColor','interp','linestyle','none'); +% view([0 1 0]) + +vi = griddata(cutpos(:, 1), cutpos(:, 3), cutvalue, xi, yi); + +figure; +hold on; +[cc, hc] = contour(xa + 30, za + 31, log10(abs(phi_ana)), clines, 'color', [0.7 0.7 0.7], 'linewidth', 2); +contour(log10(abs(vi)), clines, 'r:'); +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', 'MMCM'); legend boxoff; box on; -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% plot sphere 2 -%%----------------------------------------------------------------- - -node2=cfg(2).node; -elem2=cfg(2).elem; -mesh1=flux(2).data; -s2=sum(mesh1,2)*cfg(1).tstep; -[cutpos,cutvalue,facedata]=qmeshcut(elem2(:,1:4),node2,s2,[0 30 0; 0 30 1; 1 30 0]); -%patch('Vertices',cutpos,'Faces',facedata,'FaceVertexCData',log10(cutvalue),'FaceColor','interp','linestyle','none'); -%view([0 1 0]) -vi=griddata(cutpos(:,1),cutpos(:,3),cutvalue,xi,yi); - -figure -hold on -[cc,hc]=contour(xa+30,za+31,log10(abs(phi_ana)),clines,'color',[0.7 0.7 0.7],'linewidth',2); -contour(log10(abs(vi)),clines,'r:') -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','MMCM') +%% ----------------------------------------------------------------- + +node2 = cfg(2).node; +elem2 = cfg(2).elem; +mesh1 = flux(2).data; +s2 = sum(mesh1, 2) * cfg(1).tstep; +[cutpos, cutvalue, facedata] = qmeshcut(elem2(:, 1:4), node2, s2, [0 30 0; 0 30 1; 1 30 0]); +% patch('Vertices',cutpos,'Faces',facedata,'FaceVertexCData',log10(cutvalue),'FaceColor','interp','linestyle','none'); +% view([0 1 0]) +vi = griddata(cutpos(:, 1), cutpos(:, 3), cutvalue, xi, yi); + +figure; +hold on; +[cc, hc] = contour(xa + 30, za + 31, log10(abs(phi_ana)), clines, 'color', [0.7 0.7 0.7], 'linewidth', 2); +contour(log10(abs(vi)), clines, 'r:'); +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', 'MMCM'); legend boxoff; box on; -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% plot sphere 3 -%%----------------------------------------------------------------- - -node3=cfg(3).node; -elem3=cfg(3).elem; -mesh2=flux(3).data; -s3=sum(mesh2,2)*cfg(1).tstep; -[cutpos,cutvalue,facedata]=qmeshcut(elem3(:,1:4),node3,s3,[0 29 0; 0 29 1; 1 29 0]); - -vi=griddata(cutpos(:,1),cutpos(:,3),cutvalue,xi,yi); - -figure -%patch('Vertices',cutpos,'Faces',facedata,'FaceVertexCData',log10(cutvalue),'FaceColor','interp','linestyle','none'); -%view([0 1 0]) -hold on -[cc,hc]=contour(xa+30,za+31,log10(abs(phi_ana)),clines,'color',[0.7 0.7 0.7],'linewidth',2); -contour(log10(abs(vi)),clines,'r:') -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','MMCM') +%% ----------------------------------------------------------------- + +node3 = cfg(3).node; +elem3 = cfg(3).elem; +mesh2 = flux(3).data; +s3 = sum(mesh2, 2) * cfg(1).tstep; +[cutpos, cutvalue, facedata] = qmeshcut(elem3(:, 1:4), node3, s3, [0 29 0; 0 29 1; 1 29 0]); + +vi = griddata(cutpos(:, 1), cutpos(:, 3), cutvalue, xi, yi); + +figure; +% patch('Vertices',cutpos,'Faces',facedata,'FaceVertexCData',log10(cutvalue),'FaceColor','interp','linestyle','none'); +% view([0 1 0]) +hold on; +[cc, hc] = contour(xa + 30, za + 31, log10(abs(phi_ana)), clines, 'color', [0.7 0.7 0.7], 'linewidth', 2); +contour(log10(abs(vi)), clines, 'r:'); +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', 'MMCM'); legend boxoff; box on; diff --git a/mmclab/example/demo_example_onecube.m b/mmclab/example/demo_example_onecube.m index 61ef6199..3c03d652 100644 --- a/mmclab/example/demo_example_onecube.m +++ b/mmclab/example/demo_example_onecube.m @@ -1,6 +1,6 @@ -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% simple demonstration for debug flags -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- % % In this example, we run photon migration in a toy-problem to show % the basic steps and behaviors of the simulation code. @@ -13,34 +13,32 @@ % accumulation sites. Using a matlab script, one can visualize % the photon moving from the output of the simulation. % -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% defining mesh and input structure -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- addpath('../../matlab/'); -[cfg.node,cfg.elem]=genT6mesh(0:10:10,0:10:10,0:10:10); -cfg.elem=sortrows(cfg.elem); -cfg.elemprop=ones(size(cfg.elem,1),1); -cfg.prop=[0 0 1 1;0.005 1.0101010101 0.01 1.0]; -cfg.srcpos=[2,8,0]; -cfg.srcdir=[0 0 1]; -cfg.seed=1648335518; -cfg.nphoton=100; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-10; - -%%----------------------------------------------------------------- +[cfg.node, cfg.elem] = genT6mesh(0:10:10, 0:10:10, 0:10:10); +cfg.elem = sortrows(cfg.elem); +cfg.elemprop = ones(size(cfg.elem, 1), 1); +cfg.prop = [0 0 1 1; 0.005 1.0101010101 0.01 1.0]; +cfg.srcpos = [2, 8, 0]; +cfg.srcdir = [0 0 1]; +cfg.seed = 1648335518; +cfg.nphoton = 100; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-10; + +%% ----------------------------------------------------------------- %% run simulation and print out photon movement -%%----------------------------------------------------------------- - -cfg.debuglevel='M'; -flux=mmclab(cfg); - -cfg.debuglevel='A'; -flux=mmclab(cfg); +%% ----------------------------------------------------------------- +cfg.debuglevel = 'M'; +flux = mmclab(cfg); +cfg.debuglevel = 'A'; +flux = mmclab(cfg); diff --git a/mmclab/example/demo_example_replay.m b/mmclab/example/demo_example_replay.m index ae5ea4ef..e7ef49db 100644 --- a/mmclab/example/demo_example_replay.m +++ b/mmclab/example/demo_example_replay.m @@ -1,104 +1,104 @@ -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% demonstration of the replay feature -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- % % In this example, we run MMC using a homogeneous cubic domain, % same as in demo_example_validation.m. We save the seeds of the -% detected photons, and then rerun these photons again (i.e. +% detected photons, and then rerun these photons again (i.e. % the "replay" part). This feature allows one to identify features % that are only related to a source/detector pair. % -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- addpath('../../matlab/'); % define 1 source and 4 detectors for a uniform cube -clear cfg newcfg - -cfg.nphoton=1e6; -cfg.seed=1648335518; -[cfg.node,cfg.elem]=genT6mesh(0:2:60,0:2:60,0:2:60); -cfg.elemprop=ones(size(cfg.elem,1),1); -cfg.srcpos=[30.1,30.2,0]; -cfg.srcdir=[0 0 1]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-9; -cfg.prop=[0 0 1 1;0.005 1.0 0.01 1.0]; -cfg.debuglevel='TP'; -cfg.method='elem'; -cfg.isreflect=0; -cfg.detpos=[30. 20. 0. 1. - 30. 40. 0. 1. - 20. 30. 0. 1. - 40. 30. 0. 1.]; -cfg.issaveexit=1; % save detected photon exit position and angles -cfg.issaveseed=1; % save detected photon seeds to replay later +clear cfg newcfg; + +cfg.nphoton = 1e6; +cfg.seed = 1648335518; +[cfg.node, cfg.elem] = genT6mesh(0:2:60, 0:2:60, 0:2:60); +cfg.elemprop = ones(size(cfg.elem, 1), 1); +cfg.srcpos = [30.1, 30.2, 0]; +cfg.srcdir = [0 0 1]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-9; +cfg.prop = [0 0 1 1; 0.005 1.0 0.01 1.0]; +cfg.debuglevel = 'TP'; +cfg.method = 'elem'; +cfg.isreflect = 0; +cfg.detpos = [30. 20. 0. 1. + 30. 40. 0. 1. + 20. 30. 0. 1. + 40. 30. 0. 1.]; +cfg.issaveexit = 1; % save detected photon exit position and angles +cfg.issaveseed = 1; % save detected photon seeds to replay later % cfg.method=0; -newcfg=mmclab(cfg,'prep'); % preprocessing of the mesh to get the missing fields +newcfg = mmclab(cfg, 'prep'); % preprocessing of the mesh to get the missing fields -[cube, detp, ncfg, seeds]=mmclab(newcfg); % initial simulation +[cube, detp, ncfg, seeds] = mmclab(newcfg); % initial simulation % set up for wl replay -newcfg.replaydet=1; % replay photons detected by det#1 -newcfg.seed=seeds.data(:,detp.data(1,:)==newcfg.replaydet); -detp.ppath=detp.ppath(detp.data(1,:)==newcfg.replaydet,:); -detp.w0=detp.w0(detp.data(1,:)==newcfg.replaydet,:); -detp.data=detp.data(:,detp.data(1,:)==newcfg.replaydet); +newcfg.replaydet = 1; % replay photons detected by det#1 +newcfg.seed = seeds.data(:, detp.data(1, :) == newcfg.replaydet); +detp.ppath = detp.ppath(detp.data(1, :) == newcfg.replaydet, :); +detp.w0 = detp.w0(detp.data(1, :) == newcfg.replaydet, :); +detp.data = detp.data(:, detp.data(1, :) == newcfg.replaydet); % calculate the detected photon weight using the partial path output and prop -newcfg.replayweight=mmcdetweight(detp,newcfg.prop); -newcfg.replaytime=mmcdettime(detp,newcfg.prop); -newcfg.isnormalized=0; -newcfg.outputtype='wl'; % replay and get wl +newcfg.replayweight = mmcdetweight(detp, newcfg.prop); +newcfg.replaytime = mmcdettime(detp, newcfg.prop); +newcfg.isnormalized = 0; +newcfg.outputtype = 'wl'; % replay and get wl % now replay the detected photons -[cube2,detp2]=mmclab(newcfg); +[cube2, detp2] = mmclab(newcfg); % the two detected photon arrays should be the same. however, because % the program uses multi-threading, the orders may be different -if(all(ismember(round(detp.data'*1e10)*1e-10,round(detp2.data'*1e10)*1e-10,'rows'))) - disp('replay is successful :-)'); +if (all(ismember(round(detp.data' * 1e10) * 1e-10, round(detp2.data' * 1e10) * 1e-10, 'rows'))) + disp('replay is successful :-)'); else - disp('replay failed :-('); + disp('replay failed :-('); end % plot the Jacobian 3D profiles figure; -plotmesh([cfg.node,log10(cube2.data)],cfg.elem(:,1:4),'z=0.2','linestyle','none'); +plotmesh([cfg.node, log10(cube2.data)], cfg.elem(:, 1:4), 'z=0.2', 'linestyle', 'none'); hold on; -plotmesh([cfg.node,log10(cube2.data)],cfg.elem(:,1:4),'x=30','linestyle','none'); -view(3) -set(gca,'xlim',[0 60]) -set(gca,'ylim',[0 60]) -set(gca,'zlim',[0 60]) -shading interp +plotmesh([cfg.node, log10(cube2.data)], cfg.elem(:, 1:4), 'x=30', 'linestyle', 'none'); +view(3); +set(gca, 'xlim', [0 60]); +set(gca, 'ylim', [0 60]); +set(gca, 'zlim', [0 60]); +shading interp; % set up for wp replay -newcfg.outputtype='wp'; % replay and get wp -[cube3,detp3,~,~]=mmclab(newcfg); +newcfg.outputtype = 'wp'; % replay and get wp +[cube3, detp3, ~, ~] = mmclab(newcfg); % the two detected photon arrays should be the same. however, because % the program uses multi-threading, the orders may be different -if(all(ismember(round(detp.data'*1e10)*1e-10,round(detp3.data'*1e10)*1e-10,'rows'))) - disp('replay is successful :-)'); +if (all(ismember(round(detp.data' * 1e10) * 1e-10, round(detp3.data' * 1e10) * 1e-10, 'rows'))) + disp('replay is successful :-)'); else - disp('replay failed :-('); + disp('replay failed :-('); end % plot the Jacobian 3D profiles figure; -plotmesh([cfg.node,log10(cube3.data)],cfg.elem(:,1:4),'z=0.2','linestyle','none'); +plotmesh([cfg.node, log10(cube3.data)], cfg.elem(:, 1:4), 'z=0.2', 'linestyle', 'none'); hold on; -plotmesh([cfg.node,log10(cube3.data)],cfg.elem(:,1:4),'x=30','linestyle','none'); -view(3) -set(gca,'xlim',[0 60]) -set(gca,'ylim',[0 60]) -set(gca,'zlim',[0 60]) -shading interp \ No newline at end of file +plotmesh([cfg.node, log10(cube3.data)], cfg.elem(:, 1:4), 'x=30', 'linestyle', 'none'); +view(3); +set(gca, 'xlim', [0 60]); +set(gca, 'ylim', [0 60]); +set(gca, 'zlim', [0 60]); +shading interp; diff --git a/mmclab/example/demo_example_validation.m b/mmclab/example/demo_example_validation.m index bfaa3988..e785d774 100644 --- a/mmclab/example/demo_example_validation.m +++ b/mmclab/example/demo_example_validation.m @@ -1,7 +1,7 @@ -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% validate MMC with a homogeneous cubic domain % (see MMC paper Fig. 2) -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- % % In this example, we validate the MMCM algorithm using a homogeneous % cubic domain. This simulation generates the results @@ -13,85 +13,85 @@ % tddiffusion (for time-domain solutions) functions in the % package of Monte Carlo eXtreme (MCX) under the mcx/utils directory. % -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- -%addpath('/Please/add/path/to/mcx/utils/') +% addpath('/Please/add/path/to/mcx/utils/') addpath('../../matlab/'); -cfg.nphoton=3e6; -cfg.seed=1648335518; -[cfg.node,cfg.elem]=genT5mesh(0:2:60,0:2:60,0:2:60); -cfg.elemprop=ones(size(cfg.elem,1),1); -cfg.srcpos=[30.1,30.2,0]; -cfg.srcdir=[0 0 1]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=1e-10; -cfg.prop=[0 0 1 1;0.005 1.0 0.01 1.0]; -cfg.debuglevel='TP'; -cfg.isreflect=0; -cfg.method='elem'; - -cube=mmclab(cfg); -%cube=mmclab(cfg,'sse'); % this is faster -cube=cube.data; - -%%----------------------------------------------------------------- +cfg.nphoton = 3e6; +cfg.seed = 1648335518; +[cfg.node, cfg.elem] = genT5mesh(0:2:60, 0:2:60, 0:2:60); +cfg.elemprop = ones(size(cfg.elem, 1), 1); +cfg.srcpos = [30.1, 30.2, 0]; +cfg.srcdir = [0 0 1]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 1e-10; +cfg.prop = [0 0 1 1; 0.005 1.0 0.01 1.0]; +cfg.debuglevel = 'TP'; +cfg.isreflect = 0; +cfg.method = 'elem'; + +cube = mmclab(cfg); +% cube=mmclab(cfg,'sse'); % this is faster +cube = cube.data; + +%% ----------------------------------------------------------------- %% add paths to the necessary toolboxes -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- -c0=299792458000; +c0 = 299792458000; -twin=[cfg.tstart+cfg.tstep/2:cfg.tstep:cfg.tend]; -gates=length(twin); +twin = [cfg.tstart + cfg.tstep / 2:cfg.tstep:cfg.tend]; +gates = length(twin); -cwcb=sum(cube,2); -[cutpos,cutvalue,facedata]=qmeshcut(cfg.elem(:,1:4),cfg.node,cwcb,[0 30.2 0; 0 30.2 1; 1 30.2 0]); +cwcb = sum(cube, 2); +[cutpos, cutvalue, facedata] = qmeshcut(cfg.elem(:, 1:4), cfg.node, cwcb, [0 30.2 0; 0 30.2 1; 1 30.2 0]); -[xi,yi]=meshgrid(0:2:60,0:2:60); -vi=griddata(cutpos(:,1),cutpos(:,3),cutvalue,xi,yi); +[xi, yi] = meshgrid(0:2:60, 0:2:60); +vi = griddata(cutpos(:, 1), cutpos(:, 3), cutvalue, xi, yi); -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% plot the time-domain TPSF at [30 14 10] -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- -figure +figure; -srcpos=[30.1,30.2,0]; -detpos=[30 14 10]; +srcpos = [30.1, 30.2, 0]; +detpos = [30 14 10]; -hold on -semilogy((1:gates)/10,tddiffusion(0.005, 1, c0, 0, srcpos, detpos,twin),'r'); -idx=find(ismember(cfg.node,detpos,'rows')); -semilogy((1:gates)/10,cube(idx,:),'+'); +hold on; +semilogy((1:gates) / 10, tddiffusion(0.005, 1, c0, 0, srcpos, detpos, twin), 'r'); +idx = find(ismember(cfg.node, detpos, 'rows')); +semilogy((1:gates) / 10, cube(idx, :), '+'); -set(gca,'fontsize',20) -xlabel('t (ns)') -ylabel('Fluence TPSF (1/mm^2)') -set(gca,'yscale','log') -legend('Diffusion','MMCM') +set(gca, 'fontsize', 20); +xlabel('t (ns)'); +ylabel('Fluence TPSF (1/mm^2)'); +set(gca, 'yscale', 'log'); +legend('Diffusion', 'MMCM'); legend boxoff; box on; -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% generate a contour plot along y=30.2 -%%----------------------------------------------------------------- -figure +%% ----------------------------------------------------------------- +figure; clines = -1.5:-0.5:-8; -[xi,yi]=meshgrid(0:2:60,0:2:60); -srcs=[30.1,30.2,0]; -dets=[xi(:) 30.2*ones(size(xi(:))) yi(:)]; -phicw=reshape(cwdiffusion(0.005, 1.0, 0, srcs, dets),size(xi)); - -hold on -[c h2]=contour(xi,yi, log10(max(squeeze(phicw),1e-8)), -1.5:-0.5:-4, 'k-' ); -contour(xi,yi,log10(abs(vi*cfg.tstep)),clines,'r:') - -axis equal -set(gca,'xlim',[1 60]) -set(gca,'fontsize',20) -xlabel('x (mm)') -ylabel('z (mm)') -legend('Diffusion','MMC') +[xi, yi] = meshgrid(0:2:60, 0:2:60); +srcs = [30.1, 30.2, 0]; +dets = [xi(:) 30.2 * ones(size(xi(:))) yi(:)]; +phicw = reshape(cwdiffusion(0.005, 1.0, 0, srcs, dets), size(xi)); + +hold on; +[c h2] = contour(xi, yi, log10(max(squeeze(phicw), 1e-8)), -1.5:-0.5:-4, 'k-'); +contour(xi, yi, log10(abs(vi * cfg.tstep)), clines, 'r:'); + +axis equal; +set(gca, 'xlim', [1 60]); +set(gca, 'fontsize', 20); +xlabel('x (mm)'); +ylabel('z (mm)'); +legend('Diffusion', 'MMC'); legend boxoff; box on; diff --git a/mmclab/example/demo_head_atlas.m b/mmclab/example/demo_head_atlas.m index 30ede983..482a7391 100644 --- a/mmclab/example/demo_head_atlas.m +++ b/mmclab/example/demo_head_atlas.m @@ -1,108 +1,111 @@ -%%----------------------------------------------------------------- -% In this example, we demonstrate light transport simulation in a mesh-based -% head atlas generated from the USC 19.5-year group atlas template[Sanchez2012]). +%% ----------------------------------------------------------------- +% In this example, we demonstrate light transport simulation in a mesh-based +% head atlas generated from the USC 19.5-year group atlas template[Sanchez2012]). % -% This script is a lightweight version of the DMMC[Yan2019] simulation demo used -% for Fig.9(a) in TranYan2019(submitted). For simplicity, a coarse mesh (lower +% This script is a lightweight version of the DMMC[Yan2019] simulation demo used +% for Fig.9(a) in TranYan2019(submitted). For simplicity, a coarse mesh (lower % sampling rate) that represents part of the head(z>155) is simulated. -% +% % [Sanchez2012] C.E.Sanchez J.E.Richards and C.R.Almli, “Age-Specific MRI Templates % for Pediatric Neuroimaging,” Developmental Neuropsychology 37, 379–399 (2012). % -% [Yan2019] S.Yan, A.P.Tran, and Q.Fang, “Dual-grid mesh-based monte carlo algorithm -% for efficient photon transport simulations in complex three-dimensional media,” +% [Yan2019] S.Yan, A.P.Tran, and Q.Fang, “Dual-grid mesh-based monte carlo algorithm +% for efficient photon transport simulations in complex three-dimensional media,” % Journal of Biomedical Optics 24(2), 020503 (2019). % -% [TranYan2019] A.P.Tran, S.Yan and Q.Fang, "Improving model-based fNIRS +% [TranYan2019] A.P.Tran, S.Yan and Q.Fang, "Improving model-based fNIRS % analysis using mesh-based anatomical and light-transport models". % -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- -clc -clear +clc; +clear; load('head_atlas.mat'); %% prepare cfg for MMCLAB simulation -clear cfg -cfg.nphoton=1e7; %takes ~240s on Intel i7-8700K(12 threads) +clear cfg; +cfg.nphoton = 1e7; % takes ~240s on Intel i7-8700K(12 threads) -% medium labels:0-ambient air,1-air cavities,2-scalp,3-skull,4-csf,5-gray matter,6-white matter -cfg.node=double(node); -cfg.elem=double(elem); -cfg.elemprop=double(prop); -cfg.prop=[0,0,1,1;0,0,1,1;0.019 7.8 0.89 1.37;0.019 7.8 0.89 1.37;0.004 0.009 0.89 1.37;0.02 9.0 0.89 1.37;0.08 40.9 0.84 1.37]; +% medium labels:0-ambient air,1-air cavities,2-scalp,3-skull,4-csf,5-gray matter,6-white matter +cfg.node = double(node); +cfg.elem = double(elem); +cfg.elemprop = double(prop); +cfg.prop = [0, 0, 1, 1; 0, 0, 1, 1; 0.019 7.8 0.89 1.37; 0.019 7.8 0.89 1.37; 0.004 0.009 0.89 1.37; 0.02 9.0 0.89 1.37; 0.08 40.9 0.84 1.37]; % light source -cfg.srctype='pencil'; -cfg.srcdir=[-0.5086,-0.1822,-0.8415]; %inward-pointing source -cfg.srcpos=[133.5370,90.1988,200.0700]; %pencil beam source placed at EEG 10-5 landmark:"C4h" - cfg.srcpos=cfg.srcpos+0.001*cfg.srcdir; %ensure source is inside the mesh +cfg.srctype = 'pencil'; +cfg.srcdir = [-0.5086, -0.1822, -0.8415]; % inward-pointing source +cfg.srcpos = [133.5370, 90.1988, 200.0700]; % pencil beam source placed at EEG 10-5 landmark:"C4h" +cfg.srcpos = cfg.srcpos + 0.001 * cfg.srcdir; % ensure source is inside the mesh % 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.isreflect=1; -cfg.debuglevel='TP'; -cfg.method='grid'; %DMMC mode +cfg.isreflect = 1; +cfg.debuglevel = 'TP'; +cfg.method = 'grid'; % DMMC mode %% run mmc simulation -[flux]=mmclab(cfg); +[flux] = mmclab(cfg); %% post-simulation data processing and visualization % convert time-resolved fluence to CW fluence -CWfluence=sum(flux.data*cfg.tstep,4); +CWfluence = sum(flux.data * cfg.tstep, 4); % coronal plane selected for fluence plot -y_plane=90.5; +y_plane = 90.5; % fix spatial offset between the coordinate origins of DMMC AABB and the mesh -DMMC_AABB_origin=min(cfg.node); %spatial offset of the DMMC AABB -DMMC_voxel_origin=DMMC_AABB_origin+0.5; %centroid of the 1st voxel for DMMC AABB -DMMC_AABB_dimension=size(CWfluence); -CWfluence_DMMC=squeeze(CWfluence(:,ceil(y_plane-DMMC_AABB_origin(1,2)),:)); %along y-axis, DMMC AABB happens to have an offset very close to 3(2.9955) -[xx,zz]=meshgrid(DMMC_voxel_origin(1,1):(DMMC_voxel_origin(1,1)+DMMC_AABB_dimension(1,1)-1),DMMC_voxel_origin(1,3):(DMMC_voxel_origin(1,3)+DMMC_AABB_dimension(1,3)-1)); +DMMC_AABB_origin = min(cfg.node); % spatial offset of the DMMC AABB +DMMC_voxel_origin = DMMC_AABB_origin + 0.5; % centroid of the 1st voxel for DMMC AABB +DMMC_AABB_dimension = size(CWfluence); +CWfluence_DMMC = squeeze(CWfluence(:, ceil(y_plane - DMMC_AABB_origin(1, 2)), :)); % along y-axis, DMMC AABB happens to have an offset very close to 3(2.9955) +[xx, zz] = meshgrid(DMMC_voxel_origin(1, 1):(DMMC_voxel_origin(1, 1) + DMMC_AABB_dimension(1, 1) - 1), DMMC_voxel_origin(1, 3):(DMMC_voxel_origin(1, 3) + DMMC_AABB_dimension(1, 3) - 1)); figure; -clines=-20:0.5:0; -contourf(xx,zz,log10(abs(CWfluence_DMMC')),clines,'linestyle','--','color','w','linewidth',1.5,'DisplayName','DMMC'); -hold on;axis equal; +clines = -20:0.5:0; +contourf(xx, zz, log10(abs(CWfluence_DMMC')), clines, 'linestyle', '--', 'color', 'w', 'linewidth', 1.5, 'DisplayName', 'DMMC'); +hold on; +axis equal; colorbar('EastOutside'); % plot tissue boundaries, auxiliary functions are part of iso2mesh(http://iso2mesh.sf.net) -plane=[0 y_plane 0; 0 y_plane 1; 1 y_plane 0]; -label=unique(prop); -face=[]; -for i=1:2:size(label,1) - newface=volface(cfg.elem(prop==label(i),:)); - face=[face;newface]; +plane = [0 y_plane 0; 0 y_plane 1; 1 y_plane 0]; +label = unique(prop); +face = []; +for i = 1:2:size(label, 1) + newface = volface(cfg.elem(prop == label(i), :)); + face = [face; newface]; end -[cutpos,cutvalue,cutedges]=qmeshcut(face(:,1:3),node,node(:,1),plane); -[cutpos,cutedges]=removedupnodes(cutpos,cutedges); -cutloop=extractloops(cutedges); -[nanidx]=find(isnan(cutloop)); +[cutpos, cutvalue, cutedges] = qmeshcut(face(:, 1:3), node, node(:, 1), plane); +[cutpos, cutedges] = removedupnodes(cutpos, cutedges); +cutloop = extractloops(cutedges); +[nanidx] = find(isnan(cutloop)); -for i=1:size(nanidx,2) - if(i==9) - continue; +for i = 1:size(nanidx, 2) + if (i == 9) + continue end - if(i==1) - plot(cutpos(cutloop(1:(nanidx(i)-1)),1),cutpos(cutloop(1:(nanidx(i)-1)),3),'linestyle','--','color','k','LineWidth',1.25,'HandleVisibility','off'); - elseif(i==2) - plot(cutpos(cutloop((nanidx(i-1)+1):(nanidx(i)-1)),1),cutpos(cutloop((nanidx(i-1)+1):(nanidx(i)-1)),3),'linestyle','--','color','k','LineWidth',1.25,'HandleVisibility','off'); + if (i == 1) + plot(cutpos(cutloop(1:(nanidx(i) - 1)), 1), cutpos(cutloop(1:(nanidx(i) - 1)), 3), 'linestyle', '--', 'color', 'k', 'LineWidth', 1.25, 'HandleVisibility', 'off'); + elseif (i == 2) + plot(cutpos(cutloop((nanidx(i - 1) + 1):(nanidx(i) - 1)), 1), cutpos(cutloop((nanidx(i - 1) + 1):(nanidx(i) - 1)), 3), 'linestyle', '--', 'color', 'k', 'LineWidth', 1.25, 'HandleVisibility', 'off'); else - plot(cutpos(cutloop((nanidx(i-1)+1):(nanidx(i)-1)),1),cutpos(cutloop((nanidx(i-1)+1):(nanidx(i)-1)),3),'linestyle','--','color','k','LineWidth',1.25,'HandleVisibility','off'); + plot(cutpos(cutloop((nanidx(i - 1) + 1):(nanidx(i) - 1)), 1), cutpos(cutloop((nanidx(i - 1) + 1):(nanidx(i) - 1)), 3), 'linestyle', '--', 'color', 'k', 'LineWidth', 1.25, 'HandleVisibility', 'off'); end end % plot source, legend, etc. -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'); \ No newline at end of file +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/mmclab/example/demo_immc_basic.m b/mmclab/example/demo_immc_basic.m index a6539d57..5fa8b87b 100644 --- a/mmclab/example/demo_immc_basic.m +++ b/mmclab/example/demo_immc_basic.m @@ -2,7 +2,7 @@ % same as three benchmarks in the paper: https://doi.org/10.1364/BOE.411898 % % For iMMC, you need to edit cfg.elem and cfg.node. Extra data is needed to -% run iMMC. The data formats of cfg.elem and cfg.node for iMMC are shown +% run iMMC. The data formats of cfg.elem and cfg.node for iMMC are shown % below: %% edge-based iMMC (e-iMMC) % @@ -22,110 +22,110 @@ %% add path % 1. you need to add the path to iso2mesh toolbox if not already -%addpath('/path/to/iso2mesh/toolbox/'); +% addpath('/path/to/iso2mesh/toolbox/'); % 2. you need to add the path to MMC matlab folder -addpath('../../matlab') +addpath('../../matlab'); %% edge-based iMMC, benchmark B1 % (a) generate bounding box and insert edge -[nbox,ebox]=meshgrid6(0:1,0:1,0:1); -fbox=volface(ebox); -EPS=0.001; -nbox=[nbox; [1-EPS 0.5 0.5]; [EPS 0.5 0.5]]; % insert new nodes (node 9 and 10) -fbox=[fbox; [9 9 10]]; % insert new edge coneected by node 9 and 10 +[nbox, ebox] = meshgrid6(0:1, 0:1, 0:1); +fbox = volface(ebox); +EPS = 0.001; +nbox = [nbox; [1 - EPS 0.5 0.5]; [EPS 0.5 0.5]]; % insert new nodes (node 9 and 10) +fbox = [fbox; [9 9 10]]; % insert new edge coneected by node 9 and 10 clear cfg0 cfg; -cfg0.nphoton=1e6; -cfg0.srcpos=[0.5 0.5 1]; -cfg0.srcdir=[0 0 -1]; -cfg0.prop=[0 0 1 1;0.0458 35.6541 0.9000 1.3700; 23.0543 9.3985 0.9000 1.3700]; -cfg0.tstart=0; -cfg0.tend=5e-9; -cfg0.tstep=5e-9; -cfg0.debuglevel='TP'; -cfg0.method='grid'; -cfg0.steps=[0.01 0.01 0.01]; -cfg0.isreflect=1; -cfg0.gpuid=-1; - - -cfg=cfg0; +cfg0.nphoton = 1e6; +cfg0.srcpos = [0.5 0.5 1]; +cfg0.srcdir = [0 0 -1]; +cfg0.prop = [0 0 1 1; 0.0458 35.6541 0.9000 1.3700; 23.0543 9.3985 0.9000 1.3700]; +cfg0.tstart = 0; +cfg0.tend = 5e-9; +cfg0.tstep = 5e-9; +cfg0.debuglevel = 'TP'; +cfg0.method = 'grid'; +cfg0.steps = [0.01 0.01 0.01]; +cfg0.isreflect = 1; +cfg0.gpuid = -1; + +cfg = cfg0; % (b) generate mesh -[cfg.node,cfg.elem]=s2m(nbox,num2cell(fbox,2),1,100,'tetgen1.5',[],[],'-YY'); -cfg.elemprop=ones(size(cfg.elem,1),1); +[cfg.node, cfg.elem] = s2m(nbox, num2cell(fbox, 2), 1, 100, 'tetgen1.5', [], [], '-YY'); +cfg.elemprop = ones(size(cfg.elem, 1), 1); % (c) label the edge that has node 9 and 10 and add radii % find all elements that contains special edge between nodes 9-10 -edgeid=reshape(ismember(sort(meshedge(cfg.elem),2),[9 10],'rows'),[size(cfg.elem,1),6]); +edgeid = reshape(ismember(sort(meshedge(cfg.elem), 2), [9 10], 'rows'), [size(cfg.elem, 1), 6]); % create the edgeroi input - every appearance of that edge, we define its radius -cfg.edgeroi=zeros(size(cfg.elem,1),6); -cfg.edgeroi(edgeid)=0.1; - -cfg.noderoi=zeros(size(cfg.node,1),1); -cfg.noderoi(9)=0.1; +cfg.edgeroi = zeros(size(cfg.elem, 1), 6); +cfg.edgeroi(edgeid) = 0.1; +cfg.noderoi = zeros(size(cfg.node, 1), 1); +cfg.noderoi(9) = 0.1; % run edge-based iMMC -flux_eimmc=mmclab(cfg); +flux_eimmc = mmclab(cfg); %% node-based iMMC, benchmark B2 % (a) generate bounding box and insert edge -[nbox,ebox]=meshgrid6(0:1,0:1,0:1); -fbox=volface(ebox); -nbox=[nbox; [0.5 0.5 0.5]]; % insert new nodes (node 9) +[nbox, ebox] = meshgrid6(0:1, 0:1, 0:1); +fbox = volface(ebox); +nbox = [nbox; [0.5 0.5 0.5]]; % insert new nodes (node 9) -cfg=cfg0; +cfg = cfg0; % (b) generate mesh -[cfg.node,cfg.elem]=s2m(nbox,num2cell(fbox,2),1,100,'tetgen1.5',[],[],'-YY'); -cfg.elemprop=ones(size(cfg.elem,1),1); +[cfg.node, cfg.elem] = s2m(nbox, num2cell(fbox, 2), 1, 100, 'tetgen1.5', [], [], '-YY'); +cfg.elemprop = ones(size(cfg.elem, 1), 1); % (c) label the edge that has node 9 and 10 and add radii -cfg.noderoi=zeros(size(cfg.node,1),1); -cfg.noderoi(9)=0.1; +cfg.noderoi = zeros(size(cfg.node, 1), 1); +cfg.noderoi(9) = 0.1; % run node-based iMMC -flux_nimmc=mmclab(cfg); - +flux_nimmc = mmclab(cfg); %% face-based iMMC, benchmark B3 -cfg=cfg0; +cfg = cfg0; % (a) generate bounding box and insert edge -[cfg.node,cfg.elem]=meshgrid6(0:1,0:1,0:1); -cfg.elemprop=ones(size(cfg.elem,1),1); +[cfg.node, cfg.elem] = meshgrid6(0:1, 0:1, 0:1); +cfg.elemprop = ones(size(cfg.elem, 1), 1); % generate all triangular faces, label the top two triangles at z=1 as % faceroi and define a h=0.1mm thin-membrane -facelist=nchoosek(1:4,3); -allfaces=[]; -for i=1:length(facelist) - allfaces=[allfaces;cfg.elem(:,facelist(i,:))]; +facelist = nchoosek(1:4, 3); +allfaces = []; +for i = 1:length(facelist) + allfaces = [allfaces; cfg.elem(:, facelist(i, :))]; end % sum(allfaces>4,2)==3 gives the triangles that are made of nodes 5/6/7/8 -cfg.faceroi=reshape(double(sum(allfaces>4,2)==3), size(cfg.elem,1),size(facelist,1)); -cfg.faceroi(cfg.faceroi>0)=0.1; +cfg.faceroi = reshape(double(sum(allfaces > 4, 2) == 3), size(cfg.elem, 1), size(facelist, 1)); +cfg.faceroi(cfg.faceroi > 0) = 0.1; % run node-based iMMC -flux_fimmc=mmclab(cfg); +flux_fimmc = mmclab(cfg); %% plot the results -figure, -subplot(131) -imagesc(log10(rot90(squeeze(flux_eimmc.data(50,1:100,1:100))))) -title('edge-iMMC');axis equal -subplot(132) -imagesc(log10(rot90(squeeze(flux_nimmc.data(50,1:100,1:100))))) -title('node-iMMC');axis equal -subplot(133) -imagesc(log10(rot90(squeeze(abs(flux_fimmc.data(50,1:100,1:100)))))) -title('face-iMMC');axis equal +figure; +subplot(131); +imagesc(log10(rot90(squeeze(flux_eimmc.data(50, 1:100, 1:100))))); +title('edge-iMMC'); +axis equal; +subplot(132); +imagesc(log10(rot90(squeeze(flux_nimmc.data(50, 1:100, 1:100))))); +title('node-iMMC'); +axis equal; +subplot(133); +imagesc(log10(rot90(squeeze(abs(flux_fimmc.data(50, 1:100, 1:100)))))); +title('face-iMMC'); +axis equal; diff --git a/mmclab/example/demo_immc_vessel.m b/mmclab/example/demo_immc_vessel.m index 7d71f907..baf7ba80 100644 --- a/mmclab/example/demo_immc_vessel.m +++ b/mmclab/example/demo_immc_vessel.m @@ -1,4 +1,4 @@ -function [cfg, flux]=demo_immc_vessel(cfg) +function [cfg, flux] = demo_immc_vessel(cfg) % This example shows how to run e-iMMC on a vessel network %% load vessel data @@ -8,105 +8,105 @@ % nbox: nodes of bounding box % fbox: faces of bounding box -%addpath('/path/to/iso2mesh/toolbox/'); +% addpath('/path/to/iso2mesh/toolbox/'); -if(nargin==0) +if (nargin == 0) - vs=load('vessel.mat'); + vs = load('vessel.mat'); - edge=vs.edge; % vessel edges - fbox=vs.fbox; % bounding box faces - nbox=vs.nbox; % bounding box nodes - node=vs.node; % nodes on the vessel network - noder=vs.noder; % nodal radius of each node + edge = vs.edge; % vessel edges + fbox = vs.fbox; % bounding box faces + nbox = vs.nbox; % bounding box nodes + node = vs.node; % nodes on the vessel network + noder = vs.noder; % nodal radius of each node clear vs; %% 1. Mesh generation % (a) add the bounding box (nbox and fbox) into node and face - offset=size(nbox,1); - edge=edge+offset; % change the node index after inserting bounding box - noder=[zeros(offset,1); noder]; % add offset into noder - node=[nbox; node]; % add nodes of bounding box into node - fedge=[edge(:,1) edge]; % convert edge to face for mesh generation - face=[fbox; fedge]; % add faces of bounding box into face + offset = size(nbox, 1); + edge = edge + offset; % change the node index after inserting bounding box + noder = [zeros(offset, 1); noder]; % add offset into noder + node = [nbox; node]; % add nodes of bounding box into node + fedge = [edge(:, 1) edge]; % convert edge to face for mesh generation + face = [fbox; fedge]; % add faces of bounding box into face % (b) generate .poly file % vnode, velem: nodes and elements for generated mesh - [vnode, velem]=s2m(node,num2cell(face,2),1,100,'tetgen1.5',[],[],'-YY'); + [vnode, velem] = s2m(node, num2cell(face, 2), 1, 100, 'tetgen1.5', [], [], '-YY'); %% 2. Create edgeroi % (a) get mapping from edge to radius (you can build your own e2r) - e2r=edge2radius(edge,noder); + e2r = edge2radius(edge, noder); % (b) get edgeroi - [vnode,velem,eroi]=edgeroi(vnode,velem,e2r); + [vnode, velem, eroi] = edgeroi(vnode, velem, e2r); %% 3. Run mmc - res=0.001; % resolution: 0.001mm - cfg.nphoton=1e6; - cfg.srctype='pencil'; - cfg.srcpos=[150.5 150.5 605]*res; - cfg.srcdir=[0 0 -1]; - cfg.elemprop=ones(size(velem,1),1); - cfg.prop=[0 0 1 1; - 0.0458 35.6541 0.9000 1.3700; % dermis - 23.0543 9.3985 0.9000 1.3700]; % blood - cfg.tstart=0; - cfg.tend=5e-9; - cfg.tstep=5e-9; - cfg.debuglevel='TP'; - cfg.method='grid'; - cfg.steps=[0.001 0.001 0.001]; - cfg.gpuid=-1; - cfg.isreflect=1; - cfg.outputtype='energy'; - - cfg.elem=velem; - cfg.node=vnode*res; - cfg.edgeroi=eroi*res; - cfg.noderoi=zeros(size(vnode,1),1); - cfg.noderoi(1:size(noder,1))=noder*res; + res = 0.001; % resolution: 0.001mm + cfg.nphoton = 1e6; + cfg.srctype = 'pencil'; + cfg.srcpos = [150.5 150.5 605] * res; + cfg.srcdir = [0 0 -1]; + cfg.elemprop = ones(size(velem, 1), 1); + cfg.prop = [0 0 1 1 + 0.0458 35.6541 0.9000 1.3700 % dermis + 23.0543 9.3985 0.9000 1.3700]; % blood + cfg.tstart = 0; + cfg.tend = 5e-9; + cfg.tstep = 5e-9; + cfg.debuglevel = 'TP'; + cfg.method = 'grid'; + cfg.steps = [0.001 0.001 0.001]; + cfg.gpuid = -1; + cfg.isreflect = 1; + cfg.outputtype = 'energy'; + + cfg.elem = velem; + cfg.node = vnode * res; + cfg.edgeroi = eroi * res; + cfg.noderoi = zeros(size(vnode, 1), 1); + cfg.noderoi(1:size(noder, 1)) = noder * res; end -tic -flux=mmclab(cfg); -toc +tic; +flux = mmclab(cfg); +toc; %% plotting -figure,imagesc(log10(rot90(squeeze(flux.data(:,150,:))))) +figure; +imagesc(log10(rot90(squeeze(flux.data(:, 150, :))))); axis equal; title('energy deposition map'); - %% function: get vessel radii -function e2r = edge2radius(edge,noder) +function e2r = edge2radius(edge, noder) % vr = vesselradii(edge,noder) -% +% % get the radii for the input edges (vessels) -% +% % input: % edge: ne x 2 array. ne is the total number of edges. 2 columns represent % the indices of nodes connecting the edges -% noder: nr x 1 array storing the radius of each node. nr is the total +% noder: nr x 1 array storing the radius of each node. nr is the total % number of nodes % output: % vr: ne x 1 array storing the radius of each edge -e2r=java.util.HashMap; % set storing all vessel edges -edge=sort(edge,2); -for i=1:size(edge,1) - vr=max([noder(edge(i,1)),noder(edge(i,2))]); - e2r.put(num2str(edge(i,:)),vr); +e2r = java.util.HashMap; % set storing all vessel edges +edge = sort(edge, 2); +for i = 1:size(edge, 1) + vr = max([noder(edge(i, 1)), noder(edge(i, 2))]); + e2r.put(num2str(edge(i, :)), vr); end %% function: get edgeroi -function [node,elem,eroi]=edgeroi(node,elem,e2r) -% +function [node, elem, eroi] = edgeroi(node, elem, e2r) +% % build the edgeroi for iMMC -% +% % input: % node: node coordinates for elem % elem: input mesh containing the edges @@ -117,75 +117,75 @@ % To build the mapping, you should do % e2r.put(num2str(edge),radius) % output: -% eroi: ne x 6 array, storing the cylindrial edge-roi radii in the -% nchoosek order [(1,2),(1,3),(1,4),(2,3),(2,4),(3,4)]. +% eroi: ne x 6 array, storing the cylindrial edge-roi radii in the +% nchoosek order [(1,2),(1,3),(1,4),(2,3),(2,4),(3,4)]. % A 0 indicates no ROI. Up to 2 edges are supported -eo=[1 2; 1 3; 1 4; 2 3; 2 4; 3 4]; % edge order in an element -eroi = zeros(size(elem,1),6); +eo = [1 2; 1 3; 1 4; 2 3; 2 4; 3 4]; % edge order in an element +eroi = zeros(size(elem, 1), 6); -i=1; -while i<=size(elem,1) +i = 1; +while i <= size(elem, 1) enum = 0; % number of edges being labeled - for j=1:6 - edge=sort([elem(i,eo(j,1)) elem(i,eo(j,2))]); + for j = 1:6 + edge = sort([elem(i, eo(j, 1)) elem(i, eo(j, 2))]); if e2r.containsKey(num2str(edge)) - eroi(i,j)=e2r.get(num2str(edge)); - enum=enum+1; + eroi(i, j) = e2r.get(num2str(edge)); + enum = enum + 1; end end - - if enum>2 - % if there are more than 2 labeled edges,split and relabel the + + if enum > 2 + % if there are more than 2 labeled edges,split and relabel the % current element - [node,elem,eroi]=splitelem(node,elem,eroi,e2r,i); - i=i+3; % replace the old element with four new elements + [node, elem, eroi] = splitelem(node, elem, eroi, e2r, i); + i = i + 3; % replace the old element with four new elements end - - i=i+1; + + i = i + 1; end %% function -function [node,elem,eroi]=splitelem(node,elem,eroi,e2r,index) -% +function [node, elem, eroi] = splitelem(node, elem, eroi, e2r, index) +% % split the element that has over 2 labeled edges -% +% % input: % node: node coordinates for elem % elem: input mesh containing the edges % eroi: input data for cfg.edgeroi % e2r: java.util.HashMap mapping edge to its radius % index: index of element that needs to be split -% +% % output: % elem: mesh after spliting -eo=[1 2; 1 3; 1 4; 2 3; 2 4; 3 4]; % edge order in an element -fo=[1 2 3; 1 2 4; 1 3 4; 2 3 4]; % face order in an element - -selem=elem(index,:); % element to be split -c=meshcentroid(node,selem); % centroid of the element to be split -cindex=size(node,1)+1; -node=[node; c]; % put the centroid in the end - -newelem=[]; % 4 elements that have been split using centroid -newroi=[]; % new edge roi -for i=1:size(fo,1) - e=[selem(fo(i,1)) selem(fo(i,2)) selem(fo(i,3)) cindex]; - newelem=[newelem; e]; - - r=zeros(1,size(eo,1)); +eo = [1 2; 1 3; 1 4; 2 3; 2 4; 3 4]; % edge order in an element +fo = [1 2 3; 1 2 4; 1 3 4; 2 3 4]; % face order in an element + +selem = elem(index, :); % element to be split +c = meshcentroid(node, selem); % centroid of the element to be split +cindex = size(node, 1) + 1; +node = [node; c]; % put the centroid in the end + +newelem = []; % 4 elements that have been split using centroid +newroi = []; % new edge roi +for i = 1:size(fo, 1) + e = [selem(fo(i, 1)) selem(fo(i, 2)) selem(fo(i, 3)) cindex]; + newelem = [newelem; e]; + + r = zeros(1, size(eo, 1)); % check the edge that has radius and fill it in edgeroi - for j=1:size(eo,1) - edge=sort([e(eo(j,1)),e(eo(j,2))]); + for j = 1:size(eo, 1) + edge = sort([e(eo(j, 1)), e(eo(j, 2))]); if e2r.containsKey(num2str(edge)) - r(j)=e2r.get(num2str(edge)); + r(j) = e2r.get(num2str(edge)); end end - newroi=[newroi; r]; + newroi = [newroi; r]; end % remove the old element and insert the new elements -elem=[elem(1:index-1,:); newelem; elem(index+1:end,:)]; +elem = [elem(1:index - 1, :); newelem; elem(index + 1:end, :)]; % remove the old roi and insert the new rois -eroi=[eroi(1:index-1,:); newroi; eroi(index+1:end,:)]; \ No newline at end of file +eroi = [eroi(1:index - 1, :); newroi; eroi(index + 1:end, :)]; diff --git a/mmclab/example/demo_mcxyz_skinvessel.m b/mmclab/example/demo_mcxyz_skinvessel.m index 66f2291b..2ff18e77 100644 --- a/mmclab/example/demo_mcxyz_skinvessel.m +++ b/mmclab/example/demo_mcxyz_skinvessel.m @@ -6,90 +6,89 @@ % higher absorption (~42%) with boundaryflag=2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -clear cfg flux +clear cfg flux; %% create the skin-vessel benchmark mesh -[no,fc]=latticegrid([0 200],[0 200],[20 32 200]); % create a 3-layer tissue -no(end,:)=no(end,:)+1e-5; +[no, fc] = latticegrid([0 200], [0 200], [20 32 200]); % create a 3-layer tissue +no(end, :) = no(end, :) + 1e-5; -fc2=cell2mat(fc); -fc=[fc2(:,[1 2 3]); fc2(:,[1 3 4])]; +fc2 = cell2mat(fc); +fc = [fc2(:, [1 2 3]); fc2(:, [1 3 4])]; -[ncy,fcy]=meshacylinder([-1,99.5,99.5],[201,99.5,99.5],20,5); % add the vessel -[newnode,newelem]=surfboolean(no,fc,'first',ncy,fcy); % merge the two domains +[ncy, fcy] = meshacylinder([-1, 99.5, 99.5], [201, 99.5, 99.5], 20, 5); % add the vessel +[newnode, newelem] = surfboolean(no, fc, 'first', ncy, fcy); % merge the two domains -c0=[10,100,150,26]'; -seeds=[ones(4,2)*100, c0]; % define the regions by index +c0 = [10, 100, 150, 26]'; +seeds = [ones(4, 2) * 100, c0]; % define the regions by index -%ISO2MESH_TETGENOPT='-Y -A' -[cfg.node,cfg.elem]=s2m(newnode,newelem(:,1:3),1,30,'tetgen',seeds,[]); % creating the merged mesh domain +% ISO2MESH_TETGENOPT='-Y -A' +[cfg.node, cfg.elem] = s2m(newnode, newelem(:, 1:3), 1, 30, 'tetgen', seeds, []); % creating the merged mesh domain -cfg.unitinmm=0.005; -cfg.method='elem'; +cfg.unitinmm = 0.005; +cfg.method = 'elem'; figure; subplot(121); -plotmesh(cfg.node,cfg.elem); +plotmesh(cfg.node, cfg.elem); -cfg.elemprop=cfg.elem(:,5); -cfg.elem=cfg.elem(:,1:4); +cfg.elemprop = cfg.elem(:, 5); +cfg.elem = cfg.elem(:, 1:4); %% define other properties -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.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.srcpos=[100 100 -1]; -cfg.srcdir=[0 0 1]; +cfg.srcpos = [100 100 -1]; +cfg.srcdir = [0 0 1]; -cfg.tstart=0; -cfg.tend=5e-8; -cfg.tstep=5e-8; +cfg.tstart = 0; +cfg.tend = 5e-8; +cfg.tstep = 5e-8; % cfg.outputtype='energy'; %energy deposition in mmc varys with elem volume -cfg.outputtype='flux'; -cfg.minenergy=0.01; +cfg.outputtype = 'flux'; +cfg.minenergy = 0.01; -cfg.srctype='disk'; -cfg.srcparam1=[0.3 0 0 0]/cfg.unitinmm; % in grid unit +cfg.srctype = 'disk'; +cfg.srcparam1 = [0.3 0 0 0] / cfg.unitinmm; % in grid unit %% define wide-field disk source by extending the mesh to the widefield src -srcdef=struct('srctype',cfg.srctype,'srcpos',cfg.srcpos,'srcdir',cfg.srcdir,... - 'srcparam1',cfg.srcparam1,'srcparam2',[]); +srcdef = struct('srctype', cfg.srctype, 'srcpos', cfg.srcpos, 'srcdir', cfg.srcdir, ... + 'srcparam1', cfg.srcparam1, 'srcparam2', []); -[cfg.node,cfg.elem] = mmcaddsrc(cfg.node,[cfg.elem cfg.elemprop],... - mmcsrcdomain(srcdef,[min(cfg.node);max(cfg.node)])); +[cfg.node, cfg.elem] = mmcaddsrc(cfg.node, [cfg.elem cfg.elemprop], ... + mmcsrcdomain(srcdef, [min(cfg.node); max(cfg.node)])); - -cfg.elemprop=cfg.elem(:,5); -cfg.elem=cfg.elem(:,1:4); +cfg.elemprop = cfg.elem(:, 5); +cfg.elem = cfg.elem(:, 1:4); %% other simulation information -cfg.nphoton=1e7; -cfg.seed=1648335518; +cfg.nphoton = 1e7; +cfg.seed = 1648335518; -cfg.debuglevel='TP'; -cfg.isreflect=0; +cfg.debuglevel = 'TP'; +cfg.isreflect = 0; %% mmc simulation -flux=mmclab(cfg); -flux=flux.data; -fluxcw=sum(flux,2)*cfg.tstep*100; % multiplying 100 converts 1/mm^2 to 1/cm^2 to match mcxyz output +flux = mmclab(cfg); +flux = flux.data; +fluxcw = sum(flux, 2) * cfg.tstep * 100; % multiplying 100 converts 1/mm^2 to 1/cm^2 to match mcxyz output %% plot simulated photon profiles subplot(122); hold on; -qmeshcut(cfg.elem(cfg.elemprop>0,1:4),cfg.node*cfg.unitinmm,log10(fluxcw),'x=0.5','linestyle','none'); +qmeshcut(cfg.elem(cfg.elemprop > 0, 1:4), cfg.node * cfg.unitinmm, log10(fluxcw), 'x=0.5', 'linestyle', 'none'); view([1 0 0]); -set(gca,'zlim',[0 1],'ylim',[0 1],'zdir','reverse') +set(gca, 'zlim', [0 1], 'ylim', [0 1], 'zdir', 'reverse'); box on; -axis equal -title('MMC fluence rate (W/cm^2) per W simulated') +axis equal; +title('MMC fluence rate (W/cm^2) per W simulated'); colorbar; -colormap(jet) +colormap(jet); diff --git a/mmclab/example/demo_mmcl_b1_b1d.m b/mmclab/example/demo_mmcl_b1_b1d.m index 176adebb..26e5c3a1 100644 --- a/mmclab/example/demo_mmcl_b1_b1d.m +++ b/mmclab/example/demo_mmcl_b1_b1d.m @@ -1,7 +1,7 @@ -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% validate MMC with a homogeneous cubic domain % (see MMC paper Fig. 2 and MMCL paper Fig. 1a) -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- % % In this example, we validate the MMCM algorithm using a homogeneous % cubic domain. This simulation generates the results @@ -13,95 +13,93 @@ % tddiffusion (for time-domain solutions) functions in the % package of Monte Carlo eXtreme (MCX) under the mcx/utils directory. % -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- -%addpath('/Please/add/path/to/mcx/utils/') +% addpath('/Please/add/path/to/mcx/utils/') addpath('../../matlab/'); -clear cfg -cfg.nphoton=1e6; -cfg.seed=1648335518; -[cfg.node,cfg.elem]=genT5mesh(0:2:60,0:2:60,0:2:60); -cfg.elemprop=ones(size(cfg.elem,1),1); -cfg.srcpos=[30.1,30.2,0]; -cfg.srcdir=[0 0 1]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=1e-10; -cfg.prop=[0 0 1 1;0.005 1.0 0.01 1.0]; -cfg.debuglevel='TP'; -cfg.isreflect=0; -cfg.method='elem'; - -cfg.gpuid=1; - -b1gpu=mmclab(cfg); -b1gpu=sum(b1gpu.data,2); +clear cfg; +cfg.nphoton = 1e6; +cfg.seed = 1648335518; +[cfg.node, cfg.elem] = genT5mesh(0:2:60, 0:2:60, 0:2:60); +cfg.elemprop = ones(size(cfg.elem, 1), 1); +cfg.srcpos = [30.1, 30.2, 0]; +cfg.srcdir = [0 0 1]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 1e-10; +cfg.prop = [0 0 1 1; 0.005 1.0 0.01 1.0]; +cfg.debuglevel = 'TP'; +cfg.isreflect = 0; +cfg.method = 'elem'; + +cfg.gpuid = 1; + +b1gpu = mmclab(cfg); +b1gpu = sum(b1gpu.data, 2); %% -cfg.gpuid=-1; +cfg.gpuid = -1; -b1cpu=mmclab(cfg); -b1cpu=sum(b1cpu.data,2); +b1cpu = mmclab(cfg); +b1cpu = sum(b1cpu.data, 2); - -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% add paths to the necessary toolboxes -%%----------------------------------------------------------------- - -c0=299792458000; +%% ----------------------------------------------------------------- -twin=[cfg.tstart+cfg.tstep/2:cfg.tstep:cfg.tend]; -gates=length(twin); +c0 = 299792458000; -[xi,yi]=meshgrid(0.5:1:59.5,0.5:1:59.5); +twin = [cfg.tstart + cfg.tstep / 2:cfg.tstep:cfg.tend]; +gates = length(twin); -[cutpos1,cutvalue1,facedata1]=qmeshcut(cfg.elem(:,1:4),cfg.node,b1cpu,[0 30.5 0; 0 30.5 1; 1 30.5 0]); -[cutpos2,cutvalue2,facedata2]=qmeshcut(cfg.elem(:,1:4),cfg.node,b1gpu,[0 30.5 0; 0 30.5 1; 1 30.5 0]); -Phicpu=griddata(cutpos1(:,1),cutpos1(:,3),cutvalue1,xi,yi); -Phigpu=griddata(cutpos2(:,1),cutpos2(:,3),cutvalue2,xi,yi); +[xi, yi] = meshgrid(0.5:1:59.5, 0.5:1:59.5); +[cutpos1, cutvalue1, facedata1] = qmeshcut(cfg.elem(:, 1:4), cfg.node, b1cpu, [0 30.5 0; 0 30.5 1; 1 30.5 0]); +[cutpos2, cutvalue2, facedata2] = qmeshcut(cfg.elem(:, 1:4), cfg.node, b1gpu, [0 30.5 0; 0 30.5 1; 1 30.5 0]); +Phicpu = griddata(cutpos1(:, 1), cutpos1(:, 3), cutvalue1, xi, yi); +Phigpu = griddata(cutpos2(:, 1), cutpos2(:, 3), cutvalue2, xi, yi); %% DMMC -[cfg.node,cfg.elem]=meshgrid6(0:60:60,0:60:60,0:60:60); -cfg.elem(:,1:4)=meshreorient(cfg.node,cfg.elem(:,1:4)); +[cfg.node, cfg.elem] = meshgrid6(0:60:60, 0:60:60, 0:60:60); +cfg.elem(:, 1:4) = meshreorient(cfg.node, cfg.elem(:, 1:4)); -cfg.elemprop=ones(size(cfg.elem,1),1); -cfg.method='grid'; +cfg.elemprop = ones(size(cfg.elem, 1), 1); +cfg.method = 'grid'; -cfg.gpuid=1; +cfg.gpuid = 1; -flux=mmclab(cfg); +flux = mmclab(cfg); -Phidgpu=sum(flux.data,4); +Phidgpu = sum(flux.data, 4); -%% DMMC -cfg.gpuid=-1; +%% DMMC +cfg.gpuid = -1; -flux=mmclab(cfg); -Phidcpu=sum(flux.data,4); +flux = mmclab(cfg); +Phidcpu = sum(flux.data, 4); -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% generate a contour plot along y=30.5 -%%----------------------------------------------------------------- -figure +%% ----------------------------------------------------------------- +figure; clines = 0:-0.5:-8; -[xi,yi]=meshgrid(0.5:1:59.5,0.5:1:59.5); -srcs=[30.1,30.2,0]; -dets=[xi(:) 30.2*ones(size(xi(:))) yi(:)]; - -hold on -[c h2]=contourf(xi,yi, log10(max(squeeze(Phicpu*cfg.tstep),1e-8)), clines, 'k-', 'linewidth', 2); -contour(xi,yi,log10(abs(Phigpu*cfg.tstep)),clines,'g--','linewidth',2) -contour(xi,yi,log10(abs(squeeze(Phidcpu(1:end-1,31,1:end-1))'*cfg.tstep)),clines,'b--','linewidth',2) -contour(xi,yi,log10(abs(squeeze(Phidgpu(1:end-1,31,1:end-1))'*cfg.tstep)),clines,'r-','linewidth',1) - -axis equal -set(gca,'xlim',[0.5 59.5]) -set(gca,'fontsize',20) -xlabel('x (mm)') -ylabel('z (mm)') -legend('B1-MMC','B1-MMCL','B1D-MMC','B1D-MMCL') +[xi, yi] = meshgrid(0.5:1:59.5, 0.5:1:59.5); +srcs = [30.1, 30.2, 0]; +dets = [xi(:) 30.2 * ones(size(xi(:))) yi(:)]; + +hold on; +[c h2] = contourf(xi, yi, log10(max(squeeze(Phicpu * cfg.tstep), 1e-8)), clines, 'k-', 'linewidth', 2); +contour(xi, yi, log10(abs(Phigpu * cfg.tstep)), clines, 'g--', 'linewidth', 2); +contour(xi, yi, log10(abs(squeeze(Phidcpu(1:end - 1, 31, 1:end - 1))' * cfg.tstep)), clines, 'b--', 'linewidth', 2); +contour(xi, yi, log10(abs(squeeze(Phidgpu(1:end - 1, 31, 1:end - 1))' * cfg.tstep)), clines, 'r-', 'linewidth', 1); + +axis equal; +set(gca, 'xlim', [0.5 59.5]); +set(gca, 'fontsize', 20); +xlabel('x (mm)'); +ylabel('z (mm)'); +legend('B1-MMC', 'B1-MMCL', 'B1D-MMC', 'B1D-MMCL'); legend boxoff; box on; diff --git a/mmclab/example/demo_mmcl_b2_b2d.m b/mmclab/example/demo_mmcl_b2_b2d.m index dda287a0..3c9aa06c 100644 --- a/mmclab/example/demo_mmcl_b2_b2d.m +++ b/mmclab/example/demo_mmcl_b2_b2d.m @@ -1,173 +1,173 @@ -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% validate DMMC with MMC in a heterogeneous cubic domain % (see DMMC paper Fig. 1, and MMCL paper Fig. 1b) -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- % create a surface mesh for a 10 mm radius sphere -[nsph_10,fsph_10]=meshasphere([30 30 30],10,1.0); -[nsph_10,fsph_10]=removeisolatednode(nsph_10,fsph_10); +[nsph_10, fsph_10] = meshasphere([30 30 30], 10, 1.0); +[nsph_10, fsph_10] = removeisolatednode(nsph_10, fsph_10); % create a surface mesh for a 23 mm radius sphere -[nsph_23,fsph_23]=meshasphere([30 30 30],23,2.0); -[nsph_23,fsph_23]=removeisolatednode(nsph_23,fsph_23); +[nsph_23, fsph_23] = meshasphere([30 30 30], 23, 2.0); +[nsph_23, fsph_23] = removeisolatednode(nsph_23, fsph_23); % create a surface mesh for a 25 mm radius sphere -[nsph_25,fsph_25]=meshasphere([30 30 30],25,2.0); -[nsph_25,fsph_25]=removeisolatednode(nsph_25,fsph_25); +[nsph_25, fsph_25] = meshasphere([30 30 30], 25, 2.0); +[nsph_25, fsph_25] = removeisolatednode(nsph_25, fsph_25); -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% create simulation parameters -%%----------------------------------------------------------------- -clear cfg - -cfg.nphoton=1e8; -cfg.seed=1648335518; -cfg.srcpos=[30,30.1,0]; -cfg.srcdir=[0 0 1]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-10; -cfg.prop=[0,0,1,1;0.02 7.0 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.0 1.37]; -cfg.debuglevel='TP'; -cfg.isreflect=1; - -cfgs=[cfg cfg]; - -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- +clear cfg; + +cfg.nphoton = 1e8; +cfg.seed = 1648335518; +cfg.srcpos = [30, 30.1, 0]; +cfg.srcdir = [0 0 1]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-10; +cfg.prop = [0, 0, 1, 1; 0.02 7.0 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.0 1.37]; +cfg.debuglevel = 'TP'; +cfg.isreflect = 1; + +cfgs = [cfg cfg]; + +%% ----------------------------------------------------------------- %% tetrahedral mesh generation -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- -% generate a coarse CDT volumetric mesh from triangular surfaces of +% generate a coarse CDT volumetric mesh from triangular surfaces of % three spheres with an additional bounding box for DMMC -ISO2MESH_SESSION='dmmc1_'; +ISO2MESH_SESSION = 'dmmc1_'; -[nbox,ebox]=meshgrid6(0:60:60,0:60:60,0:60:60); -fbox=volface(ebox); -[no,fc]=mergemesh(nsph_10,fsph_10,nsph_23,fsph_23,nsph_25,fsph_25,nbox,fbox); -[no,fc]=removeisolatednode(no,fc); +[nbox, ebox] = meshgrid6(0:60:60, 0:60:60, 0:60:60); +fbox = volface(ebox); +[no, fc] = mergemesh(nsph_10, fsph_10, nsph_23, fsph_23, nsph_25, fsph_25, nbox, fbox); +[no, fc] = removeisolatednode(no, fc); -ISO2MESH_TETGENOPT='-A -q -Y' -[cfgs(1).node,cfgs(1).elem]=surf2mesh(no,fc,[0 0 0],[60.1 60.1 60.1],1,100,[1 1 1;30 30 6;30 30 15;30 30 30]);%thin layer +ISO2MESH_TETGENOPT = '-A -q -Y'; +[cfgs(1).node, cfgs(1).elem] = surf2mesh(no, fc, [0 0 0], [60.1 60.1 60.1], 1, 100, [1 1 1; 30 30 6; 30 30 15; 30 30 30]); % thin layer % [cfgs(1).node,cfgs(1).elem]=surf2mesh(no,fc,[0 0 0],[60.1 60.1 60.1],1,100,[1 1 1;30 30 6;30 30 17;30 30 30]);%thick layer -cfgs(1).method='grid'; +cfgs(1).method = 'grid'; -% generate a refined volumetric mesh from triangular surfaces of +% generate a refined volumetric mesh from triangular surfaces of % three spheres with an additional bounding box for MMC -clear ISO2MESH_TETGENOPT -ISO2MESH_SESSION='dmmc2_'; +clear ISO2MESH_TETGENOPT; +ISO2MESH_SESSION = 'dmmc2_'; -[no,fc]=mergemesh(nsph_10,fsph_10,nsph_23,fsph_23,nsph_25,fsph_25); -[no,fc]=removeisolatednode(no,fc); -srcpos=cfgs(1).srcpos; -[cfgs(2).node,cfgs(2).elem,face2]=surf2mesh(no,fc,[0 0 0],[60 60 60],1,0.25,[1 1 1 0.1;30 30 6 0.1;30 30 17 0.1;30 30 30 0.1],[],[1 1 1 1 1 1 1 1]); -[cfgs(2).node,cfgs(2).elem]=sortmesh(srcpos,cfgs(2).node,cfgs(2).elem,1:4); -cfgs(2).method='elem'; +[no, fc] = mergemesh(nsph_10, fsph_10, nsph_23, fsph_23, nsph_25, fsph_25); +[no, fc] = removeisolatednode(no, fc); +srcpos = cfgs(1).srcpos; +[cfgs(2).node, cfgs(2).elem, face2] = surf2mesh(no, fc, [0 0 0], [60 60 60], 1, 0.25, [1 1 1 0.1; 30 30 6 0.1; 30 30 17 0.1; 30 30 30 0.1], [], [1 1 1 1 1 1 1 1]); +[cfgs(2).node, cfgs(2).elem] = sortmesh(srcpos, cfgs(2).node, cfgs(2).elem, 1:4); +cfgs(2).method = 'elem'; %% -cfgs(1).gpuid=1; -b2dgpu=mmclab(cfgs(1)); -b2dgpu=sum(b2dgpu.data,4); +cfgs(1).gpuid = 1; +b2dgpu = mmclab(cfgs(1)); +b2dgpu = sum(b2dgpu.data, 4); %% -cfgs(1).gpuid=-1; -b2dcpu=mmclab(cfgs(1)); -b2dcpu=sum(b2dcpu.data,4); +cfgs(1).gpuid = -1; +b2dcpu = mmclab(cfgs(1)); +b2dcpu = sum(b2dcpu.data, 4); %% -cfgs(2).gpuid=1; -b2gpu=mmclab(cfgs(2)); -b2gpu=sum(b2gpu.data,2); +cfgs(2).gpuid = 1; +b2gpu = mmclab(cfgs(2)); +b2gpu = sum(b2gpu.data, 2); %% -cfgs(2).gpuid=-1; -b2cpu=mmclab(cfgs(2)); -b2cpu=sum(b2cpu.data,2); +cfgs(2).gpuid = -1; +b2cpu = mmclab(cfgs(2)); +b2cpu = sum(b2cpu.data, 2); -%% -[xi,yi]=meshgrid(0.5:59.5,0.5:59.5); -[cutpos1,cutvalue1,facedata1]=qmeshcut(cfgs(2).elem(:,1:4),cfgs(2).node,b2cpu,[0 30.5 0; 0 30.5 1; 1 30.5 0]); -[cutpos2,cutvalue2,facedata2]=qmeshcut(cfgs(2).elem(:,1:4),cfgs(2).node,b2gpu,[0 30.5 0; 0 30.5 1; 1 30.5 0]); -b2cpu_interpolated=griddata(cutpos1(:,1),cutpos1(:,3),cutvalue1,xi,yi); -b2gpu_interpolated=griddata(cutpos2(:,1),cutpos2(:,3),cutvalue2,xi,yi); +%% +[xi, yi] = meshgrid(0.5:59.5, 0.5:59.5); +[cutpos1, cutvalue1, facedata1] = qmeshcut(cfgs(2).elem(:, 1:4), cfgs(2).node, b2cpu, [0 30.5 0; 0 30.5 1; 1 30.5 0]); +[cutpos2, cutvalue2, facedata2] = qmeshcut(cfgs(2).elem(:, 1:4), cfgs(2).node, b2gpu, [0 30.5 0; 0 30.5 1; 1 30.5 0]); +b2cpu_interpolated = griddata(cutpos1(:, 1), cutpos1(:, 3), cutvalue1, xi, yi); +b2gpu_interpolated = griddata(cutpos2(:, 1), cutpos2(:, 3), cutvalue2, xi, yi); %% mcxcl - add voxelated mcxcl results -cfg_mcx.nphoton=cfgs(1).nphoton; +cfg_mcx.nphoton = cfgs(1).nphoton; % define three spheres with radius=10 mm, 23 mm and 25 mm within a 60x60x60 mm box -dim=60; -[xi,yi,zi]=meshgrid(0.5:(dim-0.5),0.5:(dim-0.5),0.5:(dim-0.5)); -dist=(xi-30).^2+(yi-30).^2+(zi-30).^2; -cfg_mcx.vol=ones(size(xi)); -cfg_mcx.vol(dist<625)=2;%radius 25 -cfg_mcx.vol(dist<529)=3;%radius 23 -cfg_mcx.vol(dist<100)=4;%radius 10 -cfg_mcx.vol=uint8(cfg_mcx.vol); +dim = 60; +[xi, yi, zi] = meshgrid(0.5:(dim - 0.5), 0.5:(dim - 0.5), 0.5:(dim - 0.5)); +dist = (xi - 30).^2 + (yi - 30).^2 + (zi - 30).^2; +cfg_mcx.vol = ones(size(xi)); +cfg_mcx.vol(dist < 625) = 2; % radius 25 +cfg_mcx.vol(dist < 529) = 3; % radius 23 +cfg_mcx.vol(dist < 100) = 4; % radius 10 +cfg_mcx.vol = uint8(cfg_mcx.vol); % define the source position -cfg_mcx.srcpos=[30,30.1,0]; -cfg_mcx.srcdir=[0 0 1]; -cfg_mcx.issrcfrom0=1; +cfg_mcx.srcpos = [30, 30.1, 0]; +cfg_mcx.srcdir = [0 0 1]; +cfg_mcx.issrcfrom0 = 1; % format: [mua(1/mm) mus(1/mm) g n] -cfg_mcx.prop=[0,0,1,1;0.02 7.0 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.0 1.37]; +cfg_mcx.prop = [0, 0, 1, 1; 0.02 7.0 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.0 1.37]; % time-domain simulation parameters -cfg_mcx.tstart=0; -cfg_mcx.tend=5e-9; -cfg_mcx.tstep=5e-10; - +cfg_mcx.tstart = 0; +cfg_mcx.tend = 5e-9; +cfg_mcx.tstep = 5e-10; + % GPU thread configuration -cfg_mcx.autopilot=1; -cfg_mcx.gpuid=1; +cfg_mcx.autopilot = 1; +cfg_mcx.gpuid = 1; -cfg_mcx.isreflect=1; % disable reflection at exterior boundaries -cfg_mcx.unitinmm=1; % resolution +cfg_mcx.isreflect = 1; % disable reflection at exterior boundaries +cfg_mcx.unitinmm = 1; % resolution -phimcx=mcxlabcl(cfg_mcx); -b2mcx=sum(phimcx.data,4); +phimcx = mcxlabcl(cfg_mcx); +b2mcx = sum(phimcx.data, 4); -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% generate a contour plot along y=30.5 -%%----------------------------------------------------------------- -figure +%% ----------------------------------------------------------------- +figure; clines = 0:-0.5:-8; -[xi,yi]=meshgrid(0.5:59.5,0.5:59.5); -srcs=[30.1,30.2,0]; -dets=[xi(:) 30.2*ones(size(xi(:))) yi(:)]; - -hold on -[c h2]=contourf(xi,yi, log10(max(squeeze(b2cpu_interpolated*cfgs(1).tstep),1e-8)), clines, 'k-','linewidth', 2 ); -contour(xi,yi,log10(abs(b2gpu_interpolated*cfgs(1).tstep)),clines,'g--','linewidth',2); -contour(xi,yi,log10(abs(squeeze(b2dcpu(1:end-1,31,1:end-1))'*cfgs(1).tstep)),clines,'b--','linewidth',2) -contour(xi,yi,log10(abs(squeeze(b2dgpu(1:end-1,31,1:end-1))'*cfgs(1).tstep)),clines,'r-','linewidth',1) -contour(xi,yi,log10(abs(squeeze(b2mcx(:,31,:))'*cfg_mcx.tstep)),clines,'m--') - -%plot a dashed circle with radius of 10 -[xcirc,ycirc] = cylinder(sqrt(10^2-0.5^2),200); %since we are ploting at y=30.5,0.5 from center of the sphere. -xcirc=xcirc(1,:)+30; -ycirc=ycirc(1,:)+30; -plot(xcirc,ycirc,'k--','linewidth',2); - -%plot a dashed circle with radius of 23 -[xcirc,ycirc] = cylinder(sqrt(23^2-0.5^2),200); -xcirc=xcirc(1,:)+30; -ycirc=ycirc(1,:)+30; -plot(xcirc,ycirc,'k--','linewidth',2); - -%plot a dashed circle with radius of 25 -[xcirc,ycirc] = cylinder(sqrt(25^2-0.5^2),200); -xcirc=xcirc(1,:)+30; -ycirc=ycirc(1,:)+30; -plot(xcirc,ycirc,'k--','linewidth',2); - -axis equal -set(gca,'xlim',[0.5 59.5]) -set(gca,'fontsize',20) -xlabel('x (mm)') -ylabel('z (mm)') -legend('MMC','MMCL','D-MMC','D-MMCL','MCX-CL') +[xi, yi] = meshgrid(0.5:59.5, 0.5:59.5); +srcs = [30.1, 30.2, 0]; +dets = [xi(:) 30.2 * ones(size(xi(:))) yi(:)]; + +hold on; +[c h2] = contourf(xi, yi, log10(max(squeeze(b2cpu_interpolated * cfgs(1).tstep), 1e-8)), clines, 'k-', 'linewidth', 2); +contour(xi, yi, log10(abs(b2gpu_interpolated * cfgs(1).tstep)), clines, 'g--', 'linewidth', 2); +contour(xi, yi, log10(abs(squeeze(b2dcpu(1:end - 1, 31, 1:end - 1))' * cfgs(1).tstep)), clines, 'b--', 'linewidth', 2); +contour(xi, yi, log10(abs(squeeze(b2dgpu(1:end - 1, 31, 1:end - 1))' * cfgs(1).tstep)), clines, 'r-', 'linewidth', 1); +contour(xi, yi, log10(abs(squeeze(b2mcx(:, 31, :))' * cfg_mcx.tstep)), clines, 'm--'); + +% plot a dashed circle with radius of 10 +[xcirc, ycirc] = cylinder(sqrt(10^2 - 0.5^2), 200); % since we are ploting at y=30.5,0.5 from center of the sphere. +xcirc = xcirc(1, :) + 30; +ycirc = ycirc(1, :) + 30; +plot(xcirc, ycirc, 'k--', 'linewidth', 2); + +% plot a dashed circle with radius of 23 +[xcirc, ycirc] = cylinder(sqrt(23^2 - 0.5^2), 200); +xcirc = xcirc(1, :) + 30; +ycirc = ycirc(1, :) + 30; +plot(xcirc, ycirc, 'k--', 'linewidth', 2); + +% plot a dashed circle with radius of 25 +[xcirc, ycirc] = cylinder(sqrt(25^2 - 0.5^2), 200); +xcirc = xcirc(1, :) + 30; +ycirc = ycirc(1, :) + 30; +plot(xcirc, ycirc, 'k--', 'linewidth', 2); + +axis equal; +set(gca, 'xlim', [0.5 59.5]); +set(gca, 'fontsize', 20); +xlabel('x (mm)'); +ylabel('z (mm)'); +legend('MMC', 'MMCL', 'D-MMC', 'D-MMCL', 'MCX-CL'); legend boxoff; -box on; \ No newline at end of file +box on; diff --git a/mmclab/example/demo_mmcl_b3.m b/mmclab/example/demo_mmcl_b3.m index 045fd924..81fcfc52 100644 --- a/mmclab/example/demo_mmcl_b3.m +++ b/mmclab/example/demo_mmcl_b3.m @@ -1,107 +1,113 @@ -addpath('../../../matlab/'); - -if(~exist('MMC_Collins_Atlas_Mesh_Version_2L.mat','file')) - if(~exist('MMC_Collins_Atlas_Mesh_Version_2L.tar.gz','file')) - urlwrite('http://downloads.sourceforge.net/project/mcx/mmc/AdultBrain%20Atlas%20FEM%20Mesh/Version%202/MMC_Collins_Atlas_Mesh_Version_2L.tar.gz?r=http%3A%2F%2Fsourceforge.net%2Fprojects%2Fmcx%2Ffiles%2Fmmc%2FAdultBrain%2520Atlas%2520FEM%2520Mesh%2FVersion%25202%2F&ts=1451344236&use_mirror=tcpdiag','MMC_Collins_Atlas_Mesh_Version_2L.tar.gz'); - end - if(~exist('MMC_Collins_Atlas_Mesh_Version_2L.tar','file')) - gunzip('MMC_Collins_Atlas_Mesh_Version_2L.tar.gz'); - end - if(~exist('MMC_Collins_Atlas_Mesh_Version_2L.mat','file')) - untar('MMC_Collins_Atlas_Mesh_Version_2L.tar'); - end +addpath('../../../matlab/'); + +if (~exist('MMC_Collins_Atlas_Mesh_Version_2L.mat', 'file')) + if (~exist('MMC_Collins_Atlas_Mesh_Version_2L.tar.gz', 'file')) + urlwrite('http://downloads.sourceforge.net/project/mcx/mmc/AdultBrain%20Atlas%20FEM%20Mesh/Version%202/MMC_Collins_Atlas_Mesh_Version_2L.tar.gz?r=http%3A%2F%2Fsourceforge.net%2Fprojects%2Fmcx%2Ffiles%2Fmmc%2FAdultBrain%2520Atlas%2520FEM%2520Mesh%2FVersion%25202%2F&ts=1451344236&use_mirror=tcpdiag', 'MMC_Collins_Atlas_Mesh_Version_2L.tar.gz'); + end + if (~exist('MMC_Collins_Atlas_Mesh_Version_2L.tar', 'file')) + gunzip('MMC_Collins_Atlas_Mesh_Version_2L.tar.gz'); + end + if (~exist('MMC_Collins_Atlas_Mesh_Version_2L.mat', 'file')) + untar('MMC_Collins_Atlas_Mesh_Version_2L.tar'); + end end -load MMC_Collins_Atlas_Mesh_Version_2L.mat +load MMC_Collins_Atlas_Mesh_Version_2L.mat; -clear cfg -cfg.node=node; -cfg.elem=elem(:,1:4); -cfg.elemprop=elem(:,5); +clear cfg; +cfg.node = node; +cfg.elem = elem(:, 1:4); +cfg.elemprop = elem(:, 5); -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.prop=[ 0 0 1.0000 1.0000 % background/air - 0.0190 7.8182 0.8900 1.3700 % scalp & skull are both labeled using 1 -% 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 & skull are both labeled using 1 + % 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=1e8; -cfg.method='elem'; +cfg.seed = 29012392; +cfg.nphoton = 1e8; +cfg.method = 'elem'; %% -cfg.gpuid=1; +cfg.gpuid = 1; -b3gpu=mmclab(cfg); -b3gpu=sum(b3gpu.data,2)*cfg.tstep; +b3gpu = mmclab(cfg); +b3gpu = sum(b3gpu.data, 2) * cfg.tstep; %% -cfg.gpuid=-1; +cfg.gpuid = -1; -b3cpu=mmclab(cfg); -b3cpu=sum(b3cpu.data,2)*cfg.tstep; +b3cpu = mmclab(cfg); +b3cpu = sum(b3cpu.data, 2) * cfg.tstep; -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% generate a contour plot along y=74.5 -%%----------------------------------------------------------------- -figure +%% ----------------------------------------------------------------- +figure; clines = 0:-0.5:-10; -x_min=min(cfg.node(:,1)); x_max=max(cfg.node(:,1)); bb_size(1,1)=floor(x_max-x_min); -y_min=min(cfg.node(:,2)); y_max=max(cfg.node(:,2)); bb_size(1,2)=floor(y_max-y_min); -z_min=min(cfg.node(:,3)); z_max=max(cfg.node(:,3)); bb_size(1,3)=floor(z_max-z_min); -[yi,zi]=ndgrid((y_min+0.5):(y_min+0.5+bb_size(1,2)-1),(z_min+0.5):(z_min+0.5+bb_size(1,3)-1)); - -[cutpos1,cutvalue1,facedata1]=qmeshcut(elem(:,1:4),node,b3cpu,[74.5 0 0;74.5 0 1;74.5 1 0]); -[cutpos2,cutvalue2,facedata2]=qmeshcut(elem(:,1:4),node,b3gpu,[74.5 0 0;74.5 0 1;74.5 1 0]); -b3cpu_interpolated=griddata(cutpos1(:,2),cutpos1(:,3),cutvalue1,yi,zi); -b3gpu_interpolated=griddata(cutpos2(:,2),cutpos2(:,3),cutvalue2,yi,zi); - -b3cpu_interpolated(find(b3cpu_interpolated==0))=nan; -b3gpu_interpolated(find(b3gpu_interpolated==0))=nan; - -hold on -contourf(yi,zi,log10(b3cpu_interpolated),clines,'k-','linewidth',2); -contour(yi,zi,log10(b3gpu_interpolated),clines,'g--','linewidth',2) - -x_cut=75-0.5; -plane=[x_cut 0 0;x_cut 0 1;x_cut 1 0]; -[cutpos,cutvalue,cutedges]=qmeshcut(face(:,1:3),node,node(:,1),plane); -[cutpos,cutedges]=removedupnodes(cutpos,cutedges); -cutloop=extractloops(cutedges); -[nanidx]=find(isnan(cutloop)); - -for i=1:size(nanidx,2) - if(i==1) - plot(cutpos(cutloop(1:(nanidx(i)-1)),2),cutpos(cutloop(1:(nanidx(i)-1)),3),'color','k','LineWidth',1.25,'HandleVisibility','off'); - elseif(i==2) - plot(cutpos(cutloop((nanidx(i-1)+1):(nanidx(i)-1)),2),cutpos(cutloop((nanidx(i-1)+1):(nanidx(i)-1)),3),'linestyle','--','color','k','LineWidth',1.25,'HandleVisibility','off'); +x_min = min(cfg.node(:, 1)); +x_max = max(cfg.node(:, 1)); +bb_size(1, 1) = floor(x_max - x_min); +y_min = min(cfg.node(:, 2)); +y_max = max(cfg.node(:, 2)); +bb_size(1, 2) = floor(y_max - y_min); +z_min = min(cfg.node(:, 3)); +z_max = max(cfg.node(:, 3)); +bb_size(1, 3) = floor(z_max - z_min); +[yi, zi] = ndgrid((y_min + 0.5):(y_min + 0.5 + bb_size(1, 2) - 1), (z_min + 0.5):(z_min + 0.5 + bb_size(1, 3) - 1)); + +[cutpos1, cutvalue1, facedata1] = qmeshcut(elem(:, 1:4), node, b3cpu, [74.5 0 0; 74.5 0 1; 74.5 1 0]); +[cutpos2, cutvalue2, facedata2] = qmeshcut(elem(:, 1:4), node, b3gpu, [74.5 0 0; 74.5 0 1; 74.5 1 0]); +b3cpu_interpolated = griddata(cutpos1(:, 2), cutpos1(:, 3), cutvalue1, yi, zi); +b3gpu_interpolated = griddata(cutpos2(:, 2), cutpos2(:, 3), cutvalue2, yi, zi); + +b3cpu_interpolated(find(b3cpu_interpolated == 0)) = nan; +b3gpu_interpolated(find(b3gpu_interpolated == 0)) = nan; + +hold on; +contourf(yi, zi, log10(b3cpu_interpolated), clines, 'k-', 'linewidth', 2); +contour(yi, zi, log10(b3gpu_interpolated), clines, 'g--', 'linewidth', 2); + +x_cut = 75 - 0.5; +plane = [x_cut 0 0; x_cut 0 1; x_cut 1 0]; +[cutpos, cutvalue, cutedges] = qmeshcut(face(:, 1:3), node, node(:, 1), plane); +[cutpos, cutedges] = removedupnodes(cutpos, cutedges); +cutloop = extractloops(cutedges); +[nanidx] = find(isnan(cutloop)); + +for i = 1:size(nanidx, 2) + if (i == 1) + plot(cutpos(cutloop(1:(nanidx(i) - 1)), 2), cutpos(cutloop(1:(nanidx(i) - 1)), 3), 'color', 'k', 'LineWidth', 1.25, 'HandleVisibility', 'off'); + elseif (i == 2) + plot(cutpos(cutloop((nanidx(i - 1) + 1):(nanidx(i) - 1)), 2), cutpos(cutloop((nanidx(i - 1) + 1):(nanidx(i) - 1)), 3), 'linestyle', '--', 'color', 'k', 'LineWidth', 1.25, 'HandleVisibility', 'off'); else - plot(cutpos(cutloop((nanidx(i-1)+1):(nanidx(i)-1)),2),cutpos(cutloop((nanidx(i-1)+1):(nanidx(i)-1)),3),'linestyle','--','color','k','LineWidth',1.25,'HandleVisibility','off'); + plot(cutpos(cutloop((nanidx(i - 1) + 1):(nanidx(i) - 1)), 2), cutpos(cutloop((nanidx(i - 1) + 1):(nanidx(i) - 1)), 3), 'linestyle', '--', 'color', 'k', 'LineWidth', 1.25, 'HandleVisibility', 'off'); end end -axis equal -set(gca,'xlim',[3 217]); -set(gca,'ylim',[-1 175]); -set(gca,'fontsize',20) -xlabel('x (mm)') -ylabel('z (mm)') -legend('MMC','MMCL') +axis equal; +set(gca, 'xlim', [3 217]); +set(gca, 'ylim', [-1 175]); +set(gca, 'fontsize', 20); +xlabel('x (mm)'); +ylabel('z (mm)'); +legend('MMC', 'MMCL'); legend boxoff; box on; diff --git a/mmclab/example/demo_mmcl_b4.m b/mmclab/example/demo_mmcl_b4.m index 2a960c5b..246e4421 100644 --- a/mmclab/example/demo_mmcl_b4.m +++ b/mmclab/example/demo_mmcl_b4.m @@ -1,78 +1,77 @@ %% create the skin-vessel benchmark mesh -[no,fc]=latticegrid([0 200],[0 200],[20 32 200]); % create a 3-layer tissue -no(end,:)=no(end,:); +[no, fc] = latticegrid([0 200], [0 200], [20 32 200]); % create a 3-layer tissue +no(end, :) = no(end, :); -fc2=cell2mat(fc); -fc=[fc2(:,[1 2 3]); fc2(:,[1 3 4])]; +fc2 = cell2mat(fc); +fc = [fc2(:, [1 2 3]); fc2(:, [1 3 4])]; -[ncy,fcy]=meshacylinder([-1,99.5,99.5],[201,99.5,99.5],20,5); % add the vessel -[newnode,newelem]=surfboolean(no,fc,'first',ncy,fcy); % merge the two domains +[ncy, fcy] = meshacylinder([-1, 99.5, 99.5], [201, 99.5, 99.5], 20, 5); % add the vessel +[newnode, newelem] = surfboolean(no, fc, 'first', ncy, fcy); % merge the two domains -c0=[10,100,150,26]'; -seeds=[ones(4,2)*100, c0]; % define the regions by index +c0 = [10, 100, 150, 26]'; +seeds = [ones(4, 2) * 100, c0]; % define the regions by index -[cfg_mmc.node,cfg_mmc.elem]=s2m(newnode,newelem(:,1:3),1,4,'tetgen',seeds,[]); % creating the merged mesh domain +[cfg_mmc.node, cfg_mmc.elem] = s2m(newnode, newelem(:, 1:3), 1, 4, 'tetgen', seeds, []); % creating the merged mesh domain -voxellen=0.005; -cfg_mmc.node=cfg_mmc.node*voxellen; -cfg_mmc.method='elem'; +voxellen = 0.005; +cfg_mmc.node = cfg_mmc.node * voxellen; +cfg_mmc.method = 'elem'; -figure; +figure; subplot(121); -plotmesh(cfg_mmc.node,cfg_mmc.elem); +plotmesh(cfg_mmc.node, cfg_mmc.elem); -cfg_mmc.elemprop=cfg_mmc.elem(:,5); -cfg_mmc.elem=cfg_mmc.elem(:,1:4); +cfg_mmc.elemprop = cfg_mmc.elem(:, 5); +cfg_mmc.elem = cfg_mmc.elem(:, 1:4); %% define other properties -cfg_mmc.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_mmc.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_mmc.srcpos=[100 100 -3]*voxellen; -cfg_mmc.srcdir=[0 0 1]; +cfg_mmc.srcpos = [100 100 -3] * voxellen; +cfg_mmc.srcdir = [0 0 1]; -cfg_mmc.tstart=0; -cfg_mmc.tend=5e-8; -cfg_mmc.tstep=5e-8; +cfg_mmc.tstart = 0; +cfg_mmc.tend = 5e-8; +cfg_mmc.tstep = 5e-8; % cfg.outputtype='energy'; %energy deposition in mmc varys with elem volume -cfg_mmc.outputtype='flux'; -cfg_mmc.minenergy=0.01; +cfg_mmc.outputtype = 'flux'; +cfg_mmc.minenergy = 0.01; -cfg_mmc.srctype='disk'; -cfg_mmc.srcparam1=[0.3 0 0 0]; +cfg_mmc.srctype = 'disk'; +cfg_mmc.srcparam1 = [0.3 0 0 0]; %% define wide-field disk source by extending the mesh to the widefield src -srcdef=struct('srctype',cfg_mmc.srctype,'srcpos',cfg_mmc.srcpos,'srcdir',cfg_mmc.srcdir,... - 'srcparam1',cfg_mmc.srcparam1,'srcparam2',[]); +srcdef = struct('srctype', cfg_mmc.srctype, 'srcpos', cfg_mmc.srcpos, 'srcdir', cfg_mmc.srcdir, ... + 'srcparam1', cfg_mmc.srcparam1, 'srcparam2', []); -[cfg_mmc.node,cfg_mmc.elem] = mmcaddsrc(cfg_mmc.node,[cfg_mmc.elem cfg_mmc.elemprop],... - mmcsrcdomain(srcdef,[min(cfg_mmc.node);max(cfg_mmc.node)])); +[cfg_mmc.node, cfg_mmc.elem] = mmcaddsrc(cfg_mmc.node, [cfg_mmc.elem cfg_mmc.elemprop], ... + mmcsrcdomain(srcdef, [min(cfg_mmc.node); max(cfg_mmc.node)])); - -cfg_mmc.elemprop=cfg_mmc.elem(:,5); -cfg_mmc.elem=cfg_mmc.elem(:,1:4); +cfg_mmc.elemprop = cfg_mmc.elem(:, 5); +cfg_mmc.elem = cfg_mmc.elem(:, 1:4); %% other simulation information -cfg_mmc.nphoton=1e8; -cfg_mmc.seed=1648335518; +cfg_mmc.nphoton = 1e8; +cfg_mmc.seed = 1648335518; -cfg_mmc.debuglevel='TP'; -cfg_mmc.isreflect=0; +cfg_mmc.debuglevel = 'TP'; +cfg_mmc.isreflect = 0; %% saving coarse mesh -cfg_mmc.gpuid=1; -output1=mmclab(cfg_mmc); -b4gpu=output1.data*cfg_mmc.tstep; +cfg_mmc.gpuid = 1; +output1 = mmclab(cfg_mmc); +b4gpu = output1.data * cfg_mmc.tstep; %% saving coarse mesh -cfg_mmc.gpuid=-1; -output2=mmclab(cfg_mmc); -b4cpu=output2.data*cfg_mmc.tstep; +cfg_mmc.gpuid = -1; +output2 = mmclab(cfg_mmc); +b4cpu = output2.data * cfg_mmc.tstep; %% regenerate the mesh using fine mesh % cfg_dmmc=cfg_mmc; @@ -80,13 +79,13 @@ % cfg_dmmc.node=cfg_dmmc.node*voxellen; % cfg_dmmc.elemprop=cfg_dmmc.elem(:,5); % cfg_dmmc.elem=cfg_dmmc.elem(:,1:4); -% +% % cfg_dmmc.method='grid'; % cfg_dmmc.unitinmm=voxellen; -% +% % [cfg_dmmc.node,cfg_dmmc.elem] = mmcaddsrc(cfg_dmmc.node,[cfg_dmmc.elem cfg_dmmc.elemprop],... % mmcsrcdomain(srcdef,[min(cfg_dmmc.node);max(cfg_dmmc.node)])); -% +% % cfg_dmmc.elemprop=cfg_dmmc.elem(:,5); % cfg_dmmc.elem=cfg_dmmc.elem(:,1:4); % %% saving coarse mesh @@ -94,7 +93,7 @@ % % cfg_dmmc.gpuid=1; % % b4dgpu=mmclab(cfg_dmmc); % % b4dgpu=sum(b4dgpu.data,4); -% +% % %% saving coarse mesh % cfg_dmmc.gpuid=-1; % b4dcpu=mmclab(cfg_dmmc); @@ -104,63 +103,70 @@ % x_min=min(cfg.node(:,1)); x_max=max(cfg.node(:,1)); bb_size(1,1)=floor(x_max-x_min); % y_min=min(cfg.node(:,2)); y_max=max(cfg.node(:,2)); bb_size(1,2)=floor(y_max-y_min); % z_min=min(cfg.node(:,3)); z_max=max(cfg.node(:,3)); bb_size(1,3)=floor(z_max-z_min); -[yi,zi]=ndgrid(0.0025:0.005:0.9975,0.1025:0.005:0.9975); -[cutpos1,cutvalue1,facedata1]=qmeshcut(cfg_mmc.elem(:,1:4),cfg_mmc.node,b4cpu,[0.4975 0 0;0.4975 0 1;0.4975 1 0]); -[cutpos2,cutvalue2,facedata2]=qmeshcut(cfg_mmc.elem(:,1:4),cfg_mmc.node,b4gpu,[0.4975 0 0;0.4975 0 1;0.4975 1 0]); -b4cpu_interpolated=griddata(cutpos1(:,2),cutpos1(:,3),cutvalue1,yi,zi); -b4gpu_interpolated=griddata(cutpos2(:,2),cutpos2(:,3),cutvalue2,yi,zi); +[yi, zi] = ndgrid(0.0025:0.005:0.9975, 0.1025:0.005:0.9975); +[cutpos1, cutvalue1, facedata1] = qmeshcut(cfg_mmc.elem(:, 1:4), cfg_mmc.node, b4cpu, [0.4975 0 0; 0.4975 0 1; 0.4975 1 0]); +[cutpos2, cutvalue2, facedata2] = qmeshcut(cfg_mmc.elem(:, 1:4), cfg_mmc.node, b4gpu, [0.4975 0 0; 0.4975 0 1; 0.4975 1 0]); +b4cpu_interpolated = griddata(cutpos1(:, 2), cutpos1(:, 3), cutvalue1, yi, zi); +b4gpu_interpolated = griddata(cutpos2(:, 2), cutpos2(:, 3), cutvalue2, yi, zi); -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% generate a contour plot along y=30.2 -%%----------------------------------------------------------------- -figure +%% ----------------------------------------------------------------- +figure; clines = -2:0.25:1; -hold on -[yyy,zzz]=ndgrid(-0.4975:0.005:0.4975,0.1025:0.005:0.9975); -contourf(yyy,zzz,log10(b4cpu_interpolated),clines,'k-','linewidth',2);colorbar -contour(yyy,zzz,log10(b4gpu_interpolated),clines,'m:','linecolor',[0.9100 0.4100 0.1700],'linewidth',2); - -[xcirc,ycirc] = cylinder(0.1,10); -xcirc=xcirc(1,:)-0.0025; -ycirc=ycirc(1,:)+0.4975; -plot(xcirc,ycirc,'k--','linewidth',2); - -x=[-0.5,0.5]; y=[0.16 0.16]; -plot(x,y,'k--','linewidth',2); - -%title('fluence \phi [W/mm^2/W.delivered]') -axis equal -xlabel('y (mm)');xlim([-0.5 0.5]); -ylabel('z (mm)');ylim([0.1 1]); -axis equal -%legend('MMC','MMCL') -set(gca,'fontsize',20); +hold on; +[yyy, zzz] = ndgrid(-0.4975:0.005:0.4975, 0.1025:0.005:0.9975); +contourf(yyy, zzz, log10(b4cpu_interpolated), clines, 'k-', 'linewidth', 2); +colorbar; +contour(yyy, zzz, log10(b4gpu_interpolated), clines, 'm:', 'linecolor', [0.9100 0.4100 0.1700], 'linewidth', 2); + +[xcirc, ycirc] = cylinder(0.1, 10); +xcirc = xcirc(1, :) - 0.0025; +ycirc = ycirc(1, :) + 0.4975; +plot(xcirc, ycirc, 'k--', 'linewidth', 2); + +x = [-0.5, 0.5]; +y = [0.16 0.16]; +plot(x, y, 'k--', 'linewidth', 2); + +% title('fluence \phi [W/mm^2/W.delivered]') +axis equal; +xlabel('y (mm)'); +xlim([-0.5 0.5]); +ylabel('z (mm)'); +ylim([0.1 1]); +axis equal; +% legend('MMC','MMCL') +set(gca, 'fontsize', 20); legend boxoff; box on; %% in case if you want to be consistant with Dr. Jacques' results, which is in unit: W/cm^2/W -figure +figure; clines = 0:0.25:3; -hold on -[yyy,zzz]=ndgrid(-0.04975:0.0005:0.04975,0.01025:0.0005:0.09975); -contourf(yyy,zzz,log10(b4cpu_interpolated*100),clines,'k-','linewidth',2);colorbar -contour(yyy,zzz,log10(b4gpu_interpolated*100),clines,'g--','linewidth',2); - -[xcirc,ycirc] = cylinder(0.01,10); -xcirc=xcirc(1,:)-0.00025; -ycirc=ycirc(1,:)+0.04975; -plot(xcirc,ycirc,'k--','linewidth',2); - -x=[-0.05,0.05]; y=[0.016 0.016]; -plot(x,y,'k--','linewidth',2); - - -title('fluence \phi [W/cm^2/W.delivered]') -xlabel('y [cm]');xlim([-0.05 0.05]); -ylabel('z [cm]');ylim([0.01 0.1]); -axis equal -legend('MMC','MMCL') -set(gca,'fontsize',20); +hold on; +[yyy, zzz] = ndgrid(-0.04975:0.0005:0.04975, 0.01025:0.0005:0.09975); +contourf(yyy, zzz, log10(b4cpu_interpolated * 100), clines, 'k-', 'linewidth', 2); +colorbar; +contour(yyy, zzz, log10(b4gpu_interpolated * 100), clines, 'g--', 'linewidth', 2); + +[xcirc, ycirc] = cylinder(0.01, 10); +xcirc = xcirc(1, :) - 0.00025; +ycirc = ycirc(1, :) + 0.04975; +plot(xcirc, ycirc, 'k--', 'linewidth', 2); + +x = [-0.05, 0.05]; +y = [0.016 0.016]; +plot(x, y, 'k--', 'linewidth', 2); + +title('fluence \phi [W/cm^2/W.delivered]'); +xlabel('y [cm]'); +xlim([-0.05 0.05]); +ylabel('z [cm]'); +ylim([0.01 0.1]); +axis equal; +legend('MMC', 'MMCL'); +set(gca, 'fontsize', 20); legend boxoff; -box on; \ No newline at end of file +box on; diff --git a/mmclab/example/demo_mmclab_basic.m b/mmclab/example/demo_mmclab_basic.m index b0c4237c..70bec5f3 100644 --- a/mmclab/example/demo_mmclab_basic.m +++ b/mmclab/example/demo_mmclab_basic.m @@ -8,36 +8,36 @@ % prepare simulation input -clear cfg -cfg.nphoton=1e6; -[cfg.node, face, cfg.elem]=meshabox([0 0 0],[60 60 30],6); -cfg.elemprop=ones(size(cfg.elem,1),1); -cfg.srcpos=[30 30 0]; -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=5e-9; -cfg.debuglevel='TP'; -cfg.issaveref=1; % in addition to volumetric fluence, also save surface diffuse reflectance -cfg.method='elem'; +clear cfg; +cfg.nphoton = 1e6; +[cfg.node, face, cfg.elem] = meshabox([0 0 0], [60 60 30], 6); +cfg.elemprop = ones(size(cfg.elem, 1), 1); +cfg.srcpos = [30 30 0]; +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 = 5e-9; +cfg.debuglevel = 'TP'; +cfg.issaveref = 1; % in addition to volumetric fluence, also save surface diffuse reflectance +cfg.method = 'elem'; %% run the simulation -flux=mmclab(cfg); +flux = mmclab(cfg); %% plotting the result % plot the cross-section of the fluence subplot(121); -plotmesh([cfg.node(:,1:3),log10(abs(flux.data(1:size(cfg.node,1))))],cfg.elem,'y=30','facecolor','interp','linestyle','none') +plotmesh([cfg.node(:, 1:3), log10(abs(flux.data(1:size(cfg.node, 1))))], cfg.elem, 'y=30', 'facecolor', 'interp', 'linestyle', 'none'); view([0 1 0]); colorbar; % plot the surface diffuse reflectance -if(isfield(cfg,'issaveref') && cfg.issaveref==1) +if (isfield(cfg, 'issaveref') && cfg.issaveref == 1) subplot(122); - faces=faceneighbors(cfg.elem,'rowmajor'); - hs=plotmesh(cfg.node,faces,'cdata',log10(flux.dref(:,1)),'linestyle','none'); + faces = faceneighbors(cfg.elem, 'rowmajor'); + hs = plotmesh(cfg.node, faces, 'cdata', log10(flux.dref(:, 1)), 'linestyle', 'none'); colorbar; -end \ No newline at end of file +end diff --git a/mmclab/example/demo_mmclab_slit.m b/mmclab/example/demo_mmclab_slit.m index bb6c67e2..1282f340 100644 --- a/mmclab/example/demo_mmclab_slit.m +++ b/mmclab/example/demo_mmclab_slit.m @@ -8,33 +8,33 @@ % prepare simulation input -cfg.nphoton=1e7; -[cfg.node face cfg.elem]=meshabox([0 0 0],[60 60 30],6); -cfg.elemprop=ones(size(cfg.elem,1),1); -cfg.srcpos=[20 30 -10]; -cfg.srcdir=[0 0.2 sqrt(1-0.04)]; -cfg.prop=[0 0 1 1;0.005 0.1 0 1.37]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-9; -cfg.debuglevel='TP'; -cfg.unitinmm=1; -cfg.method='elem'; -cfg.srctype='slit'; -cfg.srcparam1=[30 0 0 0]; -cfg.srcparam2=[0 0 0 0]; +cfg.nphoton = 1e7; +[cfg.node face cfg.elem] = meshabox([0 0 0], [60 60 30], 6); +cfg.elemprop = ones(size(cfg.elem, 1), 1); +cfg.srcpos = [20 30 -10]; +cfg.srcdir = [0 0.2 sqrt(1 - 0.04)]; +cfg.prop = [0 0 1 1; 0.005 0.1 0 1.37]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-9; +cfg.debuglevel = 'TP'; +cfg.unitinmm = 1; +cfg.method = 'elem'; +cfg.srctype = 'slit'; +cfg.srcparam1 = [30 0 0 0]; +cfg.srcparam2 = [0 0 0 0]; % run the simulation -flux=mmclab(cfg); +flux = mmclab(cfg); % plotting the result % if you have the SVN version of iso2mesh, use the next line to plot: % qmeshcut(cfg.elem(:,1:4),cfg.node(:,1:3),log10(abs(flux.data(:))),'y=30','linestyle','none'); -plotmesh([cfg.node(:,1:3),log10(abs(flux.data(1:size(cfg.node,1))))],cfg.elem,'x=40','facecolor','interp','linestyle','none') +plotmesh([cfg.node(:, 1:3), log10(abs(flux.data(1:size(cfg.node, 1))))], cfg.elem, 'x=40', 'facecolor', 'interp', 'linestyle', 'none'); hold on; -plotmesh([cfg.node(:,1:3),log10(abs(flux.data(1:size(cfg.node,1))))],cfg.elem,'y=30','facecolor','interp','linestyle','none') +plotmesh([cfg.node(:, 1:3), log10(abs(flux.data(1:size(cfg.node, 1))))], cfg.elem, 'y=30', 'facecolor', 'interp', 'linestyle', 'none'); view(3); colorbar; diff --git a/mmclab/example/demo_photon_sharing.m b/mmclab/example/demo_photon_sharing.m index 6b7ac321..1a85043d 100644 --- a/mmclab/example/demo_photon_sharing.m +++ b/mmclab/example/demo_photon_sharing.m @@ -4,72 +4,77 @@ %% prepare simulation input -cfg.nphoton=3e6; -[cfg.node face cfg.elem]=meshabox([0 0 0],[60 60 20],2, 2); -cfg.elemprop=ones(size(cfg.elem,1),1); -cfg.srcpos=[10 10 -2]; -cfg.srcdir=[0 0 1]; -cfg.srctype='pattern'; -cfg.srcparam1=[40.0 0.0 0.0 40]; -cfg.srcparam2=[0.0 40.0 0.0 40]; -cfg.prop=[0 0 1 1;0.01 10 0.9 1.37]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=1e-10; -cfg.gpuid=-1; -cfg.method='elem'; -cfg.debuglevel='TP'; +cfg.nphoton = 3e6; +[cfg.node face cfg.elem] = meshabox([0 0 0], [60 60 20], 2, 2); +cfg.elemprop = ones(size(cfg.elem, 1), 1); +cfg.srcpos = [10 10 -2]; +cfg.srcdir = [0 0 1]; +cfg.srctype = 'pattern'; +cfg.srcparam1 = [40.0 0.0 0.0 40]; +cfg.srcparam2 = [0.0 40.0 0.0 40]; +cfg.prop = [0 0 1 1; 0.01 10 0.9 1.37]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 1e-10; +cfg.gpuid = -1; +cfg.method = 'elem'; +cfg.debuglevel = 'TP'; %% 5 patterns represented by a 3D matrix -pat=zeros(40,40,5); -pat(:,:,1) = ones(40); % full field illumination pattern -pat(1:20,:,2) = 1; % pattern with left half bright -pat(:,1:20,3) = 1; % pattern with top half bright -pat(11:30,11:30,4) = 1; % pattern with bright square in the middle -pat(16:25,:,5) = 1; -pat(:,16:25,5) = 1; % pattern with a bright cross +pat = zeros(40, 40, 5); +pat(:, :, 1) = ones(40); % full field illumination pattern +pat(1:20, :, 2) = 1; % pattern with left half bright +pat(:, 1:20, 3) = 1; % pattern with top half bright +pat(11:30, 11:30, 4) = 1; % pattern with bright square in the middle +pat(16:25, :, 5) = 1; +pat(:, 16:25, 5) = 1; % pattern with a bright cross cfg.srcpattern = pat; %% run the simulation -flux=mmclab(cfg); +flux = mmclab(cfg); %% plot results (same as in the mmc example) -[node, ~, elem]=meshabox([0 0 0],[60 60 20],2, 2); -data = flux.data(:,1:length(node),:); -cwdata = squeeze(sum(data,3)); +[node, ~, elem] = meshabox([0 0 0], [60 60 20], 2, 2); +data = flux.data(:, 1:length(node), :); +cwdata = squeeze(sum(data, 3)); figure(); -subplot(1,3,1); title('pattern 1'); -plotmesh([node,(cwdata(1,:))'],elem,'linestyle','none'); -shading interp -axis off -view([0,0,-1]) +subplot(1, 3, 1); +title('pattern 1'); +plotmesh([node, (cwdata(1, :))'], elem, 'linestyle', 'none'); +shading interp; +axis off; +view([0, 0, -1]); -subplot(2,3,2); title('pattern 2'); -plotmesh([node,(cwdata(2,:))'],elem,'linestyle','none'); -shading interp -axis off -view([0,0,-1]) +subplot(2, 3, 2); +title('pattern 2'); +plotmesh([node, (cwdata(2, :))'], elem, 'linestyle', 'none'); +shading interp; +axis off; +view([0, 0, -1]); -subplot(2,3,3); title('pattern 3'); -plotmesh([node,(cwdata(3,:))'],elem,'linestyle','none'); -shading interp -axis off -view([0,0,-1]) +subplot(2, 3, 3); +title('pattern 3'); +plotmesh([node, (cwdata(3, :))'], elem, 'linestyle', 'none'); +shading interp; +axis off; +view([0, 0, -1]); -subplot(2,3,5); title('pattern 4'); -plotmesh([node,(cwdata(4,:))'],elem,'linestyle','none'); -shading interp -axis off -view([0,0,-1]) +subplot(2, 3, 5); +title('pattern 4'); +plotmesh([node, (cwdata(4, :))'], elem, 'linestyle', 'none'); +shading interp; +axis off; +view([0, 0, -1]); -subplot(2,3,6); title('pattern 5'); -plotmesh([node,(cwdata(5,:))'],elem,'linestyle','none'); -shading interp -axis off -view([0,0,-1]) +subplot(2, 3, 6); +title('pattern 5'); +plotmesh([node, (cwdata(5, :))'], elem, 'linestyle', 'none'); +shading interp; +axis off; +view([0, 0, -1]); diff --git a/mmclab/example/demo_sfdi_2layer.m b/mmclab/example/demo_sfdi_2layer.m index 12cf9664..80d4e0b7 100644 --- a/mmclab/example/demo_sfdi_2layer.m +++ b/mmclab/example/demo_sfdi_2layer.m @@ -1,6 +1,6 @@ -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% Simulating an SFDI source with a 2-layer brain model -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- % % In this example, we simulate an spatial-frequency domain imaging source % using a 2-layer brain model. @@ -10,89 +10,89 @@ % and white matters. The sample SFDI covers a 40 x 40 mm area from the top, % and has kx=3 with a pi/3 phase offset in the x-direction. % -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- clear cfg; clear all; %% 2-layer mesh model -layercount=3; +layercount = 3; + +if (layercount == 2) + [node, face, c0] = latticegrid([0 60], [0 60], [0 25 30]); + c0(:, 4) = [2; 1]; % maximum element size for bottom (label 1) and top (label 2) layers -if(layercount==2) - [node,face,c0]=latticegrid([0 60],[0 60],[0 25 30]); - c0(:,4)=[2;1]; % maximum element size for bottom (label 1) and top (label 2) layers - % simulate the optical properties of skull and gray-matter of a human brain model % see http://mcx.sourceforge.net/cgi-bin/index.cgi?MMC/Colin27AtlasMesh - cfg.prop=[0 0 1 1;0.02 9.0, 0.89 1.37;0.019 7.8 0.89 1.37]; + cfg.prop = [0 0 1 1; 0.02 9.0, 0.89 1.37; 0.019 7.8 0.89 1.37]; else - [node,face,c0]=latticegrid([0 60],[0 60],[0 20 25 30]); % if you like a 3-layer model - c0(:,4)=[2;2;1]; - cfg.prop=[0 0 1 1;0.02 9.0, 0.89 1.37;0.004 0.009, 0.89 1.37;0.019 7.8 0.89 1.37]; + [node, face, c0] = latticegrid([0 60], [0 60], [0 20 25 30]); % if you like a 3-layer model + c0(:, 4) = [2; 2; 1]; + cfg.prop = [0 0 1 1; 0.02 9.0, 0.89 1.37; 0.004 0.009, 0.89 1.37; 0.019 7.8 0.89 1.37]; end -[cfg.node,cfg.elem]=surf2mesh(node,face,[],[],1,[],c0); +[cfg.node, cfg.elem] = surf2mesh(node, face, [], [], 1, [], c0); -figure; +figure; subplot(121); -plotmesh(cfg.node,cfg.elem); - -cfg.elemprop=cfg.elem(:,5); -cfg.elem=cfg.elem(:,1:4); +plotmesh(cfg.node, cfg.elem); +cfg.elemprop = cfg.elem(:, 5); +cfg.elem = cfg.elem(:, 1:4); %% add source and retessellate mesh -cfg.srctype='fourier'; % define an SFDI source -cfg.srcpos=[10 10 35]; % one corner of the illumination area -kx=3; % wave number in the x-dir -ky=0; % wave number in the x-dir -xphase=pi/3; % phase offset in the x-dir, must < 2pi -yphase=0; % phase offset in the x-dir, must < 2pi -cfg.srcparam1=[40 0 0 kx+xphase/(2*pi)]; % kx is k-number in x direction -cfg.srcparam2=[0 40 0 ky+yphase/(2*pi)]; -cfg.srcdir=[0 0 -1]; +cfg.srctype = 'fourier'; % define an SFDI source +cfg.srcpos = [10 10 35]; % one corner of the illumination area +kx = 3; % wave number in the x-dir +ky = 0; % wave number in the x-dir +xphase = pi / 3; % phase offset in the x-dir, must < 2pi +yphase = 0; % phase offset in the x-dir, must < 2pi +cfg.srcparam1 = [40 0 0 kx + xphase / (2 * pi)]; % kx is k-number in x direction +cfg.srcparam2 = [0 40 0 ky + yphase / (2 * pi)]; +cfg.srcdir = [0 0 -1]; %% line 24-31 could possibly be deleted and replaced by built-in one-step command -srcdef=struct('srctype',cfg.srctype,'srcpos',cfg.srcpos,'srcdir',cfg.srcdir,... - 'srcparam1',cfg.srcparam1,'srcparam2',cfg.srcparam2); +srcdef = struct('srctype', cfg.srctype, 'srcpos', cfg.srcpos, 'srcdir', cfg.srcdir, ... + 'srcparam1', cfg.srcparam1, 'srcparam2', cfg.srcparam2); -[cfg.node,cfg.elem] = mmcaddsrc(cfg.node,[cfg.elem cfg.elemprop],... - mmcsrcdomain(srcdef,[min(cfg.node);max(cfg.node)])); +[cfg.node, cfg.elem] = mmcaddsrc(cfg.node, [cfg.elem cfg.elemprop], ... + mmcsrcdomain(srcdef, [min(cfg.node); max(cfg.node)])); -cfg.elemprop=cfg.elem(:,5); -cfg.elem=cfg.elem(:,1:4); +cfg.elemprop = cfg.elem(:, 5); +cfg.elem = cfg.elem(:, 1:4); %% other simulation information -cfg.nphoton=3e6; -cfg.seed=1648335518; +cfg.nphoton = 3e6; +cfg.seed = 1648335518; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=1e-10; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 1e-10; -cfg.debuglevel='TP'; -cfg.isreflect=1; -cfg.detpos=[30 30 0 2]; % detector position -cfg.method='elem'; +cfg.debuglevel = 'TP'; +cfg.isreflect = 1; +cfg.detpos = [30 30 0 2]; % detector position +cfg.method = 'elem'; %% mmc simulation -layer=mmclab(cfg); -%cube=mmclab(cfg,'sse'); % this is faster -layer=layer.data; -layercw=sum(layer,2); +layer = mmclab(cfg); +% cube=mmclab(cfg,'sse'); % this is faster +layer = layer.data; +layercw = sum(layer, 2); % plot simulated photon profiles subplot(122); hold on; -qmeshcut(cfg.elem(cfg.elemprop>0,1:4),cfg.node,log10(layercw),'y=30','linestyle','none'); view(3) -qmeshcut(cfg.elem(cfg.elemprop>0,1:4),cfg.node,log10(layercw),'z=27','linestyle','none'); -if(layercount~=2) - qmeshcut(cfg.elem(cfg.elemprop>0,1:4),cfg.node,log10(layercw),'z=22','linestyle','none'); +qmeshcut(cfg.elem(cfg.elemprop > 0, 1:4), cfg.node, log10(layercw), 'y=30', 'linestyle', 'none'); +view(3); +qmeshcut(cfg.elem(cfg.elemprop > 0, 1:4), cfg.node, log10(layercw), 'z=27', 'linestyle', 'none'); +if (layercount ~= 2) + qmeshcut(cfg.elem(cfg.elemprop > 0, 1:4), cfg.node, log10(layercw), 'z=22', 'linestyle', 'none'); end box on; -axis equal +axis equal; view(-56, 22); diff --git a/mmclab/example/demo_wide_det.m b/mmclab/example/demo_wide_det.m index 80bdbaf0..522d7558 100644 --- a/mmclab/example/demo_wide_det.m +++ b/mmclab/example/demo_wide_det.m @@ -1,31 +1,31 @@ addpath('../../matlab/'); addpath('..'); -clear cfg - -[node,face,c0]=latticegrid([0 60],[0 60],[0 5 10]); -c0(:,4)=[2;3]; % maximum element size for bottom (label 1) and top (label 2) layers -[node,elem]=surf2mesh(node,face,[],[],1,[],c0); - -detdef=struct('srctype','planar','srcpos',[10,10,-1],'srcdir',[0 0 1],... - 'srcparam1',[40 0 0 40],'srcparam2',[0 40 0 40]); - -[cfg.node,cfg.elem]=mmcadddet(node,elem,detdef); -cfg.elemprop=cfg.elem(:,5); -cfg.elem=cfg.elem(:,1:4); -cfg.prop = [0 0 1 1; - 0.01 1.0 0.01 1.37 - 0.05 10.0 0.9 1.37]; - +clear cfg; + +[node, face, c0] = latticegrid([0 60], [0 60], [0 5 10]); +c0(:, 4) = [2; 3]; % maximum element size for bottom (label 1) and top (label 2) layers +[node, elem] = surf2mesh(node, face, [], [], 1, [], c0); + +detdef = struct('srctype', 'planar', 'srcpos', [10, 10, -1], 'srcdir', [0 0 1], ... + 'srcparam1', [40 0 0 40], 'srcparam2', [0 40 0 40]); + +[cfg.node, cfg.elem] = mmcadddet(node, elem, detdef); +cfg.elemprop = cfg.elem(:, 5); +cfg.elem = cfg.elem(:, 1:4); +cfg.prop = [0 0 1 1 + 0.01 1.0 0.01 1.37 + 0.05 10.0 0.9 1.37]; + cfg.srcpos = [25.0 35.0 10.0]; -cfg.e0 = tsearchn(cfg.node,cfg.elem(:,1:4),cfg.srcpos); +cfg.e0 = tsearchn(cfg.node, cfg.elem(:, 1:4), cfg.srcpos); cfg.srcdir = [0, 0, -1]; cfg.srctype = 'pencil'; cfg.srcparam1 = [0 0 0 0]; cfg.srcparam2 = [0 0 0 0]; -cfg.detpos = [10.0,10.0,-1.0,0]; +cfg.detpos = [10.0, 10.0, -1.0, 0]; cfg.detparam1 = [40.0 0.0 0.0 40]; cfg.detparam2 = [0.0 40.0 0.0 40]; @@ -38,8 +38,8 @@ cfg.debuglevel = 'TP'; cfg.issaveexit = 2; -[flux,detp]=mmclab(cfg); +[flux, detp] = mmclab(cfg); figure; -imagesc(sum(detp.data,3)'); +imagesc(sum(detp.data, 3)'); axis equal; diff --git a/mmclab/example/mmclab_selftest_input.m b/mmclab/example/mmclab_selftest_input.m index 43c786ba..44459170 100644 --- a/mmclab/example/mmclab_selftest_input.m +++ b/mmclab/example/mmclab_selftest_input.m @@ -1,38 +1,38 @@ -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- %% MMClab self-test script -%%----------------------------------------------------------------- +%% ----------------------------------------------------------------- % % In this example, we generate various true or false input conditions -% and test the robustness of the script to these conditions +% and test the robustness of the script to these conditions % -dat=mmclab(); +dat = mmclab(); -cfg=struct(); -dat=mmclab(cfg); +cfg = struct(); +dat = mmclab(cfg); -[cfg.node face cfg.elem]=meshabox([0 0 0], [10 10 10],1); -dat=mmclab(cfg); +[cfg.node face cfg.elem] = meshabox([0 0 0], [10 10 10], 1); +dat = mmclab(cfg); -cfg.elem(:,5)=1; -dat=mmclab(cfg); +cfg.elem(:, 5) = 1; +dat = mmclab(cfg); -cfg.srcpos=[5 5 0]; -cfg.srcdir=[0 0 1]; -cfg.nphoton=1000; -cfg.prop=[0 0 1 1;0.1 1 0.2 1.3]; -dat=mmclab(cfg); +cfg.srcpos = [5 5 0]; +cfg.srcdir = [0 0 1]; +cfg.nphoton = 1000; +cfg.prop = [0 0 1 1; 0.1 1 0.2 1.3]; +dat = mmclab(cfg); -cfg.tstart=0; -cfg.tend=1e-9; -dat=mmclab(cfg); +cfg.tstart = 0; +cfg.tend = 1e-9; +dat = mmclab(cfg); -cfg.tstep=10e-9; -dat=mmclab(cfg); +cfg.tstep = 10e-9; +dat = mmclab(cfg); -cfg.srcpos=[-1 -1 -1]; -dat=mmclab(cfg); +cfg.srcpos = [-1 -1 -1]; +dat = mmclab(cfg); -cfg.srcparam1=[0 0 0 0]; -cfg.srcparam2=[0 0 0 0]; -dat=mmclab(cfg); +cfg.srcparam1 = [0 0 0 0]; +cfg.srcparam2 = [0 0 0 0]; +dat = mmclab(cfg); diff --git a/mmclab/example/test_albedo.m b/mmclab/example/test_albedo.m index f11b29cd..07a7dafb 100644 --- a/mmclab/example/test_albedo.m +++ b/mmclab/example/test_albedo.m @@ -4,107 +4,107 @@ %% testing albedo method -clear cfg newcfg - -cfg.nphoton=1e7; -cfg.seed=-1; - -[cfg.node,cfg.elem]=genT6mesh(0:2:60,0:2:60,0:2:60); -cfg.elemprop=ones(size(cfg.elem,1),1); -cfg.srcpos=[30.1,30.2,0]; -cfg.srcdir=[0 0 1]; -cfg.tstart=0; -cfg.tend=5e-9; -cfg.tstep=5e-9; -cfg.prop=[0 0 1 1;0.1 1.0 0.0 1.0]; -cfg.debuglevel='TP'; -cfg.isreflect=0; -cfg.detpos=[30.1 25.2 0. 1.0]; -cfg.issaveexit=1; % save detected photon exit position and angles -cfg.issaveseed=1; % save detected photon seeds to replay later -cfg.isnormalized=1; -cfg.method='elem'; +clear cfg newcfg; + +cfg.nphoton = 1e7; +cfg.seed = -1; + +[cfg.node, cfg.elem] = genT6mesh(0:2:60, 0:2:60, 0:2:60); +cfg.elemprop = ones(size(cfg.elem, 1), 1); +cfg.srcpos = [30.1, 30.2, 0]; +cfg.srcdir = [0 0 1]; +cfg.tstart = 0; +cfg.tend = 5e-9; +cfg.tstep = 5e-9; +cfg.prop = [0 0 1 1; 0.1 1.0 0.0 1.0]; +cfg.debuglevel = 'TP'; +cfg.isreflect = 0; +cfg.detpos = [30.1 25.2 0. 1.0]; +cfg.issaveexit = 1; % save detected photon exit position and angles +cfg.issaveseed = 1; % save detected photon seeds to replay later +cfg.isnormalized = 1; +cfg.method = 'elem'; % albedo method -cfg.mcmethod=1; -newcfg=mmclab(cfg,'prep'); % preprocessing of the mesh to get the missing fields -[cube1, detp1]=mmclab(newcfg); % initial simulation +cfg.mcmethod = 1; +newcfg = mmclab(cfg, 'prep'); % preprocessing of the mesh to get the missing fields +[cube1, detp1] = mmclab(newcfg); % initial simulation % mBLL method -cfg.mcmethod=0; -newcfg=mmclab(cfg,'prep'); % preprocessing of the mesh to get the missing fields -[cube2, detp2]=mmclab(newcfg); % initial simulation +cfg.mcmethod = 0; +newcfg = mmclab(cfg, 'prep'); % preprocessing of the mesh to get the missing fields +[cube2, detp2] = mmclab(newcfg); % initial simulation %% CW contour comparison figure(1); -[xi,yi] = meshgrid(0:60,0:60); +[xi, yi] = meshgrid(0:60, 0:60); slice = 30; node = cfg.node; elem = cfg.elem; -[cutpos,cutvalue,facedata] = qmeshcut(elem(:,1:4),node,cube1.data,[slice 0 0; slice 0 1; slice 1 0]); -vi=griddata(cutpos(:,2),cutpos(:,3),cutvalue,xi,yi); +[cutpos, cutvalue, facedata] = qmeshcut(elem(:, 1:4), node, cube1.data, [slice 0 0; slice 0 1; slice 1 0]); +vi = griddata(cutpos(:, 2), cutpos(:, 3), cutvalue, xi, yi); -[cutpos,cutvalue,facedata] = qmeshcut(elem(:,1:4),node,cube2.data,[slice 0 0; slice 0 1; slice 1 0]); -vi2=griddata(cutpos(:,2),cutpos(:,3),cutvalue,xi,yi); +[cutpos, cutvalue, facedata] = qmeshcut(elem(:, 1:4), node, cube2.data, [slice 0 0; slice 0 1; slice 1 0]); +vi2 = griddata(cutpos(:, 2), cutpos(:, 3), cutvalue, xi, yi); -contour(log10(abs(vi)),[1:0.5:8],'r:','LineWidth',1.5) -hold on -contour(log10(abs(vi2)),[1:0.5:8],'b','LineWidth',1.5) -grid on +contour(log10(abs(vi)), [1:0.5:8], 'r:', 'LineWidth', 1.5); +hold on; +contour(log10(abs(vi2)), [1:0.5:8], 'b', 'LineWidth', 1.5); +grid on; -xlabel('y(mm)','FontSize',20); -ylabel('z(mm)','FontSize',20); -title('plane x=30 mm','FontSize',20); -set(gca,'FontSize',20); +xlabel('y(mm)', 'FontSize', 20); +ylabel('z(mm)', 'FontSize', 20); +title('plane x=30 mm', 'FontSize', 20); +set(gca, 'FontSize', 20); -legend('albedo','mBLL'); +legend('albedo', 'mBLL'); %% detected weight comparison CW -mua=0.1; -mus=1; -mut=mua+mus; +mua = 0.1; +mus = 1; +mut = mua + mus; -w1 = detp1.w0.*(mus/mut).^double(detp1.nscat); -w2 = detp2.w0.*exp(-mua*double(detp2.ppath)); +w1 = detp1.w0 .* (mus / mut).^double(detp1.nscat); +w2 = detp2.w0 .* exp(-mua * double(detp2.ppath)); -abs(sum(w1)-sum(w2))/sum(w2) +abs(sum(w1) - sum(w2)) / sum(w2); %% detected weight comparison (TD) c0 = 3e11; n = 1; -cc = c0/n; +cc = c0 / n; nTG = 50; gate_width = 2e-11; -tpsf1 = zeros(nTG,1); -tpsf2 = zeros(nTG,1); +tpsf1 = zeros(nTG, 1); +tpsf2 = zeros(nTG, 1); for i = 1:length(detp1.ppath) - tg = floor(detp1.ppath(i)/cc/gate_width)+1; - tpsf1(tg) = tpsf1(tg)+w1(i); + tg = floor(detp1.ppath(i) / cc / gate_width) + 1; + tpsf1(tg) = tpsf1(tg) + w1(i); end for i = 1:length(detp2.ppath) - tg = floor(detp2.ppath(i)/cc/gate_width)+1; - tpsf2(tg) = tpsf2(tg)+w2(i); + tg = floor(detp2.ppath(i) / cc / gate_width) + 1; + tpsf2(tg) = tpsf2(tg) + w2(i); end %% weighted ppath and nscat comparison % scattering events -p1 = sum(double(detp1.nscat).*w1); -p1_ave = p1/length(detp1.nscat); -p2 = sum(double(detp2.nscat).*w2); -p2_ave = p2/length(detp2.nscat); +p1 = sum(double(detp1.nscat) .* w1); +p1_ave = p1 / length(detp1.nscat); +p2 = sum(double(detp2.nscat) .* w2); +p2_ave = p2 / length(detp2.nscat); % pathlength -L1 = sum(double(detp1.ppath).*w1); -L1_ave = L1/length(detp1.nscat); -L2 = sum(double(detp2.ppath).*w2); -L2_ave = L2/length(detp2.nscat); +L1 = sum(double(detp1.ppath) .* w1); +L1_ave = L1 / length(detp1.nscat); +L2 = sum(double(detp2.ppath) .* w2); +L2_ave = L2 / length(detp2.nscat); diff --git a/mmclab/mmc2json.m b/mmclab/mmc2json.m index 1849adb0..6a77a912 100644 --- a/mmclab/mmc2json.m +++ b/mmclab/mmc2json.m @@ -1,4 +1,4 @@ -function varargout = mmc2json(cfg,filestub, varargin) +function varargout = mmc2json(cfg, filestub, varargin) % % Format: % mmc2json(cfg,filestub) @@ -8,7 +8,7 @@ % 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 @@ % 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,86 +27,86 @@ % License: GNU General Public License version 3, please read LICENSE.txt for details % -singlefile = (nargin ==1 || ~isempty(regexp(filestub,'\.json$', 'once'))); +singlefile = (nargin == 1 || ~isempty(regexp(filestub, '\.json$', 'once'))); -if(nargin > 1) - [fpath, fname, fext]=fileparts(filestub); - filestub=fullfile(fpath,fname); +if (nargin > 1) + [fpath, fname, fext] = fileparts(filestub); + filestub = fullfile(fpath, fname); end %% 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,'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'); - -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); - 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, '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'); + +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); + if (length(Optode.Detector) == 1) + Optode.Detector = {Optode.Detector}; end end -if(isfield(cfg,'srcpattern') && ~isempty(cfg.srcpattern)) - Optode.Source.Pattern.Nx=size(cfg.srcpattern,1); - Optode.Source.Pattern.Ny=size(cfg.srcpattern,2); - Optode.Source.Pattern.Nz=size(cfg.srcpattern,3); - Optode.Source.Pattern.Data=single(cfg.srcpattern); - if(~singlefile) - Optode.Source.Pattern.Data=[filestub '_pattern.bin']; - fid=fopen(Optode.Source.Pattern.Data,'wb'); - fwrite(fid,cfg.srcpattern,'float32'); +if (isfield(cfg, 'srcpattern') && ~isempty(cfg.srcpattern)) + Optode.Source.Pattern.Nx = size(cfg.srcpattern, 1); + Optode.Source.Pattern.Ny = size(cfg.srcpattern, 2); + Optode.Source.Pattern.Nz = size(cfg.srcpattern, 3); + Optode.Source.Pattern.Data = single(cfg.srcpattern); + if (~singlefile) + Optode.Source.Pattern.Data = [filestub '_pattern.bin']; + fid = fopen(Optode.Source.Pattern.Data, 'wb'); + fwrite(fid, cfg.srcpattern, 'float32'); fclose(fid); end end %% define the domain and optical properties -Mesh=struct(); -Mesh=copycfg(cfg,'unitinmm',Mesh,'LengthUnit'); +Mesh = struct(); +Mesh = copycfg(cfg, 'unitinmm', Mesh, 'LengthUnit'); -if(isfield(cfg,'node') && ~isempty(cfg.node) && isfield(cfg,'elem') && ~isempty(cfg.elem)) - node=cfg.node; - elem=cfg.elem; - if(isfield(cfg,'elemprop') && size(elem,2)==4) - elem=[elem, cfg.elemprop]; +if (isfield(cfg, 'node') && ~isempty(cfg.node) && isfield(cfg, 'elem') && ~isempty(cfg.elem)) + node = cfg.node; + elem = cfg.elem; + if (isfield(cfg, 'elemprop') && size(elem, 2) == 4) + elem = [elem, cfg.elemprop]; end - if(~singlefile) - savemmcmesh(fname,node,elem); + if (~singlefile) + savemmcmesh(fname, node, elem); else - Mesh.MeshNode=single(node); - Mesh.MeshElem=uint32(elem); - if(isfield(cfg, 'edgeroi')) - Mesh.MeshROI=single(cfg.edgeroi); - elseif(isfield(cfg,'noderoi')) - Mesh.MeshROI=single(cfg.noderoi); - elseif(isfield(cfg,'faceroi')) - Mesh.MeshROI=single(cfg.faceroi); + Mesh.MeshNode = single(node); + Mesh.MeshElem = uint32(elem); + if (isfield(cfg, 'edgeroi')) + Mesh.MeshROI = single(cfg.edgeroi); + elseif (isfield(cfg, 'noderoi')) + Mesh.MeshROI = single(cfg.noderoi); + elseif (isfield(cfg, 'faceroi')) + Mesh.MeshROI = single(cfg.faceroi); end end - if(~isfield(cfg,'e0')) - cfg.e0=tsearchn(node,elem(:,1:4),cfg.srcpos); + if (~isfield(cfg, 'e0')) + cfg.e0 = tsearchn(node, elem(:, 1:4), cfg.srcpos); end - Mesh=copycfg(cfg,'e0',Mesh,'InitElem'); + Mesh = copycfg(cfg, 'e0', Mesh, 'InitElem'); else - Mesh.MeshID=fname; - warning('mesh is missing!') + Mesh.MeshID = fname; + warning('mesh is missing!'); end -Domain=struct(); -Domain=copycfg(cfg,'steps',Domain,'Step'); -if(isfield(cfg,'prop')) - prop=[(1:size(cfg.prop,1)-1)' cfg.prop(2:end,:)]; - if(~singlefile) - fid=fopen(['prop_',fname,'.dat'],'wt'); - fprintf(fid,'1 %d\n',size(prop,1)); - fprintf(fid,'%d %e %e %e %e\n',prop'); +Domain = struct(); +Domain = copycfg(cfg, 'steps', Domain, 'Step'); +if (isfield(cfg, 'prop')) + prop = [(1:size(cfg.prop, 1) - 1)' cfg.prop(2:end, :)]; + if (~singlefile) + fid = fopen(['prop_', fname, '.dat'], 'wt'); + fprintf(fid, '1 %d\n', size(prop, 1)); + fprintf(fid, '%d %e %e %e %e\n', prop'); fclose(fid); else Domain.Media = cell2struct(num2cell(cfg.prop), {'mua', 'mus', 'g', 'n'}, 2)'; @@ -117,74 +117,73 @@ %% define the simulation session flags -Session=struct(); -if(exist('fname', 'var')) - Session.ID=fname; +Session = struct(); +if (exist('fname', 'var')) + Session.ID = fname; else - Session.ID=inputname(1); + Session.ID = inputname(1); end -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,'ismomentum',Session,'DoDCS'); -Session=copycfg(cfg,'isspecular',Session,'DoSpecular'); -Session=copycfg(cfg,'outputformat',Session,'OutputFormat'); -Session=copycfg(cfg,'debuglevel',Session,'DebugFlag'); -Session=copycfg(cfg,'autopilot',Session,'DoAutoThread'); -Session=copycfg(cfg,'basisorder',Session,'BasisOrder'); - -if(isfield(cfg,'method')) - methodmap=struct('plucker', 'p', 'havel', 'h', 'badouel', 'b', 'elem', 's', 'grid', 'g'); - if(isfield(methodmap, cfg.method)) - Session.RayTracer=methodmap.(cfg.method); +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, 'ismomentum', Session, 'DoDCS'); +Session = copycfg(cfg, 'isspecular', Session, 'DoSpecular'); +Session = copycfg(cfg, 'outputformat', Session, 'OutputFormat'); +Session = copycfg(cfg, 'debuglevel', Session, 'DebugFlag'); +Session = copycfg(cfg, 'autopilot', Session, 'DoAutoThread'); +Session = copycfg(cfg, 'basisorder', Session, 'BasisOrder'); + +if (isfield(cfg, 'method')) + methodmap = struct('plucker', 'p', 'havel', 'h', 'badouel', 'b', 'elem', 's', 'grid', 'g'); + if (isfield(methodmap, cfg.method)) + Session.RayTracer = methodmap.(cfg.method); else - error('cfg.method is invalid') + error('cfg.method is invalid'); end end -if(isfield(cfg,'outputtype')) - outputtypemap=struct('flux', 'x', 'fluence', 'f', 'energy', 'e', 'jacobian', 'j', 'wl', 'l', 'wp', 'p'); - if(isfield(outputtypemap, cfg.outputtype)) - Session.OutputType=outputtypemap.(cfg.outputtype); +if (isfield(cfg, 'outputtype')) + outputtypemap = struct('flux', 'x', 'fluence', 'f', 'energy', 'e', 'jacobian', 'j', 'wl', 'l', 'wp', 'p'); + if (isfield(outputtypemap, cfg.outputtype)) + Session.OutputType = outputtypemap.(cfg.outputtype); else - error('cfg.outputtype is invalid') + error('cfg.outputtype is invalid'); end end -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,'rootpath',Session,'RootPath'); +Session = copycfg(cfg, 'nphoton', Session, 'Photons'); +% Session=copycfg(cfg,'rootpath',Session,'RootPath'); %% define the forward simulation settings -Forward.T0=cfg.tstart; -Forward.T1=cfg.tend; -Forward.Dt=cfg.tstep; -Forward=copycfg(cfg,'nout',Forward,'N0'); +Forward.T0 = cfg.tstart; +Forward.T1 = cfg.tend; +Forward.Dt = cfg.tstep; +Forward = copycfg(cfg, 'nout', Forward, 'N0'); %% assemble the complete input, save to a JSON or UBJSON input file -mmcsession=struct('Session', Session, 'Domain', Domain, 'Mesh', Mesh, 'Forward', Forward, 'Optode',Optode); +mmcsession = struct('Session', Session, 'Domain', Domain, 'Mesh', Mesh, 'Forward', Forward, 'Optode', Optode); -if(nargin == 1) - [varargout{1:nargout}] = savejson('',mmcsession, varargin{:}); -elseif(strcmp(fext,'ubj')) - [varargout{1:nargout}] = saveubjson('',mmcsession,'filename',[filestub,'.ubj'], varargin{:}); +if (nargin == 1) + [varargout{1:nargout}] = savejson('', mmcsession, varargin{:}); +elseif (strcmp(fext, 'ubj')) + [varargout{1:nargout}] = saveubjson('', mmcsession, 'filename', [filestub, '.ubj'], varargin{:}); else - [varargout{1:nargout}] = savejson('',mmcsession,'filename', [filestub,'.json'], varargin{:}); + [varargout{1:nargout}] = savejson('', mmcsession, 'filename', [filestub, '.json'], varargin{:}); 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/mmclab/mmclab.m b/mmclab/mmclab.m index 08b1fb9d..98f0dba6 100644 --- a/mmclab/mmclab.m +++ b/mmclab/mmclab.m @@ -1,23 +1,23 @@ -function varargout=mmclab(varargin) +function varargout = mmclab(varargin) % -%#############################################################################% +% #############################################################################% % Mesh-based Monte Carlo (MMC) - OpenCL % % Copyright (c) 2010-2024 Qianqian Fang % % https://mcx.space/#mmc & https://neurojson.io/ % % % -%Computational Optics & Translational Imaging (COTI) Lab [http://fanglab.org]% +% Computational Optics & Translational Imaging (COTI) Lab [http://fanglab.org]% % Department of Bioengineering, Northeastern University, Boston, MA, USA % -%#############################################################################% +% #############################################################################% % The MCX Project is funded by the NIH/NIGMS under grant R01-GM114365 % -%#############################################################################% +% #############################################################################% % Open-source codes and reusable scientific data are essential for research, % % MCX proudly developed human-readable JSON-based data formats for easy reuse.% % % -%Please visit our free scientific data sharing portal at https://neurojson.io/% +% Please visit our free scientific data sharing portal at https://neurojson.io/% % and consider sharing your public datasets in standardized JSON/JData format % -%#############################################################################% -%$Rev:: $v2024.2$Date:: $ by $Author::Qianqian Fang% -%#############################################################################% +% #############################################################################% +% $Rev:: $v2024.2$Date:: $ by $Author::Qianqian Fang% +% #############################################################################% % % Format: % [fluence,detphoton,ncfg,seeds,traj]=mmclab(cfg); @@ -27,8 +27,8 @@ % [fluence,detphoton,ncfg,seeds,traj]=mmclab(cfg, options); % % Input: -% cfg: a struct, or struct array. Each element in cfg defines -% a set of parameters for a simulation. +% cfg: a struct, or struct array. Each element in cfg defines +% a set of parameters for a simulation. % % option: (optional), options is a string, specifying additional options % option='preview': this plots the domain configuration using mcxpreview(cfg) @@ -38,10 +38,10 @@ % % cfg may contain the following fields: % -%== Required == +% == Required == % *cfg.nphoton: the total number of photons to be simulated (integer) % *cfg.prop: an N by 4 array, each row specifies [mua, mus, g, n] in order. -% the first row corresponds to medium type 0 which is +% the first row corresponds to medium type 0 which is % typically [0 0 1 1]. The second row is type 1, and so on. % *cfg.node: node array for the input tetrahedral mesh, 3 columns: (x,y,z) % *cfg.elem: element array for the input tetrahedral mesh, 4 columns @@ -52,17 +52,17 @@ % *cfg.srcpos: a 1 by 3 vector, the position of the source in mesh node length unit % *cfg.srcdir: if defined as [vx, vy, vy], it specifies the incident vector % if defined as [vx, vy, vy, focus], the first 3 elements define -% the incident vector; focus controls the convergence or +% the incident vector; focus controls the convergence or % divergence of the beam: % focus=0: collimated beam % focus<0: diverging beam from an imaginary src at c0-|focus|*[vx vy vz] % focus>0: converging beam, focusing to a point at c0+|focus|*[vx vy vz] -% where c0 is the centroid of the source domain. Setting focus does +% where c0 is the centroid of the source domain. Setting focus does % not impact pencil/isotropic/cone sources. % -%== MC simulation settings == +% == MC simulation settings == % cfg.seed: seed for the random number generator (integer) -% 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), default value: 1648335518 % cfg.isreflect: [1]-consider refractive index mismatch, 0-matched index % 2 - total absorption on exterior surface @@ -71,7 +71,7 @@ % cfg.isspecular: [1]-calculate specular reflection if source is outside % cfg.ismomentum: [0]-save momentum transfer for each detected photon % cfg.method: ray-tracing method, ["plucker"]:Plucker, "havel": Havel (SSE4), -% "badouel": partial Badouel, "elem": branchless Badouel (SSE), +% "badouel": partial Badouel, "elem": branchless Badouel (SSE), % "grid": dual-grid MMC % cfg.mcmethod: 0 use MCX-styled MC method, 1 use MCML style MC % cfg.nout: [1.0] refractive index for medium type 0 (background) @@ -80,33 +80,33 @@ % cfg.steps: [dx, dy, dz], defines the DMMC grid voxel size, % must be isostropic, i.e. dx=dy=dz, only used when % cfg.method = 'grid', by default dx=dy=dz=1 -% cfg.unitinmm: defines the default length unit (to interpret mesh nodes, src/det positions -% the default value is 1.0 (mm). For example, if the mesh node length unit is +% cfg.unitinmm: defines the default length unit (to interpret mesh nodes, src/det positions +% the default value is 1.0 (mm). For example, if the mesh node length unit is % in cm, one should set unitinmm to 10. % cfg.basisorder: [1]-linear basis, 0-piece-wise constant basis % -%== 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} % 'pencil' - default, pencil beam, no param needed % 'isotropic' - isotropic source, no param needed % 'cone' - uniform cone beam, srcparam1(1) is the half-angle in radian -% 'gaussian' - a gaussian beam, srcparam1(1) specifies the waist radius +% 'gaussian' - a gaussian beam, srcparam1(1) specifies the waist radius % (in default length unit); if one specifies a non-zero focal length -% using cfg.srcdir, the gaussian beam can be converging to or +% using cfg.srcdir, the gaussian beam can be converging to or % diverging from the waist center, which is located at srcpos+focus*srcdir; -% optionally, one can specify the wavelength lambda (in cfg.unitinmm mm), -% using srcparam1(2). This will rescale the Gaussian profile according -% to w(z)=w0*sqrt(1-(z/z0)^2), where w0 is the waist radius, z is the -% distance (in mm) to the waist center (focus), and z0 is the Rayleigh +% optionally, one can specify the wavelength lambda (in cfg.unitinmm mm), +% using srcparam1(2). This will rescale the Gaussian profile according +% to w(z)=w0*sqrt(1-(z/z0)^2), where w0 is the waist radius, z is the +% distance (in mm) to the waist center (focus), and z0 is the Rayleigh % range (in mm), and z0 is related to w0 by z0=w0^2*pi/lambda -% '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: % 'fourier' - spatial frequency domain source, similar to 'planar', except @@ -117,16 +117,16 @@ % 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 default length unit) -% '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 % 'fourierx2d' - a general 2D Fourier basis, parameters % 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 +% 'zgaussian' - an angular gaussian beam, srcparam1(1) specifies the variance in % the zenith angle % cfg.{srcparam1,srcparam2}: 1x4 vectors, see cfg.srctype for details % cfg.srcpattern: see cfg.srctype for details @@ -144,7 +144,7 @@ % if the mesh coordinates/source positions are not in mm unit, one needs to define % cfg.unitinmm (in mm) to specify the actual length unit. % -%== Optional mesh data == +% == Optional mesh data == % -cfg.facenb: element face neighbohood list (calculated by faceneighbors()) % -cfg.evol: element volume (calculated by elemvolume() with iso2mesh) % -cfg.e0: the element ID enclosing the source, if not defined, @@ -156,7 +156,7 @@ % '<': search along the backward direction % '-': search both directions % -%== Output control == +% == Output control == % cfg.issaveexit: [0]-save the position (x,y,z) and (vx,vy,vz) for a detected photon % cfg.issaveref: [0]-save diffuse reflectance/transmittance on the exterior surfaces. % The output is stored as flux.dref in a 2D array of size [#Nf, #time_gate] @@ -168,8 +168,8 @@ % cfg.issaveseed: [0]-save the RNG seed for a detected photon so one can replay % cfg.isatomic: [1]-use atomic operations for saving fluence, 0-no atomic operations % cfg.outputtype: 'flux' - output fluence-rate -% 'fluence' - fluence, -% 'energy' - energy deposit, +% 'fluence' - fluence, +% 'energy' - energy deposit, % 'jacobian' - mua Jacobian (replay mode) % 'wl'- weighted path lengths to build mua Jacobian (replay mode) % 'wp'- weighted scattering counts to build mus Jacobian (replay mode) @@ -184,15 +184,15 @@ % % % type: omit or 'omp' for multi-threading version; 'sse' for the SSE4 MMC, -% the SSE4 version is about 25% faster, but requires newer CPUs; +% the SSE4 version is about 25% faster, but requires newer CPUs; % if type='prep' with a single output, mmclab returns ncfg only. % % Output: % fluence: a struct array, with a length equals to that of cfg. % For each element of fluence, fluence(i).data is a 2D array with % dimensions [size(cfg.node,1), total-time-gates] if cfg.basisorder=1, -% or [size(cfg.elem,1), total-time-gates] if cfg.basisorder=0. -% The content of the array is the normalized fluence-rate (or others +% or [size(cfg.elem,1), total-time-gates] if cfg.basisorder=0. +% The content of the array is the normalized fluence-rate (or others % depending on cfg.outputtype) at each mesh node and time-gate. % % If cfg.issaveref is set to 1, fluence(i).dref is not empty, and stores @@ -255,225 +255,224 @@ % try - defaultocl=evalin('base','USE_MCXCL'); + defaultocl = evalin('base', 'USE_MCXCL'); catch - defaultocl=1; + defaultocl = 1; end -useopencl=defaultocl; +useopencl = defaultocl; -if(nargin==2 && ischar(varargin{2})) - if(strcmp(varargin{2},'preview') || strcmp(varargin{2},'prep') || strcmp(varargin{2},'cuda')) - useopencl=0; +if (nargin == 2 && ischar(varargin{2})) + if (strcmp(varargin{2}, 'preview') || strcmp(varargin{2}, 'prep') || strcmp(varargin{2}, 'cuda')) + useopencl = 0; end end -if(isstruct(varargin{1})) - for i=1:length(varargin{1}) - castlist={'srcpattern','srcpos','detpos','prop','workload','srcdir'}; - 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'}; + 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 end end -if(nargin==1 && ischar(varargin{1}) && strcmp(varargin{1},'gpuinfo')) - varargout{1}=mmc('gpuinfo'); - return; +if (nargin == 1 && ischar(varargin{1}) && strcmp(varargin{1}, 'gpuinfo')) + varargout{1} = mmc('gpuinfo'); + return end -if(nargin==0) - return; +if (nargin == 0) + return end -cfg=varargin{1}; -if(length(varargin)>=2) - type=varargin{2}; +cfg = varargin{1}; +if (length(varargin) >= 2) + type = varargin{2}; end - -if(~isstruct(cfg)) + +if (~isstruct(cfg)) error('cfg must be a struct or struct array'); end -len=length(cfg); -for i=1:len - if(~isfield(cfg(i),'node') || ~isfield(cfg(i),'elem')) +len = length(cfg); +for i = 1:len + if (~isfield(cfg(i), 'node') || ~isfield(cfg(i), 'elem')) error('cfg.node or cfg.elem is missing'); end - if(size(cfg(i).elem,2)>4) - cfg(i).elemprop=cfg(i).elem(:,5); + if (size(cfg(i).elem, 2) > 4) + cfg(i).elemprop = cfg(i).elem(:, 5); end - if(~isfield(cfg(i),'isreoriented') || isempty(cfg(i).isreoriented) || cfg(i).isreoriented==0) - if(isfield(cfg(i),'edgeroi') || isfield(cfg(i),'faceroi')) - [cfg(i).elem, evol, idx]=meshreorient(cfg(i).node,cfg(i).elem(:,1:4)); - else - [cfg(i).elem, evol]=meshreorient(cfg(i).node,cfg(i).elem(:,1:4)); - end - if(isfield(cfg(i),'edgeroi')) - cfg(i).edgeroi(idx,:)=cfg(i).edgeroi(idx,[1 3 2 5 4 6]); - end - if(isfield(cfg(i),'faceroi')) - cfg(i).faceroi(idx,:)=cfg(i).faceroi(idx,[2 1 3 4]); - end - cfg(i).isreoriented=1; + if (~isfield(cfg(i), 'isreoriented') || isempty(cfg(i).isreoriented) || cfg(i).isreoriented == 0) + if (isfield(cfg(i), 'edgeroi') || isfield(cfg(i), 'faceroi')) + [cfg(i).elem, evol, idx] = meshreorient(cfg(i).node, cfg(i).elem(:, 1:4)); + else + [cfg(i).elem, evol] = meshreorient(cfg(i).node, cfg(i).elem(:, 1:4)); + end + if (isfield(cfg(i), 'edgeroi')) + cfg(i).edgeroi(idx, :) = cfg(i).edgeroi(idx, [1 3 2 5 4 6]); + end + if (isfield(cfg(i), 'faceroi')) + cfg(i).faceroi(idx, :) = cfg(i).faceroi(idx, [2 1 3 4]); + end + cfg(i).isreoriented = 1; end - if(~isfield(cfg(i),'facenb') || isempty(cfg(i).facenb)) - cfg(i).facenb=faceneighbors(cfg(i).elem); + if (~isfield(cfg(i), 'facenb') || isempty(cfg(i).facenb)) + cfg(i).facenb = faceneighbors(cfg(i).elem); end - if(~isfield(cfg(i),'evol') || isempty(cfg(i).evol)) - cfg(i).evol=elemvolume(cfg(i).node,cfg(i).elem); + if (~isfield(cfg(i), 'evol') || isempty(cfg(i).evol)) + cfg(i).evol = elemvolume(cfg(i).node, cfg(i).elem); end - if(find(cfg(i).evol==0)) - fprintf(1,['degenerated elements are detected: [' sprintf('%d ',find(cfg(i).evol==0)) ']\n']); + if (find(cfg(i).evol == 0)) + fprintf(1, ['degenerated elements are detected: [' sprintf('%d ', find(cfg(i).evol == 0)) ']\n']); error(['input mesh can not contain degenerated elements, ' ... - 'please double check your input mesh; if you use a ' ... - 'widefield source, please rerun mmcsrcdomain and setting ' ... - '''Expansion'' option to a larger value (default is 1)']); + 'please double check your input mesh; if you use a ' ... + 'widefield source, please rerun mmcsrcdomain and setting ' ... + '''Expansion'' option to a larger value (default is 1)']); end - if(~isfield(cfg(i),'srcpos')) + if (~isfield(cfg(i), 'srcpos')) error('cfg.srcpos field is missing'); end - if(~isfield(cfg(i),'srcdir')) + if (~isfield(cfg(i), 'srcdir')) error('cfg.srcdir field is missing'); end - if(~isfield(cfg(i),'e0') || isempty(cfg(i).e0)) - cfg(i).e0=tsearchn(cfg(i).node,cfg(i).elem,cfg(i).srcpos); + if (~isfield(cfg(i), 'e0') || isempty(cfg(i).e0)) + cfg(i).e0 = tsearchn(cfg(i).node, cfg(i).elem, cfg(i).srcpos); end - if((isnan(cfg(i).e0) && (isfield(cfg(i),'srctype') ... - && strcmp(cfg(i).srctype,'pencil')) )|| ischar(cfg(i).e0)) + if ((isnan(cfg(i).e0) && (isfield(cfg(i), 'srctype') && strcmp(cfg(i).srctype, 'pencil'))) || ischar(cfg(i).e0)) disp('searching initial element ...'); - [cfg(i).srcpos,cfg(i).e0]=mmcraytrace(cfg(i).node,cfg(i).elem,cfg(i).srcpos,cfg(i).srcdir,cfg(i).e0); + [cfg(i).srcpos, cfg(i).e0] = mmcraytrace(cfg(i).node, cfg(i).elem, cfg(i).srcpos, cfg(i).srcdir, cfg(i).e0); end - if((isfield(cfg(i),'srctype') && strcmp(cfg(i).srctype,'pattern')) && (ndims(cfg(i).srcpattern)==2)) - cfg(i).srcpattern=reshape(cfg(i).srcpattern,... - size(cfg(i).srcpattern,1),size(cfg(i).srcpattern,2),1); + if ((isfield(cfg(i), 'srctype') && strcmp(cfg(i).srctype, 'pattern')) && (ndims(cfg(i).srcpattern) == 2)) + cfg(i).srcpattern = reshape(cfg(i).srcpattern, ... + size(cfg(i).srcpattern, 1), size(cfg(i).srcpattern, 2), 1); end - if(isnan(cfg(i).e0)) % widefield source - if(~isfield(cfg(i),'srcparam1') || ~isfield(cfg(i),'srcparam2')) + if (isnan(cfg(i).e0)) % widefield source + if (~isfield(cfg(i), 'srcparam1') || ~isfield(cfg(i), 'srcparam2')) error('for wide-field sources, you must provide srcparam1 and srcparam2'); end - if(~isfield(cfg(i),'srctype')) - cfg(i).srctype='pencil'; + if (~isfield(cfg(i), 'srctype')) + cfg(i).srctype = 'pencil'; end - srcdef=struct('srctype',cfg.srctype,'srcpos',cfg.srcpos,'srcdir',cfg.srcdir,... - 'srcparam1',cfg.srcparam1,'srcparam2',cfg.srcparam2); - sdom=mmcsrcdomain(srcdef,[min(cfg.node);max(cfg.node)]); - isinside=ismember(round(sdom*1e10)*1e-10,round(cfg(i).node*1e10)*1e-10,'rows'); - if(all(~isinside)) - if(size(cfg(i).elem,2)==4) - cfg(i).elem(:,5)=1; + srcdef = struct('srctype', cfg.srctype, 'srcpos', cfg.srcpos, 'srcdir', cfg.srcdir, ... + 'srcparam1', cfg.srcparam1, 'srcparam2', cfg.srcparam2); + sdom = mmcsrcdomain(srcdef, [min(cfg.node); max(cfg.node)]); + isinside = ismember(round(sdom * 1e10) * 1e-10, round(cfg(i).node * 1e10) * 1e-10, 'rows'); + if (all(~isinside)) + if (size(cfg(i).elem, 2) == 4) + cfg(i).elem(:, 5) = 1; end - [cfg(i).node,cfg(i).elem] = mmcaddsrc(cfg(i).node,cfg(i).elem,sdom); - cfg(i).elemprop=cfg(i).elem(:,5); - if(isfield(cfg(i),'edgeroi') || isfield(cfg(i),'faceroi')) - [cfg(i).elem, evol, idx]=meshreorient(cfg(i).node,cfg(i).elem(:,1:4)); + [cfg(i).node, cfg(i).elem] = mmcaddsrc(cfg(i).node, cfg(i).elem, sdom); + cfg(i).elemprop = cfg(i).elem(:, 5); + if (isfield(cfg(i), 'edgeroi') || isfield(cfg(i), 'faceroi')) + [cfg(i).elem, evol, idx] = meshreorient(cfg(i).node, cfg(i).elem(:, 1:4)); else - [cfg(i).elem, evol]=meshreorient(cfg(i).node,cfg(i).elem(:,1:4)); + [cfg(i).elem, evol] = meshreorient(cfg(i).node, cfg(i).elem(:, 1:4)); end - if(isfield(cfg(i),'edgeroi')) - cfg(i).edgeroi(idx,:)=cfg(i).edgeroi(idx,[1 3 2 5 4 6]); + if (isfield(cfg(i), 'edgeroi')) + cfg(i).edgeroi(idx, :) = cfg(i).edgeroi(idx, [1 3 2 5 4 6]); end - if(isfield(cfg(i),'faceroi')) - cfg(i).faceroi(idx,:)=cfg(i).faceroi(idx,[2 1 3 4]); + if (isfield(cfg(i), 'faceroi')) + cfg(i).faceroi(idx, :) = cfg(i).faceroi(idx, [2 1 3 4]); end - cfg(i).facenb=faceneighbors(cfg(i).elem); - cfg(i).evol=elemvolume(cfg(i).node,cfg(i).elem); - cfg(i).isreoriented=1; + cfg(i).facenb = faceneighbors(cfg(i).elem); + cfg(i).evol = elemvolume(cfg(i).node, cfg(i).elem); + cfg(i).isreoriented = 1; end - if(strcmp(cfg(i).srctype,'pencil') || strcmp(cfg(i).srctype,'isotropic') ... - || strcmp(cfg(i).srctype,'cone') || strcmp(cfg(i).srctype,'zgaussian')) - cfg(i).e0=tsearchn(cfg(i).node,cfg(i).elem,cfg(i).srcpos); - if(isnan(cfg(i).e0)) - cfg(i).e0=-1; + if (strcmp(cfg(i).srctype, 'pencil') || strcmp(cfg(i).srctype, 'isotropic') || ... + strcmp(cfg(i).srctype, 'cone') || strcmp(cfg(i).srctype, 'zgaussian')) + cfg(i).e0 = tsearchn(cfg(i).node, cfg(i).elem, cfg(i).srcpos); + if (isnan(cfg(i).e0)) + cfg(i).e0 = -1; end - elseif(length(find(cfg(i).elemprop<0))==1) - cfg(i).e0=find(cfg(i).elemprop<0); + elseif (length(find(cfg(i).elemprop < 0)) == 1) + cfg(i).e0 = find(cfg(i).elemprop < 0); else - cfg(i).e0=-1; + cfg(i).e0 = -1; end end - if(~isfield(cfg(i),'elemprop')) + if (~isfield(cfg(i), 'elemprop')) error('cfg.elemprop field is missing'); end - if(~isfield(cfg(i),'nphoton')) + if (~isfield(cfg(i), 'nphoton')) error('cfg.nphoton field is missing'); end - if(~isfield(cfg(i),'prop') || size(cfg(i).prop,1)=3) - mmcout=nargout-1; - varargout{nargout}=cfg; +mmcout = nargout; +if (nargout >= 3) + mmcout = nargout - 1; + varargout{nargout} = cfg; end -if(useopencl==1) - for i=1:length(cfg) - if(isfield(cfg(i),'gpuid') && ~ischar(cfg(i).gpuid) && cfg(i).gpuid<-1) - cfg(i).gpuid=1; +if (useopencl == 1) + for i = 1:length(cfg) + if (isfield(cfg(i), 'gpuid') && ~ischar(cfg(i).gpuid) && cfg(i).gpuid < -1) + cfg(i).gpuid = 1; end end - [varargout{1:mmcout}]=mmc(cfg); -elseif(length(varargin)<2) - [varargout{1:mmcout}]=mmc(cfg); -elseif(strcmp(type,'omp')) - [varargout{1:mmcout}]=mmc(cfg); -elseif(strcmp(type,'sse')) - [varargout{1:mmcout}]=mmc_sse(cfg); -elseif(strcmp(type,'prep') && nargout==1) - varargout{1}=cfg; -elseif(strcmp(type,'preview') && nargout==1) - varargout{1}=mcxpreview(cfg); + [varargout{1:mmcout}] = mmc(cfg); +elseif (length(varargin) < 2) + [varargout{1:mmcout}] = mmc(cfg); +elseif (strcmp(type, 'omp')) + [varargout{1:mmcout}] = mmc(cfg); +elseif (strcmp(type, 'sse')) + [varargout{1:mmcout}] = mmc_sse(cfg); +elseif (strcmp(type, 'prep') && nargout == 1) + varargout{1} = cfg; +elseif (strcmp(type, 'preview') && nargout == 1) + varargout{1} = mcxpreview(cfg); else error('type is not recognized'); end -if(mmcout>=2) - for i=1:length(varargout{2}) - 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 (mmcout >= 2) + for i = 1:length(varargout{2}) + 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 - newdetp.detid=int32(detp(1,:))'; - newdetp.nscat=int32(detp(2:medianum+1,:))'; % 1st medianum block is num of scattering - newdetp.ppath=detp(medianum+2:2*medianum+1,:)';% 2nd medianum block is partial path - if(isfield(cfg(i),'ismomentum') && cfg(i).ismomentum) - newdetp.mom=detp(2*medianum+2:3*medianum+1,:)'; % 3rd medianum block is the momentum transfer + newdetp.detid = int32(detp(1, :))'; + newdetp.nscat = int32(detp(2:medianum + 1, :))'; % 1st medianum block is num of scattering + newdetp.ppath = detp(medianum + 2:2 * medianum + 1, :)'; % 2nd medianum block is partial path + if (isfield(cfg(i), 'ismomentum') && cfg(i).ismomentum) + newdetp.mom = detp(2 * medianum + 2:3 * medianum + 1, :)'; % 3rd medianum block is the momentum transfer end - if(isfield(cfg(i),'issaveexit') && cfg(i).issaveexit) - newdetp.p=detp(end-6:end-4,:)'; %columns 7-5 from the right store the exit positions*/ - newdetp.v=detp(end-3:end-1,:)'; %columns 4-2 from the right store the exit dirs*/ + if (isfield(cfg(i), 'issaveexit') && cfg(i).issaveexit) + newdetp.p = detp(end - 6:end - 4, :)'; % columns 7-5 from the right store the exit positions*/ + newdetp.v = detp(end - 3:end - 1, :)'; % columns 4-2 from the right store the exit dirs*/ end - newdetp.w0=detp(end,:)'; % last column is the initial packet weight - newdetp.prop=cfg(i).prop; - if(isfield(cfg(i),'unitinmm')) - newdetp.unitinmm=cfg(i).unitinmm; + newdetp.w0 = detp(end, :)'; % last column is the initial packet weight + newdetp.prop = cfg(i).prop; + 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 @@ -496,6 +495,6 @@ end end -if(nargout>=4) - [varargout{3:end}]=deal(varargout{[end 3:end-1]}); +if (nargout >= 4) + [varargout{3:end}] = deal(varargout{[end 3:end - 1]}); end diff --git a/src/buildmmc.m b/src/buildmmc.m index 3b40762b..19d7c0fa 100644 --- a/src/buildmmc.m +++ b/src/buildmmc.m @@ -3,8 +3,8 @@ function buildmmc(varargin) % Format: % buildmmc or buildmmc('option1',value1,'option2',value2,...) % -% Compiling script for mmclab mex file in MATLAB and GNU Octave. -% If compiled successfully, the output mex file can be found in the +% Compiling script for mmclab mex file in MATLAB and GNU Octave. +% If compiled successfully, the output mex file can be found in the % mmc/mmclab folder (or ../mmclab using relative path from mmc/src) % % Author: Qianqian Fang @@ -12,7 +12,7 @@ function buildmmc(varargin) % Input: % options: without any option, this script compiles mmc.mex* using % default settings. Supported options include -% 'include': a string made of sequences of ' -I"/folder/path" ' that +% 'include': a string made of sequences of ' -I"/folder/path" ' that % can be included for compilation (format similar to the -I % option for gcc) % 'lib': a string made of sequences of ' -L"/folder/path" ' and ' @@ -22,8 +22,8 @@ function buildmmc(varargin) % % Dependency (Windows only): % 1.If you have MATLAB R2017b or later, you may skip this step. -% To compile mmclab in MATLAB R2017a or earlier on Windows, you must -% pre-install the MATLAB support for MinGW-w64 compiler +% To compile mmclab in MATLAB R2017a or earlier on Windows, you must +% pre-install the MATLAB support for MinGW-w64 compiler % https://www.mathworks.com/matlabcentral/fileexchange/52848-matlab-support-for-mingw-w64-c-c-compiler % % Note: it appears that installing the above Add On is no longer working @@ -39,8 +39,8 @@ function buildmmc(varargin) % % setenv('MW_MINGW64_LOC','C:\msys64\usr'); % -% 2.After installation of MATLAB MinGW support, you must type -% "mex -setup C" in MATLAB and select "MinGW64 Compiler (C)". +% 2.After installation of MATLAB MinGW support, you must type +% "mex -setup C" in MATLAB and select "MinGW64 Compiler (C)". % 3.Once you select the MingW C compiler, you should run "mex -setup C++" % again in MATLAB and select "MinGW64 Compiler (C++)" to compile C++. % 4.File C:\Windows\System32\OpenCL.dll must exist. You can obtain this @@ -53,72 +53,72 @@ function buildmmc(varargin) % cd(fileparts(which(mfilename))); -if(nargin==1 && strcmp(varargin{1},'clean')) - if(~isempty(dir('*.o'))) - delete('*.o'); +if (nargin == 1 && strcmp(varargin{1}, 'clean')) + if (~isempty(dir('*.o'))) + delete('*.o'); end - return; + return end -opt=struct(varargin{:}); -pname='mmc'; +opt = struct(varargin{:}); +pname = 'mmc'; clsource = fileread('mmc_core.cl'); clsrc = sprintf('0x%02x, ', char(clsource)); -clhex = ['unsigned char mmc_core_cl[] = {' sprintf('\n') clsrc(1:end-2) sprintf('\n') ... - sprintf('};\nunsigned int mmc_core_cl_len = %d;\n', length(clsource))]; +clhex = ['unsigned char mmc_core_cl[] = {' sprintf('\n') clsrc(1:end - 2) sprintf('\n') ... + sprintf('};\nunsigned int mmc_core_cl_len = %d;\n', length(clsource))]; -fp=fopen('mmc_core.clh','wb'); +fp = fopen('mmc_core.clh', 'wb'); fwrite(fp, clhex, 'char'); fclose(fp); -cflags='-c -Wall -g -DMCX_EMBED_CL -fno-strict-aliasing -m64 -DMMC_USE_SSE -DHAVE_SSE2 -msse -msse2 -msse3 -mssse3 -msse4.1 -O3 -fopenmp -DUSE_OS_TIMER -DUSE_OPENCL -DMCX_CONTAINER'; +cflags = '-c -Wall -g -DMCX_EMBED_CL -fno-strict-aliasing -m64 -DMMC_USE_SSE -DHAVE_SSE2 -msse -msse2 -msse3 -mssse3 -msse4.1 -O3 -fopenmp -DUSE_OS_TIMER -DUSE_OPENCL -DMCX_CONTAINER'; -filelist={'mmc_rand_xorshift128p.c','mmc_mesh.c','mmc_raytrace.c',... - 'mmc_utils.c','mmc_tictoc.c','mmc_host.c',... - 'mmc_highorder.cpp','mmc_cl_utils.c','mmc_cl_host.c','mmclab.cpp'}; -if(isfield(opt,'filelist')) - filelist=opt.filelist; +filelist = {'mmc_rand_xorshift128p.c', 'mmc_mesh.c', 'mmc_raytrace.c', ... + 'mmc_utils.c', 'mmc_tictoc.c', 'mmc_host.c', ... + 'mmc_highorder.cpp', 'mmc_cl_utils.c', 'mmc_cl_host.c', 'mmclab.cpp'}; +if (isfield(opt, 'filelist')) + filelist = opt.filelist; end -if(isfield(opt,'include')) - cflags=[cflags ' ' opt.include]; +if (isfield(opt, 'include')) + cflags = [cflags ' ' opt.include]; end -if(ispc) - linkflags='$LINKLIBS -fopenmp -lstdc++ -static'; - cflags=[cflags ' -I./mingw64/include -I"$MINGWROOT/opt/include"']; - linkflags=[linkflags ' ''C:\Windows\System32\OpenCL.dll'' ']; - linkvar='LINKLIBS'; +if (ispc) + linkflags = '$LINKLIBS -fopenmp -lstdc++ -static'; + cflags = [cflags ' -I./mingw64/include -I"$MINGWROOT/opt/include"']; + linkflags = [linkflags ' ''C:\Windows\System32\OpenCL.dll'' ']; + linkvar = 'LINKLIBS'; else - linkflags='\$LINKLIBS -fopenmp -static-libgcc -static-libstdc++'; - cflags=[cflags ' -fPIC ']; - linkflags=[linkflags ' -lOpenCL ']; - linkvar='LINKLIBS'; + linkflags = '\$LINKLIBS -fopenmp -static-libgcc -static-libstdc++'; + cflags = [cflags ' -fPIC ']; + linkflags = [linkflags ' -lOpenCL ']; + linkvar = 'LINKLIBS'; end -if(~exist('OCTAVE_VERSION','builtin')) - for i=1:length(filelist) - flag='CFLAGS'; - if(regexp(filelist{i},'\.[Cc][Pp][Pp]$')) - flag='CXXFLAGS'; +if (~exist('OCTAVE_VERSION', 'builtin')) + for i = 1:length(filelist) + flag = 'CFLAGS'; + if (regexp(filelist{i}, '\.[Cc][Pp][Pp]$')) + flag = 'CXXFLAGS'; end - disp(sprintf('mex OBJEXT=.o %s=''%s'' -c ''%s'' ',flag,cflags,filelist{i})); - eval(sprintf('mex OBJEXT=.o %s=''%s'' -c ''%s'' ',flag,cflags,filelist{i})); + disp(sprintf('mex OBJEXT=.o %s=''%s'' -c ''%s'' ', flag, cflags, filelist{i})); + eval(sprintf('mex OBJEXT=.o %s=''%s'' -c ''%s'' ', flag, cflags, filelist{i})); end - if(isfield(opt,'lib')) - linkflags=[linkflags ' ' opt.lib]; + if (isfield(opt, 'lib')) + linkflags = [linkflags ' ' opt.lib]; end - fn=dir('*.o'); - fprintf(1, 'mex %s -output %s -outdir ../%slab %s=''%s''\n',strjoin({fn.name}),pname,pname,linkvar,linkflags); - eval(sprintf('mex %s -output %s -outdir ../%slab %s=''%s'' ',strjoin({fn.name}),pname,pname,linkvar,linkflags)); + fn = dir('*.o'); + fprintf(1, 'mex %s -output %s -outdir ../%slab %s=''%s''\n', strjoin({fn.name}), pname, pname, linkvar, linkflags); + eval(sprintf('mex %s -output %s -outdir ../%slab %s=''%s'' ', strjoin({fn.name}), pname, pname, linkvar, linkflags)); else - linkflags=regexprep(linkflags,['[\\]*\$' linkvar],''); - for i=1:length(filelist) - cmd=sprintf('mex %s -c ''%s'' ',cflags,filelist{i}); - fprintf(stdout,'%s\n',cmd); - fflush(stdout); + linkflags = regexprep(linkflags, ['[\\]*\$' linkvar], ''); + for i = 1:length(filelist) + cmd = sprintf('mex %s -c ''%s'' ', cflags, filelist{i}); + fprintf(stdout, '%s\n', cmd); + fflush(stdout); eval(cmd); end - fn=dir('*.o'); - cmd=sprintf('mex %s -o ../%slab/%s %s ',strjoin({fn.name}),pname,pname,linkflags); - fprintf(1,'%s\n',cmd); + fn = dir('*.o'); + cmd = sprintf('mex %s -o ../%slab/%s %s ', strjoin({fn.name}), pname, pname, linkflags); + fprintf(1, '%s\n', cmd); fflush(1); eval(cmd); end