Spaces:
Running
Running
Download bioavailability.py from guminhong/Coef_SC_Model: direct link, hf CLI and curl.
- Browser
- Download file 27.1 kB
-
https://huggingface.co/spaces/guminhong/Coef_SC_Model/resolve/main/bioavailability.py
- Command line
-
hf download hf://spaces/guminhong/Coef_SC_Model/bioavailability.py
-
curl -L -o bioavailability.py https://huggingface.co/spaces/guminhong/Coef_SC_Model/resolve/main/bioavailability.py
27.1 kB
| """ | |
| bioavailability.py β SimBiology BA κ³μ° λ‘μ§ μ΄μ λͺ¨λ (λ¬Έν 5λͺ¨λΈ μ λ ¬ν) | |
| ======================================================================== | |
| SimBiology + MATLAB νΌν μν¬νλ‘λ₯Ό μμ PythonμΌλ‘ μ¬ν. | |
| λ리λͺ¨λΈ(MLP/Neural ODE)μ΄ μμΈ‘ν λ¦ΌνΒ·νκ΄ ν‘μ곑μ μΌλ‘λΆν° | |
| μ체μ΄μ©λ₯ (Bioavailability, BA)μ κ³μ°νλ€. | |
| μ΄ λ²μ μ 5κ° ODE λͺ¨λΈμ μ μ (systemic) ꡬν ꡬ쑰λ₯Ό Kagan (2014, | |
| DMD 42:1890) μ’ μ€μ κ·Έλ¦Όκ³Ό "λμΌνκ²" λ§μΆ κ²μ΄λ€. | |
| model 1 = Fig 1A λ¨μΌκ²½λ‘, μ μ 1ꡬν | |
| model 2 = Fig 2A μ΄μ€κ²½λ‘(λ¦Όν ꡬν μμ), μ μ 1ꡬν | |
| model 3 = Fig 2B μ΄μ€κ²½λ‘(λ³λ λ¦Όν ꡬν), μ μ 2ꡬν β μ¬μ©μ PPT/SimBiology λͺ¨λΈ | |
| model 4 = Fig 3A μ¬λΆν¬(λ§μ΄μ‘°μ§βλ¦Όν), μ μ 2ꡬν | |
| model 5 = Fig 3B 7ꡬν λΉμ ν(Dahlberg 2014, trastuzumab) | |
| ν‘μ ꡬλ λ°©μ(μ¬μ©μ μ ν = 곑μ ꡬλ): | |
| models 1β4 λ λ리λͺ¨λΈμ΄ μμΈ‘ν λμ ν‘μ곑μ (c_lymph, c_vessel)μ | |
| μ΄μ€μ§μλ‘ νΌν βλ―ΈλΆν μκ°μμ‘΄ μ§λμ μ λ₯ kle(t)/kve(t)λ₯Ό μ μ ODEμ | |
| μμ€νμΌλ‘ μ£Όμ νλ€. λ¬Ένμ kaΒ·SC(t)(μ: Fig 2A/2B eq.5,9)μμ SC | |
| μ μ₯κ³ λ₯Ό λͺ μμ μΌλ‘ νμ§ μκ³ ν‘μλ₯Ό 곑μ μΌλ‘ 미리 κ³μ°ν΄ λ£μ λ±κ° ννλ€. | |
| presystemic μμ€(λ¬Έν k_loss / PPT k_decay)μ ν‘μ곑μ μ μ΄λ―Έ λ°μλλ€. | |
| model 5 (Fig 3B)λ ν‘μ μμ²΄κ° λͺ μμ SC ꡬνμμμ k14 + Michaelisβ | |
| Menten(Vmax,Km) μμ‘μ΄λΌ 곑μ ꡬλκ³Ό νΈνλμ§ μλλ€. λ°λΌμ λ¬Έν ꡬ쑰 | |
| κ·Έλλ‘ λͺ μμ SC ꡬν + μλμμ ꡬλμΌλ‘ μ λΆνλ€(μλ μ£Όμ μ°Έμ‘°). | |
| μν¬νλ‘ (μλ³Έ SimBiology κ²μ¦: BA=96.8% μ¬ν νμΈ): | |
| 1. λμ ν‘μ곑μ (c_lymph, c_vessel)μ μ΄μ€μ§μλ‘ νΌν | |
| y(t) = y0 + (y00-y0)*F*(1-exp(-k_fast*t)) + (y00-y0)*(1-F)*(1-exp(-k_slow*t)) | |
| 2. mass rate μ λ: [A*exp(-B*t) + C*exp(-D*t)]*dose*0.01 | |
| A=(y00-y0)*F*k_fast, B=k_fast, C=(y00-y0)*(1-F)*k_slow, D=k_slow | |
| 3. SC / IV PK ODE μ λΆ (λͺ¨λΈλ³ ꡬν ꡬ쑰) | |
| 4. BA = AUC_SC(central) / AUC_IV(central) * 100 | |
| SimBiology λͺ¨λΈ νλΌλ―Έν° (νΌνμ£Όμ¬ SC λͺ¨λΈ, PPT '241127 to SG'): | |
| ꡬν: Central(3.557 L) / Peripheral(1.807 L) / Central lymph(0.312 L) / SC(0.0031 L) | |
| k_12=0.0992 μ€μβλ§μ΄ | |
| k_21=0.3448 λ§μ΄βμ€μ | |
| k_input=0.1920 λ¦Όνβμ€μ | |
| k_10=0.0043 μ€μβμ κ±°(μ²μ) | |
| k_decay SC μ μ₯κ³ λΆν΄(=λ¬Έν k_loss); 곑μ ꡬλμμλ 곑μ μ λ΄ν¬ | |
| νλ¦: νκ΄ν‘μβμ€μ μ§μ / λ¦Όνν‘μβλ¦Όνꡬνβ(k_input)βμ€μ | |
| """ | |
| import numpy as np | |
| from scipy.optimize import curve_fit | |
| from scipy.integrate import odeint | |
| # numpy λ²μ νΈν: 2.0+λ trapezoid, μ΄μ μ trapz | |
| _trapz = np.trapezoid if hasattr(np, "trapezoid") else np.trapz | |
| # ββ SimBiology λͺ¨λΈ νλΌλ―Έν° (PPT '241127 to SG') ββ | |
| K_12 = 0.0992 # μ€μ β λ§μ΄ (1/hr) | |
| K_21 = 0.3448 # λ§μ΄ β μ€μ (1/hr) | |
| K_INPUT = 0.1920 # λ¦Όν β μ€μ (1/hr) | |
| K_10 = 0.0043 # μ€μ β μ κ±° (1/hr) | |
| DEFAULT_DOSE = 40.0 # mg | |
| T_MAX_HR = 1000.0 # μ λΆ κ΅¬κ° (hr, β42μΌ) | |
| N_STEPS = 20000 | |
| # ββ model 4 (Fig 3A) μ¬λΆν¬ νλΌλ―Έν° ββ | |
| # μ μ λ§μ΄μ‘°μ§ β λ¦Όνκ³λ‘μ μ¬λ°°μ‘(redistribution) 1μ°¨ μμ. | |
| # Kagan et al. (2007)μ΄ μ μν κ²½λ‘. κ°μ κ°μ κ°(λ―Έκ²μ¦). | |
| K_RL_DEFAULT = 0.001 | |
| # ββ model 5 (Fig 3B, Dahlberg 2014) νλΌλ―Έν° ββ | |
| # λ Όλ¬Έ λ³Έλ¬Έμ κ°λ³ μμΉλ₯Ό νλ‘ μ 곡νμ§ μμΌλ―λ‘ μλλ ꡬ쑰 μμ°μ© | |
| # κ°μ κΈ°λ³Έκ°(placeholder, λ―Έκ²μ¦)μ΄λ€. λ Όλ¬Έμ λμΉ μ μ½μ κ·Έλλ‘ λ°μ: | |
| # k45 = k67, k36 = k34, k24 = k26, k52 = k72 | |
| M5_DEFAULTS = dict( | |
| Vmax=5.0, # SCβμ€μ MichaelisβMenten μ΅λμλ (mg/hr) [κ°μ ] | |
| Km=1.0, # MM μμ (mg) [κ°μ ] | |
| k14=0.05, # SC β νλ°© λ§μ΄λ¦Όν(comp4) (1/hr) [κ°μ ] | |
| CLd=0.10, # μ€μ β λ§μ΄ λΆν¬μ²μ μλΉ 1μ°¨μμ (1/hr) [κ°μ ] | |
| k24=0.02, # μ€μ β λ§μ΄λ¦Όν(νλ°© k24 = μ λ°© k26) (1/hr) [κ°μ ] | |
| k34=0.02, # λ§μ΄ β λ§μ΄λ¦Όν(νλ°© k34 = μ λ°© k36) (1/hr) [κ°μ ] | |
| k45=0.30, # λ§μ΄λ¦Όν β μ€μλ¦Όν(νλ°© k45 = μ λ°© k67) (1/hr) [κ°μ ] | |
| k52=0.20, # μ€μλ¦Όν β μ€μꡬν(νλ°© k52 = μ λ°© k72) (1/hr) [κ°μ ] | |
| ) | |
| def biexp_cumulative(t, y0, y00, F, k_fast, k_slow): | |
| """μ΄μ€μ§μ λμ ν‘μ곑μ (MATLAB fittingpara_v3.mμ λμΌ).""" | |
| return (y0 + (y00 - y0) * F * (1 - np.exp(-k_fast * t)) | |
| + (y00 - y0) * (1 - F) * (1 - np.exp(-k_slow * t))) | |
| def fit_biexp(t_hr, y): | |
| """ | |
| λμ 곑μ μ μ΄μ€μ§μλ‘ νΌν . μ¬λ¬ μ΄κΈ°κ°μ μλν΄ robustνκ². | |
| MATLAB μ μ½: Lower=[-1,0,0,0,0] (y0,y00,F,k_fast,k_slow), Fβ[0,1]. | |
| λ°ν: (y0, y00, F, k_fast, k_slow) λλ None(μ€ν¨). | |
| """ | |
| y = np.clip(np.asarray(y, float), 0, None) | |
| lower = [-1, 0, 0, 0, 0] | |
| upper = [np.inf, np.inf, 1, np.inf, np.inf] | |
| best, best_sse = None, np.inf | |
| for k_fast0 in (0.1, 1.0, 8.0): | |
| for y00_0 in (max(y.max(), 1.0), max(y[-1], 1.0)): | |
| try: | |
| p0 = [0, y00_0, 0.01, k_fast0, 0.01] | |
| popt, _ = curve_fit(biexp_cumulative, t_hr, y, p0=p0, | |
| bounds=(lower, upper), maxfev=5000) | |
| sse = np.sum((y - biexp_cumulative(t_hr, *popt)) ** 2) | |
| if sse < best_sse: | |
| best_sse, best = sse, popt | |
| except Exception: | |
| continue | |
| return best | |
| def rate_params(popt): | |
| """νΌν νλΌλ―Έν° β mass rate κ³μ (A,B,C,D).""" | |
| y0, y00, F, k_fast, k_slow = popt | |
| A = (y00 - y0) * F * k_fast | |
| B = k_fast | |
| C = (y00 - y0) * (1 - F) * k_slow | |
| D = k_slow | |
| return A, B, C, D | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # SC ν‘μ λͺ¨λΈ ODE (λ¬Έν 5λͺ¨λΈκ³Ό λμΌ κ΅¬μ‘°) | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _sc_ode_m1(y, t, ka, k10): | |
| """ | |
| λͺ¨λΈ 1 = λ Όλ¬Έ Fig 1A (single-pathway). | |
| λ¦ΌνΒ·νκ΄ λ―Έκ΅¬λΆ, λ¨μΌ ν‘μ. μ μ 1ꡬν(νμ λ°μ€). | |
| λ¬Έν Fig 1A: ν‘μλ kaΒ·Fλ‘ μ μ± κΈ°μ (μ λ²νΈ μμ). | |
| dC/dt = (ν‘μ μ μ ) β k10Β·C | |
| 곑μ ꡬλ: ν‘μ μ μ = ka(t) = (λ¦Όν+νκ΄ ν©μ° 곑μ )μ μ μ λ₯ . | |
| """ | |
| (c_cen,) = y | |
| return [ka(t) - k10 * c_cen] | |
| def _sc_ode_m2(y, t, kle, kve, k10): | |
| """ | |
| λͺ¨λΈ 2 = λ Όλ¬Έ Fig 2A (dual-pathway, λ¦Όν ꡬν μμ). | |
| νκ΄Β·λ¦Όν λ κ²½λ‘κ° λ λ€ μ μ μΌλ‘ μ§ν. μ μ 1ꡬν(νμ λ°μ€). | |
| λ¬Έν Fig 2A(McLennan 2003, λ ν΄): dC/dt = (k_blood+k_lymph)Β·SC/Vc Β± disp, | |
| k_lossλ μ£Όμ¬λΆμ presystemic λΆν΄(곑μ μ λ΄ν¬). | |
| dC/dt = kve(t) + kle(t) β k10Β·C | |
| """ | |
| (c_cen,) = y | |
| return [kve(t) + kle(t) - k10 * c_cen] | |
| def _sc_ode_m3(y, t, kle, kve, k10, k12, k21, k_input): | |
| """ | |
| λͺ¨λΈ 3 = λ Όλ¬Έ Fig 2B (λ³λ λ¦Όν ꡬν) = μ¬μ©μ PPT/SimBiology λͺ¨λΈ. | |
| νκ΄βμ€μ μ§μ , λ¦Όνβλ¦Όνꡬνβ(k_input)βμ€μ. λ§μ΄βμ€μ(k12,k21). μ μ 2ꡬν. | |
| λ¬Έν Fig 2B (McLennan 2005a, Kota 2007) eq.9β11 λ° PPT '241127 to SG': | |
| dm_SC/dt = βαΉ_le β αΉ_ve β k_decayΒ·m_SC (곑μ ꡬλμμλ μλ΅) | |
| dm_CL/dt = αΉ_le β k_inputΒ·m_CL | |
| dm_CC/dt = αΉ_ve β (k12Β·m_CC β k21Β·m_PC) + k_inputΒ·m_CL β k10Β·m_CC | |
| dm_PC/dt = k12Β·m_CC β k21Β·m_PC | |
| μ¬κΈ°μ αΉ_ve = kve(t), αΉ_le = kle(t) (곑μ μ μ λ₯ ). | |
| μν μμ: [μ€μ CC, λ§μ΄ PC, μ€μλ¦Όν CL]. | |
| """ | |
| c_cen, c_per, c_lym = y | |
| dc_cen = kve(t) + k_input * c_lym - k10 * c_cen - k12 * c_cen + k21 * c_per | |
| dc_per = k12 * c_cen - k21 * c_per | |
| dc_lym = kle(t) - k_input * c_lym | |
| return [dc_cen, dc_per, dc_lym] | |
| # νμνΈν λ³μΉ (ꡬλ²μ μ΄λ¦) | |
| _sc_ode = _sc_ode_m3 | |
| _sc_ode_dyn = _sc_ode_m3 | |
| def _sc_ode_m4(y, t, kle, kve, k10, k12, k21, k_input, k_rl=K_RL_DEFAULT): | |
| """ | |
| λͺ¨λΈ 4 = λ Όλ¬Έ Fig 3A (redistribution, Kagan 2007). | |
| Fig 2B ꡬ쑰 + 'μ μ λ§μ΄μ‘°μ§ β λ¦Όνκ³' μ¬λ°°μ‘(μ¬μν). | |
| λ¬Έν Fig 3A λμ: SCβλ¦Όνκ³Β·νμ₯, λ¦Όνκ³βνμ₯(k_input), | |
| νμ₯ β λ§μ΄μ‘°μ§(k12,k21), **λ§μ΄μ‘°μ§ β λ¦Όνκ³(k_rl)**, νμ₯ μμ€(k10). | |
| μ μ 2ꡬν(νμ₯ + λ§μ΄μ‘°μ§). | |
| dc_lym = kle(t) β k_inputΒ·c_lym + k_rlΒ·c_per (λ§μ΄μ‘°μ§βλ¦Όν μ¬λΆν¬) | |
| dc_cen = kve(t) + k_inputΒ·c_lym β k10Β·c_cen β k12Β·c_cen + k21Β·c_per | |
| dc_per = k12Β·c_cen β k21Β·c_per β k_rlΒ·c_per | |
| μν μμ: [μ€μ c_cen, λ§μ΄μ‘°μ§ c_per, λ¦Όνκ³ c_lym]. | |
| """ | |
| c_cen, c_per, c_lym = y | |
| dc_cen = kve(t) + k_input * c_lym - k10 * c_cen - k12 * c_cen + k21 * c_per | |
| dc_per = k12 * c_cen - k21 * c_per - k_rl * c_per | |
| dc_lym = kle(t) - k_input * c_lym + k_rl * c_per | |
| return [dc_cen, dc_per, dc_lym] | |
| def _sc_ode_m5(y, t, k10, p): | |
| """ | |
| λͺ¨λΈ 5 = λ Όλ¬Έ Fig 3B (Dahlberg 2014, trastuzumab, 7ꡬν λΉμ ν). | |
| ꡬν λ²νΈ(λ Όλ¬Έκ³Ό λμΌ): | |
| 1: SC μ£Όμ¬λΆμ | |
| 2: Central(νμ₯) 3: Peripheral(λ§μ΄μ‘°μ§) | |
| 4: νλ°© λ§μ΄λ¦Όν 5: νλ°© μ€μλ¦Όν | |
| 6: μ λ°© λ§μ΄λ¦Όν 7: μ λ°© μ€μλ¦Όν | |
| ν‘μ: SC(1)βνλ°© λ§μ΄λ¦Όν(4) 1μ°¨(k14) + SC(1)βμ€μ(2) MichaelisβMenten(Vmax,Km). | |
| μ¬λΆν¬: μ€μ(2)βλ§μ΄λ¦Όν(k24=k26), λ§μ΄(3)βλ§μ΄λ¦Όν(k34=k36). | |
| λ¦Όν λ°°μΆ: λ§μ΄λ¦Όνβμ€μλ¦Όν(k45=k67), μ€μλ¦Όνβμ€μ(k52=k72). | |
| μ μ λΆν¬: μ€μ β λ§μ΄ (CLd), μ€μ μ κ±° k10(=CL/V). | |
| λμΉ μ μ½(λ Όλ¬Έ): k45=k67, k36=k34, k24=k26, k52=k72. | |
| dm1 = βk14Β·m1 β VmaxΒ·m1/(Km+m1) | |
| dm2 = VmaxΒ·m1/(Km+m1) + k52Β·m5 + k72Β·m7 β k10Β·m2 β CLdΒ·m2 + CLdΒ·m3 β (k24+k26)Β·m2 | |
| dm3 = CLdΒ·m2 β CLdΒ·m3 β (k34+k36)Β·m3 | |
| dm4 = k14Β·m1 + k24Β·m2 + k34Β·m3 β k45Β·m4 | |
| dm5 = k45Β·m4 β k52Β·m5 | |
| dm6 = k26Β·m2 + k36Β·m3 β k67Β·m6 | |
| dm7 = k67Β·m6 β k72Β·m7 | |
| μ£Όμ: μ΄ λͺ¨λΈμ ν‘μλ λͺ μμ SC ꡬν + MM μμ‘μ΄λΌ λ리λͺ¨λΈ 곑μ | |
| ꡬλκ³Ό νΈνλμ§ μμ μλμμ ꡬλμΌλ‘ μ λΆνλ€. λν λ리λͺ¨λΈμ λ¦Όν | |
| μΆλ ₯μ΄ λ¨μΌ μ±λλΏμ΄λΌ μ λ°©/νλ°© λ¦Όνκ³λ₯Ό μ€μΈ‘ λΆλ¦¬ν μ μλ€(μλ³ λΆκ°). | |
| μλ M5_DEFAULTSλ ꡬ쑰 μμ°μ© κ°μ κ°(placeholder)μ΄λ€. | |
| """ | |
| m1, m2, m3, m4, m5, m6, m7 = y | |
| Vmax, Km = p["Vmax"], p["Km"] | |
| k14, CLd = p["k14"], p["CLd"] | |
| k24 = k26 = p["k24"] # λμΉ μ μ½ | |
| k34 = k36 = p["k34"] | |
| k45 = k67 = p["k45"] | |
| k52 = k72 = p["k52"] | |
| mm = Vmax * m1 / (Km + m1) | |
| dm1 = -k14 * m1 - mm | |
| dm2 = mm + k52 * m5 + k72 * m7 - k10 * m2 - CLd * m2 + CLd * m3 - (k24 + k26) * m2 | |
| dm3 = CLd * m2 - CLd * m3 - (k34 + k36) * m3 | |
| dm4 = k14 * m1 + k24 * m2 + k34 * m3 - k45 * m4 | |
| dm5 = k45 * m4 - k52 * m5 | |
| dm6 = k26 * m2 + k36 * m3 - k67 * m6 | |
| dm7 = k67 * m6 - k72 * m7 | |
| return [dm1, dm2, dm3, dm4, dm5, dm6, dm7] | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # IV λͺ¨λΈ ODE (SC λͺ¨λΈμ μ μ ꡬν ꡬ쑰μ μΌμΉ) | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _iv_ode_1pool(y, t, k10): | |
| """1ꡬν IV (λͺ¨λΈ 1,2μ©). t=0 μ λ ν¬μ¬ ν 1μ°¨ μ κ±°.""" | |
| (c_cen,) = y | |
| return [-k10 * c_cen] | |
| def _iv_ode_2pool(y, t, k10, k12, k21): | |
| """2ꡬν IV (λͺ¨λΈ 3,4μ©): μ€μ β λ§μ΄, μ€μ μ κ±°.""" | |
| c_cen, c_per = y | |
| return [-k10 * c_cen - k12 * c_cen + k21 * c_per, | |
| k12 * c_cen - k21 * c_per] | |
| def _iv_ode_m5(y, t, k10, p): | |
| """ | |
| λͺ¨λΈ 5 IV: SC ꡬν(1) μμ΄ IV doseλ₯Ό μ€μ(2)μ μ§μ ν¬μ¬. | |
| λλ¨Έμ§ 6ꡬν(2,3,4,5,6,7)μ μ μ λΆν¬Β·μ¬λΆν¬Β·λ¦Όν λ°°μΆμ SCμ λμΌ. | |
| μν μμ: [m2, m3, m4, m5, m6, m7]. | |
| """ | |
| m2, m3, m4, m5, m6, m7 = y | |
| CLd = p["CLd"] | |
| k24 = k26 = p["k24"] | |
| k34 = k36 = p["k34"] | |
| k45 = k67 = p["k45"] | |
| k52 = k72 = p["k52"] | |
| dm2 = k52 * m5 + k72 * m7 - k10 * m2 - CLd * m2 + CLd * m3 - (k24 + k26) * m2 | |
| dm3 = CLd * m2 - CLd * m3 - (k34 + k36) * m3 | |
| dm4 = k24 * m2 + k34 * m3 - k45 * m4 | |
| dm5 = k45 * m4 - k52 * m5 | |
| dm6 = k26 * m2 + k36 * m3 - k67 * m6 | |
| dm7 = k67 * m6 - k72 * m7 | |
| return [dm2, dm3, dm4, dm5, dm6, dm7] | |
| # νμνΈν λ³μΉ | |
| _iv_ode = lambda y, t: _iv_ode_2pool(y, t, K_10, K_12, K_21) | |
| _iv_ode_dyn = _iv_ode_2pool | |
| def compute_bioavailability(c_lymph, c_vessel, t_min, dose=DEFAULT_DOSE, | |
| drug="IgG", model=3, m5_params=None, | |
| return_detail=False): | |
| """ | |
| λ¦ΌνΒ·νκ΄ λμ ν‘μ곑μ β μ체μ΄μ©λ₯ (%). | |
| μΈμ: | |
| c_lymph, c_vessel : λμ % mass 곑μ (λ리λͺ¨λΈ μμΈ‘) | |
| t_min : μκ°μΆ (λΆ) | |
| dose : ν¬μ¬λ (mg) | |
| drug : μ½λ¬Ό μ’ λ₯ ("IgG","INS","ALB") λλ MW(μ«μ) | |
| model : 1=Fig1A, 2=Fig2A, 3=Fig2B(PPT), 4=Fig3A, 5=Fig3B | |
| m5_params : model 5 μλμμ dict (μμΌλ©΄ M5_DEFAULTS) | |
| λ°ν: | |
| BA (%) λλ return_detail=True μ dict | |
| """ | |
| # μ½λ¬Όλ³ μ μ PK νλΌλ―Έν° λ‘λ | |
| try: | |
| from drug_pk_params import get_drug_params | |
| pk = get_drug_params(drug) | |
| k12, k21 = pk["k12"], pk["k21"] | |
| k_input, k10 = pk["k_input"], pk["k10"] | |
| except Exception: | |
| k12, k21, k_input, k10 = K_12, K_21, K_INPUT, K_10 | |
| t_hr = np.asarray(t_min, float) / 60.0 | |
| pl = fit_biexp(t_hr, c_lymph) | |
| pv = fit_biexp(t_hr, c_vessel) | |
| if pl is None or pv is None: | |
| raise RuntimeError("μ΄μ€μ§μ νΌν μ€ν¨ β 곑μ μ νμΈνμΈμ.") | |
| Al, Bl, Cl, Dl = rate_params(pl) | |
| Av, Bv, Cv, Dv = rate_params(pv) | |
| def kle(t): | |
| return (Al * np.exp(-Bl * t) + Cl * np.exp(-Dl * t)) * dose * 0.01 | |
| def kve(t): | |
| return (Av * np.exp(-Bv * t) + Cv * np.exp(-Dv * t)) * dose * 0.01 | |
| # λͺ¨λΈ 1μ λ¦Όν+νκ΄ ν©μ° ν‘μλ₯Ό λ°λ‘ νΌν | |
| pt = fit_biexp(t_hr, np.asarray(c_lymph, float) + np.asarray(c_vessel, float)) | |
| if pt is not None: | |
| At, Bt, Ct, Dt = rate_params(pt) | |
| def ka(t): | |
| return (At * np.exp(-Bt * t) + Ct * np.exp(-Dt * t)) * dose * 0.01 | |
| else: | |
| ka = lambda t: kle(t) + kve(t) | |
| tt = np.linspace(0, T_MAX_HR, N_STEPS) | |
| # ββ λͺ¨λΈ μ ν (Kagan 2014 κΈ°μ€) ββ | |
| if model == 1: | |
| # Fig 1A: λ¨μΌν‘μ, μ μ 1ꡬν | |
| sc_full = odeint(_sc_ode_m1, [0], tt, args=(ka, k10)) | |
| sc = np.column_stack([sc_full[:, 0], np.zeros(len(tt)), np.zeros(len(tt))]) | |
| iv = odeint(_iv_ode_1pool, [dose], tt, args=(k10,)) | |
| elif model == 2: | |
| # Fig 2A: dual, λ¦Όνꡬν μμ, μ μ 1ꡬν | |
| sc_full = odeint(_sc_ode_m2, [0], tt, args=(kle, kve, k10)) | |
| sc = np.column_stack([sc_full[:, 0], np.zeros(len(tt)), np.zeros(len(tt))]) | |
| iv = odeint(_iv_ode_1pool, [dose], tt, args=(k10,)) | |
| elif model == 4: | |
| # Fig 3A: redistribution(λ§μ΄μ‘°μ§βλ¦Όν), μ μ 2ꡬν | |
| sc = odeint(_sc_ode_m4, [0, 0, 0], tt, | |
| args=(kle, kve, k10, k12, k21, k_input, K_RL_DEFAULT)) | |
| iv = odeint(_iv_ode_2pool, [dose, 0], tt, args=(k10, k12, k21)) | |
| elif model == 5: | |
| # Fig 3B: 7ꡬν λΉμ ν. μλμμ ꡬλ(곑μ ꡬλκ³Ό λΉνΈν). | |
| p = dict(M5_DEFAULTS) | |
| if m5_params: | |
| p.update(m5_params) | |
| sc7 = odeint(_sc_ode_m5, [dose, 0, 0, 0, 0, 0, 0], tt, args=(k10, p)) | |
| # μ€μ(comp2)λ§ BAμ μ¬μ© | |
| sc = np.column_stack([sc7[:, 1], sc7[:, 2], np.zeros(len(tt))]) | |
| iv6 = odeint(_iv_ode_m5, [dose, 0, 0, 0, 0, 0], tt, args=(k10, p)) | |
| iv = np.column_stack([iv6[:, 0], iv6[:, 1]]) | |
| else: # model == 3 (Fig 2B, PPT/SimBiology, κΈ°λ³Έ) | |
| sc = odeint(_sc_ode_m3, [0, 0, 0], tt, | |
| args=(kle, kve, k10, k12, k21, k_input)) | |
| iv = odeint(_iv_ode_2pool, [dose, 0], tt, args=(k10, k12, k21)) | |
| auc_sc = _trapz(sc[:, 0], tt) | |
| auc_iv = _trapz(iv[:, 0], tt) | |
| BA = auc_sc / auc_iv * 100.0 | |
| if return_detail: | |
| sc_plasma = sc[:, 0] | |
| cmax = float(sc_plasma.max()) | |
| peak_i = int(np.argmax(sc_plasma)) | |
| tmax = float(tt[peak_i]) | |
| after = sc_plasma[peak_i:] | |
| t_after = tt[peak_i:] | |
| if len(after) > 1 and cmax > 0: | |
| t_half = float(t_after[int(np.argmin(np.abs(after - cmax / 2)))] - tmax) | |
| else: | |
| t_half = float("nan") | |
| return { | |
| "BA": float(BA), | |
| "AUC_SC": float(auc_sc), | |
| "AUC_IV": float(auc_iv), | |
| "drug": drug, | |
| "model": model, | |
| "pk_params": dict(k10=k10, k12=k12, k21=k21, k_input=k_input), | |
| "lymph_rate_params": dict(A=Al, B=Bl, C=Cl, D=Dl), | |
| "vessel_rate_params": dict(A=Av, B=Bv, C=Cv, D=Dv), | |
| "sc_curve": sc[:, 0], | |
| "iv_curve": iv[:, 0], | |
| "central_curve": sc[:, 0], | |
| "time_hr": tt, | |
| "Cmax": cmax, | |
| "Tmax_hr": tmax, | |
| "t_half_hr": t_half, | |
| } | |
| return float(BA) | |
| def compute_bioavailability_ci(c_lymph, c_vessel, t_min, oof_resid, | |
| dose=DEFAULT_DOSE, drug="IgG", model=3, | |
| m5_params=None, n_mc=300, levels=(95.0, 99.0), | |
| seed=42, lymph_idx=0, vessel_idx=1): | |
| """ | |
| λ리λͺ¨λΈ λΆνμ€μ±μ μ νν BA μ츑ꡬκ°(μ 뒰ꡬκ°). | |
| BAλ λ리λͺ¨λΈμ΄ μμΈ‘ν λλ곑μ (c_lymph, c_vessel)μΌλ‘ κ³μ°λλλ°, κ·Έ 곑μ μλ | |
| honest OOF μμ°¨λ‘ μ λνλ λΆνμ€μ±(conformal μ츑ꡬκ°)μ΄ μλ€. μ΄ ν¨μλ κ·Έ | |
| μμ°¨λ₯Ό 곑μ μ λͺ¬ν μΉ΄λ₯Όλ‘λ‘ μ£Όμ ν΄ μ¬λ¬ κ°μ κ·Έλ΄λ―ν 곑μ μ λ§λ€κ³ , κ° κ³‘μ μ | |
| BAλ₯Ό κ³μ°ν΄ BA λΆν¬ β percentile μ츑ꡬκ°μ μ»λλ€. | |
| μΈμ: | |
| c_lymph, c_vessel : λμ % mass 곑μ (λ리λͺ¨λΈ base μμΈ‘), κ° (n_t,) | |
| t_min : μκ°μΆ (λΆ) | |
| oof_resid : OOF μμ°¨ λ°°μ΄ (n_cases, n_t, n_out) = μ€μ β μμλΈμμΈ‘. | |
| μμ κ° μκ΄μ 보쑴νκΈ° μν΄ μμ°¨ 'ν'(μΌμ΄μ€) μ 체λ₯Ό | |
| λΆνΈμ€νΈλ© μνλ§νλ€. | |
| dose, drug, model, m5_params : compute_bioavailabilityμ λμΌ | |
| n_mc : λͺ¬ν μΉ΄λ₯Όλ‘ νλ³Έ μ | |
| levels : μμΈ‘κ΅¬κ° μμ€(%) νν, μ (95, 99) | |
| seed : λμ μλ | |
| lymph_idx,vessel_idx : oof_residμ ꡬν μΆμμ lymphΒ·vessel μμΉ | |
| λ°ν: | |
| dict: base, median, std, ci({level:(lo,hi)}), samples, n_valid, | |
| curve_bands({time_hr, sc_base, iv_curve, sc_lo95/hi95, sc_lo99/hi99}) | |
| β curve_bandsλ SC νμ₯곑μ μ μμ λ³ 95%/99% μμΈ‘ λ°΄λ(κ·Έλνμ©). | |
| """ | |
| c_lymph = np.asarray(c_lymph, float) | |
| c_vessel = np.asarray(c_vessel, float) | |
| oof_resid = np.asarray(oof_resid, float) | |
| n_cases = oof_resid.shape[0] | |
| def _detail(cl, cv): | |
| return compute_bioavailability(cl, cv, t_min, dose=dose, drug=drug, | |
| model=model, m5_params=m5_params, | |
| return_detail=True) | |
| base_d = _detail(c_lymph, c_vessel) | |
| base = base_d["BA"] | |
| time_hr = np.asarray(base_d["time_hr"], float) # SC/IV 곑μ μκ°μΆ(hr) | |
| iv_curve = np.asarray(base_d["iv_curve"], float) | |
| sc_base = np.asarray(base_d["sc_curve"], float) | |
| rng = np.random.default_rng(seed) | |
| il = rng.integers(0, n_cases, n_mc) | |
| iv = rng.integers(0, n_cases, n_mc) | |
| samples = [] | |
| sc_curves = [] # νλ³Έλ³ SC νμ₯곑μ | |
| for i in range(n_mc): | |
| cl = np.clip(c_lymph + oof_resid[il[i], :, lymph_idx], 0.0, None) | |
| cv = np.clip(c_vessel + oof_resid[iv[i], :, vessel_idx], 0.0, None) | |
| try: | |
| d = _detail(cl, cv) | |
| except Exception: | |
| continue | |
| b = d["BA"] | |
| if np.isfinite(b): | |
| samples.append(b) | |
| sc_curves.append(np.asarray(d["sc_curve"], float)) | |
| samples = np.asarray(samples) | |
| sc_curves = np.asarray(sc_curves) # (n_valid, n_tt) | |
| ci = {} | |
| for lv in levels: | |
| a = (100.0 - lv) / 2.0 | |
| ci[lv] = (float(np.percentile(samples, a)), | |
| float(np.percentile(samples, 100.0 - a))) | |
| # μμ λ³ SC νμ₯곑μ λ°΄λ (μμΈ‘ κ·Έλνμ λμΌν 95%/99% νν) | |
| curve_bands = {"time_hr": time_hr, "sc_base": sc_base, "iv_curve": iv_curve} | |
| if len(sc_curves): | |
| for lv in levels: | |
| a = (100.0 - lv) / 2.0 | |
| curve_bands[f"sc_lo{int(lv)}"] = np.percentile(sc_curves, a, axis=0) | |
| curve_bands[f"sc_hi{int(lv)}"] = np.percentile(sc_curves, 100.0 - a, axis=0) | |
| return { | |
| "base": float(base), | |
| "median": float(np.median(samples)), | |
| "std": float(samples.std()), | |
| "ci": ci, | |
| "samples": samples, | |
| "n_valid": int(len(samples)), | |
| "curve_bands": curve_bands, | |
| } | |
| def compute_pk_metrics_ci(c_lymph, c_vessel, t_min, conf_half, | |
| dose=DEFAULT_DOSE, drug="IgG", model=3, | |
| m5_params=None): | |
| """ | |
| conformal μμΈ‘λ°΄λλ₯Ό κ·Έλλ‘ μ νν μ½λν μ§ν κ΅¬κ° (λͺ¬ν μΉ΄λ₯Όλ‘ μμ, λΉ λ¦). | |
| λλ μμΈ‘ κ·Έλνμ μ°λ κ²κ³Ό 'λμΌν' μμ λ³ conformal λ°ν(conf_half)μ | |
| λ¦ΌνΒ·νκ΄ κ³‘μ μ μ μ©ν΄ μν/νν ν‘μ곑μ μ λ§λ€κ³ , κ°κ°μΌλ‘ SC νμ₯곑μ μ | |
| μ λΆνλ€. κ·Έ κ²°κ³Όκ° BA κ·Έλνμ 보μ΄λ SC λ°΄λ(sc_lo/hi)λ€. μ§νλ: | |
| - BA, Tmax : μΒ·νν 곑μ μ detailμμ μ§μ | |
| - Ka, tΒ½ : μΒ·νν SC 'νμ₯곑μ 'μ ν‘μ-μμ€ μ΄μ€μ§μλ‘ νΌν ν΄ μΆμΆ | |
| (SC νμ₯곑μ μ νΌν νλ―λ‘ ν‘μ곑μ νΌν κ³Ό λ¬λ¦¬ μμ μ ) | |
| λͺ¨λ ꡬκ°μ base κ°μ ν¬ν¨νλλ‘ [min(base,lo,hi), max(base,lo,hi)]λ‘ λ§λ λ€ | |
| (λ°΄λκ° μκ°μ λ°λΌ λΉλμΉμ΄λΌ μΒ·νν μ§νκ° νμͺ½μΌλ‘ μ 릴 μ μμΌλ―λ‘). | |
| μΈμ: | |
| c_lymph, c_vessel : λ리λͺ¨λΈ base μμΈ‘ 곑μ (n_t,) | |
| t_min : μκ°μΆ (λΆ) | |
| conf_half : {level(%): (q_lymph, q_vessel)} μμ λ³ λ°ν λ°°μ΄ dict. | |
| dose, drug, model, m5_params : compute_bioavailabilityμ λμΌ | |
| λ°ν: | |
| dict: | |
| base : base 곑μ μ detail | |
| metrics : {"BA","Ka","Tmax_hr","t_half_hr"} κ°κ° base μ μΆμ κ° | |
| ci : {metric: {level: (lo, hi)}} β 4κ° μ§ν λͺ¨λ κ΅¬κ° λΆμ¬ | |
| curve_bands : {time_hr, sc_base, iv_curve, sc_lo/hi95, sc_lo/hi99} | |
| """ | |
| c_lymph = np.asarray(c_lymph, float) | |
| c_vessel = np.asarray(c_vessel, float) | |
| def _detail(cl, cv): | |
| return compute_bioavailability(cl, cv, t_min, dose=dose, drug=drug, | |
| model=model, m5_params=m5_params, | |
| return_detail=True) | |
| def _sc_fit(t_hr_curve, sc): | |
| """SC νμ₯곑μ μ ν‘μ-μμ€ μ΄μ€μ§μ A*(e^{-ke t}-e^{-ka t})λ‘ νΌν . | |
| λ°ν (Ka=ka, t_half=ln2/ke). μ€ν¨ μ (nan, nan).""" | |
| def _biexp(t, A, ka, ke): | |
| return A * (np.exp(-ke * t) - np.exp(-ka * t)) | |
| ip = int(np.argmax(sc)); cmax = float(sc[ip]) | |
| if cmax <= 0: | |
| return float("nan"), float("nan") | |
| try: | |
| popt, _ = curve_fit(_biexp, t_hr_curve, sc, | |
| p0=[cmax * 2, 0.1, 0.01], maxfev=10000, | |
| bounds=([0, 1e-4, 1e-5], [np.inf, 50, 10])) | |
| _, ka, ke = popt | |
| ka, ke = max(ka, ke), min(ka, ke) # ka(ν‘μ) > ke(μμ€) | |
| return float(ka), float(np.log(2) / ke) | |
| except Exception: | |
| return float("nan"), float("nan") | |
| base_d = _detail(c_lymph, c_vessel) | |
| t_hr_curve = np.asarray(base_d["time_hr"], float) | |
| Ka0, th0 = _sc_fit(t_hr_curve, np.asarray(base_d["sc_curve"], float)) | |
| base_metrics = {"BA": base_d["BA"], "Ka": Ka0, | |
| "Tmax_hr": base_d["Tmax_hr"], "t_half_hr": th0} | |
| metric_names = ["BA", "Ka", "Tmax_hr", "t_half_hr"] | |
| ci = {m: {} for m in metric_names} | |
| curve_bands = {"time_hr": t_hr_curve, "sc_base": base_d["sc_curve"], | |
| "iv_curve": base_d["iv_curve"]} | |
| for lv, (qL, qV) in conf_half.items(): | |
| qL = np.asarray(qL, float); qV = np.asarray(qV, float) | |
| cl_lo = np.clip(c_lymph - qL, 0, None); cl_hi = c_lymph + qL | |
| cv_lo = np.clip(c_vessel - qV, 0, None); cv_hi = c_vessel + qV | |
| d_lo = _detail(cl_lo, cv_lo) # ν‘μ곑μ νν β SC νμ₯곑μ νν | |
| d_hi = _detail(cl_hi, cv_hi) # ν‘μ곑μ μν β SC νμ₯곑μ μν | |
| sc_lo = np.asarray(d_lo["sc_curve"], float) | |
| sc_hi = np.asarray(d_hi["sc_curve"], float) | |
| Ka_lo, th_lo = _sc_fit(t_hr_curve, sc_lo) # SC λ°΄λ 곑μ μ§μ νΌν | |
| Ka_hi, th_hi = _sc_fit(t_hr_curve, sc_hi) | |
| vals = { | |
| "BA": (d_lo["BA"], d_hi["BA"]), | |
| "Ka": (Ka_lo, Ka_hi), | |
| "Tmax_hr": (d_lo["Tmax_hr"], d_hi["Tmax_hr"]), | |
| "t_half_hr": (th_lo, th_hi), | |
| } | |
| for m in metric_names: | |
| a, b = vals[m] | |
| base_v = base_metrics[m] | |
| cand = [x for x in (a, b, base_v) if np.isfinite(x)] # base ν¬ν¨ | |
| ci[m][lv] = (float(min(cand)), float(max(cand))) | |
| curve_bands[f"sc_lo{int(lv)}"] = sc_lo | |
| curve_bands[f"sc_hi{int(lv)}"] = sc_hi | |
| return {"base": base_d, "metrics": base_metrics, | |
| "ci": ci, "curve_bands": curve_bands} | |
| # ββ μ체 κ²μ¦ (μλ³Έ SimBiology BA=96.8% μ¬ν, model 3 / Fig 2B) ββ | |
| if __name__ == "__main__": | |
| dose = 40.0 | |
| def kle(t): return (10.02*np.exp(-8.868*t) + 2.407*np.exp(-0.035*t)) * dose * 0.01 | |
| def kve(t): return (0.919*np.exp(-0.035*t) + 1.061*np.exp(-1.576*t)) * dose * 0.01 | |
| tt = np.linspace(0, 1000, 20000) | |
| sc = odeint(_sc_ode_m3, [0, 0, 0], tt, | |
| args=(kle, kve, K_10, K_12, K_21, K_INPUT)) | |
| iv = odeint(_iv_ode_2pool, [dose, 0], tt, args=(K_10, K_12, K_21)) | |
| ba = _trapz(sc[:, 0], tt) / _trapz(iv[:, 0], tt) * 100 | |
| print(f"κ²μ¦(model 3, Fig 2B): BA={ba:.1f}% (μλ³Έ SimBiology 96.8%, μ€μ°¨ {abs(ba-96.8):.2f}%p)") | |