import math from .health_egfr_types import CreatinineUnit, Egfr, Sex from .math_pow import pow from .math_round_float import round_float #: Inker et al. 2021, footnote to table 2: mg/dL x 88.4 = umol/L. _UMOL_PER_MG_DL = 88.4 def egfr_ckd_epi2021(creatinine: float, unit: CreatinineUnit, age_years: int, sex: Sex) -> Egfr: """Estimated GFR by the CKD-EPI 2021 creatinine equation without race (Inker et al., NEJM 2021;385:1737-49, table 2): eGFR = 142 x min(Scr/k, 1)^a x max(Scr/k, 1)^-1.200 x 0.9938^age x 1.012 [if female] with Scr in mg/dL, k 0.7 (female) or 0.9 (male), a -0.241 (female) or -0.302 (male). Powers go through math.pow so all three languages produce the same double; the whole-number result is rounded from the unrounded estimate, never from the one-decimal value (143.4993 is 143, not 144). """ if unit == "umol-per-l": low, high = 10, 4000 elif unit == "mg-per-dl": low, high = 0.1, 45 else: raise ValueError("unit must be umol-per-l or mg-per-dl, received %r" % (unit,)) ok = not isinstance(creatinine, bool) and isinstance(creatinine, (int, float)) and math.isfinite(creatinine) if not ok or creatinine < low or creatinine > high: raise ValueError("creatinine must be a number from %s to %s %s, received %r" % (low, high, unit, creatinine)) if isinstance(age_years, bool) or not isinstance(age_years, int) or age_years < 18 or age_years > 120: raise ValueError("ageYears must be a whole number from 18 to 120, received %r" % (age_years,)) if sex != "female" and sex != "male": raise ValueError("sex must be female or male, received %r" % (sex,)) female = sex == "female" scr = float(creatinine) / _UMOL_PER_MG_DL if unit == "umol-per-l" else float(creatinine) kappa = 0.7 if female else 0.9 alpha = -0.241 if female else -0.302 ratio = scr / kappa # Below the knot the max() term is 1, above it the min() term is 1. creatinine_term = pow(ratio, alpha) if ratio <= 1 else pow(ratio, -1.2) estimate = 142 * creatinine_term * pow(0.9938, float(age_years)) if female: estimate = estimate * 1.012 return Egfr(value=round_float(estimate, 1), reported=int(round_float(estimate, 0)))