Utilisation du langage de script Lua pour le solveur électrique Newton dans OghmaNano.
1. Introduction
OghmaNano intègre une interface de script Lua qui permet de modifier le solveur numérique interne pendant l’exécution du programme. Cela offre des possibilités de contrôle avancées, telles que l’activation ou la désactivation d’équations, la modification du solveur de Newton 3D, la suspension de certains paramètres physiques pendant les transitoires ou les analyses J–V, ou la mise en œuvre de stratégies itératives personnalisées.
Cela diffère de l’utilisation de scripts externes. Des langages comme Python fonctionnent en modifiant sim.json et en lançant le solveur, ce qui les rend particulièrement adaptés aux analyses paramétriques, à l’exécution par lots et au post-traitement.
À l’inverse, Lua fonctionne à l’intérieur du solveur, ce qui permet d’intervenir directement dans le processus numérique sans modifier le code C sous-jacent.
2. Qu’est-ce que Lua ?
Lua est un langage de script léger et performant, conçu pour être intégré dans des applications plus importantes. Il est largement utilisé dans des domaines tels que les moteurs de jeu et les logiciels scientifiques, où il est nécessaire de modifier le comportement interne sans avoir à recompiler le code principal. Par rapport à Python, Lua a une empreinte beaucoup plus petite et nécessite moins de ressources lors de l’exécution, ce qui le rend plus adapté à une utilisation dans des boucles critiques en termes de performances. Par rapport à C, il est beaucoup plus facile à écrire et à modifier, tout en offrant un contrôle précis sur le comportement du programme. Ces caractéristiques font de Lua un choix particulièrement approprié pour OghmaNano, où il est utilisé pour influencer directement le solveur numérique pendant l’exécution.
Pour vous donner une idée de ce qu’est Lua, et si vous ne l’avez jamais utilisé auparavant, voici une implémentation de l’algorithme classique du tri à bulles.
a = {5, 3, 8, 1, 2}
n = #a
for i = 1, n do
for j = 1, n - i do
if a[j] > a[j+1] then
a[j], a[j+1] = a[j+1], a[j]
end
end
end
2. Accéder à l’éditeur de scripts Lua.
L’éditeur de scripts Lua est accessible à partir de la barre d’outils électrique de la fenêtre principale, comme indiqué dans ??. Cliquez sur la petite flèche déroulante située à côté du contrôle du solveur de diffusion-dérive pour ouvrir le menu, qui est illustré dans ??. Ensuite, cliquez sur « Modifier le microcode » pour ouvrir l’éditeur Lua, qui est illustré dans ??.
Appuyez sur Ctrl+S pour enregistrer le script, ou utilisez le bouton d’enregistrement dans la barre d’outils de l’éditeur. Pour activer le microcode, il faut appuyer sur le bouton d’activation, comme indiqué dans ??.
3. Un exemple simple : une cellule solaire à base de pérovskite dont les ions sont figés.
Un exemple simple de l’utilisation du langage de script Lua se trouve dans la simulation de dispositifs à base de pérovskite, où l’on peut vouloir immobiliser les ions mobiles pendant une mesure de la courbe courant-tension (J–V). Les pérovskites contiennent des ions mobiles qui se déplacent relativement lentement. En pratique, on maintient souvent un dispositif sous une tension négative afin que les ions se déplacent vers une configuration particulière, puis on effectue une mesure de la courbe courant-tension très rapide avant qu’ils n’aient le temps de réagir de manière significative.
Dans OghmaNano, lorsque le modèle d’ions pérovskites est activé, le solveur électrique permet généralement aux ions de se stabiliser à chaque étape de la tension. Cela équivaut à une analyse J–V très lente ou quasi à l’état stationnaire. Cela peut être utile dans certains cas, mais cela ne reproduit pas les expériences où la tension est balayée beaucoup plus rapidement. Pour simuler ce type de mesure, le script Lua ci-dessous peut être utilisé pour bloquer les ions lorsque la boucle électrique principale commence. La simulation peut toujours atteindre la tension de départ requise de manière normale, ce qui permet aux ions de se déplacer pendant la phase de préparation, mais une fois que la boucle principale est lancée, l’équation des ions est désactivée.
-- Initialise solver
a = dd_solver()
a.verbose = false -- Suppress solver output
-- Apply logic only in the main electrical loop
if (a.problem_type & ELEC_PROB_MAIN_LOOP) ~= 0 then
a.solve_nion = false -- Disable ion equation (freeze ions)
print("ion solver off")
else
print("ion solver on") -- Keep ions active during initialisation
end
a:run() -- Execute solver step
Dans cet exemple, l’objet « solveur » est d’abord créé, puis la quantité de données de diagnostic affichées est réduite. Le script vérifie ensuite si l’étape actuelle du solveur correspond à la boucle électrique principale. Si c’est le cas, l’équation des ions mobiles est désactivée en définissant solve_nion=false, puis le solveur est exécuté avec cet ensemble d’équations modifié. Un exemple de simulation utilisant cette méthode est inclus dans les exemples fournis avec le modèle, sous la rubrique « Cellules pérovskites/Cellule solaire pérovskite – ions figés (MAPI) ».
5. Exemple : balayage ADI (balayage implicite à direction alternée)
Un exemple plus avancé de script Lua est la mise en œuvre d’une stratégie à direction alternée pour résoudre des problèmes complexes en trois dimensions. Cette approche est étroitement liée à la méthode implicite à direction alternée (ADI), dans laquelle un problème multidimensionnel est décomposé en une séquence de problèmes de dimension inférieure.
Dans OghmaNano, cette idée peut être mise en œuvre directement au niveau du solveur en activant et en désactivant sélectivement les couplages directionnels. Au lieu de résoudre le système 3D entièrement couplé en une seule étape, le domaine est parcouru dans des directions alternées. Cela peut améliorer considérablement la stabilité et la convergence pour les problèmes de diffusion-dérive 3D complexes.
La stratégie utilisée ici consiste à diviser le problème tridimensionnel en étapes directionnelles. Lors de la première étape, le solveur opère sur des tranches dans la direction x, en résolvant l’ensemble du problème dans les directions y et z tout en supprimant les interactions dans la direction x. Lors de la deuxième étape, le solveur passe aux tranches dans la direction z et effectue l’opération complémentaire. L’erreur totale est accumulée et utilisée pour définir un critère de convergence personnalisé.
L’exemple ci-dessous illustre la manière dont une analyse de ce type, semblable à celle utilisée par ADI, peut être réalisée à l’aide de Lua :
-- Initialise solver and control variables
a = dd_solver()
cont = true
count = 0
-- Main ADI-style iteration loop
while cont == true do
-- ===== X-slice pass =====
a.set_newton_state("x") -- Use/store Newton state for x-pass
tot_error = 0.0
a.step_z = -1 -- Full domain in z
a.step_x = 1 -- Slice-by-slice in x
a.step_y = -1 -- Full domain in y
a.solve_pos_x = false -- Disable x-direction Poisson coupling
a.solve_pos_y = true
a.solve_pos_z = true
a.solve_je_x = 0 -- Disable x-direction electron current
a.solve_jh_x = 0 -- Disable x-direction hole current
a.solve_je_y = true
a.solve_jh_y = true
a.solve_je_z = true
a.solve_jh_z = true
a.solve_srh_e = true -- Keep SRH recombination active
a.solve_srh_h = true
a.solve_nion = 0 -- Disable ions
a.solve_singlet = false -- Disable excited-state physics
error = a:run() -- Execute x-slice solve
tot_error = tot_error + error
-- ===== Z-slice pass =====
a.set_newton_state("z") -- Switch to z-pass Newton state
a.step_z = 1 -- Slice-by-slice in z
a.step_x = -1 -- Full domain in x
a.step_y = -1 -- Full domain in y
a.solve_pos_x = true
a.solve_pos_y = true
a.solve_pos_z = false -- Disable z-direction Poisson coupling
a.solve_je_y = true
a.solve_jh_y = true
a.solve_je_x = true
a.solve_jh_x = true
a.solve_je_z = false -- Disable z-direction transport
a.solve_jh_z = false
a.solve_srh_e = true
a.solve_srh_h = true
a.solve_nion = false
a.solve_singlet = false
error = a:run() -- Execute z-slice solve
tot_error = tot_error + error
-- ===== Convergence logic =====
if (error < 1e-3) then -- Local convergence check
if (count > 2) then -- Ensure minimum iterations
cont = false
end
end
print("count", count, "tot error:", error)
count = count + 1
if (tot_error < 1e-7) then -- Global convergence criterion
cont = false
end
if (count > 10) then -- Safety iteration limit
cont = false
end
end
Dans cette implémentation, deux passes directionnelles sont effectuées à chaque itération. La première passe désactive les termes de transport de Poisson et de porteurs dans la direction x, ce qui revient à résoudre le système en effectuant des calculs par tranches le long de l’axe x. La deuxième passe désactive les termes correspondants dans la direction z, ce qui permet d’obtenir un balayage complémentaire.
Des états distincts de Newton sont maintenus pour chaque passage directionnel à l’aide de set_newton_state(), ce qui permet au solveur de conserver des variables internes indépendantes, telles que le potentiel électrostatique, les densités de porteurs et les taux d’occupation des pièges.
La convergence est contrôlée de manière explicite dans le script Lua. La boucle s’interrompt lorsque l’une des conditions suivantes est remplie : l’erreur et le nombre d’itérations par passage atteignent ou dépassent une valeur seuil, l’erreur cumulée descend en dessous d’une tolérance spécifiée, ou qu’un nombre maximal d’itérations est atteint.
Cet exemple illustre comment le langage de script Lua peut être utilisé pour créer des processus de résolution entièrement personnalisés. Au lieu de s’appuyer sur un schéma numérique prédéfini, l’utilisateur peut définir directement la manière dont le système multidimensionnel est décomposé, la manière dont les états intermédiaires sont gérés et la manière dont la convergence est évaluée. Ceci est particulièrement utile pour les simulations 3D complexes, où les approches entièrement couplées peuvent être instables ou inefficaces sur le plan computationnel.
3. L’objet dd_solver()
Le point d’entrée pour le contrôle de la résolution des équations électriques à l’aide de Lua est l’objet dd_solver(). Il permet d’accéder directement au solveur interne de dérive-diffusion/Newton, ce qui permet de modifier à la volée l’ensemble des équations et la stratégie de résolution.
Concrètement, l’objet « résolveur » permet d’effectuer trois opérations essentielles :
- Vérifiez le contexte actuel du solveur (par exemple, le type de problème ou le biais appliqué).
- Activez ou désactivez les équations et les couplages directionnels individuellement.
- Effectuer une étape de résolution et récupérer une mesure de convergence/d’erreur.
Les domaines les plus fréquemment utilisés sont résumés dans le tableau ??.
| Champ | Signification | Utilisation typique. |
|---|---|---|
step_x, step_y, step_z |
Définit l’étendue spatiale à résoudre dans chaque direction. -1 résout l’ensemble du domaine ; 1 effectue le calcul par tranches successives. |
Décomposition directionnelle et solveurs basés sur la méthode des tranches. |
solve_pos_x, solve_pos_y, solve_pos_z |
Permet d’activer ou de désactiver le couplage de Poisson dans chaque direction. | Découplage des effets électrostatiques le long d’axes spécifiques. |
solve_je_x, solve_je_y, solve_je_z |
Il contrôle l’équation de continuité des électrons dans chaque direction. | Commande du transport directionnel. |
solve_jh_x, solve_jh_y, solve_jh_z |
Gère l’équation de continuité du trou dans chaque direction. | Commande du transport directionnel. |
solve_srh_e, solve_srh_h |
Permet la capture des électrons et des trous selon le mécanisme de Shockley-Read-Hall. | Conservation des mécanismes de piégeage dans les systèmes réduits. |
solve_nion |
Active ou désactive l’équation des ions mobiles. | Stabilisation du mouvement ionique dans les simulations de pérovskites. |
solve_singlet |
Permet de contrôler le solveur utilisé pour les états excités (singulet). | Désactivation des principes physiques liés aux excitons/OLED pendant les simulations électriques. |
verbose |
Permet de contrôler la sortie des informations de diagnostic du solveur. | Mode de débogage ou exécution silencieuse. |
problem_type |
Indique l’étape actuelle du processus de résolution. | Appliquer la logique de manière sélective (par exemple, uniquement dans la boucle principale). |
Vapplied |
Renvoie la tension terminale appliquée. | Logique de contrôle fonctionnant en fonction des polarisations. |
scale_dphi_for_Bfree |
Paramètre d’échelle pour les mises à jour du potentiel interne. | Réglage numérique avancé. |
Outre l’accès aux champs, le solveur met à disposition un petit nombre de méthodes essentielles :
| Méthode | Rôle |
|---|---|
a:run() |
Exécute l’étape de résolution configurée et renvoie une valeur indiquant l’importance de l’erreur. |
a.set_newton_state("x") |
Sélectionne ou crée un état Newton enregistré. Cela permet de conserver des copies indépendantes des variables de solution (potentiel, densités de porteurs, taux d’occupation des pièges) pour différentes passes directionnelles. |
8. Résumé
L’utilisation du langage de script Lua dans OghmaNano permet de contrôler directement le solveur interne de dérive-diffusion, ce qui permet à l’utilisateur de modifier le système mathématique en cours de résolution pendant l’exécution. Contrairement aux approches de script externes, qui opèrent sur des fichiers d’entrée, Lua agit directement dans la boucle du solveur et peut donc modifier les ensembles d’équations, les couplages directionnels et le comportement de convergence étape par étape. Cette fonctionnalité est particulièrement utile dans les situations où la formulation standard entièrement couplée n’est ni physiquement appropriée ni numériquement efficace. Les exemples incluent le blocage des degrés de liberté lents, tels que les ions mobiles, ou la décomposition de problèmes 3D complexes en étapes directionnelles à l’aide de stratégies de type ADI.
Les exemples présentés ici illustrent deux cas d’utilisation importants. Le premier démontre une intervention minimale, où l’équation ionique est désactivée uniquement dans la boucle électrique principale afin de reproduire les conditions expérimentales de balayage rapide. Le second montre comment Lua peut être utilisé pour créer un processus de résolution personnalisé, en alternant entre des coupes directionnelles et en appliquant des critères de convergence définis par l’utilisateur.
De manière plus générale, Lua doit être considéré comme un cadre de développement de méthodes numériques au sein d’OghmaNano. Il permet à l’utilisateur de dépasser les configurations de solveur prédéfinies et de définir plutôt des stratégies de résolution personnalisées, qui sont adaptées à la fois à la physique du problème et aux propriétés numériques du système à résoudre.