Cookbook 317: Offline Clinical Toxicology Chlorine & Phosgene Toxic Inhalation Engine

This cookbook details how to deploy a localized, containerized medical toxicology, occupational health, and pulmonary critical care decision-support engine for chemical disaster response teams, industrial medicine clinics, and intensive care units ($\text{ICUs}$) to ingest toxic chemical exposure telemetry, blood gas metrics, and respiratory mechanics, differentiate between Intermediate-Solubility Rapid Airway Irritants (Chlorine [$\text{Cl}_2$]) and Low-Solubility Latent Alveolar Toxins (Phosgene [$\text{COCl}_2$]), calculate Predicted Body Weight ($\text{PBW}$), gate Nebulized Sodium Bicarbonate ($3.75\% - 4.2\%$) Neutralization and Inhaled Corticosteroid Delivery, enforce $6 - 24\text{ Hour}$ Asymptomatic Latency Observation Sentinels, and generate ARDS Lung-Protective Mechanical Ventilation Protocols ($4 - 6\text{ mL/kg}$ PBW) according to ACMT, ATS, and CHEST consensus guidelines without external cloud API reliance.


1. Clinical Background & Inhalational Toxicology Architecture

Toxic gas inhalation in industrial accidents, transport derailments, or domestic chemical mixing produces acute lung injury through water solubility and chemical reactivity gradients:


2. Pipeline & Workflow Architecture

[Exposure Telemetry: Agent (Cl2 vs COCl2), Concentration, Latency Hours, SpO2, ABG]
                                         │
                                         ▼
      [Solubility & Toxicity Classifier: Immediate Spasm vs 6-24h Latent Alveolar Risk]
                                         │
                                         ▼
     [Pharmacotherapy Gating: Nebulized NaHCO3 3.75-4.2% + Inhaled Budesonide Orders]
                                         │
                                         ▼
    [Predicted Body Weight & ARDS Lung-Protective Mechanical Ventilation (4-6 mL/kg)]
                                         │
                                         ▼
    [Mandatory 24h Latency Hospitalization Sentinel & Restrictive Fluid Directive]

3. Environment & Prerequisites

Install required scientific Python and pulmonary toxicology modeling packages:

pip install numpy scipy pandas torch torchvision matplotlib

4. Complete Offline Python / PyTorch Implementation

"""
Cookbook 317: Offline Clinical Toxicology Chlorine & Phosgene Toxic Inhalation 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 ToxicInhalationTelemetry:
    patient_id: str
    age_years: float
    gender: str # "Male" or "Female"
    height_cm: float # e.g. 178.0 cm
    actual_weight_kg: float # e.g. 88.0 kg
    # Chemical Exposure Parameters
    toxic_chemical_agent: str # "Chlorine (Cl2)", "Phosgene (COCl2)", "Ammonia (NH3)", "Hydrogen Chloride (HCl)"
    estimated_exposure_intensity: str # "Low", "Moderate", "High / Confined Space"
    time_since_exposure_hours: float # e.g. 4.5 hours
    # Clinical Signs & Symptoms
    stridor_or_laryngeal_edema: bool = False # Flag for emergent airway intubation
    severe_wheezing_or_bronchospasm: bool = True
    cough_and_choking_sensation: bool = True
    conjunctivitis_or_corneal_burns: bool = True
    hemoptysis_or_pink_frothy_sputum: bool = False # Direct alveolar hemorrhage / flooding
    # Gas Exchange & Arterial Blood Gas (ABG)
    room_air_spo2_percent: float = 91.0
    fio2_delivered: float = 0.50 # e.g. 50% via NRB mask
    pao2_mmhg: float = 68.0 # PaO2 / FiO2 = 136 mmHg (Moderate ARDS)
    paco2_mmhg: float = 46.0
    arterial_ph: float = 7.34
    # Chest Radiograph / Imaging
    chest_xray_bilateral_alveolar_infiltrates: bool = True
    trauma_or_secondary_blast_injury: bool = False

@dataclass
class ToxicInhalationReport:
    patient_id: str
    toxic_agent: str
    predicted_body_weight_kg: float
    pao2_fio2_ratio: float
    pulmonary_edema_ards_severity: str # "None / Mild Airway Irritation", "Mild ARDS (P/F 200-300)", "Moderate ARDS (P/F 100-200)", "Severe ARDS (P/F < 100)"
    antidote_and_pharmacotherapy_orders: List[str]
    ventilator_and_respiratory_orders: List[str]
    inpatient_monitoring_sentinels: List[str]
    clinical_acmt_ats_directive: str

class ToxicInhalationDecisionEngine:
    """
    Offline clinical engine for acute chlorine and phosgene gas exposure triage,
    ARDS severity classification, nebulized bicarbonate gating, and lung-protective ventilation.
    """

    def compute_pbw(self, height_cm: float, gender: str) -> float:
        height_inches = height_cm / 2.54
        if height_inches <= 60.0:
            return 50.0 if gender.lower().startswith("m") else 45.5
        
        diff_inches = height_inches - 60.0
        if gender.lower().startswith("m"):
            pbw = 50.0 + 2.3 * diff_inches
        else:
            pbw = 45.5 + 2.3 * diff_inches
        return round(float(pbw), 1)

    def calculate_ards_severity(self, pao2: float, fio2: float, infiltrates: bool) -> Tuple[float, str]:
        pf_ratio = round(pao2 / max(0.21, fio2), 1)
        
        if not infiltrates:
            if pf_ratio >= 300.0:
                return pf_ratio, "Acute Airway Chemical Irritation (No Pulmonary Edema)"
            else:
                return pf_ratio, "Acute Hypoxemic Respiratory Failure (Suspected Early Edema)"

        if pf_ratio <= 100.0:
            return pf_ratio, "Severe Toxic ARDS (PaO2/FiO2 <= 100 mmHg)"
        elif pf_ratio <= 200.0:
            return pf_ratio, "Moderate Toxic ARDS (PaO2/FiO2 101 - 200 mmHg)"
        elif pf_ratio <= 300.0:
            return pf_ratio, "Mild Toxic ARDS (PaO2/FiO2 201 - 300 mmHg)"
        else:
            return pf_ratio, "Toxic Chemical Pulmonary Edema (Compensated Gas Exchange)"

    def generate_pharmacotherapy_orders(self, d: ToxicInhalationTelemetry) -> List[str]:
        orders = []

        is_chlorine = "chlorine" in d.toxic_chemical_agent.lower() or "cl2" in d.toxic_chemical_agent.lower()
        is_phosgene = "phosgene" in d.toxic_chemical_agent.lower() or "cocl2" in d.toxic_chemical_agent.lower()

        # 1. Decontamination
        orders.append("1. DECONTAMINATION: Immediately remove all contaminated clothing; flush exposed skin and irrigate eyes with copious normal saline/water for >= 15 minutes.")

        # 2. Nebulized Sodium Bicarbonate for Chlorine
        if is_chlorine and (d.severe_wheezing_or_bronchospasm or d.cough_and_choking_sensation):
            orders.append("2. NEBULIZED SODIUM BICARBONATE: Administer 3.0 to 4.0 mL of 3.75% - 4.2% Sodium Bicarbonate solution via nebulizer every 4-6 hours PRN persistent coughing or reactive airway spasm (Prepare by diluting 8.4% NaHCO3 1:1 with sterile water).")

        # 3. Bronchodilators & Inhaled Corticosteroids
        orders.append("3. INHALED BRONCHODILATOR: Nebulized Albuterol 2.5 - 5.0 mg + Ipratropium Bromide 0.5 mg every 20-30 minutes for acute bronchospasm, then q4h scheduled.")
        orders.append("4. INHALED & SYSTEMIC CORTICOSTEROIDS: Administer Budesonide 1.0 - 2.0 mg nebulized BID (or Methylprednisolone 1.0 - 2.0 mg/kg/day IV) to suppress progressive alveolar capillary permeability.")

        # 4. Fluid Restriction
        orders.append("5. RESTRICTIVE FLUID STRATEGY: Maintain strict conservative IV fluid rate (e.g. 50-75 mL/hr D5 1/2NS); avoid crystalloid boluses to prevent aggravating toxic capillary leak alveolar flooding.")

        return orders

    def generate_ventilator_orders(self, d: ToxicInhalationTelemetry, pbw: float, ards_sev: str) -> List[str]:
        v_orders = []

        vt_6ml = round(6.0 * pbw, 0)
        vt_4ml = round(4.0 * pbw, 0)

        if d.stridor_or_laryngeal_edema:
            v_orders.append("1. CRITICAL AIRWAY ALERT: Immediate endotracheal intubation by expert under video laryngoscopy (High risk of sudden complete upper airway obstruction from laryngeal/glottic edema).")

        if "ARDS" in ards_sev or d.chest_xray_bilateral_alveolar_infiltrates:
            v_orders.append(f"1. ARDS LUNG-PROTECTIVE VENTILATION (Predicted Body Weight = {pbw} kg):")
            v_orders.append(f"   • Initial Tidal Volume (Vt): 6.0 mL/kg PBW ({vt_6ml:.0f} mL); titrate down to 4.0 mL/kg PBW ({vt_4ml:.0f} mL) if Plateau Pressure > 30 cm H2O.")
            v_orders.append("   • Plateau Pressure Target: Maintain Pplat <= 30 cm H2O (Driving Pressure <= 14 cm H2O).")
            v_orders.append("   • Positive End-Expiratory Pressure (PEEP): Titrate PEEP 8 - 14 cm H2O according to ARDSNet High-PEEP/Low-FiO2 titration grid.")
            v_orders.append("   • Permissive Hypercapnia: Allow arterial pH 7.20 - 7.30 to avoid high tidal volume barotrauma.")
        else:
            v_orders.append("1. HIGH-FLOW OXYGEN / CPAP: Deliver 100% humidified oxygen via non-rebreather mask or High-Flow Nasal Cannula (HFNC) titrated to maintain SpO2 >= 92-95%.")

        return v_orders

    def evaluate_case(self, data: ToxicInhalationTelemetry) -> ToxicInhalationReport:
        pbw = self.compute_pbw(data.height_cm, data.gender)
        pf_ratio, ards_sev = self.calculate_ards_severity(data.pao2_mmhg, data.fio2_delivered, data.chest_xray_bilateral_alveolar_infiltrates)
        rx_orders = self.generate_pharmacotherapy_orders(data)
        vent_orders = self.generate_ventilator_orders(data, pbw, ards_sev)

        sentinels = []
        is_phosgene = "phosgene" in data.toxic_chemical_agent.lower() or "cocl2" in data.toxic_chemical_agent.lower()
        if is_phosgene and data.time_since_exposure_hours < 24.0:
            sentinels.append(f"CRITICAL PHOSGENE LATENCY SENTINEL (Time Post-Exposure: {data.time_since_exposure_hours}h): Mandatory minimum 24-hour hospital admission with continuous pulse oximetry and serial CXRs. Fatal pulmonary edema can develop suddenly between 6-24 hours despite a completely normal initial presentation.")
        if data.stridor_or_laryngeal_edema:
            sentinels.append("AIRWAY EMERGENCY: Stridor indicates advanced laryngeal edema; prepare difficult airway cart and surgical cricothyrotomy backup immediately.")

        directives = []
        directives.append(f"AGENT & TIME: {data.toxic_chemical_agent} Exposure ({data.time_since_exposure_hours}h post-incident).")
        directives.append(f"RESPIRATORY STATUS: {ards_sev} (PaO2/FiO2 = {pf_ratio:.0f} mmHg).")
        directives.append(f"MANAGEMENT: {'ARDS Lung-Protective Ventilation (Vt 4-6 mL/kg PBW) + Restrictive Fluids' if 'ARDS' in ards_sev else 'Nebulized NaHCO3 / Budesonide + 24h Latency Inpatient Observation'}.")

        return ToxicInhalationReport(
            patient_id=data.patient_id,
            toxic_agent=data.toxic_chemical_agent,
            predicted_body_weight_kg=pbw,
            pao2_fio2_ratio=pf_ratio,
            pulmonary_edema_ards_severity=ards_sev,
            antidote_and_pharmacotherapy_orders=rx_orders,
            ventilator_and_respiratory_orders=vent_orders,
            inpatient_monitoring_sentinels=sentinels,
            clinical_acmt_ats_directive=" ".join(directives)
        )

# Example Execution & Verification
if __name__ == "__main__":
    engine = ToxicInhalationDecisionEngine()

    print("=" * 80)
    print("OpenPHR Clinical Toxicology Chlorine & Phosgene Toxic Inhalation Engine")
    print("=" * 80)

    # Test Case 1: 38-year-old male industrial worker exposed to high-concentration Chlorine (Cl2) gas 4.5h ago
    # Height: 178 cm (PBW = 73.1 kg) | Actual Weight: 88 kg
    # Presentation: Severe bronchospasm, choking, bilateral diffuse alveolar infiltrates on CXR
    # ABG: PaO2 = 68 mmHg on FiO2 50% -> PaO2/FiO2 = 136 mmHg (Moderate Toxic ARDS)
    # Management: Nebulized Sodium Bicarbonate (3.75-4.2%) + ARDS Ventilation (Vt 6 mL/kg = 439 mL) + Restrictive Fluids!
    chem1 = ToxicInhalationTelemetry(
        patient_id="TOX-INHAL-9104",
        age_years=38.0,
        gender="Male",
        height_cm=178.0,
        actual_weight_kg=88.0,
        toxic_chemical_agent="Chlorine (Cl2)",
        estimated_exposure_intensity="High / Confined Space",
        time_since_exposure_hours=4.5,
        severe_wheezing_or_bronchospasm=True,
        cough_and_choking_sensation=True,
        conjunctivitis_or_corneal_burns=True,
        room_air_spo2_percent=89.0,
        fio2_delivered=0.50,
        pao2_mmhg=68.0,
        chest_xray_bilateral_alveolar_infiltrates=True
    )

    rep1 = engine.evaluate_case(chem1)

    print(f"\n[Patient {rep1.patient_id} - Toxicology Evaluation]")
    print(f"Toxic Agent: {rep1.toxic_agent}")
    print(f"Predicted Body Weight (PBW): {rep1.predicted_body_weight_kg} kg")
    print(f"PaO2 / FiO2 Ratio: {rep1.pao2_fio2_ratio:.0f} mmHg ({rep1.pulmonary_edema_ards_severity})")
    print("\nAntidote & Pharmacotherapy Orders:")
    for a in rep1.antidote_and_pharmacotherapy_orders:
        print(f"  • {a}")
    print("\nVentilator & Airway Orders:")
    for v in rep1.ventilator_and_respiratory_orders:
        print(f"  • {v}")
    print("\nCritical Safety Sentinels:")
    for s in rep1.inpatient_monitoring_sentinels:
        print(f"  {s}")
    print(f"\nACMT / ATS Consensus Directive:\n{rep1.clinical_acmt_ats_directive}")

    # Test Case 2: Asymptomatic chemical worker exposed to Phosgene (COCl2) 3 hours ago -> Mandatory 24h Admission!
    chem2 = ToxicInhalationTelemetry(
        patient_id="TOX-INHAL-1042",
        age_years=29.0,
        gender="Female",
        height_cm=165.0,
        actual_weight_kg=60.0,
        toxic_chemical_agent="Phosgene (COCl2)",
        estimated_exposure_intensity="Moderate",
        time_since_exposure_hours=3.0,
        severe_wheezing_or_bronchospasm=False,
        cough_and_choking_sensation=False,
        room_air_spo2_percent=98.0,
        fio2_delivered=0.21,
        pao2_mmhg=94.0,
        chest_xray_bilateral_alveolar_infiltrates=False
    )

    rep2 = engine.evaluate_case(chem2)
    print(f"\n[Patient {rep2.patient_id}] - Sentinel: {rep2.inpatient_monitoring_sentinels[0]}")

5. Clinical Verification & Guideline Conformance


6. References