iints-sdk-python35 0.1.17__tar.gz → 0.1.19__tar.gz
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.
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/PKG-INFO +4 -1
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/README.md +1 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/pyproject.toml +3 -1
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/__init__.py +14 -2
- iints_sdk_python35-0.1.19/src/iints/analysis/edge_efficiency.py +33 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/analysis/population_report.py +3 -2
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/analysis/safety_index.py +7 -6
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/cli/cli.py +267 -4
- iints_sdk_python35-0.1.19/src/iints/core/algorithms/mock_algorithms.py +165 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/devices/models.py +5 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/patient/models.py +5 -2
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/patient/patient_factory.py +23 -4
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/patient/profile.py +1 -1
- iints_sdk_python35-0.1.19/src/iints/core/safety/__init__.py +12 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/safety/config.py +5 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/safety/input_validator.py +1 -1
- iints_sdk_python35-0.1.19/src/iints/core/safety/supervisor.py +39 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/simulator.py +117 -13
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/supervisor.py +51 -9
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/highlevel.py +57 -5
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/population/generator.py +2 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/population/runner.py +4 -3
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/research/__init__.py +3 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/research/config.py +26 -1
- iints_sdk_python35-0.1.19/src/iints/research/losses.py +98 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/research/predictor.py +0 -6
- iints_sdk_python35-0.1.19/src/iints/templates/scenarios/chaos_insulin_stacking.json +29 -0
- iints_sdk_python35-0.1.19/src/iints/templates/scenarios/chaos_runaway_ai.json +25 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints_sdk_python35.egg-info/PKG-INFO +4 -1
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints_sdk_python35.egg-info/SOURCES.txt +4 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints_sdk_python35.egg-info/requires.txt +2 -0
- iints_sdk_python35-0.1.17/src/iints/core/algorithms/mock_algorithms.py +0 -69
- iints_sdk_python35-0.1.17/src/iints/core/safety/__init__.py +0 -5
- iints_sdk_python35-0.1.17/src/iints/core/safety/supervisor.py +0 -33
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/LICENSE +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/setup.cfg +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/analysis/__init__.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/analysis/algorithm_xray.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/analysis/baseline.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/analysis/clinical_benchmark.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/analysis/clinical_metrics.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/analysis/clinical_tir_analyzer.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/analysis/diabetes_metrics.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/analysis/edge_performance_monitor.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/analysis/explainability.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/analysis/explainable_ai.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/analysis/hardware_benchmark.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/analysis/metrics.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/analysis/reporting.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/analysis/sensor_filtering.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/analysis/validator.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/api/__init__.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/api/base_algorithm.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/api/registry.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/api/template_algorithm.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/assets/iints_logo.png +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/cli/__init__.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/__init__.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/algorithms/__init__.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/algorithms/battle_runner.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/algorithms/correction_bolus.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/algorithms/discovery.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/algorithms/fixed_basal_bolus.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/algorithms/hybrid_algorithm.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/algorithms/lstm_algorithm.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/algorithms/pid_controller.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/algorithms/standard_pump_algo.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/device.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/device_manager.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/devices/__init__.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/patient/__init__.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/patient/bergman_model.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/simulation/__init__.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/core/simulation/scenario_parser.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/data/__init__.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/data/adapter.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/data/column_mapper.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/data/datasets.json +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/data/demo/__init__.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/data/demo/demo_cgm.csv +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/data/importer.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/data/ingestor.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/data/nightscout.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/data/quality_checker.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/data/registry.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/data/tidepool.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/data/universal_parser.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/data/virtual_patients/clinic_safe_baseline.yaml +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/data/virtual_patients/clinic_safe_hyper_challenge.yaml +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/data/virtual_patients/clinic_safe_hypo_prone.yaml +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/data/virtual_patients/clinic_safe_midnight.yaml +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/data/virtual_patients/clinic_safe_pizza.yaml +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/data/virtual_patients/clinic_safe_stress_meal.yaml +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/data/virtual_patients/default_patient.yaml +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/data/virtual_patients/patient_559_config.yaml +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/emulation/__init__.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/emulation/legacy_base.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/emulation/medtronic_780g.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/emulation/omnipod_5.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/emulation/tandem_controliq.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/learning/__init__.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/learning/autonomous_optimizer.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/learning/learning_system.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/metrics.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/population/__init__.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/presets/__init__.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/presets/presets.json +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/research/dataset.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/scenarios/__init__.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/scenarios/generator.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/templates/__init__.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/templates/default_algorithm.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/templates/scenarios/__init__.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/templates/scenarios/example_scenario.json +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/templates/scenarios/exercise_stress.json +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/utils/__init__.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/utils/plotting.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/utils/run_io.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/validation/__init__.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/validation/schemas.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/visualization/__init__.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/visualization/cockpit.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/visualization/uncertainty_cloud.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints_sdk_python35.egg-info/dependency_links.txt +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints_sdk_python35.egg-info/entry_points.txt +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints_sdk_python35.egg-info/top_level.txt +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/tests/test_bergman.py +0 -0
- {iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/tests/test_population.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iints-sdk-python35
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.19
|
|
4
4
|
Summary: A pre-clinical Edge-AI SDK for diabetes management validation.
|
|
5
5
|
Author-email: Rune Bobbaers <rune.bobbaers@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/python35/IINTS-SDK
|
|
@@ -42,6 +42,8 @@ Provides-Extra: research
|
|
|
42
42
|
Requires-Dist: torch>=2.0.0; extra == "research"
|
|
43
43
|
Requires-Dist: pyarrow>=12.0.0; extra == "research"
|
|
44
44
|
Requires-Dist: h5py>=3.10.0; extra == "research"
|
|
45
|
+
Requires-Dist: onnx>=1.16.0; extra == "research"
|
|
46
|
+
Requires-Dist: onnxscript>=0.1.0; extra == "research"
|
|
45
47
|
Dynamic: license-file
|
|
46
48
|
|
|
47
49
|
# IINTS-AF SDK
|
|
@@ -50,6 +52,7 @@ Dynamic: license-file
|
|
|
50
52
|
[](https://github.com/python35/IINTS-SDK/actions/workflows/python-package.yml)
|
|
51
53
|
[](https://github.com/python35/IINTS-SDK/actions/workflows/health-badges.yml)
|
|
52
54
|
[](https://github.com/python35/IINTS-SDK/actions/workflows/health-badges.yml)
|
|
55
|
+
[](https://python35.github.io/IINTS-Site/index.html)
|
|
53
56
|
|
|
54
57
|
<div style="text-align:center;">
|
|
55
58
|
<img src="Ontwerp zonder titel.png" alt="" style="display:block; margin:0 auto;">
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
[](https://github.com/python35/IINTS-SDK/actions/workflows/python-package.yml)
|
|
5
5
|
[](https://github.com/python35/IINTS-SDK/actions/workflows/health-badges.yml)
|
|
6
6
|
[](https://github.com/python35/IINTS-SDK/actions/workflows/health-badges.yml)
|
|
7
|
+
[](https://python35.github.io/IINTS-Site/index.html)
|
|
7
8
|
|
|
8
9
|
<div style="text-align:center;">
|
|
9
10
|
<img src="Ontwerp zonder titel.png" alt="" style="display:block; margin:0 auto;">
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "iints-sdk-python35"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.19"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Rune Bobbaers", email="rune.bobbaers@gmail.com" },
|
|
10
10
|
]
|
|
@@ -55,6 +55,8 @@ research = [
|
|
|
55
55
|
"torch>=2.0.0",
|
|
56
56
|
"pyarrow>=12.0.0",
|
|
57
57
|
"h5py>=3.10.0",
|
|
58
|
+
"onnx>=1.16.0",
|
|
59
|
+
"onnxscript>=0.1.0",
|
|
58
60
|
]
|
|
59
61
|
|
|
60
62
|
[project.scripts]
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import pandas as pd # Required for type hints like pd.DataFrame
|
|
4
4
|
from typing import Optional
|
|
5
5
|
|
|
6
|
-
__version__ = "0.1.
|
|
6
|
+
__version__ = "0.1.19"
|
|
7
7
|
|
|
8
8
|
# Note to developers: this SDK is currently maintained by a single author.
|
|
9
9
|
# Please report bugs via GitHub issues and feel free to contribute fixes via PRs.
|
|
@@ -20,6 +20,7 @@ from .api.base_algorithm import (
|
|
|
20
20
|
# Core Simulation Components
|
|
21
21
|
from .core.simulator import Simulator, StressEvent, SimulationLimitError
|
|
22
22
|
from .core.patient.models import PatientModel
|
|
23
|
+
from .core.patient.patient_factory import PatientFactory
|
|
23
24
|
from .core.patient.profile import PatientProfile
|
|
24
25
|
try:
|
|
25
26
|
from .core.device_manager import DeviceManager
|
|
@@ -33,7 +34,12 @@ except Exception: # pragma: no cover - fallback if torch/device manager import
|
|
|
33
34
|
from .core.safety import SafetyConfig, SafetySupervisor
|
|
34
35
|
from .core.devices.models import SensorModel, PumpModel
|
|
35
36
|
from .core.algorithms.standard_pump_algo import StandardPumpAlgorithm
|
|
36
|
-
from .core.algorithms.mock_algorithms import
|
|
37
|
+
from .core.algorithms.mock_algorithms import (
|
|
38
|
+
ConstantDoseAlgorithm,
|
|
39
|
+
RandomDoseAlgorithm,
|
|
40
|
+
RunawayAIAlgorithm,
|
|
41
|
+
StackingAIAlgorithm,
|
|
42
|
+
)
|
|
37
43
|
|
|
38
44
|
# Data Handling
|
|
39
45
|
from .data.ingestor import DataIngestor
|
|
@@ -52,6 +58,7 @@ from .data.nightscout import NightscoutConfig, import_nightscout
|
|
|
52
58
|
from .data.tidepool import TidepoolClient, load_openapi_spec
|
|
53
59
|
from .analysis.metrics import generate_benchmark_metrics # Added for benchmark
|
|
54
60
|
from .analysis.reporting import ClinicalReportGenerator
|
|
61
|
+
from .analysis.edge_efficiency import EnergyEstimate, estimate_energy_per_decision
|
|
55
62
|
from .highlevel import run_simulation, run_full, run_population
|
|
56
63
|
from .scenarios import ScenarioGeneratorConfig, generate_random_scenario
|
|
57
64
|
|
|
@@ -124,6 +131,7 @@ __all__ = [
|
|
|
124
131
|
"InsulinAlgorithm", "AlgorithmInput", "AlgorithmResult", "AlgorithmMetadata", "WhyLogEntry",
|
|
125
132
|
# Core
|
|
126
133
|
"Simulator", "StressEvent", "PatientModel", "DeviceManager",
|
|
134
|
+
"PatientFactory",
|
|
127
135
|
"PatientProfile",
|
|
128
136
|
"SimulationLimitError",
|
|
129
137
|
"SafetySupervisor",
|
|
@@ -133,6 +141,8 @@ __all__ = [
|
|
|
133
141
|
"StandardPumpAlgorithm",
|
|
134
142
|
"ConstantDoseAlgorithm",
|
|
135
143
|
"RandomDoseAlgorithm",
|
|
144
|
+
"RunawayAIAlgorithm",
|
|
145
|
+
"StackingAIAlgorithm",
|
|
136
146
|
# Data
|
|
137
147
|
"DataIngestor",
|
|
138
148
|
"ImportResult",
|
|
@@ -151,6 +161,8 @@ __all__ = [
|
|
|
151
161
|
# Analysis Metrics
|
|
152
162
|
"generate_benchmark_metrics",
|
|
153
163
|
"ClinicalReportGenerator",
|
|
164
|
+
"EnergyEstimate",
|
|
165
|
+
"estimate_energy_per_decision",
|
|
154
166
|
# Reporting
|
|
155
167
|
"generate_report",
|
|
156
168
|
"generate_quickstart_report",
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass(frozen=True)
|
|
7
|
+
class EnergyEstimate:
|
|
8
|
+
energy_joules: float
|
|
9
|
+
energy_microjoules: float
|
|
10
|
+
decisions_per_day: int
|
|
11
|
+
energy_joules_per_day: float
|
|
12
|
+
energy_millijoules_per_day: float
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def estimate_energy_per_decision(power_watts: float, latency_ms: float, decisions_per_day: int = 288) -> EnergyEstimate:
|
|
16
|
+
"""
|
|
17
|
+
Estimate energy cost per decision on any device.
|
|
18
|
+
|
|
19
|
+
Energy (J) = Power (W) * Time (s)
|
|
20
|
+
|
|
21
|
+
decisions_per_day default: 288 (5-minute control loop)
|
|
22
|
+
"""
|
|
23
|
+
latency_s = max(latency_ms, 0.0) / 1000.0
|
|
24
|
+
energy_j = max(power_watts, 0.0) * latency_s
|
|
25
|
+
energy_uj = energy_j * 1_000_000.0
|
|
26
|
+
energy_day_j = energy_j * max(int(decisions_per_day), 1)
|
|
27
|
+
return EnergyEstimate(
|
|
28
|
+
energy_joules=energy_j,
|
|
29
|
+
energy_microjoules=energy_uj,
|
|
30
|
+
decisions_per_day=max(int(decisions_per_day), 1),
|
|
31
|
+
energy_joules_per_day=energy_day_j,
|
|
32
|
+
energy_millijoules_per_day=energy_day_j * 1_000.0,
|
|
33
|
+
)
|
{iints_sdk_python35-0.1.17 → iints_sdk_python35-0.1.19}/src/iints/analysis/population_report.py
RENAMED
|
@@ -171,9 +171,10 @@ class PopulationReportGenerator:
|
|
|
171
171
|
if hypo_cols:
|
|
172
172
|
path = str(output_dir / "_plot_hypo_risk.png")
|
|
173
173
|
fig, ax = plt.subplots(figsize=(6, 4))
|
|
174
|
-
data = [df[c].dropna().
|
|
174
|
+
data = [df[c].dropna().astype(float).to_numpy() for c in hypo_cols]
|
|
175
175
|
labels = ["TBR <70 mg/dL (%)", "TBR <54 mg/dL (%)"][:len(data)]
|
|
176
|
-
bp = ax.boxplot(data,
|
|
176
|
+
bp = ax.boxplot(data, patch_artist=True)
|
|
177
|
+
ax.set_xticklabels(labels)
|
|
177
178
|
for patch, color in zip(bp["boxes"], [IINTS_BLUE, IINTS_RED]):
|
|
178
179
|
patch.set_facecolor(color)
|
|
179
180
|
patch.set_alpha(0.6)
|
|
@@ -96,7 +96,7 @@ def _interpret(score: float, penalties: Dict[str, float], weights: Dict[str, flo
|
|
|
96
96
|
|
|
97
97
|
# Identify the top penalty contributor
|
|
98
98
|
weighted = {k: weights[k] * _norm(v, NORM_SCALES[k]) for k, v in penalties.items()}
|
|
99
|
-
top_key = max(weighted, key=weighted
|
|
99
|
+
top_key = max(weighted, key=lambda k: weighted[k])
|
|
100
100
|
key_labels = {
|
|
101
101
|
"w_below54": "time critically below 54 mg/dL",
|
|
102
102
|
"w_below70": "time below 70 mg/dL",
|
|
@@ -167,8 +167,8 @@ def _compute_hypo_episode_duration(glucose: pd.Series, time_step_minutes: float)
|
|
|
167
167
|
An episode starts when glucose drops below 70 mg/dL and ends when it
|
|
168
168
|
rises back above 70 mg/dL. Returns 0.0 if no episodes.
|
|
169
169
|
"""
|
|
170
|
-
below = (glucose < 70.0).
|
|
171
|
-
if not
|
|
170
|
+
below = (glucose < 70.0).to_numpy(dtype=bool)
|
|
171
|
+
if not np.any(below):
|
|
172
172
|
return 0.0
|
|
173
173
|
|
|
174
174
|
episode_lengths: list[int] = []
|
|
@@ -228,7 +228,8 @@ def compute_safety_index(
|
|
|
228
228
|
weights = dict(weights) # defensive copy
|
|
229
229
|
_validate_weights(weights)
|
|
230
230
|
|
|
231
|
-
|
|
231
|
+
glucose_series = results_df["glucose_actual_mgdl"].astype(float)
|
|
232
|
+
glucose = glucose_series.to_numpy(dtype=float)
|
|
232
233
|
n = max(len(glucose), 1)
|
|
233
234
|
|
|
234
235
|
# --- Component 1: TBR critical < 54 mg/dL (%) ---
|
|
@@ -243,10 +244,10 @@ def compute_safety_index(
|
|
|
243
244
|
supervisor_rate = interventions / duration_hours
|
|
244
245
|
|
|
245
246
|
# --- Component 4: Mean hypo episode duration (hours) ---
|
|
246
|
-
mean_episode_hr = _compute_hypo_episode_duration(
|
|
247
|
+
mean_episode_hr = _compute_hypo_episode_duration(glucose_series, time_step_minutes) / 60.0
|
|
247
248
|
|
|
248
249
|
# --- Component 5: Tail-risk binary (1 if any glucose < 54, else 0) ---
|
|
249
|
-
tail_risk = 1.0 if (glucose < 54.0)
|
|
250
|
+
tail_risk = 1.0 if np.any(glucose < 54.0) else 0.0
|
|
250
251
|
|
|
251
252
|
penalties: Dict[str, float] = {
|
|
252
253
|
"w_below54": tbr_critical,
|
|
@@ -226,7 +226,7 @@ def evaluate(
|
|
|
226
226
|
output_dir: Annotated[Optional[Path], typer.Option(help="Output directory")] = None,
|
|
227
227
|
max_workers: Annotated[Optional[int], typer.Option(help="Max parallel workers (default: all cores)")] = None,
|
|
228
228
|
seed: Annotated[Optional[int], typer.Option(help="Random seed for reproducibility")] = None,
|
|
229
|
-
patient_model: Annotated[str, typer.Option("--patient-model", help="Patient model
|
|
229
|
+
patient_model: Annotated[str, typer.Option("--patient-model", help="Patient model: auto, bergman, custom, simglucose")] = "auto",
|
|
230
230
|
):
|
|
231
231
|
"""
|
|
232
232
|
Run a Monte Carlo population evaluation of an algorithm.
|
|
@@ -361,11 +361,15 @@ def init(
|
|
|
361
361
|
algo_content = files("iints.templates").joinpath("default_algorithm.py").read_text()
|
|
362
362
|
scenario_content = files("iints.templates.scenarios").joinpath("example_scenario.json").read_text()
|
|
363
363
|
exercise_content = files("iints.templates.scenarios").joinpath("exercise_stress.json").read_text()
|
|
364
|
+
stacking_content = files("iints.templates.scenarios").joinpath("chaos_insulin_stacking.json").read_text()
|
|
365
|
+
runaway_content = files("iints.templates.scenarios").joinpath("chaos_runaway_ai.json").read_text()
|
|
364
366
|
else:
|
|
365
367
|
from importlib import resources
|
|
366
368
|
algo_content = resources.read_text("iints.templates", "default_algorithm.py")
|
|
367
369
|
scenario_content = resources.read_text("iints.templates.scenarios", "example_scenario.json")
|
|
368
370
|
exercise_content = resources.read_text("iints.templates.scenarios", "exercise_stress.json")
|
|
371
|
+
stacking_content = resources.read_text("iints.templates.scenarios", "chaos_insulin_stacking.json")
|
|
372
|
+
runaway_content = resources.read_text("iints.templates.scenarios", "chaos_runaway_ai.json")
|
|
369
373
|
except Exception as e:
|
|
370
374
|
console.print(f"[bold red]Error reading template files: {e}[/bold red]")
|
|
371
375
|
raise typer.Exit(code=1)
|
|
@@ -381,6 +385,10 @@ def init(
|
|
|
381
385
|
f.write(scenario_content)
|
|
382
386
|
with open(project_path / "scenarios" / "exercise_stress.json", "w") as f:
|
|
383
387
|
f.write(exercise_content)
|
|
388
|
+
with open(project_path / "scenarios" / "chaos_insulin_stacking.json", "w") as f:
|
|
389
|
+
f.write(stacking_content)
|
|
390
|
+
with open(project_path / "scenarios" / "chaos_runaway_ai.json", "w") as f:
|
|
391
|
+
f.write(runaway_content)
|
|
384
392
|
|
|
385
393
|
# Create README
|
|
386
394
|
readme_content = f"""# {project_name}
|
|
@@ -573,6 +581,11 @@ def presets_run(
|
|
|
573
581
|
output_dir: Annotated[Optional[Path], typer.Option(help="Directory to save outputs")] = None,
|
|
574
582
|
compare_baselines: Annotated[bool, typer.Option(help="Run PID and standard pump baselines in the background")] = True,
|
|
575
583
|
seed: Annotated[Optional[int], typer.Option(help="Random seed for deterministic runs")] = None,
|
|
584
|
+
patient_model_type: Annotated[str, typer.Option("--patient-model", help="Patient model: auto, bergman, custom, simglucose")] = "auto",
|
|
585
|
+
sensor_noise_std: Annotated[Optional[float], typer.Option("--sensor-noise-std", help="CGM noise std (mg/dL)")] = None,
|
|
586
|
+
sensor_lag_minutes: Annotated[Optional[int], typer.Option("--sensor-lag-minutes", help="CGM lag (minutes)")] = None,
|
|
587
|
+
sensor_dropout_prob: Annotated[Optional[float], typer.Option("--sensor-dropout-prob", help="CGM dropout probability (0-1)")] = None,
|
|
588
|
+
sensor_bias: Annotated[Optional[float], typer.Option("--sensor-bias", help="CGM bias (mg/dL)")] = None,
|
|
576
589
|
safety_min_glucose: Annotated[Optional[float], typer.Option("--safety-min-glucose", help="Min plausible glucose (mg/dL)")] = None,
|
|
577
590
|
safety_max_glucose: Annotated[Optional[float], typer.Option("--safety-max-glucose", help="Max plausible glucose (mg/dL)")] = None,
|
|
578
591
|
safety_max_glucose_delta_per_5_min: Annotated[Optional[float], typer.Option("--safety-max-glucose-delta-per-5-min", help="Max glucose delta per 5 min (mg/dL)")] = None,
|
|
@@ -605,7 +618,7 @@ def presets_run(
|
|
|
605
618
|
try:
|
|
606
619
|
patient_config_name = preset.get("patient_config", "default_patient")
|
|
607
620
|
validated_patient_params = load_patient_config_by_name(patient_config_name).model_dump()
|
|
608
|
-
patient_model = iints.
|
|
621
|
+
patient_model = iints.PatientFactory.create_patient(patient_type=patient_model_type, **validated_patient_params)
|
|
609
622
|
except ValidationError as e:
|
|
610
623
|
console.print("[bold red]Patient config validation failed:[/bold red]")
|
|
611
624
|
for line in format_validation_error(e):
|
|
@@ -634,12 +647,32 @@ def presets_run(
|
|
|
634
647
|
critical_glucose_duration_minutes=safety_critical_glucose_duration_minutes,
|
|
635
648
|
)
|
|
636
649
|
|
|
650
|
+
sensor_model = None
|
|
651
|
+
if any(v is not None for v in (sensor_noise_std, sensor_lag_minutes, sensor_dropout_prob, sensor_bias)):
|
|
652
|
+
sensor_model = iints.SensorModel(
|
|
653
|
+
noise_std=float(sensor_noise_std or 0.0),
|
|
654
|
+
lag_minutes=int(sensor_lag_minutes or 0),
|
|
655
|
+
dropout_prob=float(sensor_dropout_prob or 0.0),
|
|
656
|
+
bias=float(sensor_bias or 0.0),
|
|
657
|
+
seed=resolved_seed,
|
|
658
|
+
)
|
|
659
|
+
elif patient_model_type == "auto":
|
|
660
|
+
sensor_model = iints.SensorModel(
|
|
661
|
+
noise_std=7.0,
|
|
662
|
+
lag_minutes=10,
|
|
663
|
+
dropout_prob=0.0,
|
|
664
|
+
bias=0.0,
|
|
665
|
+
seed=resolved_seed,
|
|
666
|
+
)
|
|
667
|
+
|
|
637
668
|
simulator_kwargs: Dict[str, Any] = {
|
|
638
669
|
"patient_model": patient_model,
|
|
639
670
|
"algorithm": algorithm_instance,
|
|
640
671
|
"time_step": time_step,
|
|
641
672
|
"safety_config": safety_config,
|
|
642
673
|
}
|
|
674
|
+
if sensor_model is not None:
|
|
675
|
+
simulator_kwargs["sensor_model"] = sensor_model
|
|
643
676
|
simulator_kwargs["seed"] = resolved_seed
|
|
644
677
|
if safety_config is None:
|
|
645
678
|
safety_config = SafetyConfig()
|
|
@@ -973,6 +1006,11 @@ def run(
|
|
|
973
1006
|
output_dir: Annotated[Optional[Path], typer.Option(help="Directory to save simulation results")] = None,
|
|
974
1007
|
compare_baselines: Annotated[bool, typer.Option(help="Run PID and standard pump baselines in the background")] = True,
|
|
975
1008
|
seed: Annotated[Optional[int], typer.Option(help="Random seed for deterministic runs")] = None,
|
|
1009
|
+
patient_model_type: Annotated[str, typer.Option("--patient-model", help="Patient model: auto, bergman, custom, simglucose")] = "auto",
|
|
1010
|
+
sensor_noise_std: Annotated[Optional[float], typer.Option("--sensor-noise-std", help="CGM noise std (mg/dL)")] = None,
|
|
1011
|
+
sensor_lag_minutes: Annotated[Optional[int], typer.Option("--sensor-lag-minutes", help="CGM lag (minutes)")] = None,
|
|
1012
|
+
sensor_dropout_prob: Annotated[Optional[float], typer.Option("--sensor-dropout-prob", help="CGM dropout probability (0-1)")] = None,
|
|
1013
|
+
sensor_bias: Annotated[Optional[float], typer.Option("--sensor-bias", help="CGM bias (mg/dL)")] = None,
|
|
976
1014
|
safety_min_glucose: Annotated[Optional[float], typer.Option("--safety-min-glucose", help="Min plausible glucose (mg/dL)")] = None,
|
|
977
1015
|
safety_max_glucose: Annotated[Optional[float], typer.Option("--safety-max-glucose", help="Max plausible glucose (mg/dL)")] = None,
|
|
978
1016
|
safety_max_glucose_delta_per_5_min: Annotated[Optional[float], typer.Option("--safety-max-glucose-delta-per-5-min", help="Max glucose delta per 5 min (mg/dL)")] = None,
|
|
@@ -1052,8 +1090,11 @@ def run(
|
|
|
1052
1090
|
validated_patient_params = load_patient_config_by_name(patient_config_name).model_dump()
|
|
1053
1091
|
patient_label = patient_config_name
|
|
1054
1092
|
|
|
1055
|
-
patient_model = iints.
|
|
1056
|
-
console.print(
|
|
1093
|
+
patient_model = iints.PatientFactory.create_patient(patient_type=patient_model_type, **validated_patient_params)
|
|
1094
|
+
console.print(
|
|
1095
|
+
f"Using patient model: {patient_model.__class__.__name__} "
|
|
1096
|
+
f"({patient_model_type}) with config [cyan]{patient_label}[/cyan]"
|
|
1097
|
+
)
|
|
1057
1098
|
except ValidationError as e:
|
|
1058
1099
|
console.print("[bold red]Patient config validation failed:[/bold red]")
|
|
1059
1100
|
for line in format_validation_error(e):
|
|
@@ -1117,12 +1158,31 @@ def run(
|
|
|
1117
1158
|
output_dir = resolve_output_dir(output_dir, run_id)
|
|
1118
1159
|
|
|
1119
1160
|
effective_safety_config = safety_config or SafetyConfig()
|
|
1161
|
+
sensor_model = None
|
|
1162
|
+
if any(v is not None for v in (sensor_noise_std, sensor_lag_minutes, sensor_dropout_prob, sensor_bias)):
|
|
1163
|
+
sensor_model = iints.SensorModel(
|
|
1164
|
+
noise_std=float(sensor_noise_std or 0.0),
|
|
1165
|
+
lag_minutes=int(sensor_lag_minutes or 0),
|
|
1166
|
+
dropout_prob=float(sensor_dropout_prob or 0.0),
|
|
1167
|
+
bias=float(sensor_bias or 0.0),
|
|
1168
|
+
seed=resolved_seed,
|
|
1169
|
+
)
|
|
1170
|
+
elif patient_model_type == "auto":
|
|
1171
|
+
sensor_model = iints.SensorModel(
|
|
1172
|
+
noise_std=7.0,
|
|
1173
|
+
lag_minutes=10,
|
|
1174
|
+
dropout_prob=0.0,
|
|
1175
|
+
bias=0.0,
|
|
1176
|
+
seed=resolved_seed,
|
|
1177
|
+
)
|
|
1178
|
+
|
|
1120
1179
|
simulator = iints.Simulator(
|
|
1121
1180
|
patient_model=patient_model,
|
|
1122
1181
|
algorithm=algorithm_instance,
|
|
1123
1182
|
time_step=time_step,
|
|
1124
1183
|
seed=resolved_seed,
|
|
1125
1184
|
safety_config=effective_safety_config,
|
|
1185
|
+
sensor_model=sensor_model,
|
|
1126
1186
|
)
|
|
1127
1187
|
|
|
1128
1188
|
for event in stress_events:
|
|
@@ -1725,6 +1785,180 @@ def research_prepare_azt1d(
|
|
|
1725
1785
|
console.print(f"[green]Quality report :[/green] {report}")
|
|
1726
1786
|
|
|
1727
1787
|
|
|
1788
|
+
@research_app.command("prepare-ohio")
|
|
1789
|
+
def research_prepare_ohio(
|
|
1790
|
+
input_dir: Annotated[Path, typer.Option(help="Root directory containing OhioT1DM patient_* folders")] = Path("data_packs/public/ohio_t1dm"),
|
|
1791
|
+
output: Annotated[Path, typer.Option(help="Output dataset path (CSV or Parquet)")] = Path("data_packs/public/ohio_t1dm/processed/ohio_t1dm_merged.csv"),
|
|
1792
|
+
report: Annotated[Path, typer.Option(help="Quality report output path")] = Path("data_packs/public/ohio_t1dm/quality_report.json"),
|
|
1793
|
+
time_step: Annotated[int, typer.Option(help="Expected CGM sample interval (minutes)")] = 5,
|
|
1794
|
+
max_gap_multiplier: Annotated[float, typer.Option(help="Segment-break gap multiplier")] = 2.5,
|
|
1795
|
+
dia_minutes: Annotated[float, typer.Option(help="Insulin action duration (minutes)")] = 240.0,
|
|
1796
|
+
peak_minutes: Annotated[float, typer.Option(help="IOB peak time (minutes, OpenAPS bilinear)")] = 75.0,
|
|
1797
|
+
carb_absorb_minutes: Annotated[float, typer.Option(help="Carb absorption duration (minutes)")] = 120.0,
|
|
1798
|
+
max_insulin: Annotated[float, typer.Option(help="Clip insulin units above this")] = 30.0,
|
|
1799
|
+
max_carbs: Annotated[float, typer.Option(help="Clip carb grams above this")] = 200.0,
|
|
1800
|
+
icr_default: Annotated[float, typer.Option(help="Fallback ICR (g/U)")] = 10.0,
|
|
1801
|
+
isf_default: Annotated[float, typer.Option(help="Fallback ISF (mg/dL per U)")] = 50.0,
|
|
1802
|
+
basal_default: Annotated[float, typer.Option(help="Fallback basal rate (U/hr)")] = 0.0,
|
|
1803
|
+
meal_window_min: Annotated[float, typer.Option(help="Meal→insulin matching window (minutes)")] = 30.0,
|
|
1804
|
+
isf_window_min: Annotated[float, typer.Option(help="ISF estimation window (minutes)")] = 60.0,
|
|
1805
|
+
min_meal_carbs: Annotated[float, typer.Option(help="Minimum carbs to consider a meal (g)")] = 5.0,
|
|
1806
|
+
min_bolus: Annotated[float, typer.Option(help="Minimum insulin to consider a bolus (U)")] = 0.1,
|
|
1807
|
+
):
|
|
1808
|
+
"""
|
|
1809
|
+
Prepare the OhioT1DM dataset for LSTM predictor training.
|
|
1810
|
+
|
|
1811
|
+
Reads per-patient CSVs, derives IOB/COB using the OpenAPS bilinear model,
|
|
1812
|
+
estimates effective ISF/ICR/basal per subject, adds time-of-day features,
|
|
1813
|
+
and writes the merged dataset plus a quality report.
|
|
1814
|
+
|
|
1815
|
+
Example
|
|
1816
|
+
-------
|
|
1817
|
+
iints research prepare-ohio --input-dir data_packs/public/ohio_t1dm --output ohio.parquet
|
|
1818
|
+
"""
|
|
1819
|
+
console = Console()
|
|
1820
|
+
if not input_dir.exists():
|
|
1821
|
+
console.print(f"[bold red]Input directory not found: {input_dir}[/bold red]")
|
|
1822
|
+
raise typer.Exit(code=1)
|
|
1823
|
+
|
|
1824
|
+
import subprocess, sys # noqa: E401
|
|
1825
|
+
cmd = [
|
|
1826
|
+
sys.executable,
|
|
1827
|
+
str(Path(__file__).parent.parent.parent.parent.parent / "research" / "prepare_ohio_t1dm.py"),
|
|
1828
|
+
"--input", str(input_dir),
|
|
1829
|
+
"--output", str(output),
|
|
1830
|
+
"--report", str(report),
|
|
1831
|
+
"--time-step", str(time_step),
|
|
1832
|
+
"--max-gap-multiplier", str(max_gap_multiplier),
|
|
1833
|
+
"--dia-minutes", str(dia_minutes),
|
|
1834
|
+
"--peak-minutes", str(peak_minutes),
|
|
1835
|
+
"--carb-absorb-minutes", str(carb_absorb_minutes),
|
|
1836
|
+
"--max-insulin", str(max_insulin),
|
|
1837
|
+
"--max-carbs", str(max_carbs),
|
|
1838
|
+
"--icr-default", str(icr_default),
|
|
1839
|
+
"--isf-default", str(isf_default),
|
|
1840
|
+
"--basal-default", str(basal_default),
|
|
1841
|
+
"--meal-window-min", str(meal_window_min),
|
|
1842
|
+
"--isf-window-min", str(isf_window_min),
|
|
1843
|
+
"--min-meal-carbs", str(min_meal_carbs),
|
|
1844
|
+
"--min-bolus", str(min_bolus),
|
|
1845
|
+
]
|
|
1846
|
+
try:
|
|
1847
|
+
import importlib.util as _ilu
|
|
1848
|
+
spec = _ilu.spec_from_file_location(
|
|
1849
|
+
"_prepare_ohio_t1dm",
|
|
1850
|
+
Path(__file__).parent.parent.parent.parent.parent / "research" / "prepare_ohio_t1dm.py",
|
|
1851
|
+
)
|
|
1852
|
+
if spec is not None and spec.loader is not None:
|
|
1853
|
+
import sys as _sys
|
|
1854
|
+
_old_argv = _sys.argv[:]
|
|
1855
|
+
_sys.argv = cmd[1:]
|
|
1856
|
+
try:
|
|
1857
|
+
mod = _ilu.module_from_spec(spec)
|
|
1858
|
+
spec.loader.exec_module(mod) # type: ignore[union-attr]
|
|
1859
|
+
mod.main() # type: ignore[attr-defined]
|
|
1860
|
+
finally:
|
|
1861
|
+
_sys.argv = _old_argv
|
|
1862
|
+
else:
|
|
1863
|
+
subprocess.run(cmd, check=True)
|
|
1864
|
+
except Exception as exc:
|
|
1865
|
+
console.print(f"[bold red]prepare-ohio failed: {exc}[/bold red]")
|
|
1866
|
+
raise typer.Exit(code=1)
|
|
1867
|
+
|
|
1868
|
+
console.print(f"[green]Dataset written to:[/green] {output}")
|
|
1869
|
+
console.print(f"[green]Quality report :[/green] {report}")
|
|
1870
|
+
|
|
1871
|
+
|
|
1872
|
+
@research_app.command("prepare-hupa")
|
|
1873
|
+
def research_prepare_hupa(
|
|
1874
|
+
input_dir: Annotated[Path, typer.Option(help="Root directory containing HUPA-UCM CSV files")] = Path("data_packs/public/hupa_ucm"),
|
|
1875
|
+
output: Annotated[Path, typer.Option(help="Output dataset path (CSV or Parquet)")] = Path("data_packs/public/hupa_ucm/processed/hupa_ucm_merged.csv"),
|
|
1876
|
+
report: Annotated[Path, typer.Option(help="Quality report output path")] = Path("data_packs/public/hupa_ucm/quality_report.json"),
|
|
1877
|
+
time_step: Annotated[int, typer.Option(help="Expected CGM sample interval (minutes)")] = 5,
|
|
1878
|
+
max_gap_multiplier: Annotated[float, typer.Option(help="Segment-break gap multiplier")] = 2.5,
|
|
1879
|
+
dia_minutes: Annotated[float, typer.Option(help="Insulin action duration (minutes)")] = 240.0,
|
|
1880
|
+
peak_minutes: Annotated[float, typer.Option(help="IOB peak time (minutes, OpenAPS bilinear)")] = 75.0,
|
|
1881
|
+
carb_absorb_minutes: Annotated[float, typer.Option(help="Carb absorption duration (minutes)")] = 120.0,
|
|
1882
|
+
max_insulin: Annotated[float, typer.Option(help="Clip insulin units above this")] = 30.0,
|
|
1883
|
+
max_carbs: Annotated[float, typer.Option(help="Clip carb grams above this")] = 200.0,
|
|
1884
|
+
carb_serving_grams: Annotated[float, typer.Option(help="Carb serving size (g) for carb_input")] = 10.0,
|
|
1885
|
+
basal_is_rate: Annotated[bool, typer.Option(help="Treat basal_rate as U/hr (convert to U/step)")] = False,
|
|
1886
|
+
icr_default: Annotated[float, typer.Option(help="Fallback ICR (g/U)")] = 10.0,
|
|
1887
|
+
isf_default: Annotated[float, typer.Option(help="Fallback ISF (mg/dL per U)")] = 50.0,
|
|
1888
|
+
basal_default: Annotated[float, typer.Option(help="Fallback basal rate (U/hr)")] = 0.0,
|
|
1889
|
+
meal_window_min: Annotated[float, typer.Option(help="Meal→insulin matching window (minutes)")] = 30.0,
|
|
1890
|
+
isf_window_min: Annotated[float, typer.Option(help="ISF estimation window (minutes)")] = 60.0,
|
|
1891
|
+
min_meal_carbs: Annotated[float, typer.Option(help="Minimum carbs to consider a meal (g)")] = 5.0,
|
|
1892
|
+
min_bolus: Annotated[float, typer.Option(help="Minimum insulin to consider a bolus (U)")] = 0.1,
|
|
1893
|
+
):
|
|
1894
|
+
"""
|
|
1895
|
+
Prepare the HUPA-UCM dataset for LSTM predictor training.
|
|
1896
|
+
|
|
1897
|
+
Parses per-patient CSVs, derives IOB/COB, estimates ISF/ICR/basal per
|
|
1898
|
+
subject, and writes the merged dataset plus a quality report.
|
|
1899
|
+
|
|
1900
|
+
Example
|
|
1901
|
+
-------
|
|
1902
|
+
iints research prepare-hupa --input-dir data_packs/public/hupa_ucm --output hupa.parquet
|
|
1903
|
+
"""
|
|
1904
|
+
console = Console()
|
|
1905
|
+
if not input_dir.exists():
|
|
1906
|
+
console.print(f"[bold red]Input directory not found: {input_dir}[/bold red]")
|
|
1907
|
+
raise typer.Exit(code=1)
|
|
1908
|
+
|
|
1909
|
+
import subprocess, sys # noqa: E401
|
|
1910
|
+
cmd = [
|
|
1911
|
+
sys.executable,
|
|
1912
|
+
str(Path(__file__).parent.parent.parent.parent.parent / "research" / "prepare_hupa_ucm.py"),
|
|
1913
|
+
"--input", str(input_dir),
|
|
1914
|
+
"--output", str(output),
|
|
1915
|
+
"--report", str(report),
|
|
1916
|
+
"--time-step", str(time_step),
|
|
1917
|
+
"--max-gap-multiplier", str(max_gap_multiplier),
|
|
1918
|
+
"--dia-minutes", str(dia_minutes),
|
|
1919
|
+
"--peak-minutes", str(peak_minutes),
|
|
1920
|
+
"--carb-absorb-minutes", str(carb_absorb_minutes),
|
|
1921
|
+
"--max-insulin", str(max_insulin),
|
|
1922
|
+
"--max-carbs", str(max_carbs),
|
|
1923
|
+
"--carb-serving-grams", str(carb_serving_grams),
|
|
1924
|
+
"--icr-default", str(icr_default),
|
|
1925
|
+
"--isf-default", str(isf_default),
|
|
1926
|
+
"--basal-default", str(basal_default),
|
|
1927
|
+
"--meal-window-min", str(meal_window_min),
|
|
1928
|
+
"--isf-window-min", str(isf_window_min),
|
|
1929
|
+
"--min-meal-carbs", str(min_meal_carbs),
|
|
1930
|
+
"--min-bolus", str(min_bolus),
|
|
1931
|
+
]
|
|
1932
|
+
if basal_is_rate:
|
|
1933
|
+
cmd.append("--basal-is-rate")
|
|
1934
|
+
else:
|
|
1935
|
+
cmd.append("--no-basal-is-rate")
|
|
1936
|
+
try:
|
|
1937
|
+
import importlib.util as _ilu
|
|
1938
|
+
spec = _ilu.spec_from_file_location(
|
|
1939
|
+
"_prepare_hupa_ucm",
|
|
1940
|
+
Path(__file__).parent.parent.parent.parent.parent / "research" / "prepare_hupa_ucm.py",
|
|
1941
|
+
)
|
|
1942
|
+
if spec is not None and spec.loader is not None:
|
|
1943
|
+
import sys as _sys
|
|
1944
|
+
_old_argv = _sys.argv[:]
|
|
1945
|
+
_sys.argv = cmd[1:]
|
|
1946
|
+
try:
|
|
1947
|
+
mod = _ilu.module_from_spec(spec)
|
|
1948
|
+
spec.loader.exec_module(mod) # type: ignore[union-attr]
|
|
1949
|
+
mod.main() # type: ignore[attr-defined]
|
|
1950
|
+
finally:
|
|
1951
|
+
_sys.argv = _old_argv
|
|
1952
|
+
else:
|
|
1953
|
+
subprocess.run(cmd, check=True)
|
|
1954
|
+
except Exception as exc:
|
|
1955
|
+
console.print(f"[bold red]prepare-hupa failed: {exc}[/bold red]")
|
|
1956
|
+
raise typer.Exit(code=1)
|
|
1957
|
+
|
|
1958
|
+
console.print(f"[green]Dataset written to:[/green] {output}")
|
|
1959
|
+
console.print(f"[green]Quality report :[/green] {report}")
|
|
1960
|
+
|
|
1961
|
+
|
|
1728
1962
|
@research_app.command("quality")
|
|
1729
1963
|
def research_quality(
|
|
1730
1964
|
report: Annotated[Path, typer.Option(help="Path to quality_report.json produced by prepare-azt1d")] = Path("data_packs/public/azt1d/quality_report.json"),
|
|
@@ -1790,6 +2024,35 @@ def research_quality(
|
|
|
1790
2024
|
console.print(table)
|
|
1791
2025
|
|
|
1792
2026
|
|
|
2027
|
+
@research_app.command("export-onnx")
|
|
2028
|
+
def research_export_onnx(
|
|
2029
|
+
model: Annotated[Path, typer.Option(help="Predictor checkpoint (.pt)")] = Path("models/hupa_finetuned_v2/predictor.pt"),
|
|
2030
|
+
out: Annotated[Path, typer.Option(help="Output ONNX file path")] = Path("models/predictor.onnx"),
|
|
2031
|
+
):
|
|
2032
|
+
"""
|
|
2033
|
+
Export a trained predictor to ONNX for edge/Jetson deployment.
|
|
2034
|
+
"""
|
|
2035
|
+
console = Console()
|
|
2036
|
+
if not model.exists():
|
|
2037
|
+
console.print(f"[bold red]Model not found: {model}[/bold red]")
|
|
2038
|
+
raise typer.Exit(code=1)
|
|
2039
|
+
|
|
2040
|
+
import subprocess, sys # noqa: E401
|
|
2041
|
+
cmd = [
|
|
2042
|
+
sys.executable,
|
|
2043
|
+
str(Path(__file__).parent.parent.parent.parent.parent / "research" / "export_predictor.py"),
|
|
2044
|
+
"--model", str(model),
|
|
2045
|
+
"--out", str(out),
|
|
2046
|
+
]
|
|
2047
|
+
try:
|
|
2048
|
+
subprocess.run(cmd, check=True)
|
|
2049
|
+
except Exception as exc:
|
|
2050
|
+
console.print(f"[bold red]export-onnx failed: {exc}[/bold red]")
|
|
2051
|
+
raise typer.Exit(code=1)
|
|
2052
|
+
|
|
2053
|
+
console.print(f"[green]ONNX written to:[/green] {out}")
|
|
2054
|
+
|
|
2055
|
+
|
|
1793
2056
|
@app.command("import-data")
|
|
1794
2057
|
def import_data(
|
|
1795
2058
|
input_csv: Annotated[Path, typer.Option(help="Path to CGM CSV file")],
|