-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_rules.py
More file actions
254 lines (222 loc) · 14 KB
/
test_rules.py
File metadata and controls
254 lines (222 loc) · 14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
import json
def calculate_ischemic_risk(p):
return (p['troponin'] == 1 or
p['ischemicInstability'] == 1 or
p['ischemicAngina'] == 1 or
p['ischemicHeartFailure'] == 1 or
p['ischemicArrhythmia'] == 1)
def calculate_bleeding_risk(p):
return (p['age'] >= 75 or
p['bleedingRenal'] == 1 or
p['bleedingAnemia'] == 1 or
p['bleedingAF'] == 1 or
p['bleedingStroke'] == 1)
def evaluate_rules(p):
is_high_ischemic = calculate_ischemic_risk(p)
is_high_bleeding = calculate_bleeding_risk(p)
results = {
'deviations': [],
'alerts': [],
'regimen': []
}
# 1. Oxygenation Check
if 'spo2' in p and p['spo2'] < 90:
results['alerts'].append("HYPOXEMIA ALERT: Patient SpO2 < 90%. Administer supplementary oxygen immediately.")
# 2. Reperfusion Strategy vs Antiplatelet Mapping Rules
if p['diagnosis'] == 1: # STEMI
if p['reperfusion'] == 2: # Fibrinolytics
if p['age'] >= 75:
results['regimen'].append("Aspirin (162-325mg load) + Clopidogrel (75mg daily, no load) [Guideline Preferred]")
else:
results['regimen'].append("Aspirin (162-325mg load) + Clopidogrel (300mg load) [Guideline Preferred]")
if p['p2y12'] in [2, 3]:
results['deviations'].append("CRITICAL MISMATCH: Potent antiplatelets (Prasugrel/Ticagrelor) run concurrently with Fibrinolytics.")
results['alerts'].append("HEMORRHAGE RISK HIGH: Discontinue Prasugrel/Ticagrelor immediately to mitigate intracranial bleeding risk.")
elif p['reperfusion'] == 1: # Primary PCI
results['regimen'].append("Aspirin (162-325mg load) + Prasugrel (60mg load) OR Ticagrelor (180mg load)")
if p['p2y12'] == 1 and not is_high_bleeding:
results['deviations'].append("SUBOPTIMAL PROTECTION: Clopidogrel used in standard risk PPCI path.")
results['alerts'].append("EFFICACY WARNING: Upgrade to Ticagrelor or Prasugrel for superior protection against stent thrombosis.")
elif p['p2y12'] == 0:
results['deviations'].append("CRITICAL OMISSION: A P2Y12 inhibitor is required for all STEMI patients undergoing Primary PCI.")
elif p['diagnosis'] in [2, 3]: # NSTE-ACS
if p['reperfusion'] == 4: # Conservative Medical Management
results['regimen'].append("Aspirin (81mg daily) + Ticagrelor (90mg BID for 12 months)")
if p['p2y12'] == 1 and not is_high_bleeding:
results['deviations'].append("NON-PREFERENTIAL REGIMEN: Clopidogrel selected for standard risk medical management.")
elif p['reperfusion'] == 1: # Invasive Strategy
results['regimen'].append("Aspirin + Ticagrelor (or Prasugrel administered at angiography)")
if p['p2y12'] == 1 and not is_high_bleeding:
results['deviations'].append("SUBOPTIMAL EFFICACY: Clopidogrel is less effective than Ticagrelor/Prasugrel. Switch to a high-potency agent unless contraindicated or high bleeding risk exists.")
# 3. NSTE-ACS Invasive Strategy Timing
if p['diagnosis'] in [2, 3]:
if is_high_ischemic:
results['alerts'].append("CRITICAL: Immediate Invasive Strategy Required (Angiography within 2 hours) due to presence of High Ischemic Risk Indicators (cardiogenic shock, refractory angina, heart failure, or sustained VT/VF).")
else:
results['regimen'].append("Guideline Compliant: Early Invasive Strategy (Angiography within 24 hours) is indicated for standard-risk NSTE-ACS.")
# 4. HBR Overrides
if is_high_bleeding:
if p['p2y12'] == 3: # Prasugrel in HBR
results['deviations'].append("CONTRAINDICATION OVERRIDE: Prasugrel allocated within high bleeding risk profile.")
results['alerts'].append("STOP SIGN: Immediately discontinue Prasugrel. Substitute with Clopidogrel 75mg daily.")
# Rules A, B, C
if p.get('concurrentOac', 0) == 1 or p['bleedingAF'] == 1: # Rule C
results['regimen'].append("Convert to Dual Therapy (OAC + Clopidogrel 75mg) after 1-4 weeks; completely drop Aspirin.")
elif p.get('minorBleeding', 0) == 1: # Rule B
results['regimen'].append("P2Y12 Down-Titration: Transition from Ticagrelor/Prasugrel to Clopidogrel 75mg daily due to bleeding/Hb drop.")
else: # Rule A
results['regimen'].append("Short-Course DAPT: Transition to Ticagrelor Monotherapy after 1-3 months, completely dropping Aspirin.")
# 5. GI Safety Net
has_gi_trigger = is_high_bleeding or p.get('pepticUlcer', 0) == 1 or p['age'] >= 75 or p.get('nsaid', 0) == 1
if has_gi_trigger:
if p.get('ppiPrescribed', 0) != 1:
results['alerts'].append("GASTRIC GAP: Co-prescribe a protective PPI (e.g., Pantoprazole) to manage GI bleeding margins.")
if p['p2y12'] == 1 and p.get('ppiPrescribed', 0) == 1:
results['alerts'].append("PPI Metabolic Optimization: If Clopidogrel is prescribed, Pantoprazole is preferred over Omeprazole (prevents CYP2C19 inhibition).")
# 6. Lipid Secondary Prevention
if p['statin'] != 2:
results['deviations'].append("OMISSION FAULT: Patient not initiated on baseline High-Intensity Statin therapy.")
results['regimen'].append("Initiate High-Intensity Atorvastatin 40-80mg or Rosuvastatin 20-40mg.")
if p['ldlc'] >= 70:
results['deviations'].append("LIPID GOAL MISSED: Follow-up LDL tracking >= 70 mg/dL.")
results['regimen'].append("Add Non-Statin Therapy: Append Ezetimibe 10mg daily immediately (Class 1).")
elif 55 <= p['ldlc'] < 70:
results['regimen'].append("Therapeutic Optimization: Evaluate addition of Ezetimibe to reach target < 55 mg/dL (Class 2a).")
return results
def run_tests():
# Load converted patients
with open('patients.json', 'r', encoding='utf-8') as f:
patients = json.load(f)
print(f"Loaded {len(patients)} patients for rule audit tests.")
# Test cases count
criticals = 0
warnings = 0
for i, p in enumerate(patients):
res = evaluate_rules(p)
criticals += len(res['deviations'])
warnings += len(res['alerts'])
print(f"Audit Summary of Converted Registry Dataset:")
print(f" - Total Patients Audited: {len(patients)}")
print(f" - Total Deviations/Omissions found: {criticals}")
print(f" - Total Safety Alerts triggered: {warnings}")
# Run test profiles
print("\nRunning specific guideline boundary checks:")
# Boundary Test 1: STEMI + Fibrinolytics + Ticagrelor
test1 = {
"patientId": "T1", "name": "Test STEMI Fibrinolytic Ticagrelor",
"age": 60, "gender": "Male", "diagnosis": 1, "troponin": 1, "ecg": 1,
"ischemicInstability": 0, "ischemicAngina": 0, "ischemicHeartFailure": 0, "ischemicArrhythmia": 0,
"bleedingRenal": 0, "bleedingAnemia": 0, "bleedingAF": 0, "bleedingStroke": 0,
"spo2": 95, "sbp": 120, "hr": 80, "cpType": 1,
"diabetes": 0, "ckd": 0, "priorStroke": 0, "pepticUlcer": 0, "nsaid": 0,
"minorBleeding": 0, "concurrentOac": 0, "ppiPrescribed": 0,
"reperfusion": 2, "p2y12": 2, "statin": 2, "ldlc": 65
}
r1 = evaluate_rules(test1)
assert any("CRITICAL MISMATCH" in d for d in r1['deviations']), f"Failed Test 1: {r1}"
print(" [PASS] STEMI post-fibrinolysis on Ticagrelor correctly flagged as CRITICAL MISMATCH.")
# Boundary Test 1b: STEMI + Fibrinolytics + Clopidogrel + Age >= 75
test1b = {
"patientId": "T1b", "name": "Test STEMI Fibrinolytic Clopidogrel >=75",
"age": 75, "gender": "Male", "diagnosis": 1, "troponin": 1, "ecg": 1,
"ischemicInstability": 0, "ischemicAngina": 0, "ischemicHeartFailure": 0, "ischemicArrhythmia": 0,
"bleedingRenal": 0, "bleedingAnemia": 0, "bleedingAF": 0, "bleedingStroke": 0,
"spo2": 95, "sbp": 120, "hr": 80, "cpType": 1,
"diabetes": 0, "ckd": 0, "priorStroke": 0, "pepticUlcer": 0, "nsaid": 0,
"minorBleeding": 0, "concurrentOac": 0, "ppiPrescribed": 1,
"reperfusion": 2, "p2y12": 1, "statin": 2, "ldlc": 65
}
r1b = evaluate_rules(test1b)
assert any("no load" in reg for reg in r1b['regimen']), f"Failed Test 1b: {r1b}"
print(" [PASS] STEMI post-fibrinolysis Clopidogrel (Age >= 75) correctly flags for no loading dose.")
# Boundary Test 2: NSTE-ACS + Ischemic Indicators (Angiography within 2 hours)
test2 = {
"patientId": "T2", "name": "Test NSTE-ACS High Ischemic",
"age": 60, "gender": "Male", "diagnosis": 2, "troponin": 1, "ecg": 2,
"ischemicInstability": 0, "ischemicAngina": 1, "ischemicHeartFailure": 0, "ischemicArrhythmia": 0,
"bleedingRenal": 0, "bleedingAnemia": 0, "bleedingAF": 0, "bleedingStroke": 0,
"spo2": 95, "sbp": 120, "hr": 80, "cpType": 1,
"diabetes": 0, "ckd": 0, "priorStroke": 0, "pepticUlcer": 0, "nsaid": 0,
"minorBleeding": 0, "concurrentOac": 0, "ppiPrescribed": 0,
"reperfusion": 4, "p2y12": 1, "statin": 2, "ldlc": 65
}
r2 = evaluate_rules(test2)
assert any("Immediate Invasive Strategy Required" in a for a in r2['alerts']), f"Failed Test 2: {r2}"
print(" [PASS] High Ischemic Risk NSTE-ACS patient correctly flagged for Immediate Invasive Strategy.")
# Boundary Test 3: HBR + Prasugrel (Absolute Contraindication)
test3 = {
"patientId": "T3", "name": "Test HBR Prasugrel",
"age": 76, "gender": "Male", "diagnosis": 1, "troponin": 1, "ecg": 1,
"ischemicInstability": 0, "ischemicAngina": 0, "ischemicHeartFailure": 0, "ischemicArrhythmia": 0,
"bleedingRenal": 0, "bleedingAnemia": 0, "bleedingAF": 0, "bleedingStroke": 0,
"spo2": 95, "sbp": 120, "hr": 80, "cpType": 1,
"diabetes": 0, "ckd": 0, "priorStroke": 0, "pepticUlcer": 0, "nsaid": 0,
"minorBleeding": 0, "concurrentOac": 0, "ppiPrescribed": 1,
"reperfusion": 1, "p2y12": 3, "statin": 2, "ldlc": 65
}
r3 = evaluate_rules(test3)
assert any("CONTRAINDICATION OVERRIDE" in d for d in r3['deviations']), f"Failed Test 3: {r3}"
print(" [PASS] HBR patient (Age >= 75) on Prasugrel correctly flagged as CONTRAINDICATION OVERRIDE.")
# Boundary Test 4: PPI Gastric Gap & Metabolic Optimization
test4 = {
"patientId": "T4", "name": "Test Gastric Gap and Metabolic",
"age": 78, "gender": "Male", "diagnosis": 3, "troponin": 0, "ecg": 0,
"ischemicInstability": 0, "ischemicAngina": 0, "ischemicHeartFailure": 0, "ischemicArrhythmia": 0,
"bleedingRenal": 0, "bleedingAnemia": 0, "bleedingAF": 0, "bleedingStroke": 0,
"spo2": 95, "sbp": 120, "hr": 80, "cpType": 2,
"diabetes": 0, "ckd": 0, "priorStroke": 0, "pepticUlcer": 0, "nsaid": 0,
"minorBleeding": 0, "concurrentOac": 0, "ppiPrescribed": 0,
"reperfusion": 4, "p2y12": 1, "statin": 2, "ldlc": 65
}
r4 = evaluate_rules(test4)
assert any("GASTRIC GAP" in a for a in r4['alerts']), f"Failed Test 4 Gastric Gap: {r4}"
test4['ppiPrescribed'] = 1
r4b = evaluate_rules(test4)
assert any("PPI Metabolic Optimization" in a for a in r4b['alerts']), f"Failed Test 4 Metabolic: {r4b}"
print(" [PASS] PPI Gastric Gap and CYP2C19 metabolic drug interaction rules verified.")
# Boundary Test 5: Hypoxemia check
test5 = {
"patientId": "T5", "name": "Test Hypoxemia",
"age": 60, "gender": "Male", "diagnosis": 3, "troponin": 0, "ecg": 0,
"ischemicInstability": 0, "ischemicAngina": 0, "ischemicHeartFailure": 0, "ischemicArrhythmia": 0,
"bleedingRenal": 0, "bleedingAnemia": 0, "bleedingAF": 0, "bleedingStroke": 0,
"spo2": 88, "sbp": 120, "hr": 80, "cpType": 2,
"diabetes": 0, "ckd": 0, "priorStroke": 0, "pepticUlcer": 0, "nsaid": 0,
"minorBleeding": 0, "concurrentOac": 0, "ppiPrescribed": 0,
"reperfusion": 4, "p2y12": 1, "statin": 2, "ldlc": 65
}
r5 = evaluate_rules(test5)
assert any("HYPOXEMIA ALERT" in a for a in r5['alerts']), f"Failed Test 5 Hypoxemia: {r5}"
print(" [PASS] Hypoxemia (SpO2 < 90%) check verified.")
# Boundary Test 6: HBR Rules A/B/C
# Rule B: Minor Bleeding
test6b = {
"patientId": "T6b", "name": "Test Rule B",
"age": 60, "gender": "Male", "diagnosis": 3, "troponin": 0, "ecg": 0,
"ischemicInstability": 0, "ischemicAngina": 0, "ischemicHeartFailure": 0, "ischemicArrhythmia": 0,
"bleedingRenal": 1, "bleedingAnemia": 0, "bleedingAF": 0, "bleedingStroke": 0,
"spo2": 95, "sbp": 120, "hr": 80, "cpType": 2,
"diabetes": 0, "ckd": 0, "priorStroke": 0, "pepticUlcer": 0, "nsaid": 0,
"minorBleeding": 1, "concurrentOac": 0, "ppiPrescribed": 1,
"reperfusion": 4, "p2y12": 2, "statin": 2, "ldlc": 65
}
r6b = evaluate_rules(test6b)
assert any("P2Y12 Down-Titration" in reg for reg in r6b['regimen']), f"Failed Rule B: {r6b}"
print(" [PASS] HBR Rule B (P2Y12 Down-Titration on minor bleed) verified.")
# Rule C: Concurrent OAC
test6c = {
"patientId": "T6c", "name": "Test Rule C",
"age": 60, "gender": "Male", "diagnosis": 3, "troponin": 0, "ecg": 0,
"ischemicInstability": 0, "ischemicAngina": 0, "ischemicHeartFailure": 0, "ischemicArrhythmia": 0,
"bleedingRenal": 1, "bleedingAnemia": 0, "bleedingAF": 1, "bleedingStroke": 0,
"spo2": 95, "sbp": 120, "hr": 80, "cpType": 2,
"diabetes": 0, "ckd": 0, "priorStroke": 0, "pepticUlcer": 0, "nsaid": 0,
"minorBleeding": 0, "concurrentOac": 1, "ppiPrescribed": 1,
"reperfusion": 4, "p2y12": 2, "statin": 2, "ldlc": 65
}
r6c = evaluate_rules(test6c)
assert any("Convert to Dual Therapy" in reg for reg in r6c['regimen']), f"Failed Rule C: {r6c}"
print(" [PASS] HBR Rule C (Triple to Dual therapy conversion for OAC) verified.")
print("\nAll boundary tests PASSED successfully.")
if __name__ == "__main__":
run_tests()