소프트웨어 수치해석 마지막 수정: 2026-08-05 04:11:20

1. 개요[편집]

PETSc
Portable, Extensible Toolkit for Scientific Computation
개발아르곤 국립연구소 (Argonne National Laboratory)
시작1991 — Gropp · Smith · McInnes · Balay 등
언어C (Fortran · Python · C++ 바인딩 제공)
병렬 모델MPI 분산 메모리 (+ GPU 백엔드)
핵심 객체Vec · Mat · KSP · PC · SNES · TS · DM · TAO
라이선스BSD 2-clause
파이썬 바인딩petsc4py

솔버를 바꾸려고 코드를 다시 컴파일하는 시대는 1990년대에 끝났다. 명령줄에 -pc_type gamg 를 치면 된다.

PETSc(Portable, Extensible Toolkit for Scientific Computation, “펫시”로 읽는다)는 편미분방정식에서 나오는 대규모 희소 선형·비선형 방정식계를 분산 메모리 병렬 환경에서 푸는 C 기반 수치 라이브러리 모음이다. 미국 아르곤 국립연구소에서 1991년부터 개발됐고, 오늘날 유한요소법·유한체적법 기반 오픈소스 시뮬레이션 코드의 절반쯤은 그 밑바닥에 PETSc가 깔려 있다.

PETSc가 파는 것은 알고리즘 자체라기보다 알고리즘을 갈아 끼울 수 있는 뼈대다. 크리로프 부분공간법이나 다중격자법의 이론은 다른 문서에 있고, 이 문서는 그것들이 PETSc라는 그릇 안에서 어떻게 조립되는지를 다룬다.

2. 객체 계층[편집]

PETSc는 C로 짜였지만 철저히 객체지향적이다. 모든 타입은 불투명 핸들(Mat A;)이고, XXXCreateXXXSetTypeXXXSetFromOptionsXXXSetUp → 사용 → XXXDestroy 라는 동일한 생애주기를 갖는다. 계층은 대략 아래에서 위로 쌓인다.

  • Vec — 분산 벡터. 각 MPI 랭크가 연속한 인덱스 구간을 소유한다.
  • Mat — 분산 행렬. 아래 절 참고.
  • KSP — 크릴로프 부분공간 선형 솔버(KSPGMRES가 기본, KSPCG·KSPBCGS·KSPFGMRES·KSPMINRES 등).
  • PC전처리기. KSP 안에 하나씩 들어 있으며, 사실상 반복 횟수를 결정하는 주역이다.
  • SNES — 비선형 방정식 F(u)=0F(u)=0 솔버. 내부에 KSP를 갖는다.
  • TS — 시간 적분기. 내부에 SNES를 갖는다.
  • DM — 격자·자료구조 추상화. 구조 격자용 DMDA, 비정렬 메시 위상용 DMPlex, 다물리 결합용 DMComposite, 전력망 같은 그래프용 DMNetwork.
  • TAO — 최적화 모듈. 경계 제약·PDE 제약 최적화까지 커버한다.

즉 “시간을 전진시키려면 매 스텝 뉴턴을 풀고, 뉴턴 한 걸음마다 선형계를 풀고, 그 선형계는 전처리된 크릴로프로 푼다”는 계산과학의 표준 중첩 구조가 TS ⊃ SNES ⊃ KSP ⊃ PC 라는 객체 중첩으로 그대로 대응된다.1

3. 분산 행렬과 전처리기[편집]

병렬 희소행렬 기본형은 MATMPIAIJ다. 행 단위로 랭크에 쪼개고, 각 랭크의 지역 블록을 다시 대각 블록(자기가 소유한 열)과 비대각 블록(남의 열)으로 나눠 각각 CSR로 저장한다. 이 분리 덕에 행렬-벡터 곱에서 대각 블록 계산과 원격 성분 통신을 겹칠 수 있다. 조립은 MatSetValues 로 값을 흩뿌린 뒤 MatAssemblyBegin/MatAssemblyEnd 로 두 단계로 마무리하는데, 이 사이에도 통신과 계산이 겹친다.

여기서 초심자가 가장 크게 넘어지는 지점이 **사전 할당(preallocation)**이다. 행당 비영 원소 개수를 미리 알려주지 않으면 값을 넣을 때마다 재할당과 복사가 일어나 조립이 솔버보다 느려지는 촌극이 벌어진다. 체감상 수십 배는 우습게 차이 나며, -info 로그의 MatSetValues 할당 경고나 -mat_new_nonzero_allocation_err 로 즉시 잡아야 한다.2

전처리기 쪽은 뷔페에 가깝다.

PC 타입성격전형적 용처
PCJACOBI대각 스케일링기준선, 조건수가 착한 문제
PCILU불완전 LU순차 전용. 병렬에서는 블록 안에 넣어 쓴다
PCBJACOBI · PCASM블록 야코비 · 가법 슈바르츠영역 분할법 계열, 대류 지배 문제
PCGAMG내장 대수 다중격자타원형·확산 지배 문제
PCHYPREhypre BoomerAMG 래핑대규모 포아송류
PCFIELDSPLIT블록 분할안장점계, 다물리 연성
PCLU · PCCHOLESKY직접 분해소규모, 또는 이동-역변환의 내부

실무 국룰은 단순하다. 대칭 양정치(포아송 방정식, 열전도, 구조 강성행렬)면 CG + GAMG, 비대칭·대류 지배면 GMRES + ASM(블록 내부 ILU). 비압축성 유동이나 유체-구조 연성 같은 안장점 구조가 나오면 PCFIELDSPLIT 로 속도-압력 블록을 갈라 슈어 보수를 근사하는 것이 정석이다.

4. SNES와 행렬-프리[편집]

SNES의 기본은 라인서치 뉴턴법(SNESNEWTONLS)이다. 뉴턴-랩슨법 한 걸음

J(uk)δu=F(uk),uk+1=uk+λδuJ(u_k)\,\delta u = -F(u_k), \qquad u_{k+1} = u_k + \lambda\,\delta u

에서 λ\lambda라인서치(기본값은 백트래킹 + 큐빅 보간)로 정한다. 대안으로 신뢰 영역 방법(SNESNEWTONTR), 준-뉴턴법(SNESQN, L-BFGS), 비선형 다중격자(SNESFAS), 비선형 가법 슈바르츠(SNESNASM)가 준비돼 있다.

야코비안을 손으로 짜기 싫을 때의 탈출구가 두 개다. 하나는 유한차분 색칠(coloring)로 야코비안을 자동 근사하는 -snes_fd_color, 다른 하나가 JFNK(Jacobian-Free Newton-Krylov)다. 크릴로프 솔버는 야코비안 자체가 아니라 야코비안-벡터 곱만 필요하다는 사실을 이용해

J(u)v    F(u+hv)F(u)hJ(u)\,v \;\approx\; \frac{F(u + h v) - F(u)}{h}

로 대체한다. PETSc에서는 -snes_mf(전처리 없음) 또는 -snes_mf_operator(연산자는 행렬-프리, 전처리기는 근사 행렬로 구성)로 켠다. 같은 발상의 일반형이 MATSHELL로, 행렬 대신 “벡터를 받아 벡터를 돌려주는 함수”를 등록해 두면 KSP는 그것이 진짜 행렬인지 아닌지 알 필요도 없다. 격자 위 스텐실이든 고속 푸리에 변환 기반 연산자든 전부 이 인터페이스로 들어온다.

TS는 같은 철학을 시간 방향으로 확장한 것이다. 명시적 룽게-쿠타법(TSRK), 후진 오일러·θ법·BDF 같은 암시적 계열, 강성 항만 암시적으로 처리하는 IMEX(TSARKIMEX)를 런타임 옵션으로 갈아 끼운다. 강성 방정식에서 명시적/암시적 판단이 틀렸을 때 재컴파일 없이 바꿔 볼 수 있다는 것이 실제로 큰 이득이다. 여기에 이산 수반(discrete adjoint) 모듈이 붙어 있어 민감도 해석과 PDE 제약 최적화까지 이어진다.

5. 옵션 데이터베이스라는 철학[편집]

PETSc를 다른 라이브러리와 구별짓는 단 하나를 꼽으라면 런타임 옵션 데이터베이스다. 모든 객체는 XXXSetFromOptions()에서 명령줄·환경변수·설정 파일을 읽어 자기 타입과 파라미터를 결정한다. 그래서 소스를 한 줄도 안 고치고 이런 짓이 가능하다.

mpiexec -n 256 ./app \
  -ksp_type fgmres -ksp_rtol 1e-8 \
  -pc_type fieldsplit -pc_fieldsplit_type schur \
  -fieldsplit_0_pc_type gamg -fieldsplit_1_pc_type jacobi \
  -snes_monitor -ksp_converged_reason -log_view

접두사(-fieldsplit_0_)로 중첩된 하위 솔버까지 계층적으로 지정된다는 점이 핵심이다. 진단 옵션도 한 세트다. -ksp_monitor는 잔차 이력을, -ksp_view는 실제로 조립된 솔버 구성을 통째로 출력하고, -log_view는 함수별 시간·플롭·통신량 프로파일을 뽑는다. 수렴이 안 될 때 -ksp_converged_reason이 뱉는 DIVERGED_INDEFINITE_PC 같은 문자열은 이 바닥의 공용어에 가깝다.3

기본 수렴 판정은 상대 잔차 rtol=1e-5, 절대 atol=1e-50, 발산 dtol=1e5, 최대 반복 10000이다. 1e-5가 은근히 느슨해서, 비선형 반복 안에서 쓸 때는 몰라도 최종 답으로 쓰면 후회하기 좋다. SNES 쪽 기본값은 rtol=1e-8, 스텝 기준 stol=1e-8, 최대 뉴턴 반복 50이다.

6. 성능과 확장성[편집]

병렬 성능 이야기를 할 때 PETSc 진영이 반복해서 강조하는 사실이 하나 있다. 희소 행렬-벡터 곱은 계산이 아니라 메모리 대역폭에 묶여 있다. CSR 한 행을 처리하는 데 필요한 부동소수점 연산 대비 메모리 접근량이 너무 커서, 코어를 아무리 늘려도 노드 하나의 대역폭 위로는 못 올라간다. 그래서 소켓당 코어를 다 채워도 성능이 선형으로 안 오르는 현상이 정상이며, PETSc 문서는 아예 스트림 벤치마크를 먼저 돌려 기대치를 잡으라고 안내한다.4

-log_view 가 뱉는 표에서 실제로 봐야 할 것도 정해져 있다.

  • 각 단계의 시간 비중MatMult·PCApply·PCSetUp·VecDot. 전처리기 구성이 시간의 절반을 먹고 있으면 재사용 전략(KSPSetReusePreconditioner)을 검토할 때다.
  • 부하 불균형(ratio) — 랭크별 최대/평균 비가 1.2를 크게 넘으면 분할이 잘못됐다는 뜻이다. 격자 분할을 손보거나 MatPartitioning으로 재정렬한다.
  • 축약 연산 횟수VecDot·VecNorm은 전역 동기화를 유발한다. 랭크 수가 수천을 넘어가면 GMRES의 직교화가 통신 지연으로 병목이 되기 시작하고, 이때 파이프라인 크릴로프(KSPPGMRES·KSPPIPECG)나 통신 회피 변형이 선택지가 된다.

강스케일링(strong scaling)의 한계도 냉정하다. 랭크당 미지수가 대략 1만 개 아래로 떨어지면 통신이 계산을 잡아먹어 효율이 급락한다. “코어를 두 배 늘렸는데 왜 안 빨라지죠”의 대부분은 알고리즘이 아니라 이 지점의 문제이며, 답은 문제를 키우는 것(약스케일링)이거나 노드당 작업량을 유지하는 것이다.

7. 생태계[편집]

PETSc를 직접 부르는 사람보다 모르는 채로 쓰는 사람이 훨씬 많다. MOOSE, deal.II, libMesh, FEniCS/Firedrake, PyLith, PFLOTRAN, OpenFOAM의 petsc4Foam 어댑터가 전부 PETSc를 선형·비선형 솔버 백엔드로 쓴다. 고유값 쪽은 아예 별도 프로젝트가 위에 얹혀 있는데 그것이 SLEPc이고, PETSc는 hypre·MUMPS·SuperLU_DIST·ML 같은 외부 패키지를 --download-mumps 한 줄로 끌어와 PC/KSP 타입으로 노출한다. 사용자 입장에서는 외부 직접 솔버조차 -pc_type lu -pc_factor_mat_solver_type mumps 라는 옵션 문자열 하나로 보인다.

GPU 지원은 MATAIJCUSPARSE·VECKOKKOS 처럼 Vec/Mat 구현체를 갈아 끼우는 형태로 들어와 있다. 다만 이식성이 곧 성능은 아니어서, GPU 컴퓨팅에서 이득을 보려면 행렬 조립과 전처리기 선택까지 같이 손봐야 한다는 것이 경험칙이다.5

8. 관련 문서[편집]

9. Footnotes[편집]

  1. 이 중첩이 예쁜 만큼 스택 트레이스도 깊다. 세그폴트가 났을 때 TSSolve → SNESSolve → KSPSolve → PCApply → MatMult 다섯 겹을 타고 내려가면서 “내 잘못이 어디였더라”를 되짚는 것이 PETSc 사용자의 통과의례다. 그나마 PETSc는 에러 코드를 PetscCall() 매크로로 전파하면서 호출 스택을 직접 찍어 주니 양심적인 편.

  2. “PETSc가 느려요”의 8할은 사전 할당 누락이고, 나머지 2할은 -log_view를 한 번도 안 본 것이다. 매뉴얼이 이 얘기를 몇 번이나 반복하는데도 매년 같은 질문이 메일링 리스트에 올라온다.

  3. DIVERGED_INDEFINITE_PC는 보통 “CG를 쓰면서 대칭 양정치가 아닌 전처리기를 물렸다”는 뜻이다. ILU를 CG에 붙였다가 이걸 보는 것이 국룰 입문 코스. 대칭성이 의심되면 -ksp_type gmres 로 바꿔 보면 문제가 솔버인지 행렬인지 금방 갈린다.

  4. 이 사실을 모르면 “우리 클러스터 이상한데요” 소리가 나온다. 조밀 행렬 연산은 연산 강도가 높아 코어를 갈아 넣는 만큼 나오지만, 희소 쪽은 애초에 게임이 다르다. LAPACK 벤치마크 감각으로 희소 솔버 성능을 예상하면 반드시 실망한다.

  5. 아르곤이 만든 라이브러리답게 미국 엑사스케일 프로젝트(ECP)를 거치며 GPU 백엔드가 대폭 보강됐다. 그래도 “CPU 코드에 옵션만 바꿔 붙이면 10배”는 마케팅 문구고, 실제로는 조립 커널을 GPU로 올리고 통신 패턴을 줄이는 작업이 따라와야 한다. 세상에 공짜 점심은 없다.