The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

Diffusion capacity (DLCO / TLCO): reference, Hb correction, interpretation

Diffusion measurements (DLCO in traditional units, TLCO in SI) quantify gas-exchange capacity at the alveolar-capillary membrane. The sections below cover the reference values pft computes (pft_diffusion(), GLI 2017), the hemoglobin correction (pft_dlco_hb_correct()), and the Hughes & Pride categorical classifier (pft_diffusion_interpret()).

1. Reference values

pft_diffusion() implements the GLI 2017 standard (Stanojevic et al. ERJ 2017, with the 2020 author correction applied) for adults and children aged 5-90 years (the GLI calculator caps at 85; the underlying spline tables extend to 90). By default it emits traditional units (DLCO, KCO, VA in mL/min/mmHg, mL/min/mmHg/L, and L respectively); SI.units = TRUE switches to SI units (TLCO and KCO in mmol/min/kPa and mmol/min/kPa/L). VA is the same column either way.

patient <- data.frame(
  sex = "M", age = 45, height = 178,
  dlco_measured   = 22.0,
  va_measured     = 5.8,
  kco_tr_measured = 3.79
)
out <- pft_diffusion(patient)
out[, grep("dlco|va|kco", colnames(out), value = TRUE)]
#> # A tibble: 1 × 18
#>   dlco_measured va_measured kco_tr_measured dlco_pred dlco_lln dlco_uln
#>           <dbl>       <dbl>           <dbl>     <dbl>    <dbl>    <dbl>
#> 1            22         5.8            3.79      30.3     23.4     38.3
#> # ℹ 12 more variables: dlco_zscore <dbl>, dlco_pctpred <dbl>,
#> #   kco_tr_pred <dbl>, kco_tr_lln <dbl>, kco_tr_uln <dbl>, kco_tr_zscore <dbl>,
#> #   kco_tr_pctpred <dbl>, va_pred <dbl>, va_lln <dbl>, va_uln <dbl>,
#> #   va_zscore <dbl>, va_pctpred <dbl>

The output carries the same per-measure _pred / _lln / _uln / _zscore / _pctpred shape as pft_spirometry() and pft_volumes().

2. Hemoglobin correction

DLCO measured against the standard reference Hb may misrepresent patients who are anemic (DLCO under-reads) or polycythemic (DLCO over-reads). pft_dlco_hb_correct() applies the Cotes 1972 formula to express the measured DLCO at the standard reference Hb:

\[ \text{DLCO}_\text{adj} = \text{DLCO} \cdot \frac{1.7 \cdot \text{Hb}_\text{ref}}{\text{Hb} + 0.7 \cdot \text{Hb}_\text{ref}}. \]

The reference Hb is age- and sex-dependent: 146 g/L for males aged >= 15, 134 g/L for females and for children < 15 of either sex (Cotes 1972 / Stanojevic 2017 Table 5).

# Anemic adult male: corrected DLCO is higher than measured.
pft_dlco_hb_correct(dlco = 20.0, hemoglobin = 110, sex = "M", age = 45)
#> [1] 23.39303

# Polycythemic adult male: corrected is lower than measured.
pft_dlco_hb_correct(dlco = 25.0, hemoglobin = 180, sex = "M", age = 45)
#> [1] 21.98795

Pass hemoglobin in g/L (the package does not detect or convert g/dL inputs). Apply the correction before computing z-scores when comparing across patients whose Hb varies; the GLI 2017 reference values assume Hb is at the sex-/age-specific standard.

3. Clinical sub-pattern (Hughes & Pride 2012)

pft_diffusion_interpret() classifies a diffusion result into one of six clinical categories per the Hughes & Pride 2012 framework (adopted by the Stanojevic 2017 task force). The classifier uses z-scores only, so it works identically on traditional and SI columns:

mixed_cohort <- data.frame(
  dlco_zscore   = c(-0.5, -2.0, -2.5, -2.5, -2.0,  0.0),
  va_zscore     = c(-0.5, -0.5, -2.0, -2.5, -0.5,  0.0),
  kco_tr_zscore = c(-0.5, -2.0,  0.0, -2.5,  0.5,  2.0)
)
pft_diffusion_interpret(mixed_cohort)
#>   dlco_zscore va_zscore kco_tr_zscore   diffusion_category
#> 1        -0.5      -0.5          -0.5               Normal
#> 2        -2.0      -0.5          -2.0          Parenchymal
#> 3        -2.5      -2.0           0.0          Volume loss
#> 4        -2.5      -2.5          -2.5                Mixed
#> 5        -2.0      -0.5           0.5 Vascular (suggested)
#> 6         0.0       0.0           2.0         Elevated KCO

The decision tree (Stanojevic 2017 / Hughes & Pride 2012):

Category DLCO VA KCO
Normal OK OK OK
Parenchymal low OK low
Volume loss low low OK / high
Mixed low low low
Vascular (suggested) low OK low or high
Elevated KCO OK high
Other other combinations

Categories label the z-score pattern only. Hughes & Pride 2012 describes the differential diagnosis associated with each pattern; that interpretation is out of scope for the package.

In pft_interpret() the classifier runs automatically whenever the diffusion z-score columns are present, so the diffusion_category column is attached for free in the standard workflow:

patient2 <- data.frame(
  sex = "F", age = 60, height = 165, race = "Caucasian",
  fev1_measured    = 1.6, fvc_measured    = 1.9,
  fev1fvc_measured = 0.84, tlc_measured   = 4.0,
  dlco_measured   = 10.0, va_measured    = 3.5,
  kco_tr_measured = 2.86
)
r <- pft_interpret(patient2)
r[, c("ats_classification", "diffusion_category")]
#> # A tibble: 1 × 2
#>   ats_classification diffusion_category
#>   <chr>              <chr>             
#> 1 Restricted         Mixed

4. How VA shapes the classifier output

Alveolar volume (VA) is the axis that splits restriction into the classifier’s two volume-loss categories:

These are descriptive labels for the z-score pattern; clinical interpretation of what underlies the pattern is the reader’s job.

5. Cohort-level diffusion summaries

For cohort-level breakdowns of diffusion_category, group and count with dplyr directly on a pft_interpret() result:

library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
cohort <- data.frame(
  sex    = c("M","F","M","F","M","F"),
  age    = c(45,60,30,55,70,28),
  height = c(178,165,175,160,170,180),
  race   = "Caucasian",
  fev1_measured    = c(2.5, 1.8, 4.0, 1.5, 2.2, 3.8),
  fvc_measured     = c(3.8, 2.4, 5.2, 2.5, 3.5, 5.0),
  tlc_measured     = c(6.0, 4.5, 6.8, 4.0, 6.5, 7.0),
  dlco_measured    = c(20.0, 12.5, 28.0, 10.0, 18.0, 25.0),
  va_measured      = c(5.8, 4.0, 6.5, 3.5, 5.5, 6.0),
  kco_tr_measured  = c(3.5, 3.2, 4.3, 2.9, 3.3, 4.0)
)
pft_interpret(cohort) |>
  count(sex, diffusion_category)
#> # A tibble: 5 × 3
#>   sex   diffusion_category     n
#>   <chr> <chr>              <int>
#> 1 F     Mixed                  1
#> 2 F     Normal                 1
#> 3 F     Parenchymal            1
#> 4 M     Normal                 2
#> 5 M     Parenchymal            1

See also

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.