Використання мови Lua для створення скриптів для електричного чисельного розв’язувача Ньютона в OghmaNano.
1. Вступ
OghmaNano містить вбудований інтерфейс Lua для написання скриптів, що дає змогу змінювати внутрішній числовий розв’язувач під час роботи програми. Це забезпечує розширені можливості керування, зокрема можливість увімкнення або вимкнення рівнянь, зміни тривимірного розв’язувача Ньютона, призупинення обраних фізичних процесів під час перехідних явищ або під час сканування характеристик струм-напруга, або реалізації спеціальних ітеративних стратегій.
Це відрізняється від зовнішнього скриптингу. Мови програмування, такі як Python, працюють шляхом модифікації sim.json та запуску вирішувача, що робить їх придатними для виконання серій обчислень із різними параметрами, пакетної обробки та подальшої обробки результатів.
На відміну від цього, Lua працює всередині вирішувача, що дає змогу безпосередньо впливати на числовий процес, не змінюючи базовий код на мові C.
2. Що таке Lua?
Lua — це легка, високопродуктивна мова сценаріїв, розроблена для вбудовування у великі програми. Її широко використовують у таких сферах, як ігрові рушії та наукове програмне забезпечення, де внутрішню логіку потрібно змінювати без повторної компіляції основного коду. Порівняно з Python, Lua має значно менший розмір і менші витрати на час виконання, що робить її більш придатною для виконання всередині критичних для продуктивності циклів. Порівняно з C, її значно простіше використовувати для написання та модифікації коду, при цьому зберігається можливість точного контролю над поведінкою програми. Завдяки цим властивостям Lua особливо добре підходить для OghmaNano, де її використовують для безпосереднього впливу на чисельний розв’язувач під час виконання.
Щоб ви отримали уявлення про Lua, особливо якщо ви ще не працювали з нею, ось реалізація класичного алгоритму сортування бульбашкою.
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. Відкриття редактора сценаріїв Lua.
До редактора сценаріїв Lua можна отримати доступ через панель інструментів головного вікна, як показано на ??. Натисніть на невелику стрілку розкривного списку поруч із елементом керування розв’язувача рівнянь переносу-дифузії, щоб відкрити меню, яке показано на ??. Потім натисніть «Редагувати мікрокод», щоб відкрити редактор Lua, який показано на ??.
Натисніть Ctrl+S, щоб зберегти скрипт, або скористайтеся кнопкою «Зберегти» на панелі інструментів редактора. Щоб активувати мікрокод, потрібно натиснути кнопку активації, як показано на ??.
3. Простий приклад – перовськітні сонячні елементи із замороженими іонами.
Простий приклад використання скриптів Lua можна навести на прикладі моделювання перовськитних пристроїв, де може знадобитися зафіксувати рухливі іони під час сканування залежності струму від напруги (J–V). Перовськити містять рухливі іони, які відносно повільно переміщуються. На практиці пристрій спочатку утримують при від’ємній напрузі, щоб іони перемістилися в певну конфігурацію, а потім проводять дуже швидке сканування залежності J–V, перш ніж вони встигнуть суттєво змінити свій стан.
У OghmaNano, коли ввімкнено модель іонів перовськіту, електричний розв’язувач зазвичай дозволяє іонам досягати стану рівноваги на кожному кроці зміни напруги. Це еквівалентно дуже повільному або наближеному до сталого стану скануванню залежності струму від напруги (J–V). Це може бути корисним у деяких випадках, але не відтворює експерименти, в яких напруга змінюється набагато швидше. Щоб імітувати такий тип вимірювання, можна використати наведений нижче скрипт Lua, щоб зафіксувати іони на початку основного електричного циклу. Моделювання все ще може поступово досягати необхідної початкової напруги звичайним способом, дозволяючи іонам рухатися під час підготовки, але після початку основного циклу рівняння для іонів вимикається.
-- 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
У цьому прикладі спочатку створюється об’єкт розв’язувача, а потім зменшується обсяг діагностичної інформації, що виводиться. Далі скрипт перевіряє, чи відповідає поточний етап роботи розв’язувача основному електричному контуру. Якщо так, то мобільне іонне рівняння вимикається шляхом встановлення значення solve_nion=false, після чого розв’язувач запускається з використанням цього зміненого набору рівнянь. У прикладах, що входять до моделі, можна знайти приклад моделювання, який використовує цей підхід і знаходиться в розділі «Перовськитні елементи/Перовськитна сонячна батарея – заморожені іони (MAPI)».
5. Приклад: сканування за методом ADI (альтернативний покроковий неявний метод).
Більш вдосконалений приклад використання Lua-скриптів – це реалізація стратегії чергування напрямків для розв’язання складних тривимірних задач. Цей підхід тісно пов’язаний із неявним методом чергування напрямків (ADI), в якому багатовимірну задачу розбивають на послідовність розв’язань у меншій кількості вимірів.
У OghmaNano цю ідею можна реалізувати безпосередньо на рівні розв’язувача, вибірково вмикаючи та вимикаючи направлені зв’язки. Замість того, щоб розв’язувати повністю зв’язану тривимірну систему за один крок, область обчислення опрацьовується по черзі в різних напрямках. Це може значно покращити стабільність і збіжність для складних тривимірних задач, пов’язаних із дрейфом і дифузією.
Стратегія, яка використовується тут, полягає в тому, щоб розбити тривимірну задачу на окремі етапи, кожен з яких орієнтований на певний напрямок. На першому етапі розв’язувач працює з поперечними зрізами по осі x, розв’язуючи задачу повністю в напрямках y і z, при цьому усуваються взаємозв’язки в напрямку x. На другому етапі розв’язувач переходить до поперечних зрізів по осі z і виконує додаткову операцію. Загальна похибка накопичується та використовується для визначення спеціального критерію збіжності.
Наведений нижче приклад демонструє, як можна створити сканування в стилі ADI, використовуючи 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
У цій реалізації в межах кожної ітерації виконуються два послідовні проходження. Під час першого проходження відключаються члени, що описують транспорт Пуассона та носіїв заряду в напрямку осі x, що фактично дозволяє розв’язувати систему по секціях вздовж осі x. Під час другого проходження відключаються відповідні члени, що описують напрямок осі z, і здійснюється додаткове проходження.
Для кожного напрямку обчислення підтримуються окремі стани Ньютона, що реалізується за допомогою set_newton_state(), що дозволяє розв’язувачу зберігати незалежні внутрішні змінні, такі як електростатичний потенціал, концентрації носіїв заряду та заповненість пасток.
Збіжність контролюється безпосередньо у скрипті Lua. Цикл завершується, коли або значення похибки та кількість ітерацій на кожному проході відповідають заданому пороговому значенню, або сумарна похибка опускається нижче вказаного допустимого рівня, або досягається максимальна кількість ітерацій.
Цей приклад демонструє, як за допомогою скриптів Lua можна створювати повністю індивідуальні робочі процеси для розв’язування задач. Замість використання фіксованої чисельної схеми, користувач може безпосередньо визначати, як розбивається багатовимірна система, як обробляються проміжні стани та як оцінюється збіжність. Це особливо цінно для складних тривимірних моделювань, де повністю інтегровані підходи можуть бути нестабільними або обчислювально неефективними.
3. Об’єкт dd_solver()
Точкою входу для керування електричним розв’язувачем за допомогою Lua є об’єкт dd_solver(). Це забезпечує прямий доступ до внутрішнього розв’язувача, що використовує методи дрейфу-дифузії та метод Ньютона, що дає змогу змінювати як набір рівнянь, так і стратегію розв’язування під час роботи програми.
На практиці об’єкт-розв’язувач забезпечує виконання трьох основних операцій:
- Перевірте поточний контекст вирішувача (наприклад, тип задачі або застосовані параметри).
- Увімкніть або вимкніть окремі рівняння та спрямовані зв’язки.
- Виконайте один крок алгоритму розв’язання та отримайте значення показника збіжності/похибки.
Найчастіше використовувані поля узагальнено в таблиці ??.
| Поле | Значення | Типове застосування |
|---|---|---|
step_x, step_y, step_z |
Регулює просторовий об’єм, який обчислюється в кожному напрямку. -1 обчислює значення для всієї області; 1 виконує обчислення пошарово. |
Направлений метод розкладання та алгоритми, що базуються на зрізах. |
solve_pos_x, solve_pos_y, solve_pos_z |
Увімкнює або вимикає зв’язок Пуассона в кожному напрямку. | Роз’єднання електростатичних сил уздовж обраних осей. |
solve_je_x, solve_je_y, solve_je_z |
Регулює рівняння неперервності електронного потоку в кожному напрямку. | Управління транспортними потоками за допомогою системи навігації. |
solve_jh_x, solve_jh_y, solve_jh_z |
Регулює рівняння неперервності отвору в кожному напрямку. | Управління транспортними потоками за допомогою системи навігації. |
solve_srh_e, solve_srh_h |
Забезпечує ефект захоплення електронів і дірок відповідно до моделі Шоклі–Ріда–Холла. | Збереження динаміки пасток у спрощених системах. |
solve_nion |
Увімкнює або вимикає функцію обчислення мобільності іонів. | Заморожування іонного руху в моделюванні перовськитів. |
solve_singlet |
Керує розв’язувачем для збудженого стану (синглетного стану). | Відключення фізичних процесів, пов’язаних з ексітонами/OLED, під час електротехнічних розрахунків. |
verbose |
Керує виведенням діагностичної інформації розв’язувача. | Режим налагодження або тихий режим виконання. |
problem_type |
Показує поточну стадію розв’язування. | Вибіркове застосування логіки (наприклад, лише до основного циклу). |
Vapplied |
Повертає значення прикладеної напруги на клемах. | Логіка керування, що залежить від зміщення. |
scale_dphi_for_Bfree |
Параметр масштабування для оновлення внутрішнього потенціалу. | Удосконалене налаштування числових параметрів. |
Окрім можливості доступу до полів, засіб розв’язання задач надає доступ до невеликої кількості ключових методів:
| Метод | Роль |
|---|---|
a:run() |
Виконує налаштований крок розв’язувача та повертає показник помилки. |
a.set_newton_state("x") |
Вибирає або створює збережений стан Ньютона. Це дає змогу підтримувати незалежні копії змінних розв’язку (потенціал, концентрації носіїв заряду, заповненість пасток) для різних напрямків обчислень. |
8. Підсумок.
Використання мови Lua для створення скриптів в OghmaNano забезпечує прямий контроль над внутрішнім розв’язувачем рівнянь дифузії, що дає користувачеві змогу змінювати математичну систему, яка розв’язується, під час роботи програми. На відміну від зовнішніх методів створення скриптів, які оперують з вхідними файлами, Lua працює безпосередньо в циклі розв’язувача, і тому може змінювати набори рівнянь, напрямні зв’язки та характеристики збіжності поетапно. Ця можливість особливо цінна в ситуаціях, коли стандартна повністю зв’язана модель є або фізично недоречною, або неефективною з обчислювальної точки зору. Приклади включають «заморожування» повільних ступенів свободи, таких як рухомі іони, або розкладання складних тривимірних задач на окремі етапи з використанням стратегій, подібних до ADI.
Наведені тут приклади ілюструють два основні сценарії використання. Перший демонструє мінімальне втручання, коли іонне рівняння відключається лише в основній електричній петлі для відтворення умов швидкого сканування під час експерименту. Другий показує, як Lua можна використовувати для створення спеціалізованого алгоритму розв’язання, який по черзі використовує різні напрямки сканування та застосовує визначені користувачем критерії збіжності.
У більш загальному сенсі, Lua слід розглядати як платформу для розробки чисельних методів у рамках OghmaNano. Вона дає змогу користувачеві відійти від фіксованих конфігурацій розв’язувачів і натомість визначати індивідуальні стратегії розв’язання, які відповідають як фізичним характеристикам задачі, так і числовим властивостям системи, що розв’язується.