Scripting en MATLAB
1. Introducción
En OghmaNano, el scripting en MATLAB funciona editando directamente los archivos de configuración de simulación en disco
y luego invocando el motor de simulación (oghma_core.exe) para ejecutar el modelo.
Esta sección describe este flujo de trabajo en detalle.
2. Ejecutar archivos de simulación con MATLAB
Una simulación de OghmaNano está definida completamente por un único archivo de configuración JSON,
sim.json.
Este archivo contiene el estado completo de la simulación, incluyendo la estructura del dispositivo,
los parámetros del material, los ajustes numéricos y la configuración de salida.
En muchos casos, sim.json ya existe como un archivo normal dentro del directorio de simulación.
Al controlar OghmaNano desde MATLAB, el script lee sim.json en memoria usando el
soporte JSON de MATLAB, modifica uno o más parámetros y escribe el JSON actualizado
de nuevo en disco.
Es crucial que MATLAB ejecute oghma_core.exe con su directorio de trabajo configurado en el
directorio de simulación — es decir, el directorio que contiene sim.json (y
sim.oghma).
El motor de simulación siempre lee sus archivos de entrada desde el directorio de trabajo actual,
por lo que si el directorio de trabajo es incorrecto, la simulación fallará o ejecutará el modelo equivocado.
Esta separación de responsabilidades es intencional y explícita: MATLAB es responsable de definir qué cambia en la simulación, mientras que OghmaNano es responsable de ejecutar la física usando los archivos presentes en el directorio actual.
El ejemplo siguiente demuestra este proceso cargando sim.json, modificando la movilidad de portadores
de la primera capa del dispositivo, escribiendo la configuración actualizada de nuevo en disco y luego
ejecutando la simulación desde el directorio de simulación.
% Configure esto a su carpeta de simulación (debe contener sim.json / sim.oghma)
sim_dir = "C:\path\to\your\simulation";
% Leer sim.json
sim_path = fullfile(sim_dir, "sim.json");
txt = fileread(sim_path);
data = jsondecode(txt);
% Editar un valor: movilidad de segment1 (misma ruta JSON que en la página de Python)
data.epitaxy.segment1.shape_dos.mue_y = 1.0;
% Escribir sim.json de nuevo en disco
out = jsonencode(data);
fid = fopen(sim_path, "w");
fprintf(fid, "%s", out);
fclose(fid);
% Ejecutar la simulación (el directorio de trabajo debe ser la carpeta de simulación)
orig_dir = pwd;
cd(sim_dir);
system("oghma_core.exe");
cd(orig_dir);
Si la simulación en sim.json está configurada para ejecutar una curva J–V, OghmaNano escribirá archivos de salida en el
directorio de simulación que contienen magnitudes tales como PCE, factor de llenado, \(J_{sc}\) y
\(V_{oc}\).
3. Extracción de resultados
Muchos archivos de salida de OghmaNano se escriben en formato JSON. Un patrón común consiste en leer
sim_info.dat, extraer una figura de mérito escalar (por ejemplo Voc),
y añadirla a un archivo de texto para un análisis posterior.
El ejemplo siguiente lee sim_info.dat y añade el valor de
\(V_{oc}\) a un archivo de texto separado.
% Debe ejecutarse desde (o apuntar a) un directorio de simulación completado
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;
% Añadir a un archivo de texto (un Voc por línea)
out_path = fullfile(sim_dir, "out.dat");
fid = fopen(out_path, "a");
fprintf(fid, "%g\n", voc);
fclose(fid);
3. Simulaciones más complejas
En muchos flujos de trabajo de scripting querrá ejecutar la misma simulación base varias veces con distintos valores de parámetro y mantener cada ejecución aislada en su propio directorio. Esta es la forma más sencilla de mantener limpias las salidas y evitar sobrescribir accidentalmente resultados.
El ejemplo siguiente crea un conjunto de directorios correspondientes a cuatro movilidades
(1e-5, 1e-6, 1e-7, 1e-8). Para cada directorio:
- Crea el directorio (si no existe ya).
- Copia el
sim.jsonactual en ese directorio. - Edita el
sim.jsoncopiado para establecer la movilidad objetivo. - Cambia el directorio de trabajo a ese directorio.
- Ejecuta el solucionador en ese directorio, produciendo salidas locales a esa ejecución.
Este patrón es la base del scripting por lotes en OghmaNano: un directorio por ejecución, un archivo de configuración por ejecución, y una carpeta de salida limpia para cada valor de parámetro.
% El script debe iniciarse en el directorio base de simulación
% (es decir, el directorio que contiene el sim.json de referencia).
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 el sim.json base al directorio de ejecución
dst_sim = fullfile(run_dir, "sim.json");
copyfile(src_sim, dst_sim);
% Cargar el sim.json copiado y editar la movilidad en ESA copia
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);
% Cambiar al directorio de ejecución y ejecutar allí el solucionador
cd(run_dir);
system("oghma_core.exe");
cd(base_dir);
end
4. Extracción de resultados
Después de ejecutar un lote de simulaciones en directorios de ejecución separados (por ejemplo mu_1e-05,
mu_1e-06, ...), el siguiente paso es extraer una figura de mérito clave de cada ejecución y visualizar la tendencia.
Un ejemplo común es leer el voltaje de circuito abierto \(V_{oc}\) desde
sim_info.dat en cada directorio y representarlo frente a la movilidad inversa \(1/\mu\).
El script siguiente recorre un conjunto fijo de directorios de ejecución correspondientes a movilidades
1e-5, 1e-6, 1e-7, 1e-8 y para cada directorio:
- Carga
sim_info.datcomo JSON. - Extrae
Voc. - Calcula \(1/\mu\) usando la movilidad asociada a ese directorio.
- Escribe un pequeño archivo resumen (
voc_vs_inv_mobility.dat). - Representa \(V_{oc}\) frente a \(1/\mu\).
% Ejecute esto desde el directorio BASE que contiene las carpetas de ejecución
% (mu_1e-05, mu_1e-06, ...). Si no, configure base_dir explícitamente.
base_dir = pwd;
% Las movilidades deben coincidir con los directorios de ejecución generados 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("Falta sim_info.dat en: %s", run_dir);
end
txt = fileread(info_path);
info = jsondecode(txt);
vocs(k) = info.Voc;
inv_mu(k) = 1.0 / mu;
end
% Escribir una pequeña tabla resumen en 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);
% Representar Voc frente a la movilidad inversa
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;