Unit conversion for ‘flux’ output

49 views
Skip to first unread message

Jinze Li

unread,
Dec 22, 2025, 12:46:57 PM12/22/25
to mcx-users
Dear Dr. Fang,
I recently started using MCX and had a few fundamental questions.

I want to use MCXLAB to simulate a 20mW uniform continuous light source illuminating a simplified biological tissue model, observing its light distribution and attenuation curve. However, when normalized, I observe that the magnitude of the output flux results is extremely large (approximately 10^8). Reviewing other posts, I see the default flux unit is 1/mm²/s. How should I modify my code to ensure the output flux corresponds to my 20mW light source and is converted to the unit mW/cm²?

Here is my code.

%% MCXLAB模型仿真
clear; clc; close all;
addpath('D:\mcxlab');
addpath('D:\mcxlab\matlab');
%% 1. 基本仿真参数
cfg.nphoton = 5e7;
cfg.tstart = 0;
cfg.tend = 5e-9;
cfg.tstep = 5e-9;
cfg.unitinmm = 0.01;
cfg.autopilot = 1;
cfg.gpuid = 1;
cfg.outputtype = 'flux';
%% 2. 体素模型 200×200×255
dimx = 200; dimy = 200; dimz = 255;
cfg.vol = zeros(dimx, dimy, dimz, 'uint8');
cfg.vol(:,:, 1:30) = 1; % 0.00–0.30 mm Scalp
cfg.vol(:,:,31:55) = 2; % 0.30–0.55 mm Skull
cfg.vol(:,:,56:155) = 3; % 0.55–1.55 mm CSF + Cortex
cfg.vol(:,:,156:255) = 4; % 1.55–2.55 mm Deep brain
%% 3. 光学参数(单位 mm⁻¹)
cfg.prop = [
0 0 1 1; % 0: 空气(外部)
0.018, 19.0, 0.9, 1.37; % 1: Scalp
0.016, 16.0, 0.9, 1.43; % 2: Skull
0.036, 22.0, 0.9, 1.37; % 3: Cortex
0.036, 22.0, 0.9, 1.37 % 4: Hippocampus
];
%% 4. 均匀面光源(200×200 体素全覆盖)
cfg.srctype = 'planar';
cfg.srcpos = [0, 0, 0]; % 左下角
cfg.srcdir = [0, 0, 1, 0];
cfg.srcparam1 = [dimx, 0, 0, 0]; % x 方向 200 体素
cfg.srcparam2 = [0, dimy, 0, 0]; % y 方向 200 体素
cfg.issrcfrom0 = 1;
%% 5. 边界与输出设置
cfg.isreflect = 1; % 开启外部边界反射
cfg.isnormalized = 1; % 默认就是 1(归一化)
%% 6. 运行仿真
tic;
f = mcxlab(cfg);
toc;
%% 7. 中心横断面(y=100)—— 正确量级
fluence_rate_cw = squeeze(f.data(:,100,:,1));
figure('Position',[100 100 950 700]);
imagesc(log10(fluence_rate_cw'));
colormap(jet); colorbar;
caxis([6.5 8.5]);
hold on;
% 层边界(白色虚线)
for z = [30 55 155 255]
plot([1 200], [z z], 'w--', 'LineWidth', 1.5);
end
% 坐标轴换成 mm
set(gca,'XTick',0:50:200,'XTickLabel',0:0.5:2);
set(gca,'YTick',0:50:255,'YTickLabel',0:0.5:2.55);
xlabel('X (mm)'); ylabel('Depth (mm)');
title('Log_{10}(Fluence Rate) - Center Slice (Uniform Planar Source)');
axis image;
% 1/e 深度
z_profile = squeeze(mean(mean(squeeze(f.data(:,:,:,1)), 1), 2));
[peak_val,peak_idx] = max(z_profile);
threshold = peak_val/exp(1);
idx1e = find(z_profile(peak_idx:end) <= threshold,1,'first') + peak_idx - 1;
depth_1e = (idx1e-0.5)*cfg.unitinmm;
plot([1 200], [idx1e idx1e], 'b-', 'LineWidth', 2.5);
text(10, idx1e-8, sprintf('1/e depth: %.2f mm', depth_1e), ...
'Color','blue','FontSize',12,'FontWeight','bold');
% 诊断 fluence 范围
fluence_log_data = log10(fluence_rate_cw);
min_val = min(fluence_log_data(fluence_log_data > 0));
max_val = max(fluence_log_data(:));
fprintf('实际 Log10(Fluence) 范围是:[%.2f, %.2f]\n', min_val, max_val);
%% 8. 衰减曲线
z_mm = ((1:dimz)-0.5)*cfg.unitinmm; % 真实深度 mm
figure;
semilogy(z_mm, z_profile, 'b-', 'LineWidth', 2); hold on;
semilogy(z_mm(peak_idx), peak_val, 'ro', 'MarkerSize', 8, 'MarkerFaceColor','r');
semilogy([0 2.6], [threshold threshold], 'r--','LineWidth',1.5);
semilogy(depth_1e, threshold, 'rp','MarkerSize',12,'MarkerFaceColor','r');
grid on; xlabel('Depth (mm)'); ylabel('Fluence Rate ');
title(sprintf('Center Profile - 1/e depth = %.2f mm (Peak = %.2e)', depth_1e, peak_val));
xlim([0 2.6]);
legend('Fluence rate','Peak','1/e threshold','1/e depth','Location','southwest');
fprintf('=== 诊断信息 ===\n');
fprintf('f.data 维度: %s\n', mat2str(size(f.data)));
fprintf('峰值 fluence rate = %.3e\n', peak_val);
fprintf('1/e 穿透深度 = %.2f mm\n', depth_1e);

Kind regards, 
Jinze Li

Qianqian Fang

unread,
Jan 11, 2026, 1:58:19 PMJan 11
to mcx-...@googlegroups.com, Jinze Li

hi Jinze,

the scaling question has been brought up multiple times in the mailing list, I think it is helpful if you can read these previous replies

https://groups.google.com/g/mcx-users/c/VQ0GdabxnSM/m/oc1v7zOHAQAJ
https://groups.google.com/g/mcx-users/c/nEcOnUZHb7I/m/a284tTOAAQAJ
https://groups.google.com/g/mcx-users/c/tQEw5jO1nWA/m/mcZIapwGAAAJ
https://groups.google.com/g/mcx-users/c/sbtDCbuRh90/m/KVKShOebAQAJ
https://groups.google.com/g/mcx-users/c/PNhj-sMjCZM/m/F-V-LkOkAgAJ
https://groups.google.com/g/mcx-users/c/N55J79w9FYY/m/D3IcSTfqBQAJ
https://groups.google.com/g/mcx-users/c/HziDFZZBqSc/m/e7uvp1Y0BAAJ
https://groups.google.com/g/mcx-users/c/zePFW8MDr6Y/m/NOsqJJt5AgAJ

or this FAQ

https://mcx.space/wiki/index.cgi?Doc/FAQ#How_do_I_interpret_MCX_s_output_data

because mcx/mmc solves for the Green's function (or TPSF, or the impulse response - in both time and space - if pencil beam), when you have an arbitrary spatially distributed source, or arbitrarily temporarily varying source, all you need to do is to convolve the Green's function produced by mcx/mmc by the spatial spread of the source, or by the temporary profile of the source, or both, to produce the solution that matches your actual source spatial/temporary profiles.

if your source has a scaling factor (light total watt or joule), you can simply multiply this number to the output of mcx because mcx produces a unitary solution, where the source has a unit of 1 (watt, joule, or count), and RTE is linear to the source term.


Qianqian

--
You received this message because you are subscribed to the Google Groups "mcx-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mcx-users+...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/mcx-users/de139aeb-0e5f-4dbe-bae7-2a0b5db836b2n%40googlegroups.com.

Jinze Li

unread,
Jan 25, 2026, 6:44:03 AM (8 days ago) Jan 25
to mcx-users
Dear Dr. Fang, 

Thank you for your previous response. I multiplied the output fluence rating by the corresponding coefficient as you suggested to match the light source power I wanted to simulate. However, the results obtained did not meet my expectations—the fluence rating on the model surface was significantly higher than the set light source power density. Since I'm simulating a steady-state light source, I set cfg.tend to 1 and cfg.tstep equal to cfg.tend. Yet the fluence rating on the model surface still exceeded twice the light source power density. I then set cfg.tend to 2, which aligned the model surface fluence rating with the light source. I'd like to understand whether this approach is reasonable and why cfg.tend significantly impacts the fluence rating.

Jinze Li

Fang, Qianqian

unread,
Jan 27, 2026, 12:12:16 PM (6 days ago) Jan 27
to mcx-users
Hi Jinze,

Matching a simulation model with real-world measurements is not an easy task as you might have imagined. In almost all cases, you MUST calibrate the data in order to make meaningful comparisons.

If you look into the literature, there are many publications comparing mcx based forward models against measurements from instruments. But a common pattern is that they can only compare in a relative sense, and both the simulation and the measurement data must be normalized in order to match even the scale. Most researchers focus on comparing trends and shapes of the measurements rather than the absolute scale.

There are numerous reasons why matching absolute scale is not realistic - first, your detector reading has an arbitrary scale that varies with integration time, signal amplification, and ADC quantization. Any of these steps introduce uncertain scaling factors to your data. You cannot interpret your measurement absolutely or literally. Calibration or normalization is almost always necessary (unless your measurement itself is ratiometric)

Secondly, simulations are simulations, and almost certainly, they rely on overly simplified assumptions to work. You cannot treat the simulation output literally as well. That does not mean simulations are useless - they can offer meaningful insights if you look at it at the right angles (such as looking at changes by varying one or multiple conditions).

If you have been using analytical models (exp. semi-infinite diffusion solutions) to validate your data, MC simulation is just a slightly more accurate numerical model - whatever it takes for you to match your analytical model in order to compare, you treat MC solutions in the same way - if you haven't compared your data against analytical models, perhaps you should step back and do that first. This will help you recalibrate your expectations.


Qianqian



From: mcx-...@googlegroups.com <mcx-...@googlegroups.com> on behalf of Jinze Li <liji...@gmail.com>
Sent: Sunday, January 25, 2026 6:44 AM
To: mcx-users <mcx-...@googlegroups.com>
Subject: Re: [mcx-users] Unit conversion for ‘flux’ output
 
You don't often get email from liji...@gmail.com. Learn why this is important
Reply all
Reply to author
Forward
0 new messages