""" drug_comsol_params.py — 약물별 COMSOL 입력 파라미터 (v2, 물리공식 기반) ============================================================ 약물 선택 시 해당 약물의 10개 COMSOL 파라미터를 반환한다. ★ v2 변경: BA 역산(순환 논리) 폐기 → 물리 공식·문헌 기반 재유도 기존 v1은 k_decay를 "문헌 BA가 나오도록 역산"해 넣어, 대리모델→BA 계산이 순환(BA를 넣어 BA를 얻음)이었다. v2는 이를 제거하고 각 파라미터를 물리적 근거로 독립 결정한다. 그 결과 BA는 순방향 예측값이 된다. 파라미터별 결정 방법: Lp_ve, K 조직 성질(약물 무관) → 공통 상수 (Lp_ve=8e-12, K=1e-15) sigma_ve, sigma_le Curry 반사계수 σ=1-(1-(a/R)²)², a=0.0515·MW^0.392 nm (Erickson 2009). 벽 공극반경 R_ve=6.22, R_le=24.5 nm는 파일 3종(IgG/INS/ALB) 실측 best-fit. D_gel Stokes-Einstein 자유확산 D=kBT/(6πηr) × ECM 방해인자 f=0.376·exp(0.1439·r_h[nm]) (파일 3종 실측 피팅, 37°C) p_ve, p_le 벽 확산투과도. 파일 3종 실측을 log(MW) 선형 보간. kf_m, kr_m ECM 결합 상수 → 파일(250415_Drug_list) 실측 그대로. k_decay ★ 목표 BA 재현값(calibration). 알려진 약물은 문헌 SC BA를 재현하도록 역산된 값이다(순방향 '예측'이 아니라 '재현'). LODO 검증상 물성으로 예측 불가(27.9%p)이므로 미지 약물엔 k_decay_physics(MW)(MW 로그스케일 물리추정)를 쓸 것. 물리값 원본은 K_DECAY_PHYSICS dict에 보존. TRA는 추천모델5(흡수 왜곡)라 model4 기준으로 재현함. 파일 실측 3종(IgG/INS/ALB, 251103_revised)은 sigma·p·D_gel을 실측 그대로 사용. ──────────────────────────────────────────────────────────── ★ 파라미터 근거 등급 (생체물리 문헌 감사, 상세: comsol_params_biophysics_refs_ko.md) 주의: 이 10개는 임상 PK 상수(CL·V·BA)가 아니라 조직-분자 수송 생체물리량이라 FDA/PopPK DB에서 약물별로 찾을 수 없다. 미세혈관 생리·ECM 확산·공극이론으로 유도. 🟩 물리공식/문헌실측 (5개): sigma_ve, sigma_le : Curry-Michel 공극이론 + Rippe & Haraldsson two-pore (two-pore eqs; 소공극~4nm/대공극~24nm). 파일 3종 재현. D_gel : Stokes-Einstein + ECM 방해(Pluen 2001 PNAS, Ramanujan 2002 BiophysJ). p_ve, p_le : 미세혈관 단백질 투과도 실측과 자릿수 일치 (알부민 1.8e-9, IgG 1.9~4.6e-9 m/s; Yuan 1993 PMID:8321142, PMC2363402). ⬜ 조직상수 고정 (약물 무관, 2개): Lp_ve : 사람 미세혈관 수리전도도 범위 고정. Levick & Michel 2010. K : 사람 간질 Darcy 투과도 범위 고정. Levick 1987, Q J Exp Physiol 72:409. 🟧 기전은 문헌확인, 절대 속도상수 미검증 (3개 — 파일 실측 의존): kf_m, kr_m : ECM-하이알루로난 정전기 결합은 실재 기전(J Pharm Sci 2020)이나 약물별 kon/koff 표준값 없음 → 파일(250415) 실측 사용. k_decay : SC presystemic 분해. 기전·방향(펩타이드↑ mAb↓)·BA범위(52~80%)는 문헌확인(PMC5613179; FcRn PBPK antibodies 2024 doi:10.3390/antib13030070; FcRn결손 BA 82.5%→28.3% PMC6150636)이나 약물별 속도상수 실측 없음 → MW 대리스케일. BA 역산 아님(순환 회피). ──────────────────────────────────────────────────────────── 파라미터 순서: Lp_ve, K, p_le, sigma_ve, sigma_le, p_ve, D_gel, k_decay, kf_m, kr_m """ # 약물 무관 조직 공통값 _COMMON = dict(Lp_ve=8e-12, K=1e-15) # 약물별 COMSOL 파라미터 # IgG/INS/ALB: 파일 실측(sigma·p·D_gel) + 문헌 k_decay # 그 외 7종 : 물리공식(sigma·D_gel·p) + 파일 kf/kr + 문헌 k_decay # ── k_decay 물리값(MW 스케일, BA 미보정) — 미지 약물 폴백·참조용 보존 ── K_DECAY_PHYSICS = { "INS": 3.000e-05, "EXE": 3.925e-05, "ETA": 2.000e-06, "TRA": 2.051e-06, "RIT": 2.070e-06, "IgG": 2.000e-06, "BOC": 2.056e-06, } # 위 DRUG_COMSOL의 k_decay는 아래 목표 BA를 재현하도록 보정된 값(calibration)이다. # ⚠ 이는 순방향 '예측'이 아니라 알려진 문헌 BA의 '재현'값이다. LODO 검증 결과 # 물성(MW·sigma_ve)으로 예측 불가(평균오차 27.9%p)하므로, 미지 약물에는 # k_decay_physics()(MW 로그스케일)를 써야 한다. 상세: pipeline_validation_report_ko.md CALIBRATION_BA = {"INS": 66, "EXE": 100, "ETA": 58, "TRA": 77, "RIT": 64, "IgG": 70, "BOC": 46.5} DRUG_COMSOL = { "INS": dict(MW=5.80, sigma_ve=0.1000, sigma_le=0.0000, p_ve=1.000e-08, p_le=7.200e-08, D_gel=9.400e-11, k_decay=1.494e-05, kf_m=1.450, kr_m=6.82, **_COMMON), "ALB": dict(MW=66.50, sigma_ve=0.7000, sigma_le=0.0500, p_ve=1.000e-09, p_le=1.000e-08, D_gel=6.200e-11, k_decay=3.937e-06, kf_m=0.170, kr_m=4.77, **_COMMON), "IgG": dict(MW=150.00, sigma_ve=0.9000, sigma_le=0.1000, p_ve=1.000e-09, p_le=1.000e-08, D_gel=4.500e-11, k_decay=4.102e-06, kf_m=0.480, kr_m=4.20, **_COMMON), "EXE": dict(MW=4.20, sigma_ve=0.0927, sigma_le=0.0061, p_ve=1.171e-08, p_le=8.241e-08, D_gel=1.093e-10, k_decay=1.361e-06, kf_m=0.624, kr_m=11.14, **_COMMON), "LYS": dict(MW=14.30, sigma_ve=0.2328, sigma_le=0.0159, p_ve=4.600e-09, p_le=3.700e-08, D_gel=7.628e-11, k_decay=1.415e-05, kf_m=1.451, kr_m=99.70, **_COMMON), "OVA": dict(MW=45.00, sigma_ve=0.5168, sigma_le=0.0389, p_ve=1.920e-09, p_le=1.749e-08, D_gel=5.821e-11, k_decay=5.449e-06, kf_m=0.371, kr_m=6.36, **_COMMON), "RIT": dict(MW=143.90, sigma_ve=0.9417, sigma_le=0.0954, p_ve=7.913e-10, p_le=8.182e-09, D_gel=4.909e-11, k_decay=6.238e-06, kf_m=0.296, kr_m=6.35, **_COMMON), "BOC": dict(MW=145.10, sigma_ve=0.9440, sigma_le=0.0960, p_ve=7.863e-10, p_le=8.137e-09, D_gel=4.905e-11, k_decay=1.140e-05, kf_m=0.311, kr_m=5.99, **_COMMON), "TRA": dict(MW=145.50, sigma_ve=0.9448, sigma_le=0.0962, p_ve=7.846e-10, p_le=8.123e-09, D_gel=4.904e-11, k_decay=2.666e-06, kf_m=0.517, kr_m=8.77, **_COMMON), "ETA": dict(MW=149.99, sigma_ve=0.9531, sigma_le=0.0985, p_ve=7.667e-10, p_le=7.963e-09, D_gel=4.892e-11, k_decay=6.981e-06, kf_m=0.756, kr_m=13.40, **_COMMON), } # 파일에서 직접 측정된 약물 (실측 sigma·p·D_gel, 신뢰도 높음) FILE_MEASURED = {"IgG", "INS", "ALB"} PARAM_ORDER = ["Lp_ve", "K", "p_le", "sigma_ve", "sigma_le", "p_ve", "D_gel", "k_decay", "kf_m", "kr_m"] def get_comsol_params(drug="IgG"): if drug not in DRUG_COMSOL: raise KeyError(f"약물 '{drug}' 없음. 지원: {list(DRUG_COMSOL)}") return DRUG_COMSOL[drug] def get_param_vector(drug="IgG"): p = get_comsol_params(drug) return [p[name] for name in PARAM_ORDER] def is_file_measured(drug): """파일에서 직접 측정된 약물인지 (vs 물리공식 계산).""" return drug in FILE_MEASURED def k_decay_physics(mw_kda): """미지 약물용 k_decay (MW 로그스케일 물리 추정, 1/s). BA calibration이 없는 약물에 사용. 펩타이드(~5kDa)~3e-5, mAb(~150kDa)~2e-6. ⚠ 물리 순방향 추정값 — BA 재현 보장 안 됨.""" import math return 10**(-0.8326*math.log10(mw_kda*1000.0) + -1.3896) def get_k_decay(drug, mw_kda=None): """약물 k_decay 반환. 알려진 약물은 calibration(목표 BA 재현)값, 미지 약물은 k_decay_physics(MW) 물리 추정값.""" if drug in DRUG_COMSOL: return DRUG_COMSOL[drug]["k_decay"] if mw_kda is None: raise ValueError("미지 약물은 mw_kda 필요") return k_decay_physics(mw_kda) if __name__ == "__main__": print(f"{'Drug':5s} " + " ".join(f"{n:>9s}" for n in PARAM_ORDER) + " source") for d in DRUG_COMSOL: v = get_param_vector(d) tag = "file" if d in FILE_MEASURED else "calc" print(f"{d:5s} " + " ".join(f"{x:>9.2e}" for x in v) + f" [{tag}]")