Scripting em MATLAB
1. Introdução
No OghmaNano, o scripting em MATLAB funciona editando diretamente os arquivos de configuração da simulação em disco
e então invocando o mecanismo de simulação (oghma_core.exe) para executar o modelo.
Esta seção descreve esse fluxo de trabalho em detalhes.
2. Executando arquivos de simulação com MATLAB
Uma simulação do OghmaNano é definida inteiramente por um único arquivo de configuração JSON,
sim.json.
Este arquivo contém o estado completo da simulação, incluindo a estrutura do dispositivo,
parâmetros de material, configurações numéricas e configuração de saída.
Em muitos casos, sim.json já existe como um arquivo normal dentro do diretório da simulação.
Ao controlar o OghmaNano a partir do MATLAB, o script lê sim.json na memória usando o
suporte JSON do MATLAB, modifica um ou mais parâmetros e grava o JSON
atualizado de volta em disco.
Crucialmente, o MATLAB deve executar oghma_core.exe com seu diretório de trabalho definido como o
diretório da simulação — isto é, o diretório que contém sim.json (e
sim.oghma).
O mecanismo de simulação sempre lê seus arquivos de entrada a partir do diretório de trabalho atual,
então, se o diretório de trabalho estiver incorreto, a simulação falhará ou executará o modelo errado.
Essa separação de responsabilidades é intencional e explícita: o MATLAB é responsável por definir o que muda na simulação, enquanto o OghmaNano é responsável por executar a física usando os arquivos presentes no diretório atual.
O exemplo abaixo demonstra esse processo carregando sim.json, modificando a mobilidade do portador
da primeira camada do dispositivo, gravando a configuração atualizada de volta em disco e, então,
executando a simulação a partir do diretório da simulação.
% Defina isto como a pasta da sua simulação (deve conter sim.json / sim.oghma)
sim_dir = "C:\path\to\your\simulation";
% Ler sim.json
sim_path = fullfile(sim_dir, "sim.json");
txt = fileread(sim_path);
data = jsondecode(txt);
% Editar um valor: mobilidade de segment1 (mesmo caminho JSON da página Python)
data.epitaxy.segment1.shape_dos.mue_y = 1.0;
% Gravar sim.json de volta em disco
out = jsonencode(data);
fid = fopen(sim_path, "w");
fprintf(fid, "%s", out);
fclose(fid);
% Executar a simulação (o diretório de trabalho deve ser a pasta da simulação)
orig_dir = pwd;
cd(sim_dir);
system("oghma_core.exe");
cd(orig_dir);
Se a simulação em sim.json estiver configurada para executar uma curva J–V, o OghmaNano gravará arquivos de saída no
diretório da simulação contendo quantidades como PCE, fator de preenchimento, \(J_{sc}\) e
\(V_{oc}\).
3. Extraindo resultados
Muitos arquivos de saída do OghmaNano são gravados em formato JSON. Um padrão comum é ler
sim_info.dat, extrair uma figura de mérito escalar (por exemplo Voc)
e anexá-la a um arquivo de texto para análise posterior.
O exemplo abaixo lê sim_info.dat e acrescenta o valor de
\(V_{oc}\) a um arquivo de texto separado.
% Deve ser executado a partir de (ou apontando para) um diretório de simulação concluída
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;
% Acrescentar a um arquivo de texto (um Voc por linha)
out_path = fullfile(sim_dir, "out.dat");
fid = fopen(out_path, "a");
fprintf(fid, "%g\n", voc);
fclose(fid);
3. Simulações mais complexas
Em muitos fluxos de trabalho de scripting, você desejará executar a mesma simulação base várias vezes com diferentes valores de parâmetro e manter cada execução isolada em seu próprio diretório. Essa é a forma mais simples de manter as saídas limpas e evitar sobrescrever resultados acidentalmente.
O exemplo abaixo cria um conjunto de diretórios correspondentes a quatro mobilidades
(1e-5, 1e-6, 1e-7, 1e-8). Para cada diretório, ele:
- Cria o diretório (caso ele ainda não exista).
- Copia o
sim.jsonatual para esse diretório. - Edita o
sim.jsoncopiado para definir a mobilidade alvo. - Altera o diretório de trabalho para esse diretório.
- Executa o solver nesse diretório, produzindo saídas locais para essa execução.
Esse padrão é a base do scripting em lote no OghmaNano: um diretório por execução, um arquivo de configuração por execução, e uma pasta de saída limpa para cada valor de parâmetro.
% O script deve ser iniciado no diretório base da simulação
% (isto é, o diretório que contém o sim.json de referência).
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
% Copiar o sim.json base para o diretório da execução
dst_sim = fullfile(run_dir, "sim.json");
copyfile(src_sim, dst_sim);
% Carregar o sim.json copiado e editar a mobilidade NESSA cópia
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);
% Mudar para o diretório da execução e executar o solver ali
cd(run_dir);
system("oghma_core.exe");
cd(base_dir);
end
4. Extraindo resultados
Depois de executar um lote de simulações em diretórios de execução separados (por exemplo mu_1e-05,
mu_1e-06, ...), o próximo passo é extrair uma figura de mérito chave de cada execução e visualizar a tendência.
Um exemplo comum é ler a tensão de circuito aberto \(V_{oc}\) de
sim_info.dat em cada diretório e plotá-la em função da mobilidade inversa \(1/\mu\).
O script abaixo percorre um conjunto fixo de diretórios de execução correspondentes às mobilidades
1e-5, 1e-6, 1e-7, 1e-8 e, para cada diretório:
- Carrega
sim_info.datcomo JSON. - Extrai
Voc. - Calcula \(1/\mu\) usando a mobilidade associada àquele diretório.
- Grava um pequeno arquivo de resumo (
voc_vs_inv_mobility.dat). - Plota \(V_{oc}\) vs \(1/\mu\).
% Execute isto a partir do diretório BASE que contém as pastas de execução
% (mu_1e-05, mu_1e-06, ...). Caso contrário, defina base_dir explicitamente.
base_dir = pwd;
% As mobilidades devem corresponder aos diretórios de execução gerados anteriormente
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
% Gravar uma pequena tabela-resumo em disco
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);
% Plotar Voc em função da mobilidade inversa
figure;
plot(inv_mu, vocs, "o-");
xlabel("Mobilidade inversa (1/\mu)");
ylabel("Tensão de circuito aberto V_{oc} (V)");
title("V_{oc} vs mobilidade inversa");
grid on;