Tworzenie skryptów w MATLABie
1. Wprowadzenie
W OghmaNano skrypty MATLAB działają poprzez bezpośrednią edycję plików konfiguracyjnych symulacji na dysku, a następnie uruchamianie silnika symulacyjnego (oghma_core.exe) w celu uruchomienia modelu. W tej sekcji szczegółowo opisano ten proces.
2. Uruchamianie plików symulacyjnych za pomocą programu MATLAB.
Symulacja OghmaNano jest w pełni definiowana przez pojedynczy plik konfiguracyjny w formacie JSON, sim.json. Plik ten zawiera kompletny stan symulacji, w tym strukturę urządzenia, parametry materiałowe, ustawienia numeryczne i konfigurację wyjściową. W wielu przypadkach sim.json już istnieje jako zwykły plik w katalogu symulacji.
Podczas uruchamiania programu OghmaNano z poziomu MATLAB, skrypt odczytuje dane sim.json do pamięci, wykorzystując funkcje obsługi formatu JSON w MATLAB, modyfikuje jeden lub więcej parametrów, a następnie zapisuje zaktualizowane dane JSON na dysku.
Co najważniejsze, program MATLAB musi być uruchomiony oghma_core.exe z ustawionym katalogiem roboczym na katalog symulacji – czyli katalog, w którym znajdują się sim.json (oraz sim.oghma). Silnik symulacyjny zawsze odczytuje pliki wejściowe z aktualnego katalogu roboczego, więc jeśli katalog roboczy jest nieprawidłowy, symulacja zakończy się niepowodzeniem lub uruchomi nieprawidłowy model.
To rozdzielenie zakresów odpowiedzialności jest celowe i wyraźnie określone: MATLAB odpowiada za definiowanie zmian wprowadzanych w symulacji, natomiast OghmaNano odpowiada za uruchamianie obliczeń fizycznych na podstawie plików znajdujących się w bieżącym katalogu.
Poniższy przykład ilustruje ten proces poprzez załadowanie sim.json, zmodyfikowanie mobilności nośników w pierwszej warstwie urządzenia, zapisanie zaktualizowanej konfiguracji na dysku, a następnie uruchomienie symulacji z katalogu symulacji.
% 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);
Jeśli w programie sim.json ustawiono symulację mającą na celu wygenerowanie krzywej J–V, OghmaNano zapisze pliki wynikowe w katalogu symulacji, zawierające takie parametry, jak PCE, współczynnik wypełnienia, \(J_{sc}\) i \(V_{oc}\).
3. Pobieranie wyników
Wiele plików wyjściowych programu OghmaNano zapisywanych jest w formacie JSON. Typowym rozwiązaniem jest odczytanie danych sim_info.dat, wyodrębnienie pojedynczej wartości określającej jakość (na przykład Voc) i dołączenie jej do pliku tekstowego w celu późniejszej analizy.
Poniższy przykład odczytuje wartość sim_info.dat i zapisuje wartość \(V_{oc}\) do oddzielnego pliku tekstowego.
% 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. Bardziej zaawansowane symulacje.
W wielu procesach tworzenia skryptów będziesz chciał uruchamiać tę samą podstawową symulację wielokrotnie, używając różnych wartości parametrów, i przechowywać wyniki każdego uruchomienia w oddzielnym folderze. Jest to najprostszy sposób na zachowanie porządku w wynikach i uniknięcie przypadkowego nadpisywania danych.
Poniższy przykład tworzy zestaw katalogów odpowiadających czterem różnym typom mobilności (1e-5, 1e-6, 1e-7, 1e-8). Dla każdego katalogu wykonuje następujące czynności:
- Tworzy katalog (jeśli taki katalog jeszcze nie istnieje).
- Kopiuje aktualną wersję
sim.jsondo tego katalogu. - Modyfikuje skopiowany element
sim.json, aby ustawić docelową wartość mobilności. - Zmienia bieżący katalog roboczy na wskazany katalog.
- Uruchamia program rozwiązujący w danym katalogu, generując wyniki, które są zapisywane lokalnie w tym katalogu.
Ten schemat stanowi podstawę skryptów wsadowych w OghmaNano: dla każdego uruchomienia tworzony jest oddzielny katalog, oddzielny plik konfiguracyjny oraz czysty folder wyjściowy dla każdej wartości parametru.
% 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. Pobieranie wyników
Po przeprowadzeniu serii symulacji w oddzielnych katalogach (np. mu_1e-05, mu_1e-06, ...), kolejnym krokiem jest wyodrębnienie kluczowego wskaźnika z każdej symulacji i przedstawienie go w formie graficznej, aby zilustrować tendencję. Typowym przykładem jest odczytanie napięcia w obwodzie otwartym \(V_{oc}\) z pliku sim_info.dat w każdym katalogu i przedstawienie go na wykresie w zależności od odwrotności ruchliwości \(1/\mu\).
Poniższy skrypt przeszukuje zdefiniowany zestaw katalogów, odpowiadających wartościom mobilności 1e-5, 1e-6, 1e-7, 1e-8, a dla każdego katalogu wykonuje następujące czynności:
- Wczytuje dane
sim_info.datw formacie JSON. - Fragmenty
Voc. - Oblicza wartość \(1/\mu\) na podstawie mobilności powiązanej z danym katalogiem.
- Tworzy mały plik podsumowujący (
voc_vs_inv_mobility.dat). - Porównanie fabuł \(V_{oc}\) i \(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;