اسکریپتنویسی MATLAB
1. مقدمه
در OghmaNano، اسکریپتنویسی MATLAB با ویرایش مستقیم فایلهای پیکربندی شبیهسازی روی دیسک
و سپس فراخوانی موتور شبیهسازی (oghma_core.exe) برای اجرای مدل انجام میشود.
این بخش این گردشکار را با جزئیات شرح میدهد.
2. اجرای فایلهای شبیهسازی با MATLAB
یک شبیهسازی OghmaNano بهطور کامل توسط یک فایل پیکربندی JSON واحد،
sim.json تعریف میشود.
این فایل وضعیت کامل شبیهسازی را شامل میشود، از جمله ساختار دستگاه،
پارامترهای ماده، تنظیمات عددی و پیکربندی خروجی.
در بسیاری از موارد، sim.json از قبل بهصورت یک فایل معمولی درون پوشه شبیهسازی وجود دارد.
هنگام کنترل OghmaNano از MATLAB، اسکریپت sim.json را با استفاده از پشتیبانی JSON در MATLAB
به حافظه میخواند، یک یا چند پارامتر را تغییر میدهد، و 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، ...)، گام بعدی استخراج یک شاخص کلیدی کارایی از هر اجرا و بصریسازی روند آن است.
یک مثال رایج این است که ولتاژ مدار باز \(V_{oc}\) از
sim_info.dat در هر پوشه خوانده شود و بر حسب معکوس تحرک \(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;