iints-sdk-python35 1.5.13__tar.gz → 1.5.14__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.
Files changed (296) hide show
  1. {iints_sdk_python35-1.5.13/src/iints_sdk_python35.egg-info → iints_sdk_python35-1.5.14}/PKG-INFO +1 -1
  2. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/pyproject.toml +1 -1
  3. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/__init__.py +1 -1
  4. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/algorithms/pid_controller.py +10 -2
  5. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/devices/models.py +22 -3
  6. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/patient/__init__.py +1 -1
  7. iints_sdk_python35-1.5.14/src/iints/core/patient/advanced_metabolic_model.py +331 -0
  8. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/patient/patient_factory.py +15 -0
  9. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/simulator.py +20 -8
  10. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/supervisor.py +20 -17
  11. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/realism_validator.py +25 -13
  12. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/tools/ai_realism_auditor.py +1 -1
  13. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14/src/iints_sdk_python35.egg-info}/PKG-INFO +1 -1
  14. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints_sdk_python35.egg-info/SOURCES.txt +1 -0
  15. iints_sdk_python35-1.5.14/tests/test_scientific_fidelity.py +97 -0
  16. iints_sdk_python35-1.5.13/src/iints/core/patient/advanced_metabolic_model.py +0 -226
  17. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/LICENSE +0 -0
  18. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/LICENSE-MIT-IINTS-LEGACY +0 -0
  19. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/NOTICE +0 -0
  20. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/README.md +0 -0
  21. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/setup.cfg +0 -0
  22. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/ai/__init__.py +0 -0
  23. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/ai/assistant.py +0 -0
  24. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/ai/backends/__init__.py +0 -0
  25. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/ai/backends/base.py +0 -0
  26. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/ai/backends/mistral_api.py +0 -0
  27. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/ai/backends/ollama.py +0 -0
  28. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/ai/cli.py +0 -0
  29. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/ai/mdmp_guard.py +0 -0
  30. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/ai/model_catalog.py +0 -0
  31. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/ai/prepare.py +0 -0
  32. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/ai/prompts.py +0 -0
  33. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/__init__.py +0 -0
  34. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/algorithm_xray.py +0 -0
  35. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/baseline.py +0 -0
  36. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/booth_demo.py +0 -0
  37. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/carelink_workbench.py +0 -0
  38. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/clinical_benchmark.py +0 -0
  39. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/clinical_metrics.py +0 -0
  40. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/clinical_tir_analyzer.py +0 -0
  41. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/diabetes_metrics.py +0 -0
  42. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/edge_efficiency.py +0 -0
  43. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/edge_performance_monitor.py +0 -0
  44. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/eucys_results.py +0 -0
  45. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/evidence_bundle.py +0 -0
  46. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/explainability.py +0 -0
  47. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/explainable_ai.py +0 -0
  48. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/hardware_benchmark.py +0 -0
  49. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/metrics.py +0 -0
  50. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/population_report.py +0 -0
  51. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/poster.py +0 -0
  52. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/reporting.py +0 -0
  53. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/run_quality.py +0 -0
  54. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/safety_index.py +0 -0
  55. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/safety_visualizer.py +0 -0
  56. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/sensor_filtering.py +0 -0
  57. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/study_analysis.py +0 -0
  58. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/study_engine.py +0 -0
  59. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/study_experiment.py +0 -0
  60. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/study_poster.py +0 -0
  61. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/study_protocol.py +0 -0
  62. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/analysis/validator.py +0 -0
  63. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/api/__init__.py +0 -0
  64. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/api/base_algorithm.py +0 -0
  65. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/api/registry.py +0 -0
  66. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/api/template_algorithm.py +0 -0
  67. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/assets/iints_logo.png +0 -0
  68. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/cli/__init__.py +0 -0
  69. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/cli/cli.py +0 -0
  70. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/cli/patient_cli.py +0 -0
  71. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/__init__.py +0 -0
  72. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/algorithms/__init__.py +0 -0
  73. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/algorithms/battle_runner.py +0 -0
  74. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/algorithms/clinical_baseline.py +0 -0
  75. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/algorithms/correction_bolus.py +0 -0
  76. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/algorithms/discovery.py +0 -0
  77. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/algorithms/fixed_basal_bolus.py +0 -0
  78. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/algorithms/hybrid_algorithm.py +0 -0
  79. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/algorithms/imitation_controller.py +0 -0
  80. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/algorithms/lstm_algorithm.py +0 -0
  81. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/algorithms/mock_algorithms.py +0 -0
  82. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/algorithms/mpc_controller.py +0 -0
  83. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/algorithms/neural_controller.py +0 -0
  84. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/algorithms/standard_pump_algo.py +0 -0
  85. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/device.py +0 -0
  86. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/device_manager.py +0 -0
  87. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/devices/__init__.py +0 -0
  88. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/digital_twin.py +0 -0
  89. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/patient/bergman_model.py +0 -0
  90. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/patient/hovorka_model.py +0 -0
  91. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/patient/models.py +0 -0
  92. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/patient/profile.py +0 -0
  93. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/physiology_variation.py +0 -0
  94. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/safety/__init__.py +0 -0
  95. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/safety/config.py +0 -0
  96. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/safety/input_validator.py +0 -0
  97. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/safety/supervisor.py +0 -0
  98. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/simulation/__init__.py +0 -0
  99. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/core/simulation/scenario_parser.py +0 -0
  100. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/__init__.py +0 -0
  101. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/adapter.py +0 -0
  102. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/certify.py +0 -0
  103. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/column_mapper.py +0 -0
  104. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/contracts.py +0 -0
  105. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/datasets.json +0 -0
  106. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/demo/__init__.py +0 -0
  107. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/demo/demo_cgm.csv +0 -0
  108. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/evidence.py +0 -0
  109. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/guardians.py +0 -0
  110. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/importer.py +0 -0
  111. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/ingestor.py +0 -0
  112. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/mdmp_visualizer.py +0 -0
  113. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/medtronic_live.py +0 -0
  114. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/nightscout.py +0 -0
  115. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/physiology_residual_profiles.json +0 -0
  116. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/quality_checker.py +0 -0
  117. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/realism_dashboard.py +0 -0
  118. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/realism_governance.py +0 -0
  119. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/realism_reference.py +0 -0
  120. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/realism_references.json +0 -0
  121. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/registry.py +0 -0
  122. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/research_catalog.py +0 -0
  123. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/runner.py +0 -0
  124. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/study_corruption.py +0 -0
  125. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/synthetic_mirror.py +0 -0
  126. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/tidepool.py +0 -0
  127. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/universal_parser.py +0 -0
  128. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/virtual_patients/clinic_safe_baseline.yaml +0 -0
  129. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/virtual_patients/clinic_safe_hyper_challenge.yaml +0 -0
  130. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/virtual_patients/clinic_safe_hypo_prone.yaml +0 -0
  131. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/virtual_patients/clinic_safe_midnight.yaml +0 -0
  132. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/virtual_patients/clinic_safe_pizza.yaml +0 -0
  133. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/virtual_patients/clinic_safe_stress_meal.yaml +0 -0
  134. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/virtual_patients/default_patient.yaml +0 -0
  135. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/virtual_patients/patient_559_config.yaml +0 -0
  136. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/virtual_patients/reference_azt1d_t1d.yaml +0 -0
  137. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/virtual_patients/reference_free_living_t1d.yaml +0 -0
  138. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/data/virtual_patients/reference_hupa_ucm_t1d.yaml +0 -0
  139. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/demo_assets.py +0 -0
  140. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/emulation/__init__.py +0 -0
  141. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/emulation/legacy_base.py +0 -0
  142. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/emulation/medtronic_780g.py +0 -0
  143. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/emulation/omnipod_5.py +0 -0
  144. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/emulation/tandem_controliq.py +0 -0
  145. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/highlevel.py +0 -0
  146. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/jetson/__init__.py +0 -0
  147. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/jetson/endurance.py +0 -0
  148. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/jetson/research_pipeline.py +0 -0
  149. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/learning/__init__.py +0 -0
  150. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/learning/autonomous_optimizer.py +0 -0
  151. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/learning/learning_system.py +0 -0
  152. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/live_patient/__init__.py +0 -0
  153. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/live_patient/api.py +0 -0
  154. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/live_patient/daemon.py +0 -0
  155. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/live_patient/edge_benchmark.py +0 -0
  156. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/live_patient/edge_ops.py +0 -0
  157. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/live_patient/fpga.py +0 -0
  158. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/live_patient/long_study.py +0 -0
  159. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/live_patient/medtronic_direct.py +0 -0
  160. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/live_patient/pico_pump.py +0 -0
  161. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/live_patient/runtime.py +0 -0
  162. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/live_patient/service_export.py +0 -0
  163. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/live_patient/uno_q.py +0 -0
  164. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/mdmp/__init__.py +0 -0
  165. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/mdmp/backend.py +0 -0
  166. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/mdmp/eu_ai_pact.py +0 -0
  167. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/metrics.py +0 -0
  168. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/population/__init__.py +0 -0
  169. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/population/generator.py +0 -0
  170. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/population/runner.py +0 -0
  171. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/presets/__init__.py +0 -0
  172. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/presets/evidence_sources.yaml +0 -0
  173. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/presets/forecast_calibration_profiles.yaml +0 -0
  174. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/presets/golden_benchmark.yaml +0 -0
  175. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/presets/presets.json +0 -0
  176. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/presets/safety_contract_default.yaml +0 -0
  177. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/presets/validation_profiles.yaml +0 -0
  178. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/research/__init__.py +0 -0
  179. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/research/audit.py +0 -0
  180. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/research/calibration_gate.py +0 -0
  181. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/research/config.py +0 -0
  182. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/research/control.py +0 -0
  183. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/research/control_eval.py +0 -0
  184. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/research/data_blend.py +0 -0
  185. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/research/dataset.py +0 -0
  186. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/research/evaluation.py +0 -0
  187. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/research/forecasting.py +0 -0
  188. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/research/glucose_model.py +0 -0
  189. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/research/local_ai.py +0 -0
  190. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/research/local_ai_gate.py +0 -0
  191. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/research/losses.py +0 -0
  192. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/research/metrics.py +0 -0
  193. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/research/model_registry.py +0 -0
  194. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/research/neural_control.py +0 -0
  195. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/research/predictor.py +0 -0
  196. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/research/results_manager.py +0 -0
  197. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/scenarios/__init__.py +0 -0
  198. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/scenarios/generator.py +0 -0
  199. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/scenarios/study_pack.py +0 -0
  200. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/templates/__init__.py +0 -0
  201. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/templates/default_algorithm.py +0 -0
  202. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/templates/demos/__init__.py +0 -0
  203. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/templates/demos/live_stage_demo.py +0 -0
  204. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/templates/pico_pump/README.md +0 -0
  205. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/templates/pico_pump/code.py +0 -0
  206. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/templates/pico_pump/serial_protocol.txt +0 -0
  207. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/templates/scenarios/__init__.py +0 -0
  208. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/templates/scenarios/chaos_insulin_stacking.json +0 -0
  209. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/templates/scenarios/chaos_runaway_ai.json +0 -0
  210. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/templates/scenarios/example_scenario.json +0 -0
  211. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/templates/scenarios/exercise_stress.json +0 -0
  212. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/templates/uno_q/README.md +0 -0
  213. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/templates/uno_q/iints_supervisor_bridge.ino +0 -0
  214. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/tools/digital_twin_calibrator.py +0 -0
  215. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/utils/__init__.py +0 -0
  216. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/utils/csv_safety.py +0 -0
  217. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/utils/plotting.py +0 -0
  218. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/utils/run_io.py +0 -0
  219. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/utils/url_safety.py +0 -0
  220. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/validation/__init__.py +0 -0
  221. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/validation/golden.py +0 -0
  222. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/validation/replay.py +0 -0
  223. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/validation/run_doctor.py +0 -0
  224. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/validation/run_validation.py +0 -0
  225. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/validation/safety_contract.py +0 -0
  226. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/validation/schemas.py +0 -0
  227. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/visualization/__init__.py +0 -0
  228. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/visualization/cockpit.py +0 -0
  229. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints/visualization/uncertainty_cloud.py +0 -0
  230. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints_sdk_python35.egg-info/dependency_links.txt +0 -0
  231. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints_sdk_python35.egg-info/entry_points.txt +0 -0
  232. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints_sdk_python35.egg-info/requires.txt +0 -0
  233. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/iints_sdk_python35.egg-info/top_level.txt +0 -0
  234. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_ai/__init__.py +0 -0
  235. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_ai/lineage.py +0 -0
  236. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/__init__.py +0 -0
  237. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/audit.py +0 -0
  238. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/bias_hooks.py +0 -0
  239. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/bundle.py +0 -0
  240. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/certification.py +0 -0
  241. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/cli.py +0 -0
  242. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/compare.py +0 -0
  243. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/conformance.py +0 -0
  244. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/contracts.py +0 -0
  245. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/crypto.py +0 -0
  246. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/data/conformance/vectors/delegation.json +0 -0
  247. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/data/conformance/vectors/fingerprint.json +0 -0
  248. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/data/conformance/vectors/grading.json +0 -0
  249. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/data/conformance/vectors/signing.json +0 -0
  250. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/delegate.py +0 -0
  251. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/diffing.py +0 -0
  252. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/drift.py +0 -0
  253. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/exceptions.py +0 -0
  254. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/fingerprint.py +0 -0
  255. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/fingerprint_store.py +0 -0
  256. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/hf.py +0 -0
  257. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/keys/mdmp_pub_v1.pem +0 -0
  258. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/llm_provenance.py +0 -0
  259. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/migrate.py +0 -0
  260. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/policy.py +0 -0
  261. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/prov.py +0 -0
  262. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/registry.py +0 -0
  263. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/runner.py +0 -0
  264. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/schema_export.py +0 -0
  265. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/synthetic.py +0 -0
  266. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/trust.py +0 -0
  267. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_core/visualizer.py +0 -0
  268. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_flavors/__init__.py +0 -0
  269. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_integrations/__init__.py +0 -0
  270. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_integrations/dvc.py +0 -0
  271. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_integrations/mlflow.py +0 -0
  272. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/src/mdmp_integrations/wandb.py +0 -0
  273. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_bergman.py +0 -0
  274. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_ci_governance.py +0 -0
  275. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_cli_algorithm_loading.py +0 -0
  276. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_cli_booth_demo.py +0 -0
  277. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_cli_carelink_workbench.py +0 -0
  278. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_cli_cloud_import_security.py +0 -0
  279. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_cli_demo_export.py +0 -0
  280. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_cli_demo_live.py +0 -0
  281. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_cli_edge_runtime.py +0 -0
  282. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_cli_expo_tools.py +0 -0
  283. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_cli_fpga.py +0 -0
  284. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_cli_onboarding.py +0 -0
  285. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_cli_patient_runtime.py +0 -0
  286. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_cli_poster.py +0 -0
  287. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_cli_research_workflows.py +0 -0
  288. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_cli_run_summary.py +0 -0
  289. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_install_doctor.py +0 -0
  290. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_jetson_endurance.py +0 -0
  291. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_physiology_variation.py +0 -0
  292. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_plugin_system.py +0 -0
  293. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_population.py +0 -0
  294. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_presets_realism.py +0 -0
  295. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_research_realism_tools.py +0 -0
  296. {iints_sdk_python35-1.5.13 → iints_sdk_python35-1.5.14}/tests/test_simulator_calibration.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iints-sdk-python35
3
- Version: 1.5.13
3
+ Version: 1.5.14
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
  License-Expression: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "iints-sdk-python35"
7
- version = "1.5.13"
7
+ version = "1.5.14"
8
8
  authors = [
9
9
  { name="Rune Bobbaers", email="rune.bobbaers@gmail.com" },
10
10
  ]
@@ -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.13"
14
+ __version__ = "1.5.14"
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.
@@ -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
- proposed_integral = max(-self.integral_limit, min(self.integral + error, self.integral_limit))
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
- delivered = round(delivered / self.quantization_units) * self.quantization_units
397
-
398
- if self.delivery_noise_std > 0:
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,331 @@
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,
112
+ delivered_insulin: float = 0.0,
113
+ carb_intake: float = 0.0,
114
+ delivered_glucagon_mg: float = 0.0,
115
+ fat_intake: float = 0.0,
116
+ protein_intake: float = 0.0,
117
+ current_time: Optional[float] = None,
118
+ **kwargs: Any,
119
+ ) -> float:
120
+ """Advance the 18-state metabolic model by ``time_step`` minutes.
121
+
122
+ Backward-compatible aliases are accepted for earlier scratch scripts:
123
+ ``dt_minutes``, ``delivered_glucagon``, and ``current_time_minutes``.
124
+ """
125
+ if "dt_minutes" in kwargs:
126
+ time_step = float(kwargs.pop("dt_minutes"))
127
+ if "delivered_glucagon" in kwargs:
128
+ delivered_glucagon_mg = float(kwargs.pop("delivered_glucagon"))
129
+ if "current_time_minutes" in kwargs:
130
+ current_time = float(kwargs.pop("current_time_minutes"))
131
+
132
+ # Add macronutrients and age the cannula before solving this step.
133
+ self._state[16] += max(0.0, float(fat_intake))
134
+ self._state[17] += max(0.0, float(protein_intake))
135
+ self.pump_cannula_age_minutes += max(0.0, float(time_step))
136
+
137
+ return super().update(
138
+ time_step=time_step,
139
+ delivered_insulin=delivered_insulin,
140
+ carb_intake=carb_intake,
141
+ delivered_glucagon_mg=delivered_glucagon_mg,
142
+ current_time=current_time,
143
+ )
144
+
145
+ def start_illness(self, severity: float) -> None:
146
+ self.is_ill = True
147
+ self.illness_severity = float(np.clip(severity, 0.0, 1.0))
148
+
149
+ def stop_illness(self) -> None:
150
+ self.is_ill = False
151
+ self.illness_severity = 0.0
152
+
153
+ def start_menstrual_cycle(self, current_time_minutes: float = 0.0) -> None:
154
+ self.menstrual_cycle_active = True
155
+ self.cycle_start_time_minutes = float(current_time_minutes)
156
+
157
+ def stop_menstrual_cycle(self) -> None:
158
+ self.menstrual_cycle_active = False
159
+
160
+ def trigger_event(self, event_type: str, value: Any) -> None:
161
+ if event_type == "illness":
162
+ self.start_illness(float(value))
163
+ elif event_type == "illness_end":
164
+ self.stop_illness()
165
+ elif event_type == "menstrual_cycle":
166
+ self.start_menstrual_cycle(float(value or 0.0))
167
+ elif event_type == "menstrual_cycle_end":
168
+ self.stop_menstrual_cycle()
169
+ else:
170
+ super().trigger_event(event_type, value)
171
+
172
+ def get_state(self) -> Dict[str, Any]:
173
+ state = super().get_state()
174
+ state.update({
175
+ "is_ill": self.is_ill,
176
+ "illness_severity": self.illness_severity,
177
+ "menstrual_cycle_active": self.menstrual_cycle_active,
178
+ "cycle_start_time_minutes": self.cycle_start_time_minutes,
179
+ "pump_cannula_age_minutes": self.pump_cannula_age_minutes,
180
+ })
181
+ return state
182
+
183
+ def _ode(
184
+ self,
185
+ t: float,
186
+ y: np.ndarray,
187
+ u_insulin_mu_per_min: float,
188
+ u_glucagon_pg_per_min: float,
189
+ current_time: float,
190
+ ) -> np.ndarray:
191
+ # Unpack 18 states
192
+ 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
193
+ p = self.params
194
+
195
+ Vg_abs = p.Vg * p.body_weight_kg # dL
196
+ Vi_abs = p.Vi * p.body_weight_kg # L
197
+ V_glucagon = p.V_glucagon_per_kg * p.body_weight_kg
198
+
199
+ # --- Fat & Protein Macronutrient Kinetics ---
200
+ # Fat decays very slowly, Half-life ~4 hours
201
+ k_fat = 1.0 / 240.0
202
+ dQ_fat_dt = -k_fat * Q_fat
203
+
204
+ # Protein decays very slowly, Half-life ~5 hours
205
+ k_prot = 1.0 / 300.0
206
+ dQ_prot_dt = -k_prot * Q_prot
207
+
208
+ # Protein Gluconeogenesis: ~50% of protein becomes glucose very slowly.
209
+ # R_a_prot adds to EGP. (Convert grams to mg, divide by Vg_abs to get mg/dL/min)
210
+ Ra_prot = 0.5 * k_prot * Q_prot * 1000.0 / Vg_abs
211
+
212
+ # --- Glucose rate of appearance from gut ---
213
+ Ra = (p.k_abs * Q_gut) / Vg_abs # mg/dL/min
214
+
215
+ # --- Exogenous Glucagon Kinetics ---
216
+ dY1_dt = u_glucagon_pg_per_min - Y1 / p.t_max_glucagon
217
+ dY2_dt = Y1 / p.t_max_glucagon - Y2 / p.t_max_glucagon
218
+ U_Gamma = Y2 / p.t_max_glucagon
219
+ dGamma_dt = U_Gamma / V_glucagon - p.k_e_glucagon * Gamma
220
+ dx_gluc_dt = -p.k_a_glucagon * x_gluc + p.S_glucagon * p.k_a_glucagon * Gamma
221
+
222
+ # --- Circadian Rhythms & Dawn Phenomenon ---
223
+ t_hours = (current_time / 60.0) % 24
224
+ A_circadian = 0.2 if self.dawn_phenomenon_strength > 0 else 0.0
225
+ circadian_multiplier = 1.0 + A_circadian * np.cos((2 * np.pi / 24) * (t_hours - 5.0))
226
+
227
+ # --- Exercise & Stress Physiologic Impact ---
228
+ exercise_p1_multiplier = 1.0
229
+ exercise_p3_multiplier = 1.0
230
+ exercise_glucose_uptake = 0.0
231
+ if self.is_exercising:
232
+ exercise_p1_multiplier = 1.0 + 2.0 * self.exercise_intensity
233
+ exercise_p3_multiplier = 1.0 + 2.0 * self.exercise_intensity
234
+ exercise_glucose_uptake = self.exercise_intensity * 0.005 * G
235
+
236
+ stress_p1_multiplier = 1.0
237
+ stress_p3_multiplier = 1.0
238
+ stress_Gb_multiplier = 1.0
239
+ if self.is_stressed:
240
+ stress_p1_multiplier = 1.0 - 0.2 * self.stress_intensity
241
+ stress_p3_multiplier = 1.0 - 0.7 * self.stress_intensity
242
+ stress_Gb_multiplier = 1.0 + 0.5 * self.stress_intensity
243
+
244
+ # --- Illness / Cytokine Resistance ---
245
+ illness_Gb_multiplier = 1.0 + 0.8 * self.illness_severity if self.is_ill else 1.0
246
+ illness_p3_multiplier = 1.0 - 0.5 * self.illness_severity if self.is_ill else 1.0
247
+
248
+ # --- Menstrual Cycle Hormonal Drifts ---
249
+ cycle_p3_multiplier = 1.0
250
+ if self.menstrual_cycle_active:
251
+ # 28 days = 40320 minutes
252
+ cycle_time = (current_time - self.cycle_start_time_minutes) % 40320
253
+ # Sine wave peaking in resistance (lowest p3) around day 21 (luteal phase)
254
+ cycle_p3_multiplier = 1.0 - 0.25 * np.sin(2 * np.pi * cycle_time / 40320.0)
255
+
256
+ # --- Endogenous Rescue & HAAF ---
257
+ hypo_delta = max(0.0, 70.0 - G)
258
+ rescue_multiplier = 1.0 + (hypo_delta / 10.0) * (1.0 - HAAF)
259
+
260
+ # HAAF Memory Dynamics
261
+ k_haaf_build = 0.005
262
+ k_haaf_decay = 1.0 / (24 * 60)
263
+ dHAAF_dt = k_haaf_build * hypo_delta * (1.0 - HAAF) - k_haaf_decay * HAAF
264
+
265
+ # --- Beta-cell autoimmune decay ---
266
+ dBeta_dt = -self.autoimmune_aggressiveness * Beta
267
+
268
+ # --- FFA & Ketone Dynamics ---
269
+ l_0, l_1, k_f = 0.2, 0.23, 0.1
270
+ dF_dt = l_0 * np.exp(-l_1 * I) - k_f * F
271
+
272
+ k_0, k_1, k_2 = 0.125, 0.33, 0.05
273
+ dK_dt = k_0 * F * np.exp(-k_1 * I) - k_2 * K
274
+
275
+ # --- Lipotoxicity (Insulin Resistance via FFAs) ---
276
+ lipotoxicity_factor = 0.4 / max(0.4, F)
277
+
278
+ p1_eff = p.p1 * exercise_p1_multiplier * stress_p1_multiplier
279
+ # Total p3 is degraded by lipotoxicity, acute illness, and menstrual hormonal drifts
280
+ p3_eff = p.p3 * exercise_p3_multiplier * stress_p3_multiplier * lipotoxicity_factor * illness_p3_multiplier * cycle_p3_multiplier
281
+
282
+ starvation_factor = np.exp(-0.4 * I) * (max(F, 0.4) / 0.4)
283
+ hepatic_glucose_production_multiplier = 1.0 + 3.0 * starvation_factor
284
+
285
+ # Gb is multiplied by stress, rescue adrenaline, exogenous glucagon, hepatic starvation, circadian rhythms, and illness
286
+ 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
287
+
288
+ # --- Physiological Renal Clearance ---
289
+ smooth_threshold_diff = G - 180.0
290
+ softplus_diff = 10.0 * np.log1p(np.exp(smooth_threshold_diff / 10.0))
291
+ RGC = 0.05 * softplus_diff
292
+
293
+ # --- dG/dt (INSTABILITY UPGRADE) ---
294
+ EGP = p1_eff * Gb_eff
295
+ dGdt = -X * G + EGP + Ra + Ra_prot - exercise_glucose_uptake - RGC
296
+
297
+ # --- dX/dt ---
298
+ dXdt = -p.p2 * X + p3_eff * max(I - p.Ib, 0.0)
299
+
300
+ # --- Cannula Degradation / Lipohypertrophy ---
301
+ # After 48 hours (2880 mins), absorption drops linearly by up to 30%
302
+ cannula_degradation_factor = 1.0 - 0.3 * min(1.0, max(0.0, (self.pump_cannula_age_minutes - 2880) / 2880.0))
303
+ ka_eff = p.k_a * cannula_degradation_factor
304
+
305
+ # --- dS1/dt, dS2/dt (Subcutaneous Insulin Absorption) ---
306
+ dS1dt = u_insulin_mu_per_min - ka_eff * S1
307
+ dS2dt = ka_eff * S1 - ka_eff * S2
308
+
309
+ # Rate of appearance of insulin into plasma (mU/min)
310
+ Ra_I = ka_eff * S2
311
+
312
+ # --- dI/dt (Including residual beta-cell endogenous secretion) ---
313
+ endogenous_secretion = Beta * self.gamma_healthy * max(G - p.h, 0.0)
314
+ target_Ib = p.Ib * Beta
315
+
316
+ dIdt = -p.n * (I - target_Ib) + endogenous_secretion + Ra_I / Vi_abs
317
+
318
+ # --- Dalla Man Multi-compartment Meal Kinetcs (Fat-Delayed) ---
319
+ # Fat massively delays gastric emptying.
320
+ fat_delay_factor = np.exp(-0.02 * Q_fat)
321
+ gastric_emptying_rate = (1.0 / max(float(p.tau_meal), 1.0)) * fat_delay_factor
322
+ solid_to_liquid_rate = gastric_emptying_rate * 1.5
323
+ dQ_sto1_dt = -solid_to_liquid_rate * Q_sto1
324
+ dQ_sto2_dt = solid_to_liquid_rate * Q_sto1 - gastric_emptying_rate * Q_sto2
325
+ dQ_gut_dt = gastric_emptying_rate * Q_sto2 - p.k_abs * Q_gut
326
+
327
+ return np.array([
328
+ dGdt, dXdt, dIdt, dQ_sto1_dt, dQ_sto2_dt, dQ_gut_dt,
329
+ dS1dt, dS2dt, dY1_dt, dY2_dt, dGamma_dt, dx_gluc_dt,
330
+ dHAAF_dt, dF_dt, dK_dt, dBeta_dt, dQ_fat_dt, dQ_prot_dt
331
+ ])
@@ -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 in {'stress', 'illness'}:
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
- end_type = f"{event.event_type}_end"
907
- end_event = StressEvent(
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. Rate-of-Change Protection (fast drop)
169
+ # 3. Bifurcation Risk Threshold (Physics-based velocity vector)
170
170
  glucose_rate = self._calculate_glucose_rate()
171
- if glucose_rate <= self.trend_stop:
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"NEGATIVE_TREND_LIMIT: Glucose dropping at {glucose_rate:.2f} mg/dL/min")
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. Dynamic IOB Clamp
191
- if current_iob >= self.max_iob:
192
- proposed_insulin = 0
193
- actions_taken.append(f"MAX_IOB_REACHED: IOB {current_iob:.2f}U exceeds {self.max_iob:.2f}U")
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. Insulin Stacking Check (using IOB)
203
- # If IOB is high, be more conservative with additional insulin.
204
- if current_iob > self.max_insulin_per_bolus: # Use max_bolus as proxy for "high IOB"
205
- if current_glucose < 150: # Don't stack if not significantly high
206
- reduction_factor = max(0.0, (150 - current_glucose) / 100.0) # Reduce more aggressively closer to 100
207
- if reduction_factor > 1.0:
208
- reduction_factor = 1.0
209
- proposed_insulin *= (1 - reduction_factor)
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: