This cookbook details how to deploy a localized, containerized rheumatology, clinical immunology, and pulmonary fibrosis decision-support engine for rheumatology clinics, autoimmune disease centers, and emergency departments to ingest autoimmune serologies, nailfold capillaroscopy patterns, pulmonary function tests ($\text{PFTs}$), high-resolution computed tomography ($\text{HRCT}$) lung fibrosis scores, and serial blood pressure telemetry, classify Systemic Sclerosis ($\text{SSc}$) under the ACR/EULAR 2013 Classification Criteria ($\text{Score} \ge 9$), quantify cutaneous fibrosis via the 17-site Modified Rodnan Skin Score ($\text{mRSS}$, $0 - 51\text{ points}$), stage SSc-Associated Interstitial Lung Disease ($\text{SSc-ILD}$) via the Goh / Wells algorithm ($\text{FVC}$ & $\text{HRCT}$ extent), and execute the life-saving Scleroderma Renal Crisis ($\text{SRC}$) Emergency Captopril Protocol while flagging high-dose corticosteroid contraindications according to ACR, EULAR, and Scleroderma Clinical Trials Consortium ($\text{SCTC}$) guidelines without external cloud API reliance.
Systemic sclerosis is a complex autoimmune connective tissue disease characterized by immune dysregulation, microvascular vasculopathy, and progressive tissue fibrosis across skin, lungs, gastrointestinal tract, and kidneys:
[Rheumatology Telemetry: Serologies, Nailfold Capillaries, Raynaud's, Skin & Lung Exams]
│
▼
[ACR/EULAR 2013 Classifier: 8 Weighted Diagnostic Domains -> Total Score >= 9]
│
▼
[17-Site Modified Rodnan Skin Score (mRSS) Engine: Total 0-51 & Subtype Triage]
│
▼
[SSc-ILD Staging (Goh Criteria: HRCT Extent % + FVC % / DLCO % Pulmonary Function)]
│
▼
[Scleroderma Renal Crisis (SRC) Sentinel & Emergent Captopril Titration Protocol]
Install required scientific Python and autoimmune disease modeling packages:
pip install numpy scipy pandas torch torchvision matplotlib
"""
Cookbook 323: Offline Rheumatology Systemic Sclerosis Rodnan & Renal Crisis 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, field
@dataclass
class SScClinicalTelemetry:
patient_id: str
age_years: float
# ACR/EULAR 2013 Diagnostic Criteria Parameters
skin_thickening_proximal_to_mcps: bool = False # 9 points (Sufficient on its own)
skin_thickening_fingers_type: str = "Sclerodactyly" # "None" (0), "Puffy" (2), "Sclerodactyly" (4)
fingertip_lesions_type: str = "Digital Tip Ulcers" # "None" (0), "Digital Tip Ulcers" (2), "Pitting Scars" (3)
telangiectasia_present: bool = True # 2 points
abnormal_nailfold_capillaries: bool = True # 2 points (Megacapillaries/loss)
pulmonary_involvement_present: bool = True # 2 points (PAH or ILD)
raynauds_phenomenon_present: bool = True # 3 points
ssc_specific_autoantibodies_positive: bool = True # 3 points (ACA, Scl-70, or RNA Pol III)
positive_autoantibody_name: str = "Anti-RNA Polymerase III (High SRC Risk)"
# 17-Site Modified Rodnan Skin Score (mRSS) Telemetry (0 to 3 per site)
mrss_face: int = 1
mrss_chest: int = 2
mrss_abdomen: int = 2
mrss_r_upper_arm: int = 2
mrss_l_upper_arm: int = 2
mrss_r_forearm: int = 3
mrss_l_forearm: int = 3
mrss_r_hand: int = 2
mrss_l_hand: int = 2
mrss_r_fingers: int = 3
mrss_l_fingers: int = 3
mrss_r_thigh: int = 1
mrss_l_thigh: int = 1
mrss_r_lower_leg: int = 2
mrss_l_lower_leg: int = 2
mrss_r_foot: int = 1
mrss_l_foot: int = 1
# Pulmonary Function & HRCT Telemetry
hrct_lung_fibrosis_extent_percent: float = 24.0 # % (> 20% = Extensive ILD)
fvc_percent_predicted: float = 64.0 # % (< 70% with indeterminate HRCT = Extensive)
dlco_percent_predicted: float = 52.0 # %
# Scleroderma Renal Crisis (SRC) Hemodynamic & Medication Telemetry
systolic_bp_mmhg: float = 178.0 # mmHg (>= 140 or acute rise)
diastolic_bp_mmhg: float = 104.0 # mmHg
baseline_serum_creatinine_mg_dl: float = 0.9 # mg/dL
current_serum_creatinine_mg_dl: float = 2.4 # mg/dL (Acute >50% rise)
schistocytes_present_on_smear: bool = True # Microangiopathic hemolytic anemia
platelet_count_k_ul: float = 88.0 # Thrombocytopenia (< 150 k/uL)
current_prednisone_dose_mg_day: float = 20.0 # mg/day (>= 15 mg = High SRC trigger!)
@dataclass
class SScEvaluationReport:
patient_id: str
acr_eular_total_score: int
classification_status: str # "Definite Systemic Sclerosis (ACR/EULAR Score >= 9)", "Not Classified"
criteria_breakdown: List[str]
total_mrss_score: int # 0 - 51
cutaneous_subtype: str # "Diffuse Cutaneous Systemic Sclerosis (dcSSc)", "Limited Cutaneous SSc (lcSSc)"
ssc_ild_stage: str # "Extensive / Severe SSc-ILD", "Limited SSc-ILD", "No ILD"
src_crisis_status: str # "🚨 ACUTE SCLERODERMA RENAL CRISIS (SRC)", "No Renal Crisis"
emergency_captopril_protocol: List[str]
safety_sentinels: List[str]
clinical_guideline_directive: str
class SystemicSclerosisDecisionEngine:
"""
Offline clinical engine for ACR/EULAR 2013 Systemic Sclerosis classification,
Modified Rodnan Skin Score (mRSS) assessment, SSc-ILD staging, and Scleroderma
Renal Crisis (SRC) emergency triage.
"""
def calculate_acr_eular_score(self, d: SScClinicalTelemetry) -> Tuple[int, str, List[str]]:
score = 0
breakdown = []
# Criterion 1: Skin thickening proximal to MCPs (9 pts - Standalone)
if d.skin_thickening_proximal_to_mcps:
score = 9
breakdown.append("Skin thickening of fingers extending proximal to MCP joints (9 points - Standalone Definitive Criterion).")
return 9, "Definite Systemic Sclerosis (ACR/EULAR Criteria Met)", breakdown
# Criterion 2: Skin thickening of fingers
if d.skin_thickening_fingers_type == "Sclerodactyly":
score += 4
breakdown.append("Sclerodactyly of fingers distal to MCPs (4 points).")
elif d.skin_thickening_fingers_type == "Puffy":
score += 2
breakdown.append("Puffy fingers (2 points).")
# Criterion 3: Fingertip lesions
if d.fingertip_lesions_type == "Pitting Scars":
score += 3
breakdown.append("Digital fingertip pitting scars (3 points).")
elif d.fingertip_lesions_type == "Digital Tip Ulcers":
score += 2
breakdown.append("Digital fingertip ulcers (2 points).")
# Criterion 4: Telangiectasia
if d.telangiectasia_present:
score += 2
breakdown.append("Telangiectasia (2 points).")
# Criterion 5: Abnormal nailfold capillaries
if d.abnormal_nailfold_capillaries:
score += 2
breakdown.append("Abnormal nailfold capillaries (2 points).")
# Criterion 6: Pulmonary involvement (PAH / ILD)
if d.pulmonary_involvement_present:
score += 2
breakdown.append("Pulmonary arterial hypertension and/or Interstitial lung disease (2 points).")
# Criterion 7: Raynaud's phenomenon
if d.raynauds_phenomenon_present:
score += 3
breakdown.append("Raynaud's phenomenon (3 points).")
# Criterion 8: SSc-specific autoantibodies
if d.ssc_specific_autoantibodies_positive:
score += 3
breakdown.append(f"SSc-specific autoantibodies positive ({d.positive_autoantibody_name}) (3 points).")
status = "Definite Systemic Sclerosis (ACR/EULAR Score >= 9)" if score >= 9 else f"Unclassified / Borderline SSc (Score {score} < 9)"
return score, status, breakdown
def compute_mrss_and_subtype(self, d: SScClinicalTelemetry) -> Tuple[int, str]:
mrss_total = (
d.mrss_face + d.mrss_chest + d.mrss_abdomen +
d.mrss_r_upper_arm + d.mrss_l_upper_arm +
d.mrss_r_forearm + d.mrss_l_forearm +
d.mrss_r_hand + d.mrss_l_hand +
d.mrss_r_fingers + d.mrss_l_fingers +
d.mrss_r_thigh + d.mrss_l_thigh +
d.mrss_r_lower_leg + d.mrss_l_lower_leg +
d.mrss_r_foot + d.mrss_l_foot
)
# Diffuse vs Limited Subtype:
# Diffuse has skin thickening proximal to elbows/knees or trunk (chest/abdomen/thighs/upper arms)
has_proximal_involvement = (
d.mrss_chest > 0 or d.mrss_abdomen > 0 or
d.mrss_r_upper_arm > 0 or d.mrss_l_upper_arm > 0 or
d.mrss_r_thigh > 0 or d.mrss_l_thigh > 0
)
subtype = "Diffuse Cutaneous Systemic Sclerosis (dcSSc)" if has_proximal_involvement else "Limited Cutaneous Systemic Sclerosis (lcSSc)"
return mrss_total, subtype
def stage_ssc_ild(self, d: SScClinicalTelemetry) -> Tuple[str, str]:
# Goh / Wells Criteria:
# Extensive: HRCT > 20% OR (HRCT 10-30% with FVC < 70%)
# Limited: HRCT < 20% OR (HRCT 10-30% with FVC >= 70%)
if d.hrct_lung_fibrosis_extent_percent > 20.0 or (d.hrct_lung_fibrosis_extent_percent >= 10.0 and d.fvc_percent_predicted < 70.0):
stage = "Extensive / Severe SSc-ILD (High Risk for Progressive Fibrosis)"
tx = "Initiate immunosuppression: Mycophenolate Mofetil (MMF target 2-3 g/day) +/- Nintedanib antifibrotic (150 mg BID) or Tocilizumab."
elif d.hrct_lung_fibrosis_extent_percent > 0.0:
stage = "Limited SSc-ILD (Mild-to-Moderate)"
tx = "Close serial surveillance: PFTs (FVC/DLCO) every 3-6 months. Consider MMF if active decline in FVC >= 10% or DLCO >= 15%."
else:
stage = "No SSc-ILD Detected"
tx = "Annual PFT screening and clinical pulmonary monitoring."
return stage, tx
def evaluate_src_renal_crisis(self, d: SScClinicalTelemetry) -> Tuple[str, List[str], List[str]]:
src_triggers = []
captopril_orders = []
sentinels = []
# Hypertension check
is_hypertensive = d.systolic_bp_mmhg >= 140.0 or d.diastolic_bp_mmhg >= 90.0
# Creatinine rise check (> 50% rise over baseline)
scr_rise_ratio = d.current_serum_creatinine_mg_dl / max(d.baseline_serum_creatinine_mg_dl, 0.1)
has_renal_impairment = scr_rise_ratio >= 1.5
if is_hypertensive and (has_renal_impairment or d.schistocytes_present_on_smear or "RNA Polymerase" in d.positive_autoantibody_name):
crisis_status = "🚨 ACUTE SCLERODERMA RENAL CRISIS (SRC) - MEDICAL EMERGENCY"
src_triggers.append(f"Accelerated Hypertension: {d.systolic_bp_mmhg:.0f}/{d.diastolic_bp_mmhg:.0f} mmHg.")
src_triggers.append(f"Acute Kidney Injury: SCr rise from {d.baseline_serum_creatinine_mg_dl:.1f} to {d.current_serum_creatinine_mg_dl:.1f} mg/dL ({scr_rise_ratio:.1f}x baseline).")
if d.schistocytes_present_on_smear:
src_triggers.append("Microangiopathic Hemolytic Anemia (MAHA): Schistocytes and Thrombocytopenia present.")
# Emergency Captopril Orders
captopril_orders.append("1. STAT INGESTION: Administer Captopril 6.25 - 12.5 mg PO test dose immediately.")
captopril_orders.append("2. TITRATION: Repeat Captopril 12.5 - 25 mg every 4-6 hours, titrating rapidly to 50 - 100 mg PO TID.")
captopril_orders.append("3. BLOOD PRESSURE TARGET: Aim for SBP reduction of 10 - 20 mmHg per 24 hours down to patient's normal baseline (Avoid precipitous drops to prevent ischemic stroke/renal infarction).")
captopril_orders.append("4. PERMISSIVE CREATININEMIA: Do NOT stop Captopril if serum creatinine rises further during initial days; renal recovery follows normalization of blood pressure.")
captopril_orders.append("5. SECOND-LINE AGENTS: If BP refractory to max Captopril, add Calcium Channel Blocker (Nifedipine) or IV Prostacyclin (Iloprost). Avoid ARBs as first-line.")
else:
crisis_status = "No Scleroderma Renal Crisis Detected"
# Steroid Danger Sentinel
if d.current_prednisone_dose_mg_day >= 15.0:
sentinels.append(f"CRITICAL STEROID CONTRAINDICATION: Current Prednisone dose ({d.current_prednisone_dose_mg_day:.0f} mg/day) >= 15 mg/day is a potent precipitator of Scleroderma Renal Crisis (SRC). Taper corticosteroids immediately below 10-15 mg/day unless strictly mandatory for myositis or pericarditis.")
if "RNA Polymerase" in d.positive_autoantibody_name:
sentinels.append("HIGH-RISK SEROLOGY: Anti-RNA Polymerase III positivity carries a ~30% lifetime incidence of SRC. Enforce daily home blood pressure monitoring (Report SBP >= 140 or acute rise >= 20 mmHg).")
return crisis_status, captopril_orders, sentinels
def evaluate_case(self, data: SScClinicalTelemetry) -> SScEvaluationReport:
acr_score, class_status, criteria = self.calculate_acr_eular_score(data)
mrss_total, subtype = self.compute_mrss_and_subtype(data)
ild_stage, ild_tx = self.stage_ssc_ild(data)
src_status, captopril_plan, sentinels = self.evaluate_src_renal_crisis(data)
directives = []
directives.append(f"CLASSIFICATION: {class_status} (Score {acr_score}/9).")
directives.append(f"SUBTYPE: {subtype} with mRSS {mrss_total}/51.")
directives.append(f"PULMONARY: {ild_stage}. {ild_tx}")
directives.append(f"RENAL STATUS: {src_status}.")
return SScEvaluationReport(
patient_id=data.patient_id,
acr_eular_total_score=acr_score,
classification_status=class_status,
criteria_breakdown=criteria,
total_mrss_score=mrss_total,
cutaneous_subtype=subtype,
ssc_ild_stage=ild_stage,
src_crisis_status=src_status,
emergency_captopril_protocol=captopril_plan,
safety_sentinels=sentinels,
clinical_guideline_directive=" ".join(directives)
)
# Example Execution & Verification
if __name__ == "__main__":
engine = SystemicSclerosisDecisionEngine()
print("=" * 80)
print("OpenPHR Clinical Rheumatology Systemic Sclerosis & Renal Crisis Engine")
print("=" * 80)
# Test Case 1: 52-year-old female with Diffuse Cutaneous Systemic Sclerosis,
# Anti-RNA Polymerase III positivity, SSc-ILD (HRCT 24%), and presenting with
# Acute Scleroderma Renal Crisis (BP 178/104 mmHg, SCr 2.4 mg/dL, Schistocytes).
# Trigger: Emergent Captopril Protocol & Prednisone 20 mg Warning Sentinel!
ssc1 = SScClinicalTelemetry(
patient_id="RHEUM-SSC-4409",
age_years=52.0,
skin_thickening_proximal_to_mcps=False,
skin_thickening_fingers_type="Sclerodactyly",
fingertip_lesions_type="Digital Tip Ulcers",
telangiectasia_present=True,
abnormal_nailfold_capillaries=True,
pulmonary_involvement_present=True,
raynauds_phenomenon_present=True,
ssc_specific_autoantibodies_positive=True,
positive_autoantibody_name="Anti-RNA Polymerase III",
mrss_face=1, mrss_chest=2, mrss_abdomen=2,
mrss_r_upper_arm=2, mrss_l_upper_arm=2,
mrss_r_forearm=3, mrss_l_forearm=3,
mrss_r_hand=2, mrss_l_hand=2,
mrss_r_fingers=3, mrss_l_fingers=3,
mrss_r_thigh=1, mrss_l_thigh=1,
mrss_r_lower_leg=2, mrss_l_lower_leg=2,
mrss_r_foot=1, mrss_l_foot=1,
hrct_lung_fibrosis_extent_percent=24.0,
fvc_percent_predicted=64.0,
dlco_percent_predicted=52.0,
systolic_bp_mmhg=178.0,
diastolic_bp_mmhg=104.0,
baseline_serum_creatinine_mg_dl=0.9,
current_serum_creatinine_mg_dl=2.4,
schistocytes_present_on_smear=True,
platelet_count_k_ul=88.0,
current_prednisone_dose_mg_day=20.0
)
rep1 = engine.evaluate_case(ssc1)
print(f"\n[Patient {rep1.patient_id} - Rheumatology Assessment]")
print(f"ACR/EULAR Classification: {rep1.classification_status} (Score: {rep1.acr_eular_total_score})")
print("Criteria Breakdown:")
for c in rep1.criteria_breakdown:
print(f" • {c}")
print(f"\nCutaneous Subtype: {rep1.cutaneous_subtype} (mRSS Total: {rep1.total_mrss_score}/51)")
print(f"Pulmonary Status: {rep1.ssc_ild_stage}")
print(f"Renal Crisis Status: {rep1.src_crisis_status}")
if rep1.emergency_captopril_protocol:
print("\nEmergency Captopril Protocol:")
for step in rep1.emergency_captopril_protocol:
print(f" {step}")
if rep1.safety_sentinels:
print("\nSafety Sentinels:")
for s in rep1.safety_sentinels:
print(f" 🚨 {s}")
print(f"\nGuideline Directive:\n{rep1.clinical_guideline_directive}")