wing-ops/docs/PREDICTION-GUIDE.md
jeonghyo.k 88eb6b121a feat(prediction): OpenDrift 유류 확산 시뮬레이션 통합 + CCTV/관리자 고도화
[예측]
- OpenDrift Python API 서버 및 스크립트 추가 (prediction/opendrift/)
- 시뮬레이션 상태 폴링 훅(useSimulationStatus), 로딩 오버레이 추가
- HydrParticleOverlay: deck.gl 기반 입자 궤적 시각화 레이어
- OilSpillView/LeftPanel/RightPanel: 시뮬레이션 실행·결과 표시 UI 개편
- predictionService/predictionRouter: 시뮬레이션 CRUD 및 상태 관리 API
- simulation.ts: OpenDrift 연동 엔드포인트 확장
- docs/PREDICTION-GUIDE.md: 예측 기능 개발 가이드 추가

[CCTV/항공방제]
- CCTV 오일 감지 GPU 추론 연동 (OilDetectionOverlay, useOilDetection)
- CCTV 안전관리 감지 기능 추가 (선박 출입, 침입 감지)
- oil_inference_server.py: Python GPU 추론 서버

[관리자]
- 관리자 화면 고도화 (사용자/권한/게시판/선박신호 패널)
- AdminSidebar, BoardMgmtPanel, VesselSignalPanel 신규 컴포넌트

[기타]
- DB: 시뮬레이션 결과, 선박보험 시드(1391건), 역할 정리 마이그레이션
- 팀 워크플로우 v1.6.1 동기화

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 14:55:46 +09:00

6.2 KiB

확산 예측 기능 가이드

대상: 확산 예측(OpenDrift) 기능 개발 및 유지보수 담당자


1. 아키텍처 개요

폴링 방식 — HTTP 연결 불안정 문제 해결을 위해 비동기 폴링 구조를 채택했다.

[프론트] 실행 버튼
  → POST /api/simulation/run        즉시 { execSn, status:'RUNNING' } 반환
  → "분석 중..." UI 표시
  → 3초마다 GET /api/simulation/status/:execSn 폴링

[Express 백엔드]
  → PRED_EXEC INSERT (PENDING)
  → POST Python /run-model          즉시 { job_id } 수신
  → 응답 즉시 반환 (프론트 블록 없음)
  → 백그라운드: 3초마다 Python GET /status/:job_id 폴링
  → DONE 시 PRED_EXEC UPDATE (결과 JSONB 저장)

[Python FastAPI :5003]
  → 동시 처리 초과 시 503 즉시 반환
  → 여유 시 job_id 반환 + 백그라운드 OpenDrift 시뮬레이션 실행
  → NC 결과 → JSON 변환 → 상태 DONE

2. DB 스키마 (PRED_EXEC)

PRED_EXEC_SN  SERIAL PRIMARY KEY
ACDNT_SN      INTEGER NOT NULL        -- 사고 FK
SPIL_DATA_SN  INTEGER                 -- 유출정보 FK (NULL 허용)
EXEC_NM       VARCHAR(100) UNIQUE     -- EXPC_{timestamp} 형식
ALGO_CD       VARCHAR(20) NOT NULL    -- 'OPENDRIFT'
EXEC_STTS_CD  VARCHAR(20) DEFAULT 'PENDING'
              -- PENDING | RUNNING | COMPLETED | FAILED
BGNG_DTM      TIMESTAMPTZ
CMPL_DTM      TIMESTAMPTZ
REQD_SEC      INTEGER
RSLT_DATA     JSONB                   -- 시뮬레이션 결과 전체
ERR_MSG       TEXT

인덱스: IDX_PRED_STTS (EXEC_STTS_CD), uix_pred_exec_nm (EXEC_NM, partial)


3. Python FastAPI 엔드포인트 (포트 5003)

메서드 경로 설명
GET /get-received-date 최신 예보 수신 가능 날짜
GET /get-uv/{datetime}/{category} 바람/해류 U/V 벡터 (wind|hydr)
POST /check-nc NetCDF 파일 존재 여부 확인
POST /run-model 시뮬레이션 제출 → 즉시 job_id 반환
GET /status/{job_id} 시뮬레이션 진행 상태 조회

POST /run-model 입력 파라미터

{
  "startTime": "2025-01-15 12:00:00",  // KST (내부 UTC 변환)
  "runTime": 72,                        // 예측 시간 (시간)
  "matTy": "CRUDE OIL",                // OpenDrift 유류명
  "matVol": 100.0,                     // 시간당 유출량 (m³/hr)
  "lon": 126.1,
  "lat": 36.6,
  "spillTime": 12,                     // 유출 지속 시간 (0=순간)
  "name": "EXPC_1710000000000"
}

유류 코드 매핑 (DB → OpenDrift)

DB SPIL_MAT_CD OpenDrift 이름
CRUD CRUDE OIL
DSEL DIESEL
BNKR BUNKER
HEFO IFO 180

4. Express 백엔드 주요 엔드포인트

파일: backend/src/routes/simulation.ts

메서드 경로 설명
POST /api/simulation/run 시뮬레이션 제출 → execSn 즉시 반환
GET /api/simulation/status/:execSn 프론트 폴링용 상태 조회

파일: backend/src/prediction/predictionService.ts

  • fetchPredictionList() — PRED_EXEC 목록 조회
  • fetchTrajectoryResult() — 저장된 결과 조회 (RSLT_DATA JSONB 파싱)

5. 프론트엔드 주요 파일

파일 역할
frontend/src/tabs/prediction/components/OilSpillView.tsx 예측 탭 메인 뷰, 시뮬레이션 실행·폴링 상태 관리
frontend/src/tabs/prediction/hooks/ useSimulationStatus 폴링 훅
frontend/src/tabs/prediction/services/predictionApi.ts API 요청 함수 + 타입 정의
frontend/src/tabs/prediction/components/RightPanel.tsx 풍화량·잔류량·오염면적 표시 (마지막 스텝 실제 값)
frontend/src/common/components/map/HydrParticleOverlay.tsx 해류 파티클 Canvas 오버레이

핵심 타입 (predictionApi.ts)

interface HydrGrid {
  lonInterval: number[];
  latInterval: number[];
  boundLonLat: { top: number; bottom: number; left: number; right: number };
  rows: number; cols: number;
}
interface HydrDataStep {
  value: [number[][], number[][]];  // [u_2d, v_2d]
  grid: HydrGrid;
}

폴링 훅 패턴

useQuery({
  queryKey: ['simulationStatus', execSn],
  queryFn: () => api.get(`/api/simulation/status/${execSn}`),
  enabled: execSn !== null,
  refetchInterval: (data) =>
    data?.status === 'DONE' || data?.status === 'ERROR' ? false : 3000,
});

6. Python 코드 위치 (prediction/)

prediction/opendrift/
├── api.py            FastAPI 진입점 (수정 필요: 폴링 지원 + CORS)
├── config.py         경로 설정 (수정 필요: 환경변수화)
├── createJsonResult.py  NC → JSON 변환 (핵심 후처리)
├── coastline/        TN_SHORLINE.shp (한국 해안선)
├── startup.sh / shutdown.sh
├── .env.example      환경변수 샘플
└── environment-opendrift.yml  conda 환경 재현용

7. 환경변수

backend/.env

PYTHON_API_URL=http://localhost:5003

prediction/opendrift/.env

MPR_STORAGE_ROOT=/data/storage    # NetCDF 기상·해양 데이터 루트
MPR_RESULT_ROOT=./result          # 시뮬레이션 결과 저장 경로
MAX_CONCURRENT_JOBS=4             # 동시 처리 최대 수

8. 위험 요소

위험 내용
NetCDF 파일 부재 MPR_STORAGE_ROOT 경로에 KMA GDAPS·MOHID NC 파일 필요. 없으면 시뮬레이션 불가
conda 환경 opendrift conda 환경 설치 필요 (environment-opendrift.yml)
Workers 포화 동시 4개 초과 시 503 반환 → MAX_CONCURRENT_JOBS 조정
결과 용량 12시간 결과 ≈ 1500KB/건. 90일 주기 RSLT_DATA = NULL 정리 권장

9. 관련 문서