This cookbook details how to deploy a localized, containerized pulmonology, respiratory medicine, and chronic obstructive airway disease decision-support engine for outpatient pulmonary clinics, respiratory diagnostic laboratories, and health-system disease management programs to ingest post-bronchodilator spirometry curves, fractional exhaled nitric oxide ($\text{FeNO}$), absolute blood eosinophil counts ($\text{AEC}$), smoking exposure histories, and exacerbation chronologies, evaluate GINA / GOLD Asthma-COPD Overlap ($\text{ACO}$) joint diagnostic criteria, phenotype Type 2 High ($\text{T2-High}$) Eosinophilic vs Neutrophilic Airway Endotypes, guide Single-Inhaler Triple Therapy ($\text{ICS / LABA / LAMA}$) optimization, and enforce the LABA / LAMA Monotherapy Contraindication Sentinel (preventing fatal asthma exacerbations from unshielded bronchodilators) according to Global Initiative for Asthma ($\text{GINA}$), Global Initiative for Chronic Obstructive Lung Disease ($\text{GOLD}$), and American Thoracic Society ($\text{ATS}$) consensus guidelines without external cloud API reliance.
Asthma-COPD Overlap ($\text{ACO}$) represents a complex, heterogeneous clinical phenotype characterized by persistent airflow limitation alongside prominent historical, physiological, and inflammatory features of both asthma and COPD:
[Patient Telemetry: Spirometry FEV1/FVC, FeNO, Blood Eos, Smoking, Inhaler Regimen]
│
▼
[Spirometric Obstruction & Reversibility Engine: Post-BD <0.70 + Reversibility]
│
▼
[GINA/GOLD ACO Scoring: Major Criteria (Asthma hx, >400mL, Eos>=300) + Minor]
│
▼
[T2 Biomarker Phenotyper: FeNO (>=50 vs <25 ppb) + Blood Eosinophils (>=300)]
│
▼
[LABA/LAMA Monotherapy Fatal Asthma Sentinel & Mandatory ICS Anchor Gatekeeper]
│
▼
[Single-Inhaler Triple Therapy Titrator (ICS/LABA/LAMA) + Pneumonia Sentinel]
Install required scientific Python and respiratory modeling packages:
pip install numpy scipy pandas torch torchvision matplotlib
"""
Cookbook 331: Offline Pulmonology Asthma-COPD Overlap (ACO), FeNO & Triple Inhaler Engine
OpenPHR Clinical AI Working Group (https://openphr.org)
"""
import math
import numpy as np
import pandas as pd
from typing import Dict, List, Tuple, Optional
from dataclasses import dataclass
@dataclass
class PulmonologyPatientTelemetry:
patient_id: str
age_years: float = 58.0
smoking_pack_years: float = 24.0 # >= 10 pack-years = COPD risk
# Spirometry Telemetry (Post-Bronchodilator)
post_bd_fev1_liters: float = 1.62 # L (Predicted 3.10 L -> 52.3% predicted)
predicted_fev1_liters: float = 3.10 # L
post_bd_fvc_liters: float = 2.80 # L
post_bd_fev1_fvc_ratio: float = 0.58 # < 0.70 = Persistent airflow limitation
# Bronchodilator Reversibility (Post vs Pre Albuterol)
fev1_reversibility_delta_ml: float = 430.0 # mL (> 400 mL = Major asthma criterion)
fev1_reversibility_delta_percent: float = 18.5 # % (> 15% = Marked reversibility)
# Inflammatory Biomarkers Telemetry
feno_parts_per_billion: float = 62.0 # ppb (>= 50 ppb = T2-High Eosinophilic)
blood_eosinophil_count_cells_ul: float = 420.0 # cells/uL (>= 300 = High ICS response)
total_serum_ige_iu_ml: float = 240.0 # IU/mL (> 100 = Atopy)
# Clinical History & Exacerbations
childhood_asthma_or_atopy_history: bool = True
exacerbations_past_12_months: int = 2 # Frequent exacerbator (>= 2)
prior_severe_pneumonia_history: bool = False
# Current Active Pharmacotherapy
current_regimen: str = "LABA Monotherapy (Salmeterol 50mcg BID)" # 🚨 DEADLY ASTHMA PITFALL!
@dataclass
class ACOEvaluationReport:
patient_id: str
aco_diagnostic_status: str # "Definite Asthma-COPD Overlap (ACO)", "Pure COPD", "Pure Asthma"
major_criteria_met: List[str]
minor_criteria_met: List[str]
t2_inflammatory_endotype: str # "T2-High Eosinophilic Airway Inflammation"
pharmacotherapy_recommendation: List[str]
safety_sentinels: List[str]
clinical_gina_gold_directive: str
class AsthmaCOPDOverlapDecisionEngine:
"""
Offline clinical engine for GINA/GOLD Asthma-COPD Overlap (ACO) diagnosis,
FeNO / blood eosinophil biomarker phenotyping, and single-inhaler triple therapy titration.
"""
def evaluate_aco_criteria(self, d: PulmonologyPatientTelemetry) -> Tuple[str, List[str], List[str]]:
major_met = []
minor_met = []
# 1. Baseline Persistent Airflow Limitation (Prerequisite)
has_persistent_obstruction = d.post_bd_fev1_fvc_ratio < 0.70 and d.age_years >= 40.0 and d.smoking_pack_years >= 10.0
# Major Asthma Criteria
if d.childhood_asthma_or_atopy_history:
major_met.append("Major 1: Documented childhood/early-onset asthma or atopy history.")
if d.fev1_reversibility_delta_ml >= 400.0 and d.fev1_reversibility_delta_percent >= 15.0:
major_met.append(f"Major 2: Marked bronchodilator reversibility (+{d.fev1_reversibility_delta_ml:.0f} mL and +{d.fev1_reversibility_delta_percent:.1f}%).")
if d.blood_eosinophil_count_cells_ul >= 300.0:
major_met.append(f"Major 3: Elevated blood eosinophils ({d.blood_eosinophil_count_cells_ul:.0f} cells/uL >= 300).")
# Minor Asthma Criteria
if d.feno_parts_per_billion >= 50.0:
minor_met.append(f"Minor 1: High FeNO ({d.feno_parts_per_billion:.0f} ppb >= 50 ppb).")
elif d.feno_parts_per_billion >= 25.0:
minor_met.append(f"Minor 1: Intermediate FeNO ({d.feno_parts_per_billion:.0f} ppb).")
if (d.fev1_reversibility_delta_ml >= 200.0 and d.fev1_reversibility_delta_percent >= 12.0) and not (d.fev1_reversibility_delta_ml >= 400.0):
minor_met.append(f"Minor 2: Standard bronchodilator reversibility (+{d.fev1_reversibility_delta_ml:.0f} mL and +{d.fev1_reversibility_delta_percent:.1f}%).")
if d.total_serum_ige_iu_ml >= 100.0:
minor_met.append(f"Minor 3: Elevated total serum IgE ({d.total_serum_ige_iu_ml:.0f} IU/mL >= 100).")
# Classification Logic
is_aco = has_persistent_obstruction and (len(major_met) >= 1 or len(minor_met) >= 2)
if is_aco:
status = "DEFINITE ASTHMA-COPD OVERLAP (ACO) (Meets GINA/GOLD Joint Criteria)"
elif has_persistent_obstruction:
status = "CHRONIC OBSTRUCTIVE PULMONARY DISEASE (COPD) (Without prominent asthma features)"
else:
status = "ASTHMA / NON-FIXED AIRFLOW LIMITATION"
return status, major_met, minor_met
def phenotype_t2_inflammation(self, d: PulmonologyPatientTelemetry) -> str:
is_feno_high = d.feno_parts_per_billion >= 50.0
is_eos_high = d.blood_eosinophil_count_cells_ul >= 300.0
if is_feno_high and is_eos_high:
return f"T2-HIGH EOSINOPHILIC / ALLERGIC ENDOTYPE (FeNO {d.feno_parts_per_billion:.0f} ppb, Eos {d.blood_eosinophil_count_cells_ul:.0f} cells/uL) -> Highly responsive to Inhaled Corticosteroids (ICS) and Biologics (anti-IL5/anti-IL4R)."
elif is_feno_high or is_eos_high:
return f"T2-HIGH PREDOMINANT ENDOTYPE (FeNO {d.feno_parts_per_billion:.0f} ppb or Eos {d.blood_eosinophil_count_cells_ul:.0f} cells/uL) -> Significant ICS responsiveness."
else:
return f"T2-LOW NEUTROPHILIC / PAUCIGRANULOCYTIC ENDOTYPE (FeNO {d.feno_parts_per_billion:.0f} ppb, Eos {d.blood_eosinophil_count_cells_ul:.0f} cells/uL) -> Limited ICS response; prioritize dual bronchodilation (LABA/LAMA)."
def generate_pharmacotherapy_plan(self, aco_status: str, d: PulmonologyPatientTelemetry) -> Tuple[List[str], List[str]]:
plan = []
sentinels = []
fev1_pct_pred = (d.post_bd_fev1_liters / max(d.predicted_fev1_liters, 0.1)) * 100.0
# Safety Sentinel: LABA or LAMA Monotherapy without ICS in ACO
has_laba_only = "LABA Monotherapy" in d.current_regimen or "LAMA Monotherapy" in d.current_regimen
if "ACO" in aco_status and has_laba_only:
sentinels.append(f"🚨 FATAL ASTHMA CONTRAINDICATION: Patient is on {d.current_regimen} without an Inhaled Corticosteroid (ICS). In patients with asthmatic features, LABA or LAMA monotherapy causes unopposed airway inflammation and significantly increases the risk of severe, life-threatening asthma exacerbations and death. STAT DISCONTINUE MONOTHERAPY AND INITIATE ICS-CONTAINING REGIMEN!")
# Triple Therapy Optimization
if "ACO" in aco_status:
plan.append("1. FIRST-LINE ANCHOR: Mandatory Inhaled Corticosteroid (ICS) foundation. Never prescribe long-acting bronchodilators without ICS in ACO.")
if d.exacerbations_past_12_months >= 1 or fev1_pct_pred < 60.0 or d.blood_eosinophil_count_cells_ul >= 300.0:
plan.append("2. SINGLE-INHALER TRIPLE THERAPY (ICS / LABA / LAMA):")
plan.append(" • Fluticasone Furoate / Umeclidinium / Vilanterol (Trelegy Ellipta 100/62.5/25 mcg or 200/62.5/25 mcg) 1 inhalation once daily.")
plan.append(" • Alternative: Budesonide / Glycopyrrolate / Formoterol (Breztri Aerosphere 160/9/4.8 mcg) 2 puffs BID.")
plan.append(f" ℹ️ Indication: Frequent exacerbator ({d.exacerbations_past_12_months} in past year), FEV1 {fev1_pct_pred:.1f}% predicted (<60%), and high blood eosinophils ({d.blood_eosinophil_count_cells_ul:.0f} cells/uL).")
else:
plan.append("2. DUAL THERAPY: Initiate medium-to-high dose ICS / LABA (e.g. Fluticasone/Salmeterol or Budesonide/Formoterol BID).")
# Pneumonia Risk Sentinel
if d.prior_severe_pneumonia_history and d.blood_eosinophil_count_cells_ul < 100.0:
sentinels.append("ICS-INDUCED PNEUMONIA RISK SENTINEL: High-dose ICS with low blood eosinophils (< 100 cells/uL) and prior pneumonia history significantly increases recurrent bacterial pneumonia risk. Maintain moderate-dose ICS and monitor closely.")
plan.append("3. RESCUE INHALER: Albuterol/Ipratropium MDI or ICS/Formoterol SMART protocol as needed for acute bronchospasm.")
return plan, sentinels
def evaluate_case(self, data: PulmonologyPatientTelemetry) -> ACOEvaluationReport:
status, majors, minors = self.evaluate_aco_criteria(data)
t2_endotype = self.phenotype_t2_inflammation(data)
plan, sentinels = self.generate_pharmacotherapy_plan(status, data)
directives = []
directives.append(f"DIAGNOSIS: {status}.")
directives.append(f"ENDOTYPE: {t2_endotype}.")
directives.append("THERAPY: Single-inhaler triple therapy (ICS/LABA/LAMA) with strict prohibition of LABA/LAMA monotherapy.")
return ACOEvaluationReport(
patient_id=data.patient_id,
aco_diagnostic_status=status,
major_criteria_met=majors,
minor_criteria_met=minors,
t2_inflammatory_endotype=t2_endotype,
pharmacotherapy_recommendation=plan,
safety_sentinels=sentinels,
clinical_gina_gold_directive=" ".join(directives)
)
# Example Execution & Verification
if __name__ == "__main__":
engine = AsthmaCOPDOverlapDecisionEngine()
print("=" * 80)
print("OpenPHR Clinical Pulmonology Asthma-COPD Overlap (ACO) & Triple Inhaler Engine")
print("=" * 80)
# Test Case 1: 58-year-old male, 24 pack-year smoking history, history of childhood asthma.
# Post-BD FEV1/FVC: 0.58 (< 0.70). FEV1 Reversibility: +430 mL and +18.5% (Major Criterion).
# Biomarkers: FeNO 62 ppb (>= 50 ppb), Blood Eosinophils 420 cells/uL (>= 300 cells/uL) -> T2-High!
# Currently on LABA Monotherapy -> 🚨 FATAL ASTHMA CONTRAINDICATION SENTINEL!
# Triage: Single-Inhaler Triple Therapy (Trelegy/Breztri) + STAT Monotherapy Cessation!
aco1 = PulmonologyPatientTelemetry(
patient_id="PULM-ACO-4401",
age_years=58.0,
smoking_pack_years=24.0,
post_bd_fev1_liters=1.62,
predicted_fev1_liters=3.10,
post_bd_fvc_liters=2.80,
post_bd_fev1_fvc_ratio=0.58,
fev1_reversibility_delta_ml=430.0,
fev1_reversibility_delta_percent=18.5,
feno_parts_per_billion=62.0,
blood_eosinophil_count_cells_ul=420.0,
total_serum_ige_iu_ml=240.0,
childhood_asthma_or_atopy_history=True,
exacerbations_past_12_months=2,
current_regimen="LABA Monotherapy (Salmeterol 50mcg BID)"
)
rep1 = engine.evaluate_case(aco1)
print(f"\n[Patient {rep1.patient_id} - Airway Phenotype Assessment]")
print(f"ACO Status: {rep1.aco_diagnostic_status}")
print("\nMajor Criteria Met:")
for m in rep1.major_criteria_met:
print(f" • {m}")
print("\nMinor Criteria Met:")
for mn in rep1.minor_criteria_met:
print(f" • {mn}")
print(f"\nInflammatory Endotype:\n {rep1.t2_inflammatory_endotype}")
print("\nPharmacotherapy Recommendations:")
for rx in rep1.pharmacotherapy_recommendation:
print(f" {rx}")
if rep1.safety_sentinels:
print("\nSafety Sentinels:")
for s in rep1.safety_sentinels:
print(f" 🚨 {s}")
print(f"\nGINA / GOLD Consensus Directive:\n{rep1.clinical_gina_gold_directive}")