aicfd#
CFD 해석 결과를 신경망으로 예측하는 모델 5종의 기술 문서다. 건물 외부 유동, 사무실 실내 공조, 비강 기류를 각각 다루는데, 다루는 대상은 달라도 학습 골격은 하나를 같이 쓴다.
모델마다 독립된 repo 로 관리하고 배포한다. 이 superproject 는 배포용이 아니라, 다섯을 나란히 두고 한자리에서 읽기 위한 것이다.
어디부터 읽나#
| 알고 싶은 것 | 문서 |
|---|---|
| 5종이 무엇이 같고 무엇이 다른가 | 이 페이지의 모델 목록 · 공통 아키텍처 |
| 값이 어떤 공간에서 어떤 단위로 흐르는가 | 데이터 공간 |
| 정확도를 무엇으로 재는가 | Metric |
| 학습 데이터가 어떻게 만들어지는가 | 전처리 |
| 값을 어떤 O(1) 공간으로 보내 학습하는가 | nondim |
| 왜 이 설계인가 (대안과 근거) | 설계 근거 |
| 데이터 재생성·재학습 절차 | 운영 절차 |
| 학습이 이상할 때 | 장비·런타임 이슈 |
용어#
문서 전체가 아래 표기를 따른다. 코드 식별자는 등폭체(nondim), 개념어는 일반 서체다.
모델 이름#
repo 이름을 그대로 쓰고 줄이지 않는다. 이름은 aicfd-<표현>-<대상>-<target> 순서다.
세 자리 중 하나라도 빼면 이름이 겹친다. 비강을 다루는 repo 가 aicfd-grid-nasal-rgb 과
aicfd-mesh-nasal-physical 둘이라서, 대상만으로는 어느 쪽인지 알 수 없다.
대상이 target 보다 앞에 온다. 그래서 이름순으로 늘어놓으면 같은 대상을 다루는 repo 가 붙어 나온다.
aicfd-grid-building-physical 바로 다음이 aicfd-grid-building-rgb 이고, 그 뒤에
aicfd-grid-indoor-physical 이 온다.
- 첫째 자리는 표현이다.
grid는 유동 해석 결과의 체적 단면을 격자로 예측한다.mesh는 유한요소 해석 결과의 벽면 flux 장을 표면 mesh 위에서 예측한다. WSS 는 그중 첫 필드이고, 수증기 질량 flux 와 벽면 열 flux 가 추가될 예정이다. - 둘째 자리는 대상이다.
building은 건물 외부 유동,indoor는 사무실 1개 실내,nasal은 비강이다. - 셋째 자리는 target 이다.
physical은 물리량이고,rgb는 렌더 이미지다.
| repo | 대상 | 예측 대상 |
|---|---|---|
aicfd-grid-building-physical |
건물 외부 유동 | 물리량 단면 |
aicfd-grid-indoor-physical |
사무실 1개 실내 | 물리량 단면 |
aicfd-grid-building-rgb |
건물 외부 유동 | 렌더 이미지 단면 |
aicfd-grid-nasal-rgb |
비강 유동 | 렌더 이미지 단면 |
aicfd-mesh-nasal-physical |
비강 표면 | vertex 별 표면 flux (현재 WSS) |
두 개의 분류 축#
| 축 | 값 | 뜻 | 해당 모델 |
|---|---|---|---|
| 표현 | grid | 필드를 정규 격자 이미지 (b,c,h,w) 로 다룬다 |
aicfd-grid-building-physical, aicfd-grid-indoor-physical, aicfd-grid-building-rgb, aicfd-grid-nasal-rgb |
| mesh | 삼각형 표면 mesh 의 vertex 위에서 직접 다룬다 | aicfd-mesh-nasal-physical | |
| target | 물리량 | 예측 대상이 실제 물리 단위 값(m/s, Pa, °C, WSS) | aicfd-grid-building-physical, aicfd-grid-indoor-physical, aicfd-mesh-nasal-physical |
| 렌더 이미지 | 예측 대상이 이미 색으로 렌더된 이미지 바이트 | aicfd-grid-building-rgb, aicfd-grid-nasal-rgb |
두 축의 교집합을 부를 때는 물리량-grid(aicfd-grid-building-physical, aicfd-grid-indoor-physical), 물리량-mesh(aicfd-mesh-nasal-physical), 렌더-grid(aicfd-grid-building-rgb, aicfd-grid-nasal-rgb) 로 쓴다.
'physical' 이라는 단어의 세 가지 쓰임
- repo 이름의 셋째 자리
physical - 텐서 공간 이름
physical— dequantization 을 거친 물리 단위 텐서 (데이터 공간) - 위 표의 target 축 값 "물리량"
등폭체 physical 은 셋 중 공간을 가리킨다.
그 밖의 용어#
| 개념어 | 뜻 | 코드에서의 이름 |
|---|---|---|
| 예측 필드 | pressure, velocity, temperature, k, WSS 같은 예측 대상 물리량 | mode, pred_fields |
| 정답(truth) | 데이터셋이 제공하는 참값 | truth, mesh 에서는 sample dict 의 target |
| contour | 한 z 단면의 필드 값 격자 | contour, ContourDict |
| fluid 화소/vertex | 유체 영역에 속해 metric 에 포함되는 격자점 | domain_mask != 0, mesh 는 전 vertex |
모델 목록#
| aicfd-grid-building-physical | aicfd-grid-indoor-physical | aicfd-grid-building-rgb | aicfd-grid-nasal-rgb | aicfd-mesh-nasal-physical | |
|---|---|---|---|---|---|
| 표현 | grid | grid | grid | grid | mesh |
| target | 물리량 | 물리량 | 렌더 이미지 | 렌더 이미지 | 물리량(WSS) |
| 예측 필드 | pressure, velocity, k | velocity, temperature | pressure, velocity | pressure, velocity | wss (표면 flux 중 현재 구현분) |
| 지원 모델군 | Reg, AE, EDM(2D/3D, Physical/Latent), EDMwithReg | Reg | Reg, Reg3D, AE, EDM(2D/3D, Pixel/Latent), EDMwithReg | Reg 2D·3D | DiffusionNet Reg |
| 학습 공간 | nondim |
nondim |
[-1,1] |
[-1,1] |
nondim |
| metric 단위 | 물리 단위 | 물리 단위 | [0,255] 화소값 |
[0,255] 화소값 |
WSS 단위 |
| Collator | 있음 | 있음 | 있음 | 있음 | 없음 |
| 조건 입력 | 풍속·높이 | 센서 5점 온도·높이 | 풍속·높이 | 풍속·높이 | 유속·단면적 |
| 상태 | 운용 | Reg 만 운용, AE/EDM 미배선 | 운용 | 운용 | 운용 |
aicfd-grid-building-rgb 과 aicfd-grid-nasal-rgb 의 AE/EDM 코드는 뿌리가 같고, aicfd-grid-nasal-rgb 은 거기서 회귀만
남긴 부분집합이다. aicfd-grid-indoor-physical 은 AE/EDM/3D 코드가 들어 있기는 하지만 실내 데이터에 맞게 배선되어 있지 않다.
표에 없는 차이는 대부분 도메인에서 온다. 격자 크기, 조건 입력 구성, 데이터 규모 같은 것들이다. 구조를 이해하는 데 필요한 차이는 위 표와 데이터 공간, 모델별 차이 에 모아 두었으니 그쪽을 보면 된다.
공통 아키텍처#
여기서부터는 다섯 모델이 함께 쓰는 골격이다. 각 repo 가 따로 배포되기 때문에 이 골격은 공용 패키지가 아니라
repo 마다 들어 있는 복사본이다. 그래서 한쪽을 고치면 나머지에도 같은 수정을 옮겨야 한다
(패키지 디렉터리는 다섯 repo 모두 aicfd/ 다).
학습 루프#
Workspace(fold 단위) → Trainer(epoch 단위) → finalize_fold
scripts/train.py 가 fold 를 순회하고, 각 fold 안에서 epoch 을 돌리며 검증 지표가 개선되지 않으면 조기 종료한다
(patience 초과 시 최고 성능 checkpoint 로 복원). fold 종료 시 post-hoc EMA 후보를 골라 test 를 돌리고 결과 csv 를 쓴다.
데이터 적재#
| 구성요소 | 단위 | 역할 |
|---|---|---|
Dataset (utils/dataset.py) |
샘플 1개 | h5 읽기, 윈도우/케이스 샘플링 |
Collator (utils/collator.py) |
배치 1개 | 스택, crop 또는 pad, 증강, 공간 변환, 조건 입력 정규화 |
Collator 는 CPU 에서 float32 로만 동작하고, GPU 이동은 to_device 가 일괄 처리한다.
Dataset 변종은 단일 슬라이스(DatasetImage), 깊이 윈도우(DatasetDepthSeq), 케이스 전체(DatasetDepthCase) 세 가지다.
aicfd-mesh-nasal-physical 은 Collator 가 없다. mesh 는 vertex 수가 가변이고 희소 연산자를 함께 들고 다녀 하나의 밀집 텐서로
묶을 수 없다. Dataset 이 기하 연산자 사전계산과 target 정규화까지 마친 샘플 dict 를 내보내고, 배치는
collate_fn=list 로 만든 파이썬 리스트다.
모델 기반 클래스#
models/base_model.py 의 BaseModel 이 train/val/eval 루프, 온라인 가중치와 EMA 가중치를 바꿔 끼우는 컨텍스트
매니저, checkpoint 생성·적재를 담당한다. 확산 계열은 BaseModelPostHocEMA 를 써서 여러 EMA 표준편차 후보를
사후 재구성해 최적을 고른다. 회귀 계열은 일반 SWA 형태의 EMA 를 쓴다.
Metric 컨테이너#
Metric 은 {예측 필드: {지표 이름: [값]}} 구조의 dict 서브클래스로, 배치 누적(.sum)·가중(.mul)·이름
병합(.extend) 만 제공한다. 지표의 정의와 해석은 Metric 문서 에 있다.
공유 범위#
| 파일 | 다섯 모델에서 |
|---|---|
utils/prefetch.py, utils/train_helper.py |
동일 |
utils/scheduler.py, utils/ema.py |
grid 4종은 scheduler 가 동일하고, 그중 aicfd-grid-nasal-rgb 을 뺀 3종은 ema 까지 동일하다. aicfd-mesh-nasal-physical 은 scheduler 를 WarmupConst 로 축약하고, aicfd-grid-nasal-rgb 은 ema 의 eval_index 를 nn.Buffer 로 보관한다 |
utils/metric.py, utils/model_helper.py, models/base_model.py |
절반만 공통. 나머지는 표현과 정규화 방식에서 달라진다 |
check_drift.sh 가 위 구분대로 검사한다.
데이터 공간#
디스크에 저장된 값이 그대로 신경망에 들어가지는 않는다. 어느 모델이든 저장값을 크기가 인 학습 공간으로 한 번 옮기고, 평가할 때 그 변환을 그대로 되돌린다. 변환은 전부 invertible affine 이라 되돌리는 데 오차가 없다. 변환의 모양은 다섯 모델이 다르지 않다. 그 affine 을 어떻게 정하느냐만 다르다.
공간 목록#
| 공간 | 뜻 | 배치 형상 | 쓰는 모델 |
|---|---|---|---|
uint16 |
h5 에 저장된 양자화 값 | (b, …, c) 채널 마지막 |
전부 |
physical |
dequantization 을 거친 물리 단위 텐서 | (b, c, …) 채널 앞 |
물리량-grid |
nondim |
학습·예측이 일어나는 정규화 공간 | (b, c, …) / mesh 는 (N,) |
물리량 3종 |
[-1,1] 화소 |
학습·예측이 일어나는 정규화 공간 | (b, c, h, w) |
렌더-grid |
edm |
확산 학습용 rescale 공간 | (b, c, …) |
aicfd-grid-building-physical, aicfd-grid-building-rgb |
latent → ldm |
AE 인코더 출력과 그 정규화 | (b, c_lat, h', w') |
aicfd-grid-building-physical, aicfd-grid-building-rgb |
dequantization (grid 공통)#
grid 모델은 저장값이 uint16 이라, 무엇을 하든 먼저 물리 단위로 풀어 놓는다.
amin/amax 는 필드별 저장 범위이고 cfg.dataset.maxima 로 넘어온다. velocity 는 풀고 나서 u/v/w 3채널로 나뉜다.
렌더-grid 는 저장값이 이미 이미지 바이트라 이 단계가 아예 없다.
nondim#
물리 단위로 풀어 놓은 값(렌더-grid 라면 저장 바이트)을 다시 신경망이 입력으로 받는 공간으로 옮긴다. 이것도 invertible affine 이다. 모델마다 다른 건 계수를 어떻게 잡느냐뿐이다.
| 모델 | 계수 결정 | 목표 |
|---|---|---|
aicfd-grid-building-rgb, aicfd-grid-nasal-rgb |
고정 상수 | 값이 |
aicfd-grid-building-physical |
기준 풍속별 표본 통계 | 표준편차 1 |
aicfd-grid-indoor-physical |
채널별 전역 통계 + 기준온도 차감 | 표준편차 1 |
aicfd-mesh-nasal-physical |
물리 유도 지수 + 해석 설정값에서 온 상수 | 면적가중 중앙값 32 |
식과 유도, 통계를 어디서 구하는지는 nondim 에 모아 두었다.
nondim 이라는 이름
nondim 은 특정 수식의 이름이 아니다. 물리량 3종이 각자의 학습 공간을 부를 때 쓰는 공통 인터페이스 이름에 가깝다.
세 모델 모두 physical_to_nondim / nondim_to_physical 을 갖고 있고, 안에 든 식만 서로 다르다.
렌더-grid 2종은 같은 일을 상수 한 줄로 끝내기 때문에 따로 이름을 두지 않았다.
조건 입력의 단위#
physical_info 는 같은 배열이라도 자리에 따라 단위가 다르다. 물리량-grid 에서 정규화 계수를 계산할 때
이 구분을 놓치면 계수가 틀어진다.
| 위치 | 단위 |
|---|---|
h5 원본, Dataset·Collator 의 raw_pinfos |
원값 (풍속 26.0, 높이 mm, 센서 온도 °C) |
모델 입력 batch_dict['input']['physical_info'] |
정규화값 (building 은 풍속÷100·높이÷최대값, indoor 는 raw / PINFO_DIVISORS) |
AE 의 최상위 batch_dict['physical_info'] |
원값 |
모델은 정규화값에서 원값을 복원해 계수를 만든다 — building 은 풍속에 100 을 곱하고, indoor 는 PINFO_DIVISORS 를
되곱한다. _batch_pinfos() 가 위치 차이를 흡수한다. 렌더-grid 는 조건 입력을 정규화 계수에 쓰지 않으므로
이 구분이 필요 없다.
모델별 차이#
공통 구조는 위에서 다뤘으니, 여기서는 모델마다 다른 부분만 본다. 먼저 다섯을 나란히 놓고 무엇이 들어가서 무엇이 나오는지부터 확정하고, 그 다음에 모델별로 설명이 필요한 것만 따로 본다.
입출력 사양#
2D 회귀 기본 설정(reg-*-base, diffusionnet-base) 기준이다. 신경망이 실제로 받는 것은
기하 입력과 scalar 조건 둘뿐이고, 정답 필드는 어느 경로로도 입력에 들어가지 않는다
(예외는 깊이 경로).
aicfd-grid-building-physical |
aicfd-grid-indoor-physical |
aicfd-grid-building-rgb |
aicfd-grid-nasal-rgb |
aicfd-mesh-nasal-physical |
|
|---|---|---|---|---|---|
| 기하 입력 | 3채널 — domain_mask 1 + proximity_mask 2. 전부 255 로 나눈다 |
vertex 좌표와 삼각형, 그리고 거기서 만든 기하 연산자 | |||
| 기하 입력의 형상 | 576² crop | 256² pad (도메인 216×153) | 576² 또는 256² crop | 256² crop | vertex 가변 |
| scalar 조건 | 풍속, 슬라이스 높이 | 슬라이스 높이, 센서 5점 온도 T_S1..T_S5 |
풍속, 슬라이스 높이 | 유속, 슬라이스 높이 | 유속 라벨, vertex 별 기도 단면적 |
| 조건 개수·단위 | 2 — m/s, mm | 6 — mm, °C ×5 | 2 — m/s, mm | 2 — 라벨, mm | 3 — 라벨(부호·크기 따로), cm² |
| 조건 정규화 | 풍속÷100, 높이÷최대 높이 | raw ÷ PINFO_DIVISORS = [2800, 40, 40, 40, 40, 40] |
풍속÷100, 높이÷최대 높이 | 유속÷100, 높이÷최대 높이 | 라벨÷12, 단면적은 m² → cm² 환산만 |
| 조건을 넣는 방식 | 조건마다 ImgFiLM 하나씩(2개), 각각 기하 입력을 변조한 뒤 이어붙인다 → 6채널 |
조건마다 ImgFiLM 하나씩(6개), 변조 결과를 더한 뒤 원본 기하 입력을 이어붙인다 → 6채널 |
aicfd-grid-building-physical 과 동일 (2개 변조 후 이어붙이기) | NasalFiLM 이 조건 3개를 MLP 에 통과시켜 DiffusionNet block 마다 를 만든다. vertex 마다 값이 다르다 |
|
| 예측 채널 | 5 — pressure 1, velocity 3, k 1 | 4 — velocity 3, temperature 1 | 6 — pressure 3, velocity 3 (렌더 RGB) | 6 — pressure 3, velocity 3 (렌더 RGB) | 1 — vertex 당 WSS 스칼라 |
| 예측이 나오는 공간 | nondim |
nondim |
[-1,1] |
[-1,1] |
nondim |
| 출력 머리 | pressure 와 velocity·k 두 갈래로 나눠 디코딩하고 MMTM 으로 섞는다 | velocity 와 temperature 두 갈래 | 단일 머리 6채널 | 단일 머리 1채널 | |
proximity_mask 는 2D 슬라이스에 z 방향 맥락을 주는 채널이다. 각 화소에서 형상이 있는 가장 가까운
아래 슬라이스와 위 슬라이스까지의 거리를 재고 그 역수를 넣는다. 그래서 두 채널이다. 한 장짜리 단면만 보고는
알 수 없는 "이 화소가 건물 바로 위인가, 한참 위인가" 를 이것이 알려준다.
정답 필드는 왜 input_fields 에 들어 있나
설정의 input_fields 는 신경망 입력 목록이 아니라 h5 에서 읽어올 키 목록이다.
pressure·velocity 같은 이름이 거기 있는 것은 정답으로 쓰기 위해 읽는다는 뜻이고,
Collator 가 그것들을 truth 로 갈라낸다. 신경망의 forward(mask, physical_info) 는
기하 입력과 조건만 받는다.
깊이 경로 (3D)#
3D 회귀는 위 표와 두 군데가 다르다. 슬라이스를 장씩 묶어 로 다룬다.
| 2D | 3D | |
|---|---|---|
| 기하 입력 | domain_mask + proximity_mask = 3채널 |
domain_mask 1채널만. 깊이 축이 실제로 있으니 z 맥락을 대신 넣어 줄 이유가 없다 |
| 추가 입력 | 없음 | context — 정답 슬라이스 일부를 그대로 넣는다. depth_mask 가 1 인 자리만 남기고 나머지는 0 |
| 푸는 문제 | 조건에서 단면 한 장을 만든다 | 주어진 슬라이스 사이를 메운다 |
| metric 대상 | fluid 화소 전부 | depth_mask 가 0 인 슬라이스만. 주어진 슬라이스는 예측한 것이 아니라 제외한다 |
그래서 3D 회귀는 조건 생성기가 아니라 깊이 방향 보간기다. 학습할 때는 몇 장을 줄지
(depth_mask) 샘플마다 새로 정하고, 평가할 때는 창을 옮겨 가며 케이스 전체를 복원한다.
aicfd-grid-building-physical#
가장 많은 모델군을 갖는다. contour 는 공간을 함께 들고 다니는 ContourDict 로 다루고,
physical ↔ nondim ↔ {edm, ldm} 을 샘플별 계수로 왕복한다.
| 모델군 | 학습 공간 | loss |
|---|---|---|
FBFRegDist, FBF2RegDist, FBF*RegNoProx |
nondim |
필드별 L1 |
AutoencoderContour(VQ) |
nondim |
재구성 |
AutoencoderDomain(VQ/Prox) |
도메인 마스크 [-1,1] |
재구성 |
PhysicalEDM, PhysicalEDM3D |
edm |
확산 MSE |
LatentEDM, LatentEDM3D |
ldm |
확산 MSE |
EDMwithReg, LDMwithReg |
위와 동일 + 회귀 예측을 조건으로 융합 |
Latent 계열은 AE 두 개(도메인·contour)를 불러 nondim → latent → ldm 으로 인코딩하고, 평가 때만 디코더를 쓴다.
3D 모델은 contour 에 깊이 축을 더한 (b,c,D,h,w) 를 다룬다 — 깊이 경로 참고.
fluid 영역은 obj 단면을 z 슬라이스마다 래스터화해 만든다. 이 방법이 성립하는 이유는 외부 유동이기 때문이다 — 해석 영역이 풍동 상자이고 건물이 그 안의 장애물이라 "solid = obj 내부"가 유체의 여집합과 정확히 일치한다.
aicfd-grid-indoor-physical#
단일 사무실 형상이라 모델·각도 축이 없다. 예측 필드는 velocity 와 temperature 이며 온도는 섭씨로 저장한다.
| 항목 | 값 |
|---|---|
| 형상 | data/geo/260602_officeroom_r0_S.obj 하나. 모든 케이스가 같은 bounding box |
| 케이스 | 21개 |
| 슬라이스 | 케이스당 13장, z = 0.2 ~ 2.6 m (0.2 m 간격) |
| 격자 | 216 × 153 화소, 화소당 0.02 m |
| fold | aicfd/folds/21.yaml — 5-fold, 검증 2 고정, 학습 16~17 / 테스트 2~3 |
| 모델 설정 | reg-256-base(FBFUNet2), reg-256-fbfunet1(FBFUNet1) |
좌표계는 해석 결과의 로컬 프레임(최소 코너가 원점)을 따르고, 전처리가 obj 를 그 프레임으로 평행이동한다.
z 는 양쪽이 같은 기준이라 그대로 쓴다. gt_max_height.txt 에 기록되는 216 은 contour 의 최대 변 길이(화소)이며,
pad 캔버스 크기는 이 값보다 커야 한다.
- 캔버스: 216×153 도메인을 256² 캔버스에 채워 넣는다(crop 이 아니라 pad). 학습은 임의 위치, 평가는 좌하단 고정.
- fluid 마스크:
domain_mask/255를 연속값 마스크로 써서 정답과 예측 양쪽에 곱한다. 경계는 0~1 사이, pad 영역은 0 이다. - 조건 입력: 모델은 5점 관측에서 전체 장을 복원하는 보간기다. 엑셀 조건표(풍속·발열량·평형온도)는 실시간에 관측할 수 없어 입력에서 제외돼 있다. 남은 것이 입출력 사양 의 6채널이다.
- 정규화: 풍속이 입력이 아니므로 기준 풍속 구간이 없다. 채널당 전역 scale 하나 + 온도 bias.
fluid 영역은 obj 그룹별 단면 래스터와 CFD 점군 bounding box 의 교집합이다. 설계 근거는 fluid 영역 정의 참고.
경계 화소의 온도는 물리값이 아니다
마스크가 전처리(절대 온도 공간)와 Collator(ΔT 공간) 두 곳에서 곱해지고 두 공간의 원점이 다르다. 그래서 반투명 경계 화소를 inverse transform 한 값은 CFD 값도 저장값도 아니다. 예측과 정답이 같은 경로를 지나므로 metric 과 디지털 트윈은 서로 일관되지만, 그 화소 하나의 값 자체는 물리 온도가 아니다. velocity 는 bias 가 0 이고 벽면 값도 0 이라 영향이 없다.
온도 단위는 원본 .ip 만 켈빈이고, 전처리에서 섭씨로 바꾼 뒤로는 저장·metric·출력이 모두 섭씨다.
nondim 공간은 온도차라서 켈빈과 섭씨가 같다.
aicfd-grid-building-rgb#
aicfd-grid-building-physical 과 같은 모델군을 갖되 target 이 렌더 이미지다. 물리 단위 공간이 없고 정규화가 상수이므로
ContourDict 도 샘플별 계수도 없다. 정규화 상태를 갖는 것은 EDM/LDM 뿐이고 그 계수는 checkpoint 에 저장된다.
EDMCollator 의 기본값 scale=2/255, bias=-1 은 추가 정규화가 필요 없는 경로(LDM, 3D 회귀)를 위한 것이라
결과가 그냥 [-1,1] 이다. 도메인 밖은 흰색(1)으로 채운다.
aicfd-grid-nasal-rgb#
aicfd-grid-building-rgb 에서 회귀 2D·3D 만 남긴 부분집합이다. 확산도 AE 도 없고 정규화 상태 자체가 없다 (3D 는 깊이 경로). 가장 작은 grid 모델이라 공통 코드 변경을 먼저 확인해 보기 좋다.
aicfd-mesh-nasal-physical#
유일한 mesh 모델이다. vertex 수가 가변인 삼각형 표면을 그대로 받아 vertex 별 스칼라 WSS 를 예측한다. 격자도, 화소 공간도, Collator 도, 확산·AE 도 없다.
h5 (verts/faces, 면 중심 WSS, 면적, 유속, cavity 부피, vertex 별 단면적)
→ normalize_positions → get_operators (Laplacian, 질량, eigenpair, gradient operator) [디스크 캐시]
→ physical_to_nondim → 면 값을 면적가중으로 vertex 에 뿌림
→ net(features, 기하 연산자, FiLM(유속, 단면적)) → vertex 별 예측
→ nondim_to_physical → metric (WSS 단위)
- input scalar: 좌표, HKS, 또는 둘 다. HKS 는 디스크 캐시.
- 조건화: 단면적을 조건으로 같이 주는 이유는 WSS 를 정하는 국소 유속이 유량÷단면적이기 때문이다. 단면적은 벽 건너편까지 봐야 나오는 값이라 표면 위의 확산만으로는 복원되지 않는다. cavity 안에서 조화 퍼텐셜을 풀어 등위면 조각의 넓이를 vertex 마다 스칼라 하나씩 주고, 그 값으로 조건화한다 (구하는 법은 전처리, 조건 구성은 입출력 사양). 유량이 절대 단위로 들어오므로 단면적도 절대 단위로 두어야 둘의 비가 유속이 된다.
- 기하 연산자: Laplacian eigendecomposition 이 가장 오래 걸리므로
(verts, faces)해시를 키로 디스크 캐시한다. - 배치 크기는 1 이다. 여러 샘플을 묶어야 하면
accum_steps로 기울기를 누적한다. - 정밀도: 기하·확산 연산은 float32 고정, MLP 만 자동 혼합정밀도.
- 크기 계수는 해석 설정값에서 정한다. ρ, ν, 라벨을 질량유량으로 바꾸는 상수가 전 케이스 공통이라 셋을 곱해 두면 target 이 dimensionless group 그 자체가 되고, 통계가 들어갈 자리가 없다.
평가 결과는 vertex 별 WSS 스칼라와 turbo 색을 담은 이진 PLY 로, 예측과 정답을 같은 색 범위로 나란히 저장한다.
표면 flux 확장#
이 모델의 대상은 벽면 flux 장 전반이고 WSS 는 그중 첫 필드다. 수증기 질량 flux 와 벽면 열 flux 가 추가될 예정이다. 현재 구현은 단일 필드로 고정돼 있어 확장 시 다음이 바뀐다.
| 지점 | 현재 |
|---|---|
| h5 키 | wss 하나를 직접 읽는다 (utils/dataset.py) |
| 정규화 | physical_to_nondim 이 WSS 전용 지수와 기준값을 쓴다 |
| 출력 | 신경망 C_out=1, vertex 당 스칼라 하나 |
| 결과 저장 | PLY vertex 속성 이름이 wss 로 고정 (utils/model_helper.py) |
| metric | Metric 은 필드 이름을 dict 키로 받으므로 구조 변경은 필요 없다 |
세 필드는 모두 벽면 법선 방향 기울기에 수송계수를 곱한 flux 이고, 면적분이 면 상수값 × 면적으로 정리된다. 구조가 같아서 면적가중 기준값과 면적가중 metric 이 그대로 적용된다.
| 필드 | 벽면 flux | 면적분 |
|---|---|---|
| WSS | ||
| 벽면 열 flux | ||
| 수증기 질량 flux |
기준값의 유속 의존성만 필드별로 다르다 — WSS 의 지수는 WSS nondimensionalization 참고.
파일 지도#
grid 4종 공통 경로다. aicfd-mesh-nasal-physical 은 collator.py·edm_helper.py 가 없다.
| 경로 | 내용 |
|---|---|
scripts/train.py |
fold·epoch 루프, 조기 종료, fold 마무리 |
models/base_model.py |
공통 학습·검증·평가 루프, EMA 교체, checkpoint |
models/regression.py, models/reg_3d.py |
결정론적 회귀 |
models/{autoencoder,edm,edm_3d,edm_with_reg}.py |
AE·확산 (building 2종만) |
models/diffusionnet.py, models/modules/backbone.py |
DiffusionNet 회귀 (aicfd-mesh-nasal-physical) |
utils/dataset.py |
h5 읽기, 샘플링, mesh 는 기하 연산자·정규화까지 |
utils/collator.py |
배치 구성, 공간 변환, 조건 입력 정규화 |
utils/metric.py |
Metric, compute_submetric, ContourDict |
utils/edm_helper.py |
정규화 계수 계산, EDM 전처리 모듈 |
scripts/preprocess/ |
원본 해석 결과 → h5 (전처리) |