iints-sdk-python35 1.5.13__tar.gz → 1.5.15__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-1.5.13/src/iints_sdk_python35.egg-info → iints_sdk_python35-1.5.15}/PKG-INFO +1 -1
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/pyproject.toml +1 -1
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/__init__.py +1 -1
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/algorithms/pid_controller.py +10 -2
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/devices/models.py +22 -3
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/patient/__init__.py +1 -1
- iints_sdk_python35-1.5.15/src/iints/core/patient/advanced_metabolic_model.py +336 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/patient/patient_factory.py +15 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/simulator.py +20 -8
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/supervisor.py +20 -17
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/realism_validator.py +25 -13
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/tools/ai_realism_auditor.py +1 -1
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15/src/iints_sdk_python35.egg-info}/PKG-INFO +1 -1
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints_sdk_python35.egg-info/SOURCES.txt +1 -0
- iints_sdk_python35-1.5.15/tests/test_scientific_fidelity.py +97 -0
- iints_sdk_python35-1.5.13/src/iints/core/patient/advanced_metabolic_model.py +0 -226
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/LICENSE +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/LICENSE-MIT-IINTS-LEGACY +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/NOTICE +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/README.md +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/setup.cfg +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/ai/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/ai/assistant.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/ai/backends/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/ai/backends/base.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/ai/backends/mistral_api.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/ai/backends/ollama.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/ai/cli.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/ai/mdmp_guard.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/ai/model_catalog.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/ai/prepare.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/ai/prompts.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/algorithm_xray.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/baseline.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/booth_demo.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/carelink_workbench.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/clinical_benchmark.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/clinical_metrics.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/clinical_tir_analyzer.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/diabetes_metrics.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/edge_efficiency.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/edge_performance_monitor.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/eucys_results.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/evidence_bundle.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/explainability.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/explainable_ai.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/hardware_benchmark.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/metrics.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/population_report.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/poster.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/reporting.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/run_quality.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/safety_index.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/safety_visualizer.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/sensor_filtering.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/study_analysis.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/study_engine.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/study_experiment.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/study_poster.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/study_protocol.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/analysis/validator.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/api/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/api/base_algorithm.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/api/registry.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/api/template_algorithm.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/assets/iints_logo.png +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/cli/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/cli/cli.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/cli/patient_cli.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/algorithms/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/algorithms/battle_runner.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/algorithms/clinical_baseline.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/algorithms/correction_bolus.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/algorithms/discovery.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/algorithms/fixed_basal_bolus.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/algorithms/hybrid_algorithm.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/algorithms/imitation_controller.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/algorithms/lstm_algorithm.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/algorithms/mock_algorithms.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/algorithms/mpc_controller.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/algorithms/neural_controller.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/algorithms/standard_pump_algo.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/device.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/device_manager.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/devices/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/digital_twin.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/patient/bergman_model.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/patient/hovorka_model.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/patient/models.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/patient/profile.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/physiology_variation.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/safety/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/safety/config.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/safety/input_validator.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/safety/supervisor.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/simulation/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/simulation/scenario_parser.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/adapter.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/certify.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/column_mapper.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/contracts.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/datasets.json +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/demo/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/demo/demo_cgm.csv +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/evidence.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/guardians.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/importer.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/ingestor.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/mdmp_visualizer.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/medtronic_live.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/nightscout.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/physiology_residual_profiles.json +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/quality_checker.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/realism_dashboard.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/realism_governance.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/realism_reference.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/realism_references.json +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/registry.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/research_catalog.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/runner.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/study_corruption.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/synthetic_mirror.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/tidepool.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/universal_parser.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/virtual_patients/clinic_safe_baseline.yaml +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/virtual_patients/clinic_safe_hyper_challenge.yaml +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/virtual_patients/clinic_safe_hypo_prone.yaml +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/virtual_patients/clinic_safe_midnight.yaml +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/virtual_patients/clinic_safe_pizza.yaml +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/virtual_patients/clinic_safe_stress_meal.yaml +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/virtual_patients/default_patient.yaml +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/virtual_patients/patient_559_config.yaml +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/virtual_patients/reference_azt1d_t1d.yaml +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/virtual_patients/reference_free_living_t1d.yaml +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/data/virtual_patients/reference_hupa_ucm_t1d.yaml +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/demo_assets.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/emulation/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/emulation/legacy_base.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/emulation/medtronic_780g.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/emulation/omnipod_5.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/emulation/tandem_controliq.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/highlevel.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/jetson/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/jetson/endurance.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/jetson/research_pipeline.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/learning/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/learning/autonomous_optimizer.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/learning/learning_system.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/live_patient/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/live_patient/api.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/live_patient/daemon.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/live_patient/edge_benchmark.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/live_patient/edge_ops.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/live_patient/fpga.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/live_patient/long_study.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/live_patient/medtronic_direct.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/live_patient/pico_pump.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/live_patient/runtime.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/live_patient/service_export.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/live_patient/uno_q.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/mdmp/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/mdmp/backend.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/mdmp/eu_ai_pact.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/metrics.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/population/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/population/generator.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/population/runner.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/presets/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/presets/evidence_sources.yaml +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/presets/forecast_calibration_profiles.yaml +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/presets/golden_benchmark.yaml +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/presets/presets.json +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/presets/safety_contract_default.yaml +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/presets/validation_profiles.yaml +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/research/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/research/audit.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/research/calibration_gate.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/research/config.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/research/control.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/research/control_eval.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/research/data_blend.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/research/dataset.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/research/evaluation.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/research/forecasting.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/research/glucose_model.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/research/local_ai.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/research/local_ai_gate.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/research/losses.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/research/metrics.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/research/model_registry.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/research/neural_control.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/research/predictor.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/research/results_manager.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/scenarios/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/scenarios/generator.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/scenarios/study_pack.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/templates/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/templates/default_algorithm.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/templates/demos/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/templates/demos/live_stage_demo.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/templates/pico_pump/README.md +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/templates/pico_pump/code.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/templates/pico_pump/serial_protocol.txt +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/templates/scenarios/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/templates/scenarios/chaos_insulin_stacking.json +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/templates/scenarios/chaos_runaway_ai.json +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/templates/scenarios/example_scenario.json +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/templates/scenarios/exercise_stress.json +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/templates/uno_q/README.md +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/templates/uno_q/iints_supervisor_bridge.ino +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/tools/digital_twin_calibrator.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/utils/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/utils/csv_safety.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/utils/plotting.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/utils/run_io.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/utils/url_safety.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/validation/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/validation/golden.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/validation/replay.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/validation/run_doctor.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/validation/run_validation.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/validation/safety_contract.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/validation/schemas.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/visualization/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/visualization/cockpit.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/visualization/uncertainty_cloud.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints_sdk_python35.egg-info/dependency_links.txt +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints_sdk_python35.egg-info/entry_points.txt +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints_sdk_python35.egg-info/requires.txt +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints_sdk_python35.egg-info/top_level.txt +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_ai/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_ai/lineage.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/audit.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/bias_hooks.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/bundle.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/certification.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/cli.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/compare.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/conformance.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/contracts.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/crypto.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/data/conformance/vectors/delegation.json +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/data/conformance/vectors/fingerprint.json +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/data/conformance/vectors/grading.json +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/data/conformance/vectors/signing.json +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/delegate.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/diffing.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/drift.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/exceptions.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/fingerprint.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/fingerprint_store.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/hf.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/keys/mdmp_pub_v1.pem +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/llm_provenance.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/migrate.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/policy.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/prov.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/registry.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/runner.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/schema_export.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/synthetic.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/trust.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_core/visualizer.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_flavors/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_integrations/__init__.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_integrations/dvc.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_integrations/mlflow.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/mdmp_integrations/wandb.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_bergman.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_ci_governance.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_cli_algorithm_loading.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_cli_booth_demo.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_cli_carelink_workbench.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_cli_cloud_import_security.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_cli_demo_export.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_cli_demo_live.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_cli_edge_runtime.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_cli_expo_tools.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_cli_fpga.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_cli_onboarding.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_cli_patient_runtime.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_cli_poster.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_cli_research_workflows.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_cli_run_summary.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_install_doctor.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_jetson_endurance.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_physiology_variation.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_plugin_system.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_population.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_presets_realism.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_research_realism_tools.py +0 -0
- {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/tests/test_simulator_calibration.py +0 -0
|
@@ -11,7 +11,7 @@ except ImportError: # pragma: no cover - Python < 3.8 fallback
|
|
|
11
11
|
try:
|
|
12
12
|
__version__ = version("iints-sdk-python35")
|
|
13
13
|
except PackageNotFoundError: # pragma: no cover - source tree fallback
|
|
14
|
-
__version__ = "1.5.
|
|
14
|
+
__version__ = "1.5.15"
|
|
15
15
|
|
|
16
16
|
# Note to developers: this SDK is currently maintained by a single author.
|
|
17
17
|
# Please report bugs via GitHub issues and feel free to contribute fixes via PRs.
|
{iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/algorithms/pid_controller.py
RENAMED
|
@@ -40,7 +40,15 @@ class PIDController(InsulinAlgorithm):
|
|
|
40
40
|
self._log_reason("Derivative term calculated", "control_parameter", derivative)
|
|
41
41
|
|
|
42
42
|
# Integral term (accumulated error) with anti-windup protection
|
|
43
|
-
|
|
43
|
+
# SCIENTIFIC UPGRADE: Pharmacokinetic (PK) Feed-Forward Integration
|
|
44
|
+
# We dynamically drain the integral windup based on the actual Insulin On Board (mass balance).
|
|
45
|
+
pk_feed_forward_inhibition = data.insulin_on_board * 2.0 # Tuning parameter for PK dampening
|
|
46
|
+
|
|
47
|
+
proposed_integral = max(
|
|
48
|
+
-self.integral_limit,
|
|
49
|
+
min(self.integral + error - pk_feed_forward_inhibition, self.integral_limit)
|
|
50
|
+
)
|
|
51
|
+
|
|
44
52
|
unsaturated_output = (
|
|
45
53
|
self.kp * error
|
|
46
54
|
+ self.ki * proposed_integral
|
|
@@ -56,7 +64,7 @@ class PIDController(InsulinAlgorithm):
|
|
|
56
64
|
)
|
|
57
65
|
else:
|
|
58
66
|
self.integral = proposed_integral
|
|
59
|
-
self._log_reason("Integral term updated", "control_parameter", self.integral)
|
|
67
|
+
self._log_reason(f"Integral term updated (dampened by {pk_feed_forward_inhibition:.2f} due to {data.insulin_on_board:.1f}U IOB)", "control_parameter", self.integral)
|
|
60
68
|
|
|
61
69
|
# PID formula
|
|
62
70
|
insulin_dose = (self.kp * error +
|
|
@@ -393,9 +393,28 @@ class PumpModel:
|
|
|
393
393
|
reason = f"max_units_per_step {self.max_units_per_step:.2f}"
|
|
394
394
|
|
|
395
395
|
if self.quantization_units:
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
396
|
+
# SCIENTIFIC UPGRADE: discrete micro-stepper quantization.
|
|
397
|
+
# The pump delivers integer motor steps; optional noise is modeled as
|
|
398
|
+
# missed or extra steps instead of continuous Gaussian dose drift.
|
|
399
|
+
micro_steps = round(delivered / self.quantization_units)
|
|
400
|
+
|
|
401
|
+
if self.delivery_noise_std > 0:
|
|
402
|
+
# Instead of adding Gaussian noise, we simulate physical rotor slip per micro-step.
|
|
403
|
+
slip_prob = min(0.15, self.delivery_noise_std) # Convert abstract std into slip probability
|
|
404
|
+
actual_steps = micro_steps
|
|
405
|
+
for _ in range(int(micro_steps)):
|
|
406
|
+
if float(self._rng.random()) < slip_prob:
|
|
407
|
+
# 70% chance to miss a step (friction/backlash), 30% chance to double-step (momentum)
|
|
408
|
+
if float(self._rng.random()) < 0.7:
|
|
409
|
+
actual_steps -= 1
|
|
410
|
+
else:
|
|
411
|
+
actual_steps += 1
|
|
412
|
+
micro_steps = max(0, actual_steps)
|
|
413
|
+
|
|
414
|
+
delivered = micro_steps * self.quantization_units
|
|
415
|
+
delivered = max(0.0, delivered)
|
|
416
|
+
elif self.delivery_noise_std > 0:
|
|
417
|
+
# Fallback for continuous infusion models without quantization
|
|
399
418
|
delivered += float(self._rng.normal(0, self.delivery_noise_std))
|
|
400
419
|
delivered = max(0.0, delivered)
|
|
401
420
|
|
|
@@ -6,6 +6,6 @@ try:
|
|
|
6
6
|
from .advanced_metabolic_model import AdvancedMetabolicModel
|
|
7
7
|
except ImportError: # pragma: no cover - scipy may not be installed
|
|
8
8
|
BergmanPatientModel = None # type: ignore[assignment,misc]
|
|
9
|
-
AdvancedMetabolicModel = None
|
|
9
|
+
AdvancedMetabolicModel = None # type: ignore[assignment,misc]
|
|
10
10
|
|
|
11
11
|
__all__ = ["PatientProfile", "PatientModel", "BergmanPatientModel", "AdvancedMetabolicModel"]
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from typing import Any, Dict, List, Optional
|
|
3
|
+
from scipy.integrate import solve_ivp
|
|
4
|
+
|
|
5
|
+
from .bergman_model import BergmanPatientModel, BergmanParameters
|
|
6
|
+
|
|
7
|
+
class AdvancedMetabolicModel(BergmanPatientModel):
|
|
8
|
+
"""
|
|
9
|
+
Advanced Metabolic Model for IINTS-AF.
|
|
10
|
+
Extends the 13-state Bergman model to an 18-state model including:
|
|
11
|
+
- F: Free Fatty Acids (FFA) (mmol/L)
|
|
12
|
+
- K: Ketone Bodies (mmol/L)
|
|
13
|
+
- Beta: Residual Beta-cell mass fraction (0.0 to 1.0)
|
|
14
|
+
- Q_fat: Fat stomach pool (grams)
|
|
15
|
+
- Q_prot: Protein stomach pool (grams)
|
|
16
|
+
|
|
17
|
+
Includes lipotoxicity, DKA, illness, menstrual cycles, and cannula degradation.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
initial_beta_mass: float = 0.0, # 0.0 = completely destroyed, 1.0 = healthy
|
|
23
|
+
autoimmune_aggressiveness: float = 7e-6, # Decay rate of beta cells per min
|
|
24
|
+
initial_ffa: float = 0.4,
|
|
25
|
+
initial_ketones: float = 0.1,
|
|
26
|
+
gamma_healthy: float = 0.005,
|
|
27
|
+
**kwargs,
|
|
28
|
+
) -> None:
|
|
29
|
+
self.initial_beta_mass = initial_beta_mass
|
|
30
|
+
self.autoimmune_aggressiveness = autoimmune_aggressiveness
|
|
31
|
+
self.initial_ffa = initial_ffa
|
|
32
|
+
self.initial_ketones = initial_ketones
|
|
33
|
+
self.gamma_healthy = gamma_healthy
|
|
34
|
+
|
|
35
|
+
# --- NEW GAMECHANGER STATES & FLAGS ---
|
|
36
|
+
self.is_ill = False
|
|
37
|
+
self.illness_severity = 0.0 # 0.0 to 1.0
|
|
38
|
+
|
|
39
|
+
self.menstrual_cycle_active = False
|
|
40
|
+
self.cycle_start_time_minutes = 0.0 # Time offset for the 28-day wave
|
|
41
|
+
|
|
42
|
+
self.pump_cannula_age_minutes = 0.0 # Tracks lipohypertrophy
|
|
43
|
+
|
|
44
|
+
super().__init__(**kwargs)
|
|
45
|
+
|
|
46
|
+
# Override the 13-state with 18-state
|
|
47
|
+
# State vector: [G, X, I, Q_sto1, Q_sto2, Q_gut, S1, S2, Y1, Y2, Gamma, x_gluc, HAAF, F, K, Beta, Q_fat, Q_prot]
|
|
48
|
+
self._state = np.array([
|
|
49
|
+
self.initial_glucose, # 0: G
|
|
50
|
+
0.0, # 1: X
|
|
51
|
+
self.params.Ib, # 2: I
|
|
52
|
+
0.0, # 3: Q_sto1
|
|
53
|
+
0.0, # 4: Q_sto2
|
|
54
|
+
0.0, # 5: Q_gut
|
|
55
|
+
0.0, # 6: S1
|
|
56
|
+
0.0, # 7: S2
|
|
57
|
+
0.0, # 8: Y1
|
|
58
|
+
0.0, # 9: Y2
|
|
59
|
+
0.0, # 10: Gamma
|
|
60
|
+
0.0, # 11: x_gluc
|
|
61
|
+
0.0, # 12: HAAF
|
|
62
|
+
self.initial_ffa, # 13: F (FFA)
|
|
63
|
+
self.initial_ketones, # 14: K (Ketones)
|
|
64
|
+
self.initial_beta_mass,# 15: Beta
|
|
65
|
+
0.0, # 16: Q_fat
|
|
66
|
+
0.0, # 17: Q_prot
|
|
67
|
+
], dtype=np.float64)
|
|
68
|
+
|
|
69
|
+
def reset(self) -> None:
|
|
70
|
+
super().reset()
|
|
71
|
+
self._state = np.array([
|
|
72
|
+
self.initial_glucose, 0.0, self.params.Ib, 0.0, 0.0, 0.0, 0.0, 0.0,
|
|
73
|
+
0.0, 0.0, 0.0, 0.0, 0.0, self.initial_ffa, self.initial_ketones, self.initial_beta_mass, 0.0, 0.0
|
|
74
|
+
], dtype=np.float64)
|
|
75
|
+
self.pump_cannula_age_minutes = 0.0
|
|
76
|
+
|
|
77
|
+
def get_patient_state(self) -> Dict[str, float]:
|
|
78
|
+
state_dict = super().get_patient_state()
|
|
79
|
+
state_dict.update({
|
|
80
|
+
"plasma_ffa_mmol_L": float(self._state[13]),
|
|
81
|
+
"plasma_ketones_mmol_L": float(self._state[14]),
|
|
82
|
+
"residual_beta_cell_mass": float(self._state[15]),
|
|
83
|
+
"fat_pool_g": float(self._state[16]),
|
|
84
|
+
"protein_pool_g": float(self._state[17]),
|
|
85
|
+
})
|
|
86
|
+
return state_dict
|
|
87
|
+
|
|
88
|
+
def set_state(self, state: Dict[str, Any]) -> None:
|
|
89
|
+
if "ode_state" in state:
|
|
90
|
+
ode_state = np.array(state["ode_state"], dtype=np.float64)
|
|
91
|
+
if ode_state.size == 13:
|
|
92
|
+
# Upgrade legacy 13-state to 18-state
|
|
93
|
+
ode_state = np.append(ode_state, [self.initial_ffa, self.initial_ketones, self.initial_beta_mass, 0.0, 0.0])
|
|
94
|
+
elif ode_state.size == 16:
|
|
95
|
+
# Upgrade legacy 16-state to 18-state
|
|
96
|
+
ode_state = np.append(ode_state, [0.0, 0.0])
|
|
97
|
+
self._state = ode_state
|
|
98
|
+
# Call super for the rest, but temporarly pop ode_state so super doesn't overwrite it
|
|
99
|
+
st_copy = state.copy()
|
|
100
|
+
if "ode_state" in st_copy:
|
|
101
|
+
del st_copy["ode_state"]
|
|
102
|
+
super().set_state(st_copy)
|
|
103
|
+
self.is_ill = bool(state.get("is_ill", self.is_ill))
|
|
104
|
+
self.illness_severity = float(state.get("illness_severity", self.illness_severity))
|
|
105
|
+
self.menstrual_cycle_active = bool(state.get("menstrual_cycle_active", self.menstrual_cycle_active))
|
|
106
|
+
self.cycle_start_time_minutes = float(state.get("cycle_start_time_minutes", self.cycle_start_time_minutes))
|
|
107
|
+
self.pump_cannula_age_minutes = float(state.get("pump_cannula_age_minutes", self.pump_cannula_age_minutes))
|
|
108
|
+
|
|
109
|
+
def update(
|
|
110
|
+
self,
|
|
111
|
+
time_step: float = 0.0,
|
|
112
|
+
delivered_insulin: float = 0.0,
|
|
113
|
+
carb_intake: float = 0.0,
|
|
114
|
+
delivered_glucagon_mg: float = 0.0,
|
|
115
|
+
current_time: Optional[float] = None,
|
|
116
|
+
**kwargs: Any,
|
|
117
|
+
) -> float:
|
|
118
|
+
"""Advance the 18-state metabolic model by ``time_step`` minutes.
|
|
119
|
+
|
|
120
|
+
The public signature stays compatible with ``BergmanPatientModel``.
|
|
121
|
+
Advanced-only inputs are accepted as keyword arguments:
|
|
122
|
+
``fat_intake`` and ``protein_intake``. Backward-compatible aliases are
|
|
123
|
+
accepted for earlier scratch scripts: ``dt_minutes``,
|
|
124
|
+
``delivered_glucagon``, and ``current_time_minutes``.
|
|
125
|
+
"""
|
|
126
|
+
if "dt_minutes" in kwargs:
|
|
127
|
+
time_step = float(kwargs.pop("dt_minutes"))
|
|
128
|
+
if "delivered_glucagon" in kwargs:
|
|
129
|
+
delivered_glucagon_mg = float(kwargs.pop("delivered_glucagon"))
|
|
130
|
+
if "current_time_minutes" in kwargs:
|
|
131
|
+
current_time = float(kwargs.pop("current_time_minutes"))
|
|
132
|
+
|
|
133
|
+
fat_intake = float(kwargs.pop("fat_intake", 0.0))
|
|
134
|
+
protein_intake = float(kwargs.pop("protein_intake", 0.0))
|
|
135
|
+
|
|
136
|
+
# Add macronutrients and age the cannula before solving this step.
|
|
137
|
+
self._state[16] += max(0.0, fat_intake)
|
|
138
|
+
self._state[17] += max(0.0, protein_intake)
|
|
139
|
+
self.pump_cannula_age_minutes += max(0.0, float(time_step))
|
|
140
|
+
|
|
141
|
+
return super().update(
|
|
142
|
+
time_step=time_step,
|
|
143
|
+
delivered_insulin=delivered_insulin,
|
|
144
|
+
carb_intake=carb_intake,
|
|
145
|
+
delivered_glucagon_mg=delivered_glucagon_mg,
|
|
146
|
+
current_time=current_time,
|
|
147
|
+
**kwargs,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
def start_illness(self, severity: float) -> None:
|
|
151
|
+
self.is_ill = True
|
|
152
|
+
self.illness_severity = float(np.clip(severity, 0.0, 1.0))
|
|
153
|
+
|
|
154
|
+
def stop_illness(self) -> None:
|
|
155
|
+
self.is_ill = False
|
|
156
|
+
self.illness_severity = 0.0
|
|
157
|
+
|
|
158
|
+
def start_menstrual_cycle(self, current_time_minutes: float = 0.0) -> None:
|
|
159
|
+
self.menstrual_cycle_active = True
|
|
160
|
+
self.cycle_start_time_minutes = float(current_time_minutes)
|
|
161
|
+
|
|
162
|
+
def stop_menstrual_cycle(self) -> None:
|
|
163
|
+
self.menstrual_cycle_active = False
|
|
164
|
+
|
|
165
|
+
def trigger_event(self, event_type: str, value: Any) -> None:
|
|
166
|
+
if event_type == "illness":
|
|
167
|
+
self.start_illness(float(value))
|
|
168
|
+
elif event_type == "illness_end":
|
|
169
|
+
self.stop_illness()
|
|
170
|
+
elif event_type == "menstrual_cycle":
|
|
171
|
+
self.start_menstrual_cycle(float(value or 0.0))
|
|
172
|
+
elif event_type == "menstrual_cycle_end":
|
|
173
|
+
self.stop_menstrual_cycle()
|
|
174
|
+
else:
|
|
175
|
+
super().trigger_event(event_type, value)
|
|
176
|
+
|
|
177
|
+
def get_state(self) -> Dict[str, Any]:
|
|
178
|
+
state = super().get_state()
|
|
179
|
+
state.update({
|
|
180
|
+
"is_ill": self.is_ill,
|
|
181
|
+
"illness_severity": self.illness_severity,
|
|
182
|
+
"menstrual_cycle_active": self.menstrual_cycle_active,
|
|
183
|
+
"cycle_start_time_minutes": self.cycle_start_time_minutes,
|
|
184
|
+
"pump_cannula_age_minutes": self.pump_cannula_age_minutes,
|
|
185
|
+
})
|
|
186
|
+
return state
|
|
187
|
+
|
|
188
|
+
def _ode(
|
|
189
|
+
self,
|
|
190
|
+
t: float,
|
|
191
|
+
y: np.ndarray,
|
|
192
|
+
u_insulin_mu_per_min: float,
|
|
193
|
+
u_glucagon_pg_per_min: float,
|
|
194
|
+
current_time: float,
|
|
195
|
+
) -> np.ndarray:
|
|
196
|
+
# Unpack 18 states
|
|
197
|
+
G, X, I, Q_sto1, Q_sto2, Q_gut, S1, S2, Y1, Y2, Gamma, x_gluc, HAAF, F, K, Beta, Q_fat, Q_prot = y
|
|
198
|
+
p = self.params
|
|
199
|
+
|
|
200
|
+
Vg_abs = p.Vg * p.body_weight_kg # dL
|
|
201
|
+
Vi_abs = p.Vi * p.body_weight_kg # L
|
|
202
|
+
V_glucagon = p.V_glucagon_per_kg * p.body_weight_kg
|
|
203
|
+
|
|
204
|
+
# --- Fat & Protein Macronutrient Kinetics ---
|
|
205
|
+
# Fat decays very slowly, Half-life ~4 hours
|
|
206
|
+
k_fat = 1.0 / 240.0
|
|
207
|
+
dQ_fat_dt = -k_fat * Q_fat
|
|
208
|
+
|
|
209
|
+
# Protein decays very slowly, Half-life ~5 hours
|
|
210
|
+
k_prot = 1.0 / 300.0
|
|
211
|
+
dQ_prot_dt = -k_prot * Q_prot
|
|
212
|
+
|
|
213
|
+
# Protein Gluconeogenesis: ~50% of protein becomes glucose very slowly.
|
|
214
|
+
# R_a_prot adds to EGP. (Convert grams to mg, divide by Vg_abs to get mg/dL/min)
|
|
215
|
+
Ra_prot = 0.5 * k_prot * Q_prot * 1000.0 / Vg_abs
|
|
216
|
+
|
|
217
|
+
# --- Glucose rate of appearance from gut ---
|
|
218
|
+
Ra = (p.k_abs * Q_gut) / Vg_abs # mg/dL/min
|
|
219
|
+
|
|
220
|
+
# --- Exogenous Glucagon Kinetics ---
|
|
221
|
+
dY1_dt = u_glucagon_pg_per_min - Y1 / p.t_max_glucagon
|
|
222
|
+
dY2_dt = Y1 / p.t_max_glucagon - Y2 / p.t_max_glucagon
|
|
223
|
+
U_Gamma = Y2 / p.t_max_glucagon
|
|
224
|
+
dGamma_dt = U_Gamma / V_glucagon - p.k_e_glucagon * Gamma
|
|
225
|
+
dx_gluc_dt = -p.k_a_glucagon * x_gluc + p.S_glucagon * p.k_a_glucagon * Gamma
|
|
226
|
+
|
|
227
|
+
# --- Circadian Rhythms & Dawn Phenomenon ---
|
|
228
|
+
t_hours = (current_time / 60.0) % 24
|
|
229
|
+
A_circadian = 0.2 if self.dawn_phenomenon_strength > 0 else 0.0
|
|
230
|
+
circadian_multiplier = 1.0 + A_circadian * np.cos((2 * np.pi / 24) * (t_hours - 5.0))
|
|
231
|
+
|
|
232
|
+
# --- Exercise & Stress Physiologic Impact ---
|
|
233
|
+
exercise_p1_multiplier = 1.0
|
|
234
|
+
exercise_p3_multiplier = 1.0
|
|
235
|
+
exercise_glucose_uptake = 0.0
|
|
236
|
+
if self.is_exercising:
|
|
237
|
+
exercise_p1_multiplier = 1.0 + 2.0 * self.exercise_intensity
|
|
238
|
+
exercise_p3_multiplier = 1.0 + 2.0 * self.exercise_intensity
|
|
239
|
+
exercise_glucose_uptake = self.exercise_intensity * 0.005 * G
|
|
240
|
+
|
|
241
|
+
stress_p1_multiplier = 1.0
|
|
242
|
+
stress_p3_multiplier = 1.0
|
|
243
|
+
stress_Gb_multiplier = 1.0
|
|
244
|
+
if self.is_stressed:
|
|
245
|
+
stress_p1_multiplier = 1.0 - 0.2 * self.stress_intensity
|
|
246
|
+
stress_p3_multiplier = 1.0 - 0.7 * self.stress_intensity
|
|
247
|
+
stress_Gb_multiplier = 1.0 + 0.5 * self.stress_intensity
|
|
248
|
+
|
|
249
|
+
# --- Illness / Cytokine Resistance ---
|
|
250
|
+
illness_Gb_multiplier = 1.0 + 0.8 * self.illness_severity if self.is_ill else 1.0
|
|
251
|
+
illness_p3_multiplier = 1.0 - 0.5 * self.illness_severity if self.is_ill else 1.0
|
|
252
|
+
|
|
253
|
+
# --- Menstrual Cycle Hormonal Drifts ---
|
|
254
|
+
cycle_p3_multiplier = 1.0
|
|
255
|
+
if self.menstrual_cycle_active:
|
|
256
|
+
# 28 days = 40320 minutes
|
|
257
|
+
cycle_time = (current_time - self.cycle_start_time_minutes) % 40320
|
|
258
|
+
# Sine wave peaking in resistance (lowest p3) around day 21 (luteal phase)
|
|
259
|
+
cycle_p3_multiplier = 1.0 - 0.25 * np.sin(2 * np.pi * cycle_time / 40320.0)
|
|
260
|
+
|
|
261
|
+
# --- Endogenous Rescue & HAAF ---
|
|
262
|
+
hypo_delta = max(0.0, 70.0 - G)
|
|
263
|
+
rescue_multiplier = 1.0 + (hypo_delta / 10.0) * (1.0 - HAAF)
|
|
264
|
+
|
|
265
|
+
# HAAF Memory Dynamics
|
|
266
|
+
k_haaf_build = 0.005
|
|
267
|
+
k_haaf_decay = 1.0 / (24 * 60)
|
|
268
|
+
dHAAF_dt = k_haaf_build * hypo_delta * (1.0 - HAAF) - k_haaf_decay * HAAF
|
|
269
|
+
|
|
270
|
+
# --- Beta-cell autoimmune decay ---
|
|
271
|
+
dBeta_dt = -self.autoimmune_aggressiveness * Beta
|
|
272
|
+
|
|
273
|
+
# --- FFA & Ketone Dynamics ---
|
|
274
|
+
l_0, l_1, k_f = 0.2, 0.23, 0.1
|
|
275
|
+
dF_dt = l_0 * np.exp(-l_1 * I) - k_f * F
|
|
276
|
+
|
|
277
|
+
k_0, k_1, k_2 = 0.125, 0.33, 0.05
|
|
278
|
+
dK_dt = k_0 * F * np.exp(-k_1 * I) - k_2 * K
|
|
279
|
+
|
|
280
|
+
# --- Lipotoxicity (Insulin Resistance via FFAs) ---
|
|
281
|
+
lipotoxicity_factor = 0.4 / max(0.4, F)
|
|
282
|
+
|
|
283
|
+
p1_eff = p.p1 * exercise_p1_multiplier * stress_p1_multiplier
|
|
284
|
+
# Total p3 is degraded by lipotoxicity, acute illness, and menstrual hormonal drifts
|
|
285
|
+
p3_eff = p.p3 * exercise_p3_multiplier * stress_p3_multiplier * lipotoxicity_factor * illness_p3_multiplier * cycle_p3_multiplier
|
|
286
|
+
|
|
287
|
+
starvation_factor = np.exp(-0.4 * I) * (max(F, 0.4) / 0.4)
|
|
288
|
+
hepatic_glucose_production_multiplier = 1.0 + 3.0 * starvation_factor
|
|
289
|
+
|
|
290
|
+
# Gb is multiplied by stress, rescue adrenaline, exogenous glucagon, hepatic starvation, circadian rhythms, and illness
|
|
291
|
+
Gb_eff = p.Gb * stress_Gb_multiplier * rescue_multiplier * max(0.0, 1.0 + x_gluc) * hepatic_glucose_production_multiplier * circadian_multiplier * illness_Gb_multiplier
|
|
292
|
+
|
|
293
|
+
# --- Physiological Renal Clearance ---
|
|
294
|
+
smooth_threshold_diff = G - 180.0
|
|
295
|
+
softplus_diff = 10.0 * np.log1p(np.exp(smooth_threshold_diff / 10.0))
|
|
296
|
+
RGC = 0.05 * softplus_diff
|
|
297
|
+
|
|
298
|
+
# --- dG/dt (INSTABILITY UPGRADE) ---
|
|
299
|
+
EGP = p1_eff * Gb_eff
|
|
300
|
+
dGdt = -X * G + EGP + Ra + Ra_prot - exercise_glucose_uptake - RGC
|
|
301
|
+
|
|
302
|
+
# --- dX/dt ---
|
|
303
|
+
dXdt = -p.p2 * X + p3_eff * max(I - p.Ib, 0.0)
|
|
304
|
+
|
|
305
|
+
# --- Cannula Degradation / Lipohypertrophy ---
|
|
306
|
+
# After 48 hours (2880 mins), absorption drops linearly by up to 30%
|
|
307
|
+
cannula_degradation_factor = 1.0 - 0.3 * min(1.0, max(0.0, (self.pump_cannula_age_minutes - 2880) / 2880.0))
|
|
308
|
+
ka_eff = p.k_a * cannula_degradation_factor
|
|
309
|
+
|
|
310
|
+
# --- dS1/dt, dS2/dt (Subcutaneous Insulin Absorption) ---
|
|
311
|
+
dS1dt = u_insulin_mu_per_min - ka_eff * S1
|
|
312
|
+
dS2dt = ka_eff * S1 - ka_eff * S2
|
|
313
|
+
|
|
314
|
+
# Rate of appearance of insulin into plasma (mU/min)
|
|
315
|
+
Ra_I = ka_eff * S2
|
|
316
|
+
|
|
317
|
+
# --- dI/dt (Including residual beta-cell endogenous secretion) ---
|
|
318
|
+
endogenous_secretion = Beta * self.gamma_healthy * max(G - p.h, 0.0)
|
|
319
|
+
target_Ib = p.Ib * Beta
|
|
320
|
+
|
|
321
|
+
dIdt = -p.n * (I - target_Ib) + endogenous_secretion + Ra_I / Vi_abs
|
|
322
|
+
|
|
323
|
+
# --- Dalla Man Multi-compartment Meal Kinetcs (Fat-Delayed) ---
|
|
324
|
+
# Fat massively delays gastric emptying.
|
|
325
|
+
fat_delay_factor = np.exp(-0.02 * Q_fat)
|
|
326
|
+
gastric_emptying_rate = (1.0 / max(float(p.tau_meal), 1.0)) * fat_delay_factor
|
|
327
|
+
solid_to_liquid_rate = gastric_emptying_rate * 1.5
|
|
328
|
+
dQ_sto1_dt = -solid_to_liquid_rate * Q_sto1
|
|
329
|
+
dQ_sto2_dt = solid_to_liquid_rate * Q_sto1 - gastric_emptying_rate * Q_sto2
|
|
330
|
+
dQ_gut_dt = gastric_emptying_rate * Q_sto2 - p.k_abs * Q_gut
|
|
331
|
+
|
|
332
|
+
return np.array([
|
|
333
|
+
dGdt, dXdt, dIdt, dQ_sto1_dt, dQ_sto2_dt, dQ_gut_dt,
|
|
334
|
+
dS1dt, dS2dt, dY1_dt, dY2_dt, dGamma_dt, dx_gluc_dt,
|
|
335
|
+
dHAAF_dt, dF_dt, dK_dt, dBeta_dt, dQ_fat_dt, dQ_prot_dt
|
|
336
|
+
])
|
{iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.15}/src/iints/core/patient/patient_factory.py
RENAMED
|
@@ -16,6 +16,14 @@ except Exception:
|
|
|
16
16
|
HovorkaPatientModel = None # type: ignore[assignment,misc]
|
|
17
17
|
HOVORKA_AVAILABLE = False
|
|
18
18
|
|
|
19
|
+
|
|
20
|
+
try:
|
|
21
|
+
from .advanced_metabolic_model import AdvancedMetabolicModel
|
|
22
|
+
ADVANCED_METABOLIC_AVAILABLE = True
|
|
23
|
+
except Exception:
|
|
24
|
+
AdvancedMetabolicModel = None # type: ignore[assignment,misc]
|
|
25
|
+
ADVANCED_METABOLIC_AVAILABLE = False
|
|
26
|
+
|
|
19
27
|
try:
|
|
20
28
|
from simglucose.simulation.env import T1DSimEnv
|
|
21
29
|
from simglucose.patient.t1dpatient import T1DPatient
|
|
@@ -55,6 +63,13 @@ class PatientFactory:
|
|
|
55
63
|
print("Warning: Bergman model not available, falling back to custom model")
|
|
56
64
|
return CustomPatientModel(initial_glucose=initial_glucose, **kwargs)
|
|
57
65
|
return BergmanPatientModel(initial_glucose=initial_glucose, **kwargs)
|
|
66
|
+
elif patient_type in {'advanced', 'advanced_metabolic'}:
|
|
67
|
+
if not ADVANCED_METABOLIC_AVAILABLE or AdvancedMetabolicModel is None:
|
|
68
|
+
print("Warning: Advanced metabolic model not available, falling back to bergman/custom model")
|
|
69
|
+
if BERGMAN_AVAILABLE and BergmanPatientModel is not None:
|
|
70
|
+
return BergmanPatientModel(initial_glucose=initial_glucose, **kwargs)
|
|
71
|
+
return CustomPatientModel(initial_glucose=initial_glucose, **kwargs)
|
|
72
|
+
return AdvancedMetabolicModel(initial_glucose=initial_glucose, **kwargs)
|
|
58
73
|
elif patient_type == 'hovorka':
|
|
59
74
|
if not HOVORKA_AVAILABLE or HovorkaPatientModel is None:
|
|
60
75
|
print("Warning: Hovorka model not available, falling back to custom model")
|
|
@@ -899,20 +899,32 @@ class Simulator:
|
|
|
899
899
|
self.add_stress_event(end_event)
|
|
900
900
|
elif event.event_type == 'exercise_end':
|
|
901
901
|
self.patient_model.stop_exercise()
|
|
902
|
-
elif event.event_type
|
|
902
|
+
elif event.event_type == 'stress':
|
|
903
903
|
start_stress = getattr(self.patient_model, 'start_stress', None)
|
|
904
904
|
if callable(start_stress):
|
|
905
905
|
start_stress(float(event.value or 0.0))
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
start_time=current_time + event.duration,
|
|
909
|
-
event_type=end_type,
|
|
910
|
-
)
|
|
911
|
-
self.add_stress_event(end_event)
|
|
912
|
-
elif event.event_type in {'stress_end', 'illness_end'}:
|
|
906
|
+
self.add_stress_event(StressEvent(start_time=current_time + event.duration, event_type='stress_end'))
|
|
907
|
+
elif event.event_type == 'stress_end':
|
|
913
908
|
stop_stress = getattr(self.patient_model, 'stop_stress', None)
|
|
914
909
|
if callable(stop_stress):
|
|
915
910
|
stop_stress()
|
|
911
|
+
elif event.event_type == 'illness':
|
|
912
|
+
start_illness = getattr(self.patient_model, 'start_illness', None)
|
|
913
|
+
if callable(start_illness):
|
|
914
|
+
start_illness(float(event.value or 0.0))
|
|
915
|
+
else:
|
|
916
|
+
start_stress = getattr(self.patient_model, 'start_stress', None)
|
|
917
|
+
if callable(start_stress):
|
|
918
|
+
start_stress(float(event.value or 0.0))
|
|
919
|
+
self.add_stress_event(StressEvent(start_time=current_time + event.duration, event_type='illness_end'))
|
|
920
|
+
elif event.event_type == 'illness_end':
|
|
921
|
+
stop_illness = getattr(self.patient_model, 'stop_illness', None)
|
|
922
|
+
if callable(stop_illness):
|
|
923
|
+
stop_illness()
|
|
924
|
+
else:
|
|
925
|
+
stop_stress = getattr(self.patient_model, 'stop_stress', None)
|
|
926
|
+
if callable(stop_stress):
|
|
927
|
+
stop_stress()
|
|
916
928
|
elif event.event_type == 'ratio_change':
|
|
917
929
|
duration = event.duration if event.duration > 0 else float("inf")
|
|
918
930
|
self._ratio_overrides.append(
|
|
@@ -166,11 +166,15 @@ class IndependentSupervisor:
|
|
|
166
166
|
safety_status = SafetyLevel.WARNING
|
|
167
167
|
actions_taken.append("WARNING: Hyperglycemia detected")
|
|
168
168
|
|
|
169
|
-
# 3.
|
|
169
|
+
# 3. Bifurcation Risk Threshold (Physics-based velocity vector)
|
|
170
170
|
glucose_rate = self._calculate_glucose_rate()
|
|
171
|
-
|
|
171
|
+
|
|
172
|
+
# Calculate 30-min trajectory without new insulin (pure momentum)
|
|
173
|
+
momentum_trajectory = current_glucose + (glucose_rate * 30.0)
|
|
174
|
+
|
|
175
|
+
if momentum_trajectory <= self.severe_hypoglycemia_threshold:
|
|
172
176
|
proposed_insulin = 0
|
|
173
|
-
actions_taken.append(f"
|
|
177
|
+
actions_taken.append(f"BIFURCATION_RISK: Momentum trajectory crosses {momentum_trajectory:.1f} mg/dL")
|
|
174
178
|
safety_status = self._max_level(safety_status, SafetyLevel.CRITICAL)
|
|
175
179
|
|
|
176
180
|
# 3b. Formal safety contract (logic validation)
|
|
@@ -187,10 +191,11 @@ class IndependentSupervisor:
|
|
|
187
191
|
)
|
|
188
192
|
safety_status = self._max_level(safety_status, SafetyLevel.CRITICAL)
|
|
189
193
|
|
|
190
|
-
# 4.
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
+
# 4. Pharmacodynamic (PD) Mass-Balance IOB Clearance
|
|
195
|
+
max_safe_bolus = max(0.0, self.max_iob - current_iob)
|
|
196
|
+
if proposed_insulin > max_safe_bolus:
|
|
197
|
+
proposed_insulin = max_safe_bolus
|
|
198
|
+
actions_taken.append(f"PD_CLEARANCE_LIMIT / High IOB: Active IOB {current_iob:.2f}U restricts max safe bolus to {max_safe_bolus:.2f}U")
|
|
194
199
|
safety_status = self._max_level(safety_status, SafetyLevel.WARNING)
|
|
195
200
|
|
|
196
201
|
# 5. Insulin Dose Limits
|
|
@@ -199,16 +204,14 @@ class IndependentSupervisor:
|
|
|
199
204
|
actions_taken.append(f"LIMIT: Bolus capped at {self.max_insulin_per_bolus}U")
|
|
200
205
|
safety_status = self._max_level(safety_status, SafetyLevel.WARNING)
|
|
201
206
|
|
|
202
|
-
# 6.
|
|
203
|
-
#
|
|
204
|
-
if current_iob >
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
actions_taken.append(f"CAUTION: High IOB ({current_iob:.2f}U) - insulin reduced to prevent stacking")
|
|
211
|
-
safety_status = self._max_level(safety_status, SafetyLevel.WARNING)
|
|
207
|
+
# 6. Scientific Stacking Prevention (Pharmacodynamic feedback)
|
|
208
|
+
# We modulate insulin based on an exponential decay curve against target glucose (100 mg/dL)
|
|
209
|
+
if current_iob > 0.5 and current_glucose < 160:
|
|
210
|
+
distance_to_target = max(0.0, current_glucose - 100.0)
|
|
211
|
+
pd_reduction_factor = np.exp(-distance_to_target / 50.0)
|
|
212
|
+
proposed_insulin *= (1.0 - pd_reduction_factor)
|
|
213
|
+
actions_taken.append(f"PD_STACKING_PREVENTION: Dose reduced by {pd_reduction_factor*100:.1f}% due to unabsorbed IOB ({current_iob:.2f}U)")
|
|
214
|
+
safety_status = self._max_level(safety_status, SafetyLevel.WARNING)
|
|
212
215
|
|
|
213
216
|
# 7. Glucose Rate of Change (legacy alarm)
|
|
214
217
|
if len(self.glucose_history) >= 2:
|