Files
HC900-Crawler/mcp-server/pid_trace_algorithm.md
windpacer 16fc7a2598 Initial commit: HC900 Crawler
Honeywell HC900을 Modbus TCP로 직접 폴링 → gRPC → C# 크롤러 → PostgreSQL.
기존 Experion OPC UA 데이터 경로를 HC900 직접 통신으로 대체.

- industrial-comm/cpp: C++ Modbus 게이트웨이 (gRPC 서버)
- src: C# .NET 8 ASP.NET Core 크롤러 + 웹 UI (3-Layer)
- mcp-server: Python FastMCP (RAG/NL2SQL/P&ID)
- 다중 컨트롤러(N-Controller) 지원

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 20:28:14 +09:00

12 KiB

P&ID 흐름 추적 · From/To 추출 알고리즘 사양서

출처: P10-EQP-BLOCK.dxf 협업 역설계로 검증된 규칙 통합 (2026-05-18). 참조 자산: mcp-server/legend_symbols.json(심볼 시그니처), mcp-server/block_template_library.json(블록 템플릿), mcp-server/legend_probe.py(프로브). 관련 메모리: feedback-trace-reporting-granularity, reference-lineno-leader-rule, project-legend-symbol-catalog.


0. 목적과 핵심 전제 (지배 규칙)

  • 목적: 도면에서 유체 흐름을 추적해 랜드마크 간 From/To 연결그래프라인번호·출처를 추출.
  • 답변 단위: "FCV-10101 어디야?" → "라인 P-10149-40A-F1A-n (출처 T-10100) 상, P-10101 흡입헤더·토출·F-10102A/B 거쳐 FIT-10101 하류". 수동밸브/체크/호스/레듀서 등 commodity는 절대 열거 안 함.
  • 정밀 카운트 아님: 견적용 개수 검출이 목적이 아니라 연결·위상 파악이 목적.

노드 분류

분류 처리
랜드마크 노드 설비(P-,T-,E-,C-,D-,F-,SC-…), 컨트롤밸브/태그계기(FCV-,FIT-,LIC-…), 모터 From/To 그래프의 정점
투명 통과 (commodity) 수동 볼/체크/글로브밸브, 레듀서, 플렉시블호스, 스트레이너, 플랜지 흐름 안 끊기게 브리지만, 노드 아님, 출력에 미열거
연결 매체 배관(pipings) 엣지. line_number·출처 보유

1. 입력 자산

  1. 설비 블록: 태그명 INSERT (이름=태그). 위치 = virtual_entities() 월드 bbox (insert (0,0)+내부절대좌표 / 또는 실좌표 — 변환이 흡수).
  2. 심볼 템플릿 라이브러리: 명명 블록 정의의 정규화 시그니처(상대좌표·길이·각도·토폴로지, 원/호/SOLID 수). 회전·미러 불변 종류식별 + 월드기하 방향산출 2계층.
  3. raw 지오메트리: modelspace LINE/LWPOLYLINE/ARC/CIRCLE/SOLID/HATCH — 실제 그려진 배관·commodity 심볼.
  4. OFFPAGE_CONNECTOR: 방향성 블록(LINE 5~6) + 본체 bbox 내부 TEXT 2개(출처설비/서비스, 라인번호/연속키).
  5. 라인번호 TEXT + 지시선: 직접배치 또는 leader(SOLID/선-구성 chevron 화살촉 + stem).

2. 알고리즘 단계

Phase 1 — 랜드마크 노드 추출

  • 모든 INSERT 순회. 이름이 태그패턴(^[A-Z0-9]{1,4}-?\d{3,5} 또는 명시 설비명)이면 설비 노드: tag, world bbox 중심, 카테고리(prefix 규칙).
  • 태그계기/컨트롤밸브: 심볼(글로브밸브 등) + 인접 태그TEXT(FCV-/FIT-…) → 태그계기 노드. 태그=인접 라벨, 위치=심볼 월드좌표.
  • -SAME/중복 복제 = 동일 노드로 병합(같은 물리설비).

Phase 2 — 배관망 + commodity 투명 브리지

  • raw LINE/LWPOLYLINE → 끝점 그래프(좌표 양자화). 세그먼트 = 잠재 배관.
  • commodity 심볼 인식 → 투명 통과:
    • 소형 빈 CIRCLE r≈0.28~0.46 (+ bowtie 바/대각) = 볼밸브 → pass-through. (r 필터 하한 0.28 필수; faceted·무원 변형은 클러스터 패턴으로)
    • SOLID 삼각형 + 단일사선 = 체크밸브(방향성) → pass-through
    • 닫힌 LWPOLY 채움 = 글로브 / ARC 돔+stem = 컨트롤·다이어프램 (단 태그 있으면 랜드마크, 없으면 commodity)
    • 레듀서/플렉시블호스/스트레이너/플랜지 = pass-through
    • 회전·미러는 virtual_entities() 월드기하로 흡수. 블록명은 힌트, 방향근거 금지.
  • gap-통과 브리지: 배관 끊김 → 진행 흐름벡터 방향(콘)으로 lookahead, gap에 commodity 심볼 있으면 그 너머 공선 세그먼트로 연결 계속.

Phase 3 — 위상 인식 (흐름방향·분기·합류·루프)

  • 흐름방향 = 의미적: 발원지(OFFPAGE/탱크/펌프)에서 누적 흐름벡터. DXF 선 정점순서 무시, 역행 금지, 방문엣지 가드(진동 방지).
  • FLOW_DIRECTION 화살표: 만나면 그 위치 흐름방향을 월드기하 apex→tail 벡터로 확정(이름 아님). 의미적 추정보다 우선.
  • 엘보: 직각 굽힘은 끝점공유로 따라감(수평→수직 등).
  • TEE = 분기/합류: 한 점에 3선 이상. 분기 시 본류+지선 분할.
  • 재순환(킥백) 루프: 한 지선이 이미 방문한 흡입측으로 복귀 = 정상 사이클. 무한루프 아님 → recirculation 엣지로 표기, 그 지선 종료.
  • 헤더/매니폴드: 수평선에 수직 분기 다수 → 합류 매니폴드. 좌단 블라인드플랜지=막힘(흐름 반대편).
  • 병렬 트레인: 동일 x/y의 평행 분기→합류 (예 F-10102A/B 수직병렬).
  • OFFPAGE 짝: 본체 내부 라인번호/연속키 TEXT 추출. 동일 연속키 가진 커넥터끼리 페어 → 라인 점프(시트/위치). 방향 = 커넥터 월드기하.

Phase 4 — 라인번호 ↔ 배관 귀속

  • 케이스 A 직접배치: 텍스트가 배관 복도 근접(수평배관 위 평행, 또는 수직배관 옆 span중간 가로배치). 박스 내 최근접 세그먼트.
  • 케이스 B 지시선: 화살촉(SOLID 또는 1.0바+0.66대각 선-구성 chevron) → tip 좌표가 닿는 배관 = 대상. tip↔배관 매칭 허용오차 극소(sub-0.5u, ≈0) — 밀집부 오매칭 방지. stem(LINE/LWPOLY/SPLINE/LEADER 무관) → landing → 텍스트 역추적도 성립.
  • 모호 분해: 근접 평행 수직 2개 등 기하로 불가 시 → 흐름-토폴로지 컨텍스트(어느 배관이 추적경로/설비에 실제 연결)로 결정.

Phase 5 — 랜드마크 From/To 환원

  • 투명 commodity 체인 붕괴(collapse): 랜드마크→(commodity*)→랜드마크 를 랜드마크↔랜드마크 단일 엣지로.
  • 엣지 = from_tag(상류 랜드마크), to_tag(하류 랜드마크). From/To에 배관번호 안 넣음.
  • 상/하류 = 흐름방향으로 결정. 미결정 시 무방향(from/to 임의·플래그).
  • 배관번호·출처 = pipings 레코드/엣지 속성(권위). 랜드마크 위치질의는 랜드마크→인접배관→line_number+OFFPAGE출처 조인 조립.

3. 출력 스키마 (pid_equipment 정합)

카테고리 from_tag / to_tag line_number
equipment / control_valve / motor / instrument 인접 랜드마크 태그 ↔ 랜드마크 태그 (옵션) 얹힌 라인 단일 참조, From/To 불포함
pipings 라인 양끝 랜드마크 / OFFPAGE 짝 그 배관 라인번호 (권위)
  • recirculation/bypass 엣지는 타입 플래그로 구분(정상 위상, 누락·추측 금지).
  • 재실행 결정성: 기존 From/To 초기화 후 재계산하되 수동 import 잠금(ConnectionLocked) 보존.

4. 핵심 불변식 (검증된 함정 회피)

  1. 흐름방향은 의미적(발원지 기준), 선 정점순서·블록명 불신. 방문엣지 가드 필수(self-oscillation 방지).
  2. 회전/미러 → 종류는 불변시그니처, 방향은 virtual_entities() 월드기하. 동일형상 다른이름(FLOW_DIR 3종 등) 주의.
  3. 볼밸브 r≈0.280.46 (소형 지배, 도면 다수). 펌프 케이싱 r≈23 (≥4.5 아님).
  4. 재순환선 = 정상 사이클. 끊지 말고 루프로 표기.
  5. 화살촉 tip↔배관 = sub-0.5u 준-정확. 화살촉은 SOLID 또는 선-구성 chevron.
  6. From/To = 랜드마크↔랜드마크. 배관번호는 엣지/pipings 속성. commodity 미열거(답변 단위 전제).

5. 정직한 한계 / 미검증

  • raw 패턴매칭은 퍼지: 재현율 100% 보장 못 함(회전·스케일·작도변형·배관병합).
  • 밀집부(토출·HATCH다수)는 좁은 허용오차 없이는 오탐.
  • 지시선 변형: SOLID·선-구성 chevron 검증됨. SPLINE 곡선 stem 미검증.
  • 직접배치 평행수직 모호 → 토폴로지 컨텍스트 의존(자동화 시 흐름추적 선행 필요).
  • OFFPAGE 짝 매칭은 연속키 텍스트 정확추출 전제(밀집·회전 텍스트 노이즈 가능).

6. 구현 상태 · 다음 세션 인계 (2026-05-18 2차 세션 종료 시점)

산출물 (확정·보존)

  • 사양서: mcp-server/pid_trace_algorithm.md (이 문서)
  • 구현체: mcp-server/pid_tracer.py — Phase 1·1b·2·3·4·5 구현 (미드스트림 라우팅 미완)
  • 카탈로그: mcp-server/legend_symbols.json, mcp-server/block_template_library.json, mcp-server/legend_probe.py
  • 출력: mcp-server/storage/P10-EQP-BLOCK_connections.json (C# 소비 포맷 호환)
  • C# 소비경로: AnalyzeConnectionsAsync 이미 <prefix>_connections.json edges 소비 (이전 세션 구현)

정답 레퍼런스 (협업 검증된 ground truth)

  • P-10101 시스템 전체 위상 = 흡입 T-10100/T-10101 합류 + 킥백 재순환 루프 + 토출 → 병렬필터 F-10102A/B → MASS_FLOW_METER(FIT-10101) → FCV(+바이패스) → E-10103
  • 주의: 핸드오프 기억상 "FCV-10101" 이나 도면 실제 인접 버블은 FCV-10116 (도면 권위)

현재 어디까지 (2026-05-18 2차 세션 (a) 보강)

현재 트레이서 실측 출력:

  • 랜드마크 57, OFFPAGE 시드 1, 볼앵커 372, raw 14,764, 라인번호귀속 227
  • OFFPAGE T-10100 시드: T-10100 노드만 (공급선 P-10101 미완주)
  • P-10101 discharge 시드: P-10101 → F-10102B → F-10102A → FIT-10101 (여기서 멈춤)

완료·검증:

  1. OFFPAGE 발원 소스 시드: OFFPAGE_CONNECTOR 4종 중 LEFT_TO_RIGHT 처리. apex = 본체 주축 두 극단 중 '뾰족한'(정점 1개) 쪽, 방향 = 뒷변중점→apex (월드기하 권위). 본체 근접 TEXT 분류 → 출처태그 T-10100 발원 노드 등록 + 라인번호 P-10149-40A-F1A-n 시드 부착. (공급선이 P-10101 까지 완주는 미달 — §아래)
  2. ⬆️ 랜드마크 통과-후-재개: resume_nozzle — 블록 실체범위(SOLID/원반경 포함 world_extent) 밖, 안정적 시드 흐름축 투영 최대 미방문 노즐로 재개. 결과: P-10101 → F-10102B → F-10102A → FIT-10101 (이전: F-10102A 에서 멈춤).
  3. ⬆️ 명명 심볼 = 태그계기 합성: MASS_FLOW_METER/CONTROL_VALVE_GLOBE/ FLOW_METER_VARIABLE-AREA 를 commodity 에서 제외, 인접 함수코드+번호 버블 TEXT 로 태그 합성 (FIT+10101FIT-10101, FCV+10116FCV-10116). 블록명은 종류 힌트, 태그는 인접 TEXT 권위.
  4. ⬆️ 일반 전방 gap-브리지: commodity/작도 끊김을 흐름축 콘(dot>0.85+수직오프셋 최소)으로 점프, 착지점에서 정상 conn 재전진(역행 억제).
  5. ⬆️ 볼앵커 과포함 정밀화: r 0.28~0.46 + 동반 단선(≤2.6) ≥2 조건 → 560→372.
  6. 🧩 Phase 4·5 실코드화: 라인번호 귀속(SOLID tip sub-0.5u / 직접배치, 227건), 재순환 엣지·OFFPAGE 라인번호 엣지 속성.

남은 미완 (다음 세션 계속 (a)2/(a)3):

  • 밀집 미드스트림 라우팅: FIT-10101 → FCV-10116 → E-10103 장거리 런이 계기 테이크오프·샘플 분기 fitting 기하에 갇힘. 계기-테이크오프 거부 + 헤더/TEE 추종 필요.
  • 공급선 P-10101 완주: OFFPAGE 시드가 흡입헤더까지 라우팅 미완(하향 드리프트).
  • TEE 분기 본류/지선 분할·OFFPAGE 동일연속키 짝 매칭 = 미구현(골격).

(b) C# 연동·DB 반영 (착수 전):

  1. 트레이서 의미 엣지 산출 후 AnalyzeConnectionsAsync 를 P10-EQP-BLOCK 출력 연결
  2. From/To = 랜드마크↔랜드마크만(배관번호 미내장, pipings/엣지 속성) — §3 스키마대로 DB 반영
  3. 수동 import 잠금(ConnectionLocked) 보존 회귀 확인

검증 진입점(SEEDS)·정답 위상은 pid_tracer.py 주석 및 본 문서 §2·메모리에 보존됨.