MATLAB 脚本
1. 介绍
在 OghmaNano 中,MATLAB 脚本通过直接编辑磁盘上的仿真配置文件,
然后调用仿真引擎(oghma_core.exe)来运行模型。
本节将详细说明这一工作流程。
2. 使用 MATLAB 运行仿真文件
一个 OghmaNano 仿真完全由单个 JSON 配置文件
sim.json 定义。
该文件包含仿真的完整状态,包括器件结构、
材料参数、数值设置和输出配置。
在许多情况下,sim.json 已经作为普通文件存在于仿真目录中。
使用 MATLAB 驱动 OghmaNano 时,脚本会使用 MATLAB 的
JSON 支持将 sim.json 读入内存,修改一个或多个参数,然后将更新后的 JSON
写回磁盘。
关键的是,MATLAB 必须在工作目录设置为仿真目录时运行 oghma_core.exe —— 也就是包含 sim.json(以及
sim.oghma)的目录。
仿真引擎总是从当前工作目录读取输入文件,
因此如果工作目录不正确,仿真将失败或运行错误的模型。
这种职责分离是有意且明确的: MATLAB 负责定义仿真中改变什么, 而 OghmaNano 负责利用当前目录中存在的文件运行物理模型。
下面的示例通过加载 sim.json、修改第一器件层的载流子
迁移率、将更新后的配置写回磁盘,然后
从仿真目录执行仿真来演示这一过程。
% Set this to your simulation folder (must contain sim.json / sim.oghma)
sim_dir = "C:\path\to\your\simulation";
% Read sim.json
sim_path = fullfile(sim_dir, "sim.json");
txt = fileread(sim_path);
data = jsondecode(txt);
% Edit a value: mobility of segment1 (same JSON path as the Python page)
data.epitaxy.segment1.shape_dos.mue_y = 1.0;
% Write sim.json back to disk
out = jsonencode(data);
fid = fopen(sim_path, "w");
fprintf(fid, "%s", out);
fclose(fid);
% Run the simulation (working directory must be the simulation folder)
orig_dir = pwd;
cd(sim_dir);
system("oghma_core.exe");
cd(orig_dir);
如果 sim.json 中的仿真被设置为运行 J–V 曲线,OghmaNano 将把输出文件写入
仿真目录,其中包含诸如 PCE、填充因子、\(J_{sc}\) 和
\(V_{oc}\) 等量。
3. 提取结果
许多 OghmaNano 输出文件以 JSON 格式写出。一个常见模式是读取
sim_info.dat,提取一个标量性能指标(例如 Voc),
并将其附加到文本文件中供后续分析。
下面的示例读取 sim_info.dat 并将
\(V_{oc}\) 的值附加到单独的文本文件中。
% Must be run from (or pointed at) a completed simulation directory
sim_dir = "C:\path\to\your\simulation";
info_path = fullfile(sim_dir, "sim_info.dat");
txt = fileread(info_path);
info = jsondecode(txt);
voc = info.Voc;
% Append to a text file (one Voc per line)
out_path = fullfile(sim_dir, "out.dat");
fid = fopen(out_path, "a");
fprintf(fid, "%g\n", voc);
fclose(fid);
3. 更复杂的仿真
在许多脚本工作流程中,您会希望使用不同参数值多次运行同一个基础仿真, 并将每次运行各自隔离在自己的目录中。这是保持输出整洁并避免 意外覆盖结果的最简单方法。
下面的示例创建了一组对应于四个迁移率的目录
(1e-5、1e-6、1e-7、1e-8)。对于每个目录,它会:
- 创建该目录(如果它尚不存在)。
- 将当前的
sim.json复制到该目录中。 - 编辑复制后的
sim.json以设置目标迁移率。 - 将工作目录切换到该目录。
- 在该目录中运行求解器,从而生成该次运行本地的输出。
这种模式是 OghmaNano 中批处理脚本的基础:每次运行一个目录,每次运行一个配置文件, 并为每个参数值保留一个干净的输出文件夹。
% The script should be started in the base simulation directory
% (i.e. the directory containing the reference sim.json).
base_dir = pwd;
mobilities = [1e-5, 1e-6, 1e-7, 1e-8];
src_sim = fullfile(base_dir, "sim.json");
for k = 1:numel(mobilities)
mu = mobilities(k);
run_name = sprintf("mu_%.0e", mu);
run_dir = fullfile(base_dir, run_name);
if ~exist(run_dir, "dir")
mkdir(run_dir);
end
% Copy the base sim.json into the run directory
dst_sim = fullfile(run_dir, "sim.json");
copyfile(src_sim, dst_sim);
% Load the copied sim.json and edit the mobility in THAT copy
txt = fileread(dst_sim);
data = jsondecode(txt);
data.epitaxy.segment1.shape_dos.mue_y = mu;
out = jsonencode(data);
fid = fopen(dst_sim, "w");
fprintf(fid, "%s", out);
fclose(fid);
% Change into the run directory and execute the solver there
cd(run_dir);
system("oghma_core.exe");
cd(base_dir);
end
4. 提取结果
在单独的运行目录中完成一批仿真之后(例如 mu_1e-05、
mu_1e-06、...),下一步是从每次运行中提取一个关键性能指标并将趋势可视化。
一个常见示例是从每个目录中的 sim_info.dat 读取开路电压 \(V_{oc}\),
并将其相对于反迁移率 \(1/\mu\) 作图。
下面的脚本扫描一组固定的运行目录,这些目录对应的迁移率为
1e-5、1e-6、1e-7、1e-8,并对每个目录执行:
- 将
sim_info.dat作为 JSON 读取。 - 提取
Voc。 - 使用与该目录关联的迁移率计算 \(1/\mu\)。
- 写出一个简要汇总文件(
voc_vs_inv_mobility.dat)。 - 绘制 \(V_{oc}\) 对 \(1/\mu\) 的图。
% Run this from the BASE directory that contains the run folders
% (mu_1e-05, mu_1e-06, ...). If not, set base_dir explicitly.
base_dir = pwd;
% Mobilities must match the run directories you generated earlier
mobilities = [1e-5, 1e-6, 1e-7, 1e-8];
inv_mu = zeros(size(mobilities));
vocs = zeros(size(mobilities));
for k = 1:numel(mobilities)
mu = mobilities(k);
run_dir = fullfile(base_dir, sprintf("mu_%.0e", mu));
info_path = fullfile(run_dir, "sim_info.dat");
if ~exist(info_path, "file")
error("Missing sim_info.dat in: %s", run_dir);
end
txt = fileread(info_path);
info = jsondecode(txt);
vocs(k) = info.Voc;
inv_mu(k) = 1.0 / mu;
end
% Write a small summary table to disk
out_path = fullfile(base_dir, "voc_vs_inv_mobility.dat");
fid = fopen(out_path, "w");
fprintf(fid, "# inv_mobility(1/mu) Voc(V)\n");
for k = 1:numel(inv_mu)
fprintf(fid, "%.6e %g\n", inv_mu(k), vocs(k));
end
fclose(fid);
% Plot Voc against inverse mobility
figure;
plot(inv_mu, vocs, "o-");
xlabel("Inverse mobility (1/\mu)");
ylabel("Open-circuit voltage V_{oc} (V)");
title("V_{oc} vs inverse mobility");
grid on;