1. 개요
| 제조해 Method of Manufactured Solutions | |
|---|---|
| 분야 | 코드 검증(code verification) |
| 핵심 발상 | 해를 먼저 정하고 소스항을 역산한다 |
| 판정 지표 | 관측 수렴 차수 pobs 가 이론 차수와 일치하는가 |
| 정리 | Steinberg & Roache (1985), Roache (2002), Salari & Knupp (2000) |
| 못 잡는 것 | 모델 오류, 해의 존재·유일성, 비매끈 해 전용 버그 |
제조해(Method of Manufactured Solutions, MMS)는 원하는 해를 먼저 지어낸 다음 그 해가 정확해가 되도록 지배 방정식에 소스항을 역산해 넣고, 코드가 그 해를 이론 수렴 차수로 재현하는지 보는 코드 검증 기법이다. 「정답지를 먼저 쓰고 시험지를 거꾸로 만든다」고 보면 된다.
검증 및 확인 문서가 MMS의 다섯 단계를 이미 요약했으니, 여기서는 그 요약이 생략한 것들 — 해를 어떻게 골라야 버그가 숨지 못하는지, 경계조건을 어떻게 맞추는지, 차수 시험이 어떤 버그를 잡고 어떤 버그를 놓치는지 — 를 판다. 핵심 메시지는 하나다. MMS는 「오차가 작다」를 보는 게 아니라 **「오차가 줄어드는 속도가 맞다」**를 본다. 오차 크기는 거짓말을 할 수 있어도, 차수는 거의 거짓말을 못 한다.
2. 코드 검증과 솔루션 검증은 다른 질문이다
V&V 용어에서 **검증(verification)**은 두 갈래다.
| 코드 검증 | 솔루션 검증 | |
|---|---|---|
| 질문 | 이산화와 구현이 맞는가 | 이 계산의 이산화 오차는 얼마인가 |
| 정답 | 있음(제조해) | 없음(외삽으로 추정) |
| 대표 도구 | MMS + 차수 시험 | 격자 수렴 지수, 리처드슨 외삽법 |
| 빈도 | 코드가 바뀔 때마다 | 계산을 할 때마다 |
GCI는 코드가 이미 맞다는 전제 위에서 오차 막대를 그린다. 그 전제를 세워 주는 것이 MMS다. 순서가 뒤집히면 — 버그 있는 코드로 GCI를 계산하면 — 「수렴은 아주 잘 되는데 엉뚱한 방정식으로 수렴하는」 해에 정교한 오차 막대를 붙이게 된다. 실제로 메시 독립성 연구는 통과하면서 MMS는 떨어지는 코드가 흔하다. 격자를 아무리 늘려도 틀린 이산 방정식의 해는 틀린 채로 수렴하기 때문이다.
3. 절차를 한 줄씩
연산자 과 문제 이 있다고 하자.
- 매끈한 함수 를 고른다.
- 기호 연산으로 를 계산한다. 손으로 하지 말고 SymPy·Maple·Mathematica로 한다.
- 수정된 문제 를 코드에 넣는다. 경계·초기조건도 에서 뽑는다.
- 격자 간격 에서 오차 를 잰다.
- 관측 차수를 계산한다.
판정 기준은 「 가 이론 차수 로 다가가는가」다. 성긴 격자에서는 고차 항 때문에 조금 어긋나도 되고, 세분할수록 붙어야 한다. 문턱값을 박아 둔 자동 회귀 테스트로 돌리는 게 정석이다.
4. 검산 — 차수 시험은 버그를 어떻게 잡나
변수 계수 확산 문제 , , 구간 에 제조해 를 골랐다. 양 끝 값이 0이 아니어서 디리클레 경계값이 실제로 쓰이도록 일부러 를 넣었다. 소스항은
2차 중앙 유한차분법(면 계수 )으로 풀고 최대노름 오차를 쟀다.
| 정상 코드 | 버그 코드 | |||
|---|---|---|---|---|
| 10 | 8.18e-3 | — | 7.39e-2 | — |
| 20 | 2.04e-3 | 2.006 | 7.23e-2 | 0.032 |
| 40 | 5.11e-4 | 1.997 | 7.02e-2 | 0.042 |
| 80 | 1.28e-4 | 2.000 | 6.89e-2 | 0.028 |
| 160 | 3.19e-5 | 2.000 | 6.81e-2 | 0.016 |
버그는 한 글자짜리다. 왼쪽 면 계수 를 로 잘못 적었다. 그러면 이산 연산자가 가 아니라 다른 연산자로 수렴해(일관성 상실) 차수가 0 이 된다. 눈여겨볼 점은 에서 버그 코드의 오차가 7% 남짓이라는 것이다. 공학 그림 하나 그려 보면 「대충 맞네」 소리가 나올 크기다. 오차 크기만 봤으면 통과했을 버그를, 차수는 첫 세분에서 바로 잡는다.
정말 상수 계수 로 시험했으면 어땠을까? 이라 버그가 아예 드러나지 않는다. 이게 다음 절의 이유다.
5. 제조해를 고르는 법 — 모든 항이 일을 하게
MMS가 잡는 버그는 제조해가 건드린 항의 버그뿐이다. 그래서 해 선택에 규칙이 있다(Salari & Knupp, Roache).
- 모든 항이 0이 아니어야 한다. 선형 해는 2계 도함수가 0이라 확산항 버그를 못 잡는다. 상수 계수는 계수 미분항을 못 잡는다. 시간 의존이 없으면 시간 적분기를 못 잡는다.
- 모든 항의 크기가 비슷해야 한다. 대류항이 확산항의 배면 확산항의 버그는 반올림 잡음에 묻힌다. 나비에-스토크스 방정식용 해는 대개 레이놀즈수를 1~100 수준으로 맞춘 사인·코사인 조합을 쓴다.
- 충분히 매끈해야 한다. 이론 차수는 해의 계 도함수가 유계라는 가정에서 나온다. 꺾인 해를 넣으면 코드가 맞아도 차수가 떨어진다.
- 좌표축을 섞어야 한다. 처럼 변수분리된 해는 교차 미분항 를 거의 시험하지 않는다. 비직교 격자 코드라면 같이 축을 섞는 항을 넣는다.
- 물리적일 필요는 없다. 단, 밀도·온도 같은 양은 양수로 유지해야 코드가 상태방정식에서 NaN을 뱉지 않는다.
여기서 「모든 항」은 연산자의 항만이 아니라 코드 경로까지 포함한다. 경계 근처의 특수 스텐실, 병렬 영역 경계의 고스트 셀 교환, 격자 비균일도 보정 — 이런 것들은 해가 아니라 격자와 분할 선택으로 건드려야 한다. 그래서 MMS는 균일 격자 하나로 끝내지 않고 일부러 비틀린 격자와 여러 프로세스 분할로 다시 돌린다1.
6. 경계조건과 차수 시험의 함정
경계조건도 제조해에서 뽑는다. 디리클레면 의 값을, 노이만이면 을 해석적으로 넣는다. 벽함수·출구 조건처럼 코드가 내부적으로 정해 버리는 경계는 그대로 시험할 수 없다 — 그런 경계는 제조해를 그 조건에 맞게 고르거나(예: 출구에서 기울기 0이 되도록) 별도 시험으로 뺀다.
1차 경계가 전체를 1차로 끌어내린다. 내부는 2차인데 노이만 경계를 1차 한쪽 차분으로 넣으면, 최대노름 차수는 대개 1차로 떨어진다(전역 노름에서는 1.5차 같은 어중간한 값이 나오기도 한다). 「노름에 따라 차수가 다르다」는 건 대개 경계층 국소 오차의 신호다. 그래서 와 를 둘 다 본다.
반올림 바닥. 격자를 계속 세분하면 언젠가 이산화 오차가 반복 해법 허용오차나 부동소수점 연산 반올림에 닿는다. 그 아래에서 가 0으로 무너지는 건 버그가 아니다. 선형 해법 수렴 기준을 이산화 오차보다 두세 자리 아래로 잡아 두면 이 바닥을 늦출 수 있다.
시공간 혼합 차수. 시간 2차·공간 2차 코드를 시험할 때는 로 같이 줄인다. 공간만 줄이면 시간 오차 바닥이 남아 차수가 무너진다. 공간 2차·시간 1차라면 로 줄여야 공간 차수가 깨끗이 보인다.
7. MMS가 못 하는 것
- 물리 모델 검사가 아니다. 난류 모델 상수가 틀렸어도 그 모델을 정확히 이산화했다면 MMS는 통과한다. 그건 확인(validation)의 몫이다.
- 해의 존재·유일성·안정성을 보증하지 않는다. 제조해는 원래 문제에 없는 소스항을 넣으므로, 원래 문제가 특정 매개변수에서 불안정해지는 성질은 따로 본다.
- 비매끈 해 전용 경로를 못 본다. 충격파 포착 전변분 감소 제한자가 극값에서 1차로 떨어지는 건 정상 동작이다. 제한자가 켜지는 상황의 버그는 리만 문제 같은 정확해와 비교하는 고전 시험이 더 잘 잡는다.
- 차수에 영향 없는 버그는 놓친다. 예를 들어 소스항 계수 0.5를 0.500001로 적은 버그는 차수를 바꾸지 않는다. 다만 이런 것은 오차 상수에 드러나므로, 표의 오차 크기 자체도 이전 버전과 비교해 둔다.
Roy 등(2004)은 압축성 유한체적 코드 두 개(Premo, Wind)에 MMS를 적용해 시험한 옵션에서 2차 공간 정확도를 확인했고, 그 과정에서 MMS가 찾아낸 코딩 실수도 함께 보고했다. 쓰인 사인·코사인 조합 제조해는 지금도 압축성 코드 검증의 출발점으로 그대로 가져다 쓰인다. 그리고 「오래 쓴 코드라 괜찮다」는 검증이 아니다2.
8. 역사와 실무 도구
발상 자체는 오래됐다. 스타인버그와 로치(Steinberg & Roache, 1985)가 기호 연산으로 소스항을 만드는 체계적 방법을 보였고, 「Method of Manufactured Solutions」라는 이름과 표준 절차는 로치의 2002년 논문과 샌디아의 살라리·크누프 보고서(2000)가 정착시켰다. 이후 ASME V&V 20 같은 표준과 오버캄프·로이의 교과서가 코드 검증의 기본 도구로 정리했다.
실무에서는 소스항이 수백 항이 되므로 사람이 손으로 옮기지 않는다. SymPy로 소스항을 만들고 C·Fortran 코드로 내보내는 것까지 자동화한다. 손으로 옮긴 소스항에 오타가 나면, 맞는 코드가 차수 시험에서 떨어지는 웃픈 상황이 생긴다3. 큰 코드는 이런 시험을 CI에 넣어 매 커밋마다 차수를 확인한다.
9. 관련 문서
- 검증 및 확인 · 격자 수렴 지수 · 메시 독립성 연구 · 리처드슨 외삽법
- 절단오차 · 유한차분법 · 유한체적법 · 경계 조건
- 나비에-스토크스 방정식 · 열방정식 · 포아송 방정식
- 불확실성 정량화 · 부동소수점 연산 · 회귀 테스트
10. Footnotes
이 문서의 주요 출처
- Roache (2002), Code Verification by the Method of Manufactured Solutions, J. Fluids Eng. 124(1), 4-10
- Salari & Knupp (2000), Code Verification by the Method of Manufactured Solutions, Sandia Report SAND2000-1444
- Oberkampf & Roy (2010), Verification and Validation in Scientific Computing, Cambridge University Press
- ASME V&V 20-2009, Standard for Verification and Validation in Computational Fluid Dynamics and Heat Transfer
- Roy, Nelson, Smith & Ober (2004), Verification of Euler/Navier-Stokes codes using the method of manufactured solutions, Int. J. Numer. Meth. Fluids 44(6), 599-620
의견을 반영할게요. 감사합니다.