Strona główna Przykłady Zrzuty ekranu Instrukcja obsługi Logo Bluesky. YouTube ☰
OghmaNano Platforma do symulacji wielofizycznych procesów zachodzących w optoelektronicznych urządzeniach i systemach fotonicznych. POBIERZ Przewodnik szybkiego uruchomienia

Implementacja skryptów Lua dla elektrycznego solvera Newtona w programie OghmaNano.

1. Wprowadzenie

OghmaNano zawiera wbudowany interfejs skryptowy Lua, który umożliwia modyfikowanie wewnętrznego solvera numerycznego w czasie rzeczywistym. Pozwala to na zaawansowaną kontrolę, taką jak włączanie lub wyłączanie równań, modyfikowanie trójwymiarowego solvera Newtona, zatrzymywanie wybranych parametrów fizycznych podczas stanów przejściowych lub skanowań charakterystyki prądowo-napięciowej (J–V) lub wdrażanie niestandardowych strategii iteracyjnych.

Jest to odmienne od wykorzystywania zewnętrznych skryptów. Języki takie jak Python działają poprzez modyfikowanie sim.json i uruchamianie modułu rozwiązującego, co czyni je odpowiednimi do przeprowadzania analiz parametrów, wykonywania zadań wsadowych i przetwarzania wyników.

W przeciwieństwie do tego, Lua działa wewnątrz modułu rozwiązującego, umożliwiając bezpośrednią ingerencję w proces obliczeniowy bez konieczności modyfikowania podstawowego kodu w języku C.

2. Czym jest Lua?

Lua to lekki, wydajny język skryptowy, który został zaprojektowany do wbudowywania w większe aplikacje. Jest szeroko stosowany w takich dziedzinach, jak silniki gier i oprogramowanie naukowe, gdzie konieczne jest modyfikowanie wewnętrznego działania bez ponownej kompilacji głównego kodu. W porównaniu z językiem Python, Lua zajmuje znacznie mniej miejsca i generuje mniejsze obciążenie podczas działania, co czyni go bardziej odpowiednim do wykonywania w krytycznych dla wydajności pętlach. W porównaniu z językiem C, pisanie i modyfikowanie kodu w Lua jest znacznie łatwiejsze, a jednocześnie zapewnia precyzyjną kontrolę nad zachowaniem programu. Dzięki tym właściwościom Lua doskonale nadaje się do OghmaNano, gdzie jest wykorzystywany do bezpośredniego wpływania na numeryczny solver podczas działania programu.

Aby dać ci wyobrażenie o języku Lua, jeśli jeszcze w nim nie programowałeś, poniżej znajduje się implementacja klasycznego algorytmu sortowania bąbelkowego.

Electrical ribbon in OghmaNano showing the drift diffusion solver control
Elektryczna taśma w programie OghmaNano, prezentująca dostęp do elementów sterujących solverem równania dyfuzji.
Dropdown menu in the electrical ribbon showing the edit microcode option
Rozwijane menu z paska narzędzi elektrycznego, wyświetlające opcję „Edytuj mikroprogram”.
Lua scripting editor in OghmaNano
Edytor skryptów Lua w programie OghmaNano.

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. Otwieranie edytora skryptów Lua.

Edytor skryptów Lua jest dostępny na pasku narzędzi okna głównego, jak pokazano na ilustracji ??. Kliknij małą strzałkę rozwijającą obok kontrolki solvera równań dyfuzji, aby otworzyć menu, które jest przedstawione na ilustracji ??. Następnie kliknij opcję „Edytuj mikrokod”, aby otworzyć edytor Lua, który jest pokazany na ilustracji ??.

Naciśnij Ctrl+S, aby zapisać skrypt, lub użyj przycisku zapisu w pasku narzędzi edytora. Aby włączyć mikrokod, należy nacisnąć przycisk aktywacji, jak pokazano na ilustracji ??.

3. Prosty przykład – ogniwa słoneczne z perowskitu z zablokowanymi jonami.

Prosty przykład zastosowania języka skryptowego Lua można znaleźć w symulacjach urządzeń perowskitowych, gdzie można chcieć zatrzymać ruchliwe jony podczas pomiaru charakterystyki prądowo-napięciowej (J–V). Perowskity zawierają ruchliwe jony, które przemieszczają się stosunkowo wolno. W praktyce najpierw poddaje się urządzenie działaniu ujemnego napięcia, aby jony ułożyły się w określonej konfiguracji, a następnie bardzo szybko wykonuje się pomiar charakterystyki prądowo-napięciowej, zanim zdążą one w znaczący sposób zmienić swoje położenie.

W programie OghmaNano, gdy włączony jest model jonów perowskitu, solver elektryczny zazwyczaj umożliwia jonowi relaksację w każdym kroku zmiany napięcia. Jest to równoważne bardzo powolnemu lub zbliżonemu do stanu ustalonego pomiarowi charakterystyki prądowo-napięciowej (J–V). Może to być przydatne w niektórych przypadkach, ale nie odzwierciedla to eksperymentów, w których napięcie zmienia się znacznie szybciej. Aby symulować tego typu pomiar, można użyć poniższego skryptu Lua, który „zamraża” jony w momencie rozpoczęcia głównej pętli elektrycznej. Symulacja nadal może osiągać wymagane początkowe napięcie w normalny sposób, umożliwiając jonowi przemieszczanie się podczas przygotowań, ale po wejściu do głównej pętli równanie jonowe zostaje wyłączone.


-- 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

W tym przykładzie najpierw tworzony jest obiekt solvera, a następnie zmniejszana jest ilość danych wyjściowych służących do diagnostyki. Następnie skrypt sprawdza, czy aktualny etap działania solvera odpowiada głównemu obwodowi elektrycznemu. Jeśli tak, równanie opisujące ruch jonów jest wyłączane poprzez ustawienie wartości solve_nion=false, a następnie solver jest uruchamiany z tym zmodyfikowanym zestawem równań. Przykładowa symulacja wykorzystująca tę metodę znajduje się w przykładach dołączonych do modelu, w sekcji „Perowskitowe ogniwa/Perowskitowe ogniwo słoneczne – zamrożone jony (MAPI)”.

5. Przykład: skanowanie metodą ADI (Alternating-Direction Implicit).

Bardziej zaawansowanym przykładem wykorzystania języka Lua jest implementacja strategii opartej na naprzemiennych kierunkach, służącej do rozwiązywania złożonych problemów w przestrzeni trójwymiarowej. To podejście jest ściśle związane z metodą naprzemiennych kierunków (ADI), w której wielowymiarowy problem jest rozkładany na sekwencję rozwiązań w niższych wymiarach.

W OghmaNano tę koncepcję można zaimplementować bezpośrednio na poziomie solvera, poprzez selektywne włączanie i wyłączanie kierunkowych sprzężeń. Zamiast rozwiązywać w jednym kroku w pełni sprzężony trójwymiarowy system, obszar analizy jest przetwarzany naprzemiennie w różnych kierunkach. Może to znacząco poprawić stabilność i zbieżność w przypadku trudnych trójwymiarowych problemów związanych z dryfem i dyfuzją.

Zastosowana tutaj strategia polega na podziale trójwymiarowego problemu na oddzielne etapy, w których obliczenia prowadzone są w określonych kierunkach. W pierwszym etapie algorytm rozwiązuje problem w przekrojach wzdłuż osi x, uwzględniając pełny zakres w osiach y i z, przy jednoczesnym eliminowaniu zależności w kierunku x. W drugim etapie algorytm przełącza się na przekroje wzdłuż osi z i wykonuje uzupełniające obliczenia. Całkowity błąd jest akumulowany i wykorzystywany do zdefiniowania niestandardowego kryterium zbieżności.

Poniższy przykład ilustruje, jak można skonstruować skan w stylu ADI, korzystając z języka 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

W tej implementacji w każdej iteracji wykonywane są dwa cykle obliczeń w różnych kierunkach. W pierwszym cyklu wyłączane są składniki równania Poissona i transportu nośników w kierunku x, co w efekcie prowadzi do rozwiązywania równania dla poszczególnych przekrojów wzdłuż osi x. W drugim cyklu wyłączane są odpowiednie składniki w kierunku z, co daje w rezultacie uzupełniający cykl obliczeń.

Dla każdego kierunku obliczeń utrzymywane są oddzielne stany Newtona, co umożliwia zachowanie niezależnych zmiennych wewnętrznych, takich jak potencjał elektrostatyczny, gęstość nośników i stopień wypełnienia pułapek, zgodnie z set_newton_state().

Proces konwergencji jest kontrolowany w sposób wyraźny w skrypcie Lua. Pętla kończy się, gdy spełniony zostanie jeden z następujących warunków: błąd i liczba iteracji w danym przebiegu osiągną określony próg, skumulowany błąd spadnie poniżej zdefiniowanej wartości tolerancji lub zostanie osiągnięta maksymalna liczba iteracji.

Ten przykład ilustruje, w jaki sposób skryptów Lua można użyć do tworzenia w pełni konfigurowalnych procesów rozwiązywania problemów. Zamiast polegać na ustalonym schemacie numerycznym, użytkownik może bezpośrednio zdefiniować sposób rozkładu wielowymiarowego systemu, sposób zarządzania stanami pośrednimi oraz sposób oceny zbieżności. Jest to szczególnie przydatne w przypadku złożonych symulacji 3D, w których w pełni sprzężone metody mogą być niestabilne lub obliczeniowo nieefektywne.

3. Obiekt dd_solver()

Punktem wyjścia dla sterowania rozwiązaniem równań elektrycznych za pomocą języka Lua jest obiekt dd_solver(). Zapewnia on bezpośredni dostęp do wewnętrznego solvera opartego na metodzie dryfu i dyfuzji/metodzie Newtona, umożliwiając modyfikację zarówno zestawu równań, jak i strategii rozwiązywania w czasie rzeczywistym.

W praktyce obiekt solver umożliwia wykonanie trzech podstawowych operacji:

  1. Sprawdź aktualny kontekst działania algorytmu (np. typ problemu lub zastosowane ustawienia).
  2. Włącz lub wyłącz poszczególne równania i sprzężenia kierunkowe.
  3. Wykonaj krok algorytmu rozwiązywania i pobierz wartość miernika konwergencji/błędu.

Najczęściej stosowane pola przedstawiono w tabeli ??.

Pole Znaczenie Typowe zastosowanie
step_x, step_y, step_z Określa zakres przestrzenny, w jakim przeprowadzane jest obliczenie w każdym kierunku. -1 rozwiązuje problem dla całego obszaru; 1 wykonuje obliczenia warstwa po warstwie. Metoda dekompozycji kierunkowej i algorytmy oparte na przekrojach.
solve_pos_x, solve_pos_y, solve_pos_z Włącza lub wyłącza sprzężenie Poissona w każdym kierunku. Rozdzielenie oddziaływań elektrostatycznych wzdłuż wybranych osi.
solve_je_x, solve_je_y, solve_je_z Kontroluje równanie ciągłości elektronów w każdym kierunku. Sterowanie transportem w określonym kierunku.
solve_jh_x, solve_jh_y, solve_jh_z Kontroluje równanie ciągłości przepływu w każdym kierunku. Sterowanie transportem w określonym kierunku.
solve_srh_e, solve_srh_h Umożliwia wychwytywanie elektronów i dziur zgodnie z mechanizmem Shockleya–Reada–Halla. Zachowanie dynamiki pułapek w uproszczonych systemach.
solve_nion Włącza lub wyłącza funkcję obliczania równania jonów w urządzeniu mobilnym. Zatrzymywanie ruchu jonów w symulacjach perowskitów.
solve_singlet Steruje rozwiązaniem równań dla stanu wzbudzonego (stan singletowy). Wyłączanie mechanizmów fizycznych związanych z eksytonami/OLED podczas rozwiązywania problemów elektrycznych.
verbose Steruje wyświetlaniem komunikatów diagnostycznych solvera. Tryb debugowania lub tryb cichej pracy.
problem_type Wskazuje aktualny etap działania algorytmu. Stosowanie logiki w sposób selektywny (np. tylko w głównej pętli).
Vapplied Zwraca wartość przyłożonego napięcia na zaciskach. Logika sterowania zależna od polaryzacji.
scale_dphi_for_Bfree Parametr skalujący dla aktualizacji wewnętrznego potencjału. Zaawansowana optymalizacja parametrów numerycznych.

Oprócz możliwości dostępu do pól, moduł rozwiązujący udostępnia kilka kluczowych metod:

Metoda Rola
a:run() Wykonuje skonfigurowany krok algorytmu rozwiązywania i zwraca wartość metryki błędu.
a.set_newton_state("x") Wybiera lub tworzy zapisany stan Newtona. Umożliwia to utrzymywanie niezależnych kopii zmiennych rozwiązania (potencjału, gęstości nośników, zapełnienia pułapek) dla różnych kierunków obliczeń.

8. Podsumowanie

Skryptowanie w języku Lua w programie OghmaNano umożliwia bezpośrednią kontrolę nad wewnętrznym solverem równań dyfuzji, co pozwala użytkownikowi modyfikować rozwiązywany system matematyczny w czasie rzeczywistym. W przeciwieństwie do zewnętrznych metod skryptowania, które operują na plikach wejściowych, Lua działa wewnątrz pętli solvera, dzięki czemu może modyfikować zestawy równań, kierunkowe sprzężenia i zachowanie algorytmu w każdym kroku. Ta możliwość jest szczególnie przydatna w sytuacjach, gdy standardowe, w pełni sprzężone podejście nie jest ani fizycznie odpowiednie, ani numerycznie efektywne. Przykłady obejmują zamrażanie wolnych stopni swobody, takich jak ruchome jony, lub rozkładanie złożonych problemów 3D na kierunkowe etapy za pomocą strategii w stylu ADI.

Przedstawione tutaj przykłady ilustrują dwa kluczowe zastosowania. Pierwszy pokazuje minimalną interwencję, w której równanie jonowe jest wyłączone tylko w głównym obwodzie elektrycznym, aby odtworzyć warunki eksperymentalne przy szybkim skanowaniu. Drugi przykład demonstruje, jak Lua może być wykorzystana do tworzenia niestandardowego algorytmu rozwiązywania, przełączającego się między sekwencyjnymi przekrojami i stosującego zdefiniowane przez użytkownika kryteria zbieżności.

Ogólnie rzecz biorąc, Lua należy traktować jako platformę do tworzenia metod numerycznych w ramach OghmaNano. Umożliwia ona użytkownikowi odejście od z góry ustalonych konfiguracji solverów i zamiast tego definiowanie dostosowanych strategii rozwiązywania, które uwzględniają zarówno fizykę problemu, jak i właściwości numeryczne rozwiązywanego systemu.