OghmaNano에서 전기적 뉴턴 솔버에 대한 Lua 스크립팅
1. 서론
OghmaNano는 내장된 Lua 스크립팅 인터페이스를 제공하여 런타임 시 내부 수치 솔버를 수정할 수 있게 합니다. 이를 통해 방정식의 활성화/비활성화, 3차원 뉴턴 솔버의 변경, 과도 상태나 J–V 스캔 중 특정 물리 현상의 고정 처리, 그리고 사용자 정의 반복 전략의 구현과 같은 고급 제어가 가능합니다.
이는 외부 스크립팅과는 구별된다. 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 스크립팅 편집기 접근 방법
유한차분 시간영역법(FDTD) 스크립트 편집기는 메인 창의 전기적 리본 메뉴에서 접근할 수 있으며, 이는 ??에 나와 있습니다. 드리프트-확산 솔버 제어 옆에 위치한 작은 드롭다운 화살표를 클릭하면 메뉴가 열리는데, 이는 ??에 표시되어 있습니다. 이후 ‘마이크로코드 편집’을 클릭하면 유한차분 시간영역법(FDTD) 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 값을 설정하여 이동 이온 관련 방정식을 비활성화한 뒤, 수정된 방정식 세트를 기반으로 솔버가 실행됩니다. “Perovskite cells/Perovskite solar cell - frozen ions (MAPI)” 항목에 포함된 예제 시뮬레이션에서 이러한 방식이 활용된 사례를 확인할 수 있습니다.
5. 예제: ADI 스캐닝(교차 방향 암시적 방법)
Lua 스크립팅을 활용한 보다 고급적인 예시로는 복잡한 3차원 문제를 해결하기 위한 교차 방향 암시적(ADI) 전략의 구현이 있다. 이 방법은 다차원 문제를 여러 개의 저차원 문제들로 분해하여 순차적으로 해결하는 방식으로, 교차 방향 암시적 방법과 밀접한 관련이 있다.
OghmaNano에서는 이러한 기법을 솔버 레벨에서 구현할 수 있으며, 방향성 결합을 선택적으로 활성화하거나 비활성화함으로써 실현됩니다. 완전히 결합된 3차원 시스템을 한 번에 해결하는 대신, 계산 영역을 교차 방향으로 순차적으로 스캔하는 방식을 사용합니다. 이 방법은 해결이 까다로운 3차원 드리프트-확산 문제에서 안정성과 수렴성을 크게 향상시킬 수 있습니다.
여기서 사용되는 전략은 3차원 문제를 방향별로 분할하여 처리하는 것입니다. 첫 번째 단계에서는 솔버가 x-슬라이스 단위로 작동하여 y와 z 방향에 대한 전체 영역을 해석하되 x 방향의 결합 효과는 제거합니다. 두 번째 단계에서는 솔버가 z-슬라이스 단위로 전환하여 그에 상응하는 연산을 수행합니다. 이때 발생하는 총 오차가 누적되어 사용자 정의 수렴 기준으로 활용됩니다.
아래 예시는 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차원 시뮬레이션에서 특히 유용하다.
3. dd_solver() 객체
OghmaNano에서 전기적 솔버를 런타임 제어하기 위한 진입점은 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") |
저장된 뉴턴 솔버 상태를 선택하거나 생성합니다. 이를 통해 x-축 및 z-축 방향 스캔 시 각각에 대해 전위, 전하 캐리어 밀도, 트랩 점유도와 같은 해법 변수들의 독립적인 복사본을 유지할 수 있습니다. |
8. 요약
OghmaNano에서의 Lua 스크립팅 기능을 통해 내부 드리프트-확산 솔버를 직접 제어할 수 있으며, 사용자는 런타임 시 해결되는 수학적 방정식 체계를 자유롭게 변경할 수 있다. 외부 스크립트가 입력 파일을 기반으로 작동하는 것과 달리 Lua는 솔버 루프 내부에서 실행되므로 단계별로 방정식 집합, 방향성 결합 방식 및 수렴 특성을 변경할 수 있다. 이러한 기능은 기존의 완전 결합 형태의 수식 모델이 물리적으로 부적절하거나 수치적 효율성이 떨어지는 경우에 특히 유용하다. 예를 들어 이동 이온과 같은 느리게 변하는 변수들을 고정시키거나, ADI 방식을 활용하여 복잡한 3차원 문제를 방향성 기반의 단계들로 분해하는 것이 가능하다.
여기서 제시된 예시들은 두 가지 주요 활용 사례를 보여준다. 첫 번째 예시에서는 빠른 스캔 실험 조건을 재현하기 위해 이온 관련 방정식만을 주요 전기적 루프 내에서 비활성화하는 최소한의 개입 방식을 보여준다. 두 번째 예시에서는 Lua를 활용하여 방향별 슬라이스 처리를 번갈아 수행하고 사용자가 지정한 수렴 기준을 적용함으로써 맞춤형 솔버 워크플로우를 구축하는 방법을 설명한다.
보다 일반적으로, Lua는 OghmaNano 내에서 수치 해석 기법 개발을 위한 프레임워크로 간주되어야 한다. 이를 통해 사용자는 미리 정해진 솔버 설정에만 의존하는 대신, 문제의 물리적 특성 및 해석 대상 시스템의 수치적 특성에 부합하는 맞춤형 해법 전략을 설계할 수 있다.