iints-sdk-python35 0.0.18__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. iints/__init__.py +183 -0
  2. iints/analysis/__init__.py +12 -0
  3. iints/analysis/algorithm_xray.py +387 -0
  4. iints/analysis/baseline.py +92 -0
  5. iints/analysis/clinical_benchmark.py +198 -0
  6. iints/analysis/clinical_metrics.py +551 -0
  7. iints/analysis/clinical_tir_analyzer.py +136 -0
  8. iints/analysis/diabetes_metrics.py +43 -0
  9. iints/analysis/edge_efficiency.py +33 -0
  10. iints/analysis/edge_performance_monitor.py +315 -0
  11. iints/analysis/explainability.py +94 -0
  12. iints/analysis/explainable_ai.py +232 -0
  13. iints/analysis/hardware_benchmark.py +221 -0
  14. iints/analysis/metrics.py +117 -0
  15. iints/analysis/population_report.py +188 -0
  16. iints/analysis/reporting.py +345 -0
  17. iints/analysis/safety_index.py +311 -0
  18. iints/analysis/sensor_filtering.py +54 -0
  19. iints/analysis/validator.py +273 -0
  20. iints/api/__init__.py +0 -0
  21. iints/api/base_algorithm.py +307 -0
  22. iints/api/registry.py +103 -0
  23. iints/api/template_algorithm.py +195 -0
  24. iints/assets/iints_logo.png +0 -0
  25. iints/cli/__init__.py +0 -0
  26. iints/cli/cli.py +2598 -0
  27. iints/core/__init__.py +1 -0
  28. iints/core/algorithms/__init__.py +0 -0
  29. iints/core/algorithms/battle_runner.py +138 -0
  30. iints/core/algorithms/correction_bolus.py +95 -0
  31. iints/core/algorithms/discovery.py +92 -0
  32. iints/core/algorithms/fixed_basal_bolus.py +58 -0
  33. iints/core/algorithms/hybrid_algorithm.py +92 -0
  34. iints/core/algorithms/lstm_algorithm.py +138 -0
  35. iints/core/algorithms/mock_algorithms.py +162 -0
  36. iints/core/algorithms/pid_controller.py +88 -0
  37. iints/core/algorithms/standard_pump_algo.py +64 -0
  38. iints/core/device.py +0 -0
  39. iints/core/device_manager.py +64 -0
  40. iints/core/devices/__init__.py +3 -0
  41. iints/core/devices/models.py +160 -0
  42. iints/core/patient/__init__.py +9 -0
  43. iints/core/patient/bergman_model.py +341 -0
  44. iints/core/patient/models.py +285 -0
  45. iints/core/patient/patient_factory.py +117 -0
  46. iints/core/patient/profile.py +41 -0
  47. iints/core/safety/__init__.py +12 -0
  48. iints/core/safety/config.py +37 -0
  49. iints/core/safety/input_validator.py +95 -0
  50. iints/core/safety/supervisor.py +39 -0
  51. iints/core/simulation/__init__.py +0 -0
  52. iints/core/simulation/scenario_parser.py +61 -0
  53. iints/core/simulator.py +874 -0
  54. iints/core/supervisor.py +367 -0
  55. iints/data/__init__.py +53 -0
  56. iints/data/adapter.py +142 -0
  57. iints/data/column_mapper.py +398 -0
  58. iints/data/datasets.json +132 -0
  59. iints/data/demo/__init__.py +1 -0
  60. iints/data/demo/demo_cgm.csv +289 -0
  61. iints/data/importer.py +275 -0
  62. iints/data/ingestor.py +162 -0
  63. iints/data/nightscout.py +128 -0
  64. iints/data/quality_checker.py +550 -0
  65. iints/data/registry.py +166 -0
  66. iints/data/tidepool.py +38 -0
  67. iints/data/universal_parser.py +813 -0
  68. iints/data/virtual_patients/clinic_safe_baseline.yaml +9 -0
  69. iints/data/virtual_patients/clinic_safe_hyper_challenge.yaml +9 -0
  70. iints/data/virtual_patients/clinic_safe_hypo_prone.yaml +9 -0
  71. iints/data/virtual_patients/clinic_safe_midnight.yaml +9 -0
  72. iints/data/virtual_patients/clinic_safe_pizza.yaml +9 -0
  73. iints/data/virtual_patients/clinic_safe_stress_meal.yaml +9 -0
  74. iints/data/virtual_patients/default_patient.yaml +11 -0
  75. iints/data/virtual_patients/patient_559_config.yaml +11 -0
  76. iints/emulation/__init__.py +80 -0
  77. iints/emulation/legacy_base.py +414 -0
  78. iints/emulation/medtronic_780g.py +337 -0
  79. iints/emulation/omnipod_5.py +367 -0
  80. iints/emulation/tandem_controliq.py +393 -0
  81. iints/highlevel.py +451 -0
  82. iints/learning/__init__.py +3 -0
  83. iints/learning/autonomous_optimizer.py +194 -0
  84. iints/learning/learning_system.py +122 -0
  85. iints/metrics.py +34 -0
  86. iints/population/__init__.py +11 -0
  87. iints/population/generator.py +131 -0
  88. iints/population/runner.py +327 -0
  89. iints/presets/__init__.py +28 -0
  90. iints/presets/presets.json +114 -0
  91. iints/research/__init__.py +30 -0
  92. iints/research/config.py +68 -0
  93. iints/research/dataset.py +319 -0
  94. iints/research/losses.py +73 -0
  95. iints/research/predictor.py +329 -0
  96. iints/scenarios/__init__.py +3 -0
  97. iints/scenarios/generator.py +92 -0
  98. iints/templates/__init__.py +0 -0
  99. iints/templates/default_algorithm.py +91 -0
  100. iints/templates/scenarios/__init__.py +0 -0
  101. iints/templates/scenarios/chaos_insulin_stacking.json +29 -0
  102. iints/templates/scenarios/chaos_runaway_ai.json +25 -0
  103. iints/templates/scenarios/example_scenario.json +35 -0
  104. iints/templates/scenarios/exercise_stress.json +30 -0
  105. iints/utils/__init__.py +3 -0
  106. iints/utils/plotting.py +50 -0
  107. iints/utils/run_io.py +152 -0
  108. iints/validation/__init__.py +133 -0
  109. iints/validation/schemas.py +94 -0
  110. iints/visualization/__init__.py +34 -0
  111. iints/visualization/cockpit.py +691 -0
  112. iints/visualization/uncertainty_cloud.py +612 -0
  113. iints_sdk_python35-0.0.18.dist-info/METADATA +225 -0
  114. iints_sdk_python35-0.0.18.dist-info/RECORD +118 -0
  115. iints_sdk_python35-0.0.18.dist-info/WHEEL +5 -0
  116. iints_sdk_python35-0.0.18.dist-info/entry_points.txt +10 -0
  117. iints_sdk_python35-0.0.18.dist-info/licenses/LICENSE +28 -0
  118. iints_sdk_python35-0.0.18.dist-info/top_level.txt +1 -0
@@ -0,0 +1,337 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Medtronic 780G Emulator - IINTS-AF
4
+ Emulates the Medtronic MiniMed 780G with SmartGuard algorithm.
5
+
6
+ Based on:
7
+ - FDA 510(k) clearance documentation
8
+ - Clinical studies (Bergenstal et al.)
9
+ - User manual and technical specifications
10
+
11
+ Part of the #WeAreNotWaiting movement for transparent diabetes tech.
12
+ """
13
+
14
+ import numpy as np
15
+ from typing import Dict, List, Optional, Any
16
+ from dataclasses import dataclass
17
+
18
+ from .legacy_base import (
19
+ LegacyEmulator, PumpBehavior, PIDParameters, SafetyLimits,
20
+ SafetyLevel, EmulatorDecision
21
+ )
22
+
23
+
24
+ @dataclass
25
+ class Medtronic780GBehavior(PumpBehavior):
26
+ """Medtronic 780G specific behavior profile"""
27
+ # Additional 780G-specific parameters
28
+ auto_basal_enabled: bool = True
29
+ target_range_low: float = 100.0 # mg/dL (configurable 100-120)
30
+ target_range_high: float = 120.0 # mg/dL
31
+ max_auto_basal: float = 6.0 # units/hour
32
+ predictive_low_suspend: bool = True
33
+ plsg_window: int = 30 # minutes
34
+ plsg_threshold: float = 70.0 # mg/dL
35
+ time_step_minutes: float = 5.0 # Explicitly define the decision interval
36
+
37
+ def __init__(self):
38
+ super().__init__(
39
+ pump_name="Medtronic MiniMed 780G",
40
+ manufacturer="Medtronic",
41
+ safety_limits=SafetyLimits(
42
+ low_suspend_threshold=70.0,
43
+ high_suspend_threshold=250.0,
44
+ max_bolus=10.0,
45
+ max_basal_rate=6.0,
46
+ max_daily_total=80.0,
47
+ auto_off_duration=60.0,
48
+ low_suspend_duration=5.0,
49
+ target_glucose=120.0
50
+ ),
51
+ pid_parameters=PIDParameters(
52
+ kp=0.02, # Proportional gain (tuned for 780G)
53
+ ki=0.005, # Integral gain
54
+ kd=0.03, # Derivative gain
55
+ target_glucose=120.0,
56
+ integral_limit=5.0
57
+ ),
58
+ correction_factor=50.0,
59
+ carb_ratio=10.0,
60
+ insulin_sensitivity_factor=50.0,
61
+ active_insulin_duration=4.0,
62
+ safety_level=SafetyLevel.CONSERVATIVE
63
+ )
64
+
65
+
66
+ class Medtronic780GEmulator(LegacyEmulator):
67
+ """
68
+ Emulates Medtronic 780G SmartGuard algorithm.
69
+
70
+ Based on Medtronic 780G Clinical User Guide, Section 4.2 (SmartGuard).
71
+
72
+ The 780G uses a hybrid closed-loop system with:
73
+ - Automatic basal delivery (auto-basal)
74
+ - Automatic correction boluses
75
+ - Predictive Low Glucose Suspend (PLGS)
76
+ - Target glucose range (configurable 100-120 mg/dL)
77
+
78
+ Key characteristics:
79
+ - Conservative approach to avoid hypoglycemia
80
+ - Frequent insulin delivery (every 5 minutes)
81
+ - Automatic correction for elevated glucose
82
+ - Meal detection triggers additional insulin
83
+
84
+ Sources:
85
+ - Bergenstal et al. "New Closed-Loop Insulin Delivery System"
86
+ - FDA 510(k) K193510
87
+ - Medtronic 780G User Guide
88
+ """
89
+
90
+ def __init__(self):
91
+ """Initialize the 780G emulator"""
92
+ super().__init__()
93
+ self.behavior = Medtronic780GBehavior()
94
+
95
+ def _get_default_behavior(self) -> Medtronic780GBehavior:
96
+ """Get 780G default behavior"""
97
+ return Medtronic780GBehavior()
98
+
99
+ def get_sources(self) -> List[Dict[str, str]]:
100
+ """Get sources for 780G emulation logic"""
101
+ return [
102
+ {
103
+ 'title': 'Bergenstal et al. - Hybrid Closed-Loop Therapy',
104
+ 'type': 'clinical_study',
105
+ 'year': '2020',
106
+ 'url': 'https://doi.org/10.1056/NEJMoa2003479'
107
+ },
108
+ {
109
+ 'title': 'FDA 510(k) K193510 - MiniMed 780G System',
110
+ 'type': 'regulatory',
111
+ 'year': '2020',
112
+ 'url': 'https://www.accessdata.fda.gov/'
113
+ },
114
+ {
115
+ 'title': 'Medtronic 780G User Guide',
116
+ 'type': 'technical_manual',
117
+ 'year': '2020',
118
+ 'url': 'https://www.medtronicdiabetes.com/'
119
+ }
120
+ ]
121
+
122
+ def emulate_decision(self,
123
+ glucose: float,
124
+ velocity: float,
125
+ insulin_on_board: float,
126
+ carbs: float,
127
+ current_time: float = 0) -> EmulatorDecision:
128
+ """
129
+ Emulate 780G decision-making for current conditions.
130
+
131
+ The 780G makes decisions every 5 minutes:
132
+ 1. Check for automatic correction bolus (micro-bolus)
133
+ 2. Check for auto-basal adjustment
134
+ 3. Check for PLGS (Predictive Low Glucose Suspend)
135
+ 4. Apply safety constraints
136
+
137
+ Args:
138
+ glucose: Current glucose (mg/dL)
139
+ velocity: Rate of change (mg/dL/min)
140
+ insulin_on_board: Current IOB (units)
141
+ carbs: Carbs consumed (grams)
142
+ current_time: Simulation time (minutes)
143
+
144
+ Returns:
145
+ EmulatorDecision with insulin delivery details
146
+ """
147
+ reasoning = []
148
+ safety_overrides = []
149
+ action = 'deliver'
150
+ insulin_delivered = 0.0
151
+ pid = self.behavior.pid_parameters
152
+
153
+ # --- Update internal state ---
154
+ time_step_minutes = self.behavior.time_step_minutes
155
+
156
+ if self.state['previous_glucose'] is not None:
157
+ # Re-calculate velocity based on actual time step
158
+ self.state['velocity'] = (glucose - self.state['previous_glucose']) / time_step_minutes
159
+ else:
160
+ self.state['velocity'] = velocity # Use provided velocity if no previous data
161
+ self.state['previous_glucose'] = glucose
162
+
163
+ # --- 1. Initial Safety Check & PLGS (Predictive Low Glucose Suspend) ---
164
+ should_suspend, suspend_reasons, safety_adjustment_factor = self._check_safety_constraints(
165
+ glucose, self.state['velocity'], insulin_on_board, carbs, current_time
166
+ )
167
+ reasoning.extend(suspend_reasons)
168
+
169
+ if self.behavior.predictive_low_suspend and self.state['velocity'] < 0: # Only suspend if glucose is falling
170
+ predicted_glucose = glucose + self.state['velocity'] * self.behavior.plsg_window
171
+ if predicted_glucose < self.behavior.plsg_threshold:
172
+ action = 'suspend_insulin'
173
+ insulin_delivered = 0.0
174
+ safety_overrides.append(
175
+ f"PLGS activated: predicted glucose {predicted_glucose:.0f} mg/dL in "
176
+ f"{self.behavior.plsg_window} min. Insulin suspended."
177
+ )
178
+ reasoning.append(safety_overrides[-1])
179
+
180
+ if action != 'suspend_insulin': # If not suspended by PLGS or initial safety check
181
+
182
+ # --- 2. Calculate PID correction (Auto-Correction Bolus) ---
183
+ error = glucose - pid.target_glucose
184
+
185
+ # Update integral term (cumulative error over time)
186
+ self.state['integral_term'] += error * time_step_minutes
187
+ self.state['integral_term'] = max(-pid.integral_limit,
188
+ min(pid.integral_limit,
189
+ self.state['integral_term']))
190
+
191
+ # Derivative term is based on glucose velocity (trend)
192
+ derivative_term = self.state['velocity']
193
+
194
+ # Calculate total PID output (insulin units per time_step)
195
+ pid_insulin_correction = (
196
+ pid.kp * error +
197
+ pid.ki * self.state['integral_term'] +
198
+ pid.kd * derivative_term
199
+ ) / self.behavior.correction_factor
200
+
201
+ # --- 3. Add Meal Bolus ---
202
+ meal_bolus = 0.0
203
+ if carbs > 0:
204
+ meal_bolus = carbs / self.behavior.carb_ratio
205
+ reasoning.append(
206
+ f"Meal detected: {carbs:.0f}g -> {meal_bolus:.2f} U meal bolus"
207
+ )
208
+
209
+ # --- 4. Combine and apply internal limits ---
210
+ total_calculated_insulin = max(0, pid_insulin_correction + meal_bolus)
211
+
212
+ # Apply max bolus limit
213
+ total_calculated_insulin = min(total_calculated_insulin, self.behavior.safety_limits.max_bolus)
214
+
215
+ # Apply individual safety adjustment factor from _check_safety_constraints
216
+ insulin_delivered = total_calculated_insulin * safety_adjustment_factor
217
+
218
+ # The 780G delivers frequent small automatic correction boluses.
219
+ # This is primarily the pid_insulin_correction.
220
+ if insulin_delivered > 0:
221
+ if meal_bolus > 0:
222
+ reasoning.append(f"Insulin delivered for meal and auto-correction: {insulin_delivered:.2f} U")
223
+ elif pid_insulin_correction > 0:
224
+ reasoning.append(f"Auto-correction micro-bolus: {insulin_delivered:.2f} U (PID output based on glucose error and trend).")
225
+ else:
226
+ reasoning.append("No insulin delivered. Glucose at or near target, or PLGS active.")
227
+
228
+ # Create decision
229
+ decision = EmulatorDecision(
230
+ insulin_delivered=insulin_delivered,
231
+ action=action,
232
+ reasoning=reasoning,
233
+ safety_overrides=safety_overrides,
234
+ predicted_glucose=glucose + self.state['velocity'] * 30, # 30-min prediction (simplified)
235
+ confidence=0.90 # Higher confidence for a well-established pump
236
+ )
237
+
238
+ self._decision_history.append(decision)
239
+
240
+ return decision
241
+
242
+ def get_algorithm_personality(self) -> Dict:
243
+ """
244
+ Get the algorithm's "personality" characteristics.
245
+
246
+ Returns:
247
+ Dictionary with personality traits
248
+ """
249
+ return {
250
+ 'name': 'Medtronic 780G SmartGuard',
251
+ 'type': 'Hybrid Closed-Loop',
252
+ 'personality': {
253
+ 'aggressiveness': 'Conservative',
254
+ 'hypo_aversion': 'High',
255
+ 'response_speed': 'Moderate',
256
+ 'correction_aggressiveness': 'Moderate',
257
+ 'meal_handling': 'Automatic correction bolus',
258
+ 'predictive_features': 'PLGS, meal detection'
259
+ },
260
+ 'key_differences': [
261
+ 'Target glucose 100-120 mg/dL (configurable)',
262
+ 'Automatic correction boluses every 5 minutes',
263
+ 'Conservative approach to avoid hypoglycemia',
264
+ 'Strong predictive low glucose suspend'
265
+ ],
266
+ 'limitations': [
267
+ 'Requires meal announcements for best results',
268
+ 'Conservative tuning may lead to higher glucose',
269
+ 'No exercise mode integration'
270
+ ]
271
+ }
272
+
273
+
274
+ def demo_medtronic_780g():
275
+ """Demonstrate Medtronic 780G emulator"""
276
+ print("=" * 70)
277
+ print("MEDTRONIC 780G EMULATOR DEMONSTRATION")
278
+ print("=" * 70)
279
+
280
+ emulator = Medtronic780GEmulator()
281
+
282
+ # Print behavior profile
283
+ print("\nAlgorithm Personality:")
284
+ personality = emulator.get_algorithm_personality()
285
+ print(f" Name: {personality['name']}")
286
+ print(f" Type: {personality['type']}")
287
+ print(f" Aggressiveness: {personality['personality']['aggressiveness']}")
288
+ print(f" Hypo Aversion: {personality['personality']['hypo_aversion']}")
289
+
290
+ # Print sources
291
+ print("\nSources:")
292
+ for source in emulator.get_sources():
293
+ print(f" - [{source['type']}] {source['title']} ({source['year']})")
294
+
295
+ # Simulate scenarios
296
+ print("\nScenario Simulation:")
297
+ print("-" * 50)
298
+
299
+ scenarios = [
300
+ {'glucose': 180, 'velocity': 1.0, 'iob': 1.0, 'carbs': 0, 'desc': 'High glucose rising'},
301
+ {'glucose': 120, 'velocity': 0.5, 'iob': 2.0, 'carbs': 0, 'desc': 'At target, moderate IOB'},
302
+ {'glucose': 70, 'velocity': -1.5, 'iob': 1.0, 'carbs': 0, 'desc': 'Falling toward low'},
303
+ {'glucose': 250, 'velocity': 2.0, 'iob': 0.5, 'carbs': 30, 'desc': 'High with meal'},
304
+ {'glucose': 60, 'velocity': -2.5, 'iob': 0.5, 'carbs': 0, 'desc': 'Low with rapid fall'},
305
+ ]
306
+
307
+ for i, scenario in enumerate(scenarios, 1):
308
+ decision = emulator.emulate_decision(
309
+ glucose=scenario['glucose'],
310
+ velocity=scenario['velocity'],
311
+ insulin_on_board=scenario['iob'],
312
+ carbs=scenario['carbs'],
313
+ current_time=i * 5
314
+ )
315
+
316
+ print(f"\n Scenario {i}: {scenario['desc']}")
317
+ print(f" Glucose: {scenario['glucose']} mg/dL, Velocity: {scenario['velocity']} mg/dL/min")
318
+ print(f" IOB: {scenario['iob']} U, Carbs: {scenario['carbs']}g")
319
+ print(f" -> Action: {decision.action}, Insulin: {decision.insulin_delivered:.2f} U")
320
+ print(f" Reasoning: {', '.join(decision.reasoning[:2])}")
321
+
322
+ if decision.safety_overrides:
323
+ print(f" [WARN] Safety: {', '.join(decision.safety_overrides)}")
324
+
325
+ # Export behavior report
326
+ print("\nBehavior Report:")
327
+ report = emulator.export_behavior_report()
328
+ print(f" Pump: {report['pump_name']}")
329
+ print(f" Decisions: {report['decision_count']}")
330
+
331
+ print("\n" + "=" * 70)
332
+ print("MEDTRONIC 780G EMULATOR DEMONSTRATION COMPLETE")
333
+ print("=" * 70)
334
+
335
+
336
+ if __name__ == "__main__":
337
+ demo_medtronic_780g()