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을 불러오고, 첫 번째 소자 층의 캐리어
이동도를 수정한 뒤, 업데이트된 구성을 다시 디스크에 기록하고,
마지막으로 시뮬레이션 디렉터리에서 시뮬레이션을 실행하는 과정을 보여줍니다.
% 시뮬레이션 폴더로 설정하십시오(sim.json / sim.oghma가 있어야 함)
sim_dir = "C:\path\to\your\simulation";
% sim.json 읽기
sim_path = fullfile(sim_dir, "sim.json");
txt = fileread(sim_path);
data = jsondecode(txt);
% 값 편집: segment1의 이동도(Python 페이지와 같은 JSON 경로)
data.epitaxy.segment1.shape_dos.mue_y = 1.0;
% sim.json을 다시 디스크에 쓰기
out = jsonencode(data);
fid = fopen(sim_path, "w");
fprintf(fid, "%s", out);
fclose(fid);
% 시뮬레이션 실행(작업 디렉터리는 시뮬레이션 폴더여야 함)
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}\) 값을 별도의 텍스트 파일에 추가하는 방법을 보여줍니다.
% 완료된 시뮬레이션 디렉터리에서 실행하거나(또는 그 디렉터리를 가리키도록) 해야 합니다
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;
% 텍스트 파일에 추가(한 줄에 Voc 하나)
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의 배치 스크립팅의 기초입니다: 실행당 하나의 디렉터리, 실행당 하나의 구성 파일, 그리고 각 파라미터 값에 대한 깔끔한 출력 폴더입니다.
% 스크립트는 기준 시뮬레이션 디렉터리에서 시작되어야 합니다
% (즉, 기준 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
% 기준 sim.json을 실행 디렉터리로 복사
dst_sim = fullfile(run_dir, "sim.json");
copyfile(src_sim, dst_sim);
% 복사된 sim.json을 불러와 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);
% 실행 디렉터리로 이동하여 այնտեղ서 해석기 실행
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\)를 플로팅합니다.
% 실행 폴더를 포함하는 기준 디렉터리에서 실행하십시오
% (mu_1e-05, mu_1e-06, ...). 그렇지 않다면 base_dir를 명시적으로 설정하십시오.
base_dir = pwd;
% 이동도 값은 앞서 생성한 실행 디렉터리와 일치해야 합니다
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
% 작은 요약 표를 디스크에 기록
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);
% 역이동도에 대해 Voc 플로팅
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;