Feat: Implement interconnected organ simulation
This commit refactors the organ simulation to enable dynamic interactions between organs, replacing the previous "faked" or hardcoded connections.
Key changes include:
- Major Refactoring: Changed the `Organ::update` method signature to `update(Patient& patient, double deltaTime_s)`, allowing organs to access the shared patient state and other organs. This was propagated to all organ classes.
- Blood Chemistry Model: Introduced a central `Blood` struct in the `Patient` model to track shared resources like oxygen, CO2, glucose, and toxins.
- Organ System Interconnections:
- Lungs & Brain: Lungs now perform gas exchange affecting the blood. The brain consumes O2, produces CO2, and its GCS is affected by hypoxia/hypercapnia.
- Liver-Gallbladder: Gallbladder now receives bile directly from the liver's production rate.
- Digestive System: Stomach passes chyme to the intestines, which absorb glucose into the blood. The pancreas responds to blood glucose changes.
- Renal System: Kidneys' GFR is now influenced by the heart's aortic pressure, and they produce urine that fills the bladder directly.
- Cardiovascular & Neurological: The heart rate responds to hypoxia, and the brain uses live aortic pressure from the heart.
- Comprehensive Test Scenario: Updated the main example to include a 60-second simulation with a meal and a lung injury event to verify the new interconnected system.
This creates a more realistic and scalable physiological simulation framework where organ behaviors are emergent from their interactions.
This commit is contained in:
+2
-8
@@ -1,4 +1,5 @@
|
||||
#include "MedicalLib/Bladder.h"
|
||||
#include "MedicalLib/Patient.h"
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
@@ -11,14 +12,7 @@ Bladder::Bladder(int id)
|
||||
pressure_cmH2O(5.0),
|
||||
internalSphincterClosed(true) {}
|
||||
|
||||
void Bladder::update(double deltaTime_s) {
|
||||
// In a connected model, this would be called by the Kidneys.
|
||||
// For now, simulate a constant fill rate from the kidneys.
|
||||
const double urineInflow_ml_per_s = 0.02;
|
||||
if (currentState != MicturitionState::VOIDING) {
|
||||
addUrine(urineInflow_ml_per_s * deltaTime_s);
|
||||
}
|
||||
|
||||
void Bladder::update(Patient& patient, double deltaTime_s) {
|
||||
// Simple pressure model: pressure increases with volume
|
||||
pressure_cmH2O = (currentVolume_mL / capacity_mL) * 60.0;
|
||||
|
||||
|
||||
+48
-8
@@ -1,4 +1,6 @@
|
||||
#include "MedicalLib/Brain.h"
|
||||
#include "MedicalLib/Patient.h" // For Blood struct
|
||||
#include "MedicalLib/Heart.h" // For Heart data
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
@@ -29,13 +31,17 @@ Brain::Brain(int id)
|
||||
cerebellum = {"Cerebellum", 0.6, 60.0};
|
||||
}
|
||||
|
||||
void Brain::update(double deltaTime_s) {
|
||||
void Brain::update(Patient& patient, double deltaTime_s) {
|
||||
totalTime_s += deltaTime_s;
|
||||
|
||||
// In a real scenario, MAP would be provided by the circulatory system (Heart)
|
||||
// For now, we'll just keep it stable with minor fluctuations.
|
||||
meanArterialPressure_mmHg += getFluctuation(0.1);
|
||||
meanArterialPressure_mmHg = std::clamp(meanArterialPressure_mmHg, 85.0, 95.0);
|
||||
// Get Mean Arterial Pressure from the Heart
|
||||
if (const Heart* heart = getOrgan<Heart>(patient)) {
|
||||
meanArterialPressure_mmHg = heart->getAorticPressure();
|
||||
} else {
|
||||
// If no heart, use a default stable value
|
||||
meanArterialPressure_mmHg += getFluctuation(0.1);
|
||||
meanArterialPressure_mmHg = std::clamp(meanArterialPressure_mmHg, 85.0, 95.0);
|
||||
}
|
||||
|
||||
updateActivity(deltaTime_s);
|
||||
updatePressures(meanArterialPressure_mmHg);
|
||||
@@ -45,6 +51,37 @@ void Brain::update(double deltaTime_s) {
|
||||
if (eegData.size() > eegHistorySize) {
|
||||
eegData.pop_back();
|
||||
}
|
||||
|
||||
// --- Blood Interaction ---
|
||||
Blood& blood = patient.blood;
|
||||
// Brain consumes O2 and produces CO2. Rate depends on activity.
|
||||
double totalActivity = (frontalLobe.activityLevel + temporalLobe.activityLevel +
|
||||
parietalLobe.activityLevel + occipitalLobe.activityLevel +
|
||||
cerebellum.activityLevel) / 5.0;
|
||||
|
||||
// O2 consumption
|
||||
double o2_consumption = 0.1 * totalActivity * deltaTime_s; // % per second
|
||||
blood.oxygenSaturation -= o2_consumption;
|
||||
|
||||
// CO2 production
|
||||
double co2_production = 0.08 * totalActivity * deltaTime_s; // mmHg per second
|
||||
blood.co2PartialPressure_mmHg += co2_production;
|
||||
|
||||
// Update GCS based on blood gas levels
|
||||
if (blood.oxygenSaturation < 85.0) {
|
||||
gcsScore = 10;
|
||||
} else if (blood.oxygenSaturation < 75.0) {
|
||||
gcsScore = 6;
|
||||
} else {
|
||||
gcsScore = 15;
|
||||
}
|
||||
|
||||
if (blood.co2PartialPressure_mmHg > 60.0) {
|
||||
gcsScore = std::min(gcsScore, 12); // CO2 narcosis
|
||||
}
|
||||
if (blood.co2PartialPressure_mmHg > 80.0) {
|
||||
gcsScore = std::min(gcsScore, 8);
|
||||
}
|
||||
}
|
||||
|
||||
void Brain::updateActivity(double deltaTime_s) {
|
||||
@@ -52,9 +89,12 @@ void Brain::updateActivity(double deltaTime_s) {
|
||||
frontalLobe.activityLevel += getFluctuation(0.005);
|
||||
frontalLobe.activityLevel = std::clamp(frontalLobe.activityLevel, 0.7, 0.9);
|
||||
|
||||
// GCS is a clinical score, doesn't typically change second-to-second.
|
||||
// This is a placeholder for future, more complex pathology simulation.
|
||||
gcsScore = 15;
|
||||
// GCS is a clinical score, doesn't typically change second-to-second,
|
||||
// but it will be affected by severe hypoxia or hypercapnia.
|
||||
// This is a simplified model.
|
||||
if (gcsScore > 8) { // Only check if not already severely impaired
|
||||
if (cerebralPerfusionPressure_mmHg < 50) gcsScore = 8; // Reduced perfusion
|
||||
}
|
||||
}
|
||||
|
||||
void Brain::updatePressures(double meanArterialPressure) {
|
||||
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
#include "MedicalLib/Esophagus.h"
|
||||
#include "MedicalLib/Patient.h"
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
@@ -9,7 +10,7 @@ Esophagus::Esophagus(int id)
|
||||
currentState(PeristalsisState::IDLE),
|
||||
lowerEsophagealSphincterTone(20.0) {}
|
||||
|
||||
void Esophagus::update(double deltaTime_s) {
|
||||
void Esophagus::update(Patient& patient, double deltaTime_s) {
|
||||
// Simulate a swallow every 15 seconds for demonstration
|
||||
static double timeSinceLastSwallow = 0.0;
|
||||
timeSinceLastSwallow += deltaTime_s;
|
||||
|
||||
+10
-5
@@ -1,4 +1,6 @@
|
||||
#include "MedicalLib/Gallbladder.h"
|
||||
#include "MedicalLib/Patient.h"
|
||||
#include "MedicalLib/Liver.h"
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
@@ -10,12 +12,15 @@ Gallbladder::Gallbladder(int id)
|
||||
storedBile_mL(30.0),
|
||||
bileConcentrationFactor(5.0) {}
|
||||
|
||||
void Gallbladder::update(double deltaTime_s) {
|
||||
// A real model would be driven by liver output and CCK hormone for contraction.
|
||||
// For now, simulate slow storage and concentration, with a periodic contraction.
|
||||
void Gallbladder::update(Patient& patient, double deltaTime_s) {
|
||||
// Get bile from the liver
|
||||
if (const Liver* liver = getOrgan<Liver>(patient)) {
|
||||
double bileProduced_mL = liver->getBileProductionRate() * deltaTime_s;
|
||||
storeBile(bileProduced_mL);
|
||||
}
|
||||
|
||||
// Simulate bile coming from the liver
|
||||
storeBile(0.005 * deltaTime_s); // Slow constant trickle
|
||||
// A real model would also be driven by CCK hormone for contraction.
|
||||
// For now, simulate slow storage and concentration, with a periodic contraction.
|
||||
|
||||
switch (currentState) {
|
||||
case GallbladderState::STORING:
|
||||
|
||||
+13
-2
@@ -1,4 +1,5 @@
|
||||
#include "MedicalLib/Heart.h"
|
||||
#include "MedicalLib/Patient.h"
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
@@ -57,11 +58,21 @@ Heart::Heart(int id, int numLeads)
|
||||
}
|
||||
}
|
||||
|
||||
void Heart::update(double deltaTime_s) {
|
||||
void Heart::update(Patient& patient, double deltaTime_s) {
|
||||
// --- Electrical Simulation Update ---
|
||||
totalTime_s += deltaTime_s;
|
||||
|
||||
// Compensatory response to hypoxia
|
||||
double o2_saturation = patient.blood.oxygenSaturation;
|
||||
double targetHeartRate = 75.0;
|
||||
if (o2_saturation < 90.0) {
|
||||
targetHeartRate = 75.0 + (90.0 - o2_saturation) * 2.0; // Increase HR as SpO2 drops
|
||||
}
|
||||
|
||||
// Move current heart rate towards the target
|
||||
heartRate += (targetHeartRate - heartRate) * 0.1 * deltaTime_s;
|
||||
heartRate += getFluctuation(0.01); // Slow variation in underlying rate
|
||||
heartRate = std::max(60.0, std::min(heartRate, 100.0));
|
||||
heartRate = std::max(60.0, std::min(heartRate, 140.0));
|
||||
double cycleDuration_s = 60.0 / heartRate;
|
||||
|
||||
double oldCyclePosition = cardiacCyclePosition_s;
|
||||
|
||||
+6
-9
@@ -1,4 +1,5 @@
|
||||
#include "MedicalLib/Intestines.h"
|
||||
#include "MedicalLib/Patient.h"
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
@@ -23,20 +24,16 @@ Intestines::Intestines(int id)
|
||||
colon = {"Colon", 1.5, 0.5, 0.1, 1.0}; // High water absorption
|
||||
}
|
||||
|
||||
void Intestines::update(double deltaTime_s) {
|
||||
// For demonstration, simulate chyme arriving from the stomach
|
||||
static double timeSinceChyme = 0.0;
|
||||
timeSinceChyme += deltaTime_s;
|
||||
if (timeSinceChyme > 25.0) {
|
||||
receiveChyme(10.0); // Receive 10mL of chyme
|
||||
timeSinceChyme = 0.0;
|
||||
}
|
||||
|
||||
void Intestines::update(Patient& patient, double deltaTime_s) {
|
||||
if (chymeVolume_mL > 0) {
|
||||
// Simplified absorption model: total absorption is an average of all segments
|
||||
double totalNutrientAbsorption = (duodenum.nutrientAbsorptionRate + jejunum.nutrientAbsorptionRate + ileum.nutrientAbsorptionRate + colon.nutrientAbsorptionRate) / 4.0;
|
||||
double totalWaterAbsorption = (duodenum.waterAbsorptionRate + jejunum.waterAbsorptionRate + ileum.waterAbsorptionRate + colon.waterAbsorptionRate) / 4.0;
|
||||
|
||||
// Absorb glucose into the blood
|
||||
double glucoseAbsorption = totalNutrientAbsorption * chymeVolume_mL * 0.001 * deltaTime_s;
|
||||
patient.blood.glucose_mg_per_dL += glucoseAbsorption;
|
||||
|
||||
// Reduce chyme volume based on absorption
|
||||
double absorbedVolume = (totalNutrientAbsorption * 0.01 + totalWaterAbsorption * 0.1) * deltaTime_s;
|
||||
chymeVolume_mL -= absorbedVolume;
|
||||
|
||||
+18
-4
@@ -1,4 +1,7 @@
|
||||
#include "MedicalLib/Kidneys.h"
|
||||
#include "MedicalLib/Patient.h"
|
||||
#include "MedicalLib/Heart.h"
|
||||
#include "MedicalLib/Bladder.h"
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
@@ -28,7 +31,7 @@ Kidneys::Kidneys(int id)
|
||||
}
|
||||
}
|
||||
|
||||
void Kidneys::update(double deltaTime_s) {
|
||||
void Kidneys::update(Patient& patient, double deltaTime_s) {
|
||||
// Recalculate total capacity based on nephron health
|
||||
totalFiltrationCapacity = 0.0;
|
||||
for (const auto& nephron : nephrons) {
|
||||
@@ -38,14 +41,25 @@ void Kidneys::update(double deltaTime_s) {
|
||||
}
|
||||
totalFiltrationCapacity /= nephrons.size();
|
||||
|
||||
// GFR is dependent on overall health
|
||||
const double baseline_gfr = 125.0 * totalFiltrationCapacity;
|
||||
// GFR is dependent on blood pressure from the heart
|
||||
double perfusionPressure = 90.0; // Assume normal MAP if heart is not present
|
||||
if (const Heart* heart = getOrgan<Heart>(patient)) {
|
||||
perfusionPressure = heart->getAorticPressure();
|
||||
}
|
||||
double pressureModifier = std::clamp(perfusionPressure / 90.0, 0.5, 1.2);
|
||||
|
||||
const double baseline_gfr = 125.0 * totalFiltrationCapacity * pressureModifier;
|
||||
gfr_mL_per_min += 0.1 * (baseline_gfr - gfr_mL_per_min) * deltaTime_s + getFluctuation(0.5);
|
||||
|
||||
// Urine output is related to GFR but also hydration status (not modeled yet)
|
||||
// Urine output is related to GFR
|
||||
urineOutput_mL_per_s = gfr_mL_per_min / 60.0 * 0.01; // Simplified relationship
|
||||
urineOutput_mL_per_s += getFluctuation(0.001);
|
||||
|
||||
// Pass urine to the bladder
|
||||
if (Bladder* bladder = getOrgan<Bladder>(patient)) {
|
||||
bladder->addUrine(urineOutput_mL_per_s * deltaTime_s);
|
||||
}
|
||||
|
||||
// Simulate electrolyte balance
|
||||
bloodSodium_mEq_per_L += getFluctuation(0.05);
|
||||
bloodPotassium_mEq_per_L += getFluctuation(0.01);
|
||||
|
||||
+19
-1
@@ -1,4 +1,5 @@
|
||||
#include "MedicalLib/Liver.h"
|
||||
#include "MedicalLib/Patient.h" // For Blood struct
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
@@ -28,7 +29,7 @@ Liver::Liver(int id)
|
||||
}
|
||||
}
|
||||
|
||||
void Liver::update(double deltaTime_s) {
|
||||
void Liver::update(Patient& patient, double deltaTime_s) {
|
||||
// Recalculate total capacity based on lobule health (for future use)
|
||||
totalMetabolicCapacity = 0.0;
|
||||
for (const auto& lobule : lobules) {
|
||||
@@ -58,6 +59,23 @@ void Liver::update(double deltaTime_s) {
|
||||
alt_U_per_L = std::clamp(alt_U_per_L, 10.0, 40.0);
|
||||
ast_U_per_L = std::clamp(ast_U_per_L, 10.0, 40.0);
|
||||
bilirubin_mg_per_dL = std::clamp(bilirubin_mg_per_dL, 0.3, 1.2);
|
||||
|
||||
// --- Blood Interaction ---
|
||||
Blood& blood = patient.blood;
|
||||
// 1. Toxin Filtration
|
||||
double toxinFiltrationRate = 0.1 * totalMetabolicCapacity * deltaTime_s; // a.u. per second
|
||||
double toxinsRemoved = blood.toxins_au * toxinFiltrationRate;
|
||||
blood.toxins_au -= toxinsRemoved;
|
||||
blood.toxins_au = std::max(0.0, blood.toxins_au);
|
||||
|
||||
// 2. Glucose regulation (Gluconeogenesis / Glycogenolysis)
|
||||
const double highGlucose = 120.0;
|
||||
const double lowGlucose = 80.0;
|
||||
if (patient.blood.glucose_mg_per_dL > highGlucose) {
|
||||
patient.blood.glucose_mg_per_dL -= (patient.blood.glucose_mg_per_dL - highGlucose) * 0.1 * totalMetabolicCapacity * deltaTime_s;
|
||||
} else if (patient.blood.glucose_mg_per_dL < lowGlucose) {
|
||||
patient.blood.glucose_mg_per_dL += (lowGlucose - patient.blood.glucose_mg_per_dL) * 0.1 * totalMetabolicCapacity * deltaTime_s;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Liver::getSummary() const {
|
||||
|
||||
+32
-2
@@ -1,4 +1,5 @@
|
||||
#include "MedicalLib/Lungs.h"
|
||||
#include "MedicalLib/Patient.h" // For Blood struct
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
@@ -37,7 +38,7 @@ Lungs::Lungs(int id)
|
||||
mainBronchus = {"Main Bronchus", 0.8};
|
||||
}
|
||||
|
||||
void Lungs::update(double deltaTime_s) {
|
||||
void Lungs::update(Patient& patient, double deltaTime_s) {
|
||||
totalTime_s += deltaTime_s;
|
||||
|
||||
updateRespiratoryMechanics(deltaTime_s);
|
||||
@@ -48,6 +49,24 @@ void Lungs::update(double deltaTime_s) {
|
||||
if (capnographyData.size() > capnographyHistorySize) {
|
||||
capnographyData.pop_back();
|
||||
}
|
||||
|
||||
// --- Blood Interaction ---
|
||||
Blood& blood = patient.blood;
|
||||
// Gas exchange is driven by the pressure gradient between alveoli and blood
|
||||
double ventilationFactor = (tidalVolume_mL / 500.0) * (respirationRate / 16.0);
|
||||
ventilationFactor = std::clamp(ventilationFactor, 0.5, 1.5); // Clamp effect
|
||||
|
||||
// Oxygenation: Blood O2 moves towards the lung's O2 level
|
||||
double o2_gradient = oxygenSaturation - blood.oxygenSaturation;
|
||||
blood.oxygenSaturation += o2_gradient * 0.8 * ventilationFactor * deltaTime_s;
|
||||
blood.oxygenSaturation = std::clamp(blood.oxygenSaturation, 0.0, 100.0);
|
||||
|
||||
// CO2 Removal: Blood CO2 moves towards the lung's (low) CO2 level
|
||||
// We'll model the lung's CO2 as being lower than the blood's target
|
||||
double effectiveAlveolarCO2 = 40.0 / ventilationFactor;
|
||||
double co2_gradient = blood.co2PartialPressure_mmHg - effectiveAlveolarCO2;
|
||||
blood.co2PartialPressure_mmHg -= co2_gradient * 0.5 * deltaTime_s;
|
||||
blood.co2PartialPressure_mmHg = std::clamp(blood.co2PartialPressure_mmHg, 0.0, 200.0);
|
||||
}
|
||||
|
||||
void Lungs::updateRespiratoryMechanics(double deltaTime_s) {
|
||||
@@ -68,12 +87,14 @@ void Lungs::updateRespiratoryMechanics(double deltaTime_s) {
|
||||
}
|
||||
|
||||
// Pressure and Volume dynamics
|
||||
double totalCompliance = rightUpperLobe.compliance + rightMiddleLobe.compliance + rightLowerLobe.compliance + leftUpperLobe.compliance + leftLowerLobe.compliance;
|
||||
|
||||
double flowRate_mL_s = 0;
|
||||
if (currentState == RespiratoryState::INSPIRATION) {
|
||||
// Simple sine wave for pressure generation
|
||||
double pressure_wave = sin(M_PI * (cyclePosition_s / inspirationDuration));
|
||||
peakInspiratoryPressure_cmH2O = 15.0 * pressure_wave; // 15 cmH2O peak
|
||||
flowRate_mL_s = (peakInspiratoryPressure_cmH2O / mainBronchus.resistance) * 100;
|
||||
flowRate_mL_s = (peakInspiratoryPressure_cmH2O / mainBronchus.resistance) * 100 * totalCompliance;
|
||||
tidalVolume_mL += flowRate_mL_s * deltaTime_s;
|
||||
} else { // EXPIRATION
|
||||
peakInspiratoryPressure_cmH2O = 0;
|
||||
@@ -138,6 +159,15 @@ std::string Lungs::getSummary() const {
|
||||
}
|
||||
|
||||
// --- Getters Implementation ---
|
||||
void Lungs::inflictDamage(double damage) {
|
||||
double damageFactor = 1.0 - std::clamp(damage, 0.0, 1.0);
|
||||
rightUpperLobe.compliance *= damageFactor;
|
||||
rightMiddleLobe.compliance *= damageFactor;
|
||||
rightLowerLobe.compliance *= damageFactor;
|
||||
leftUpperLobe.compliance *= damageFactor;
|
||||
leftLowerLobe.compliance *= damageFactor;
|
||||
}
|
||||
|
||||
double Lungs::getRespirationRate() const { return respirationRate; }
|
||||
double Lungs::getOxygenSaturation() const { return oxygenSaturation; }
|
||||
double Lungs::getTidalVolume() const { return tidalVolume_mL; }
|
||||
|
||||
+25
-12
@@ -1,4 +1,5 @@
|
||||
#include "MedicalLib/Pancreas.h"
|
||||
#include "MedicalLib/Patient.h"
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
@@ -19,22 +20,34 @@ Pancreas::Pancreas(int id)
|
||||
amylaseSecretion_U_per_L(80.0),
|
||||
lipaseSecretion_U_per_L(40.0) {}
|
||||
|
||||
void Pancreas::update(double deltaTime_s) {
|
||||
// In a real model, hormone secretion would be driven by blood glucose.
|
||||
// Enzyme secretion would be driven by food in the duodenum.
|
||||
void Pancreas::update(Patient& patient, double deltaTime_s) {
|
||||
// Hormone secretion is driven by blood glucose.
|
||||
const double glucose = patient.blood.glucose_mg_per_dL;
|
||||
const double highGlucoseThreshold = 120.0;
|
||||
const double lowGlucoseThreshold = 80.0;
|
||||
|
||||
// Insulin response
|
||||
if (glucose > highGlucoseThreshold) {
|
||||
insulinSecretion_units_per_hr += (glucose - highGlucoseThreshold) * 0.1 * deltaTime_s;
|
||||
} else {
|
||||
insulinSecretion_units_per_hr -= 0.5 * deltaTime_s;
|
||||
}
|
||||
|
||||
// Glucagon response
|
||||
if (glucose < lowGlucoseThreshold) {
|
||||
glucagonSecretion_ng_per_hr += (lowGlucoseThreshold - glucose) * 0.2 * deltaTime_s;
|
||||
} else {
|
||||
glucagonSecretion_ng_per_hr -= 1.0 * deltaTime_s;
|
||||
}
|
||||
|
||||
// Enzyme secretion would be driven by food in the duodenum (not yet modeled).
|
||||
// For now, we just simulate minor fluctuations around a baseline.
|
||||
|
||||
// Endocrine fluctuations
|
||||
insulinSecretion_units_per_hr += getFluctuation(0.05);
|
||||
glucagonSecretion_ng_per_hr += getFluctuation(0.5);
|
||||
|
||||
// Exocrine fluctuations
|
||||
amylaseSecretion_U_per_L += getFluctuation(0.2);
|
||||
lipaseSecretion_U_per_L += getFluctuation(0.2);
|
||||
|
||||
// Clamp to healthy ranges
|
||||
insulinSecretion_units_per_hr = std::clamp(insulinSecretion_units_per_hr, 0.5, 2.0);
|
||||
glucagonSecretion_ng_per_hr = std::clamp(glucagonSecretion_ng_per_hr, 40.0, 60.0);
|
||||
// Clamp to healthy/possible ranges
|
||||
insulinSecretion_units_per_hr = std::clamp(insulinSecretion_units_per_hr, 0.5, 10.0);
|
||||
glucagonSecretion_ng_per_hr = std::clamp(glucagonSecretion_ng_per_hr, 20.0, 100.0);
|
||||
amylaseSecretion_U_per_L = std::clamp(amylaseSecretion_U_per_L, 60.0, 100.0);
|
||||
lipaseSecretion_U_per_L = std::clamp(lipaseSecretion_U_per_L, 20.0, 60.0);
|
||||
}
|
||||
|
||||
+3
-2
@@ -58,9 +58,10 @@ Patient initializePatient(int patientId) {
|
||||
* @param deltaTime_s The time elapsed in seconds.
|
||||
*/
|
||||
void updatePatient(Patient& patient, double deltaTime_s) {
|
||||
// Update all organs
|
||||
// Update all organs. The new update function handles all internal state changes
|
||||
// and inter-organ interactions.
|
||||
for (auto& organ : patient.organs) {
|
||||
organ->update(deltaTime_s);
|
||||
organ->update(patient, deltaTime_s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
#include "MedicalLib/SpinalCord.h"
|
||||
#include "MedicalLib/Patient.h"
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
@@ -21,7 +22,7 @@ SpinalCord::SpinalCord(int id)
|
||||
ascendingSensoryTract = {"Ascending Sensory Tract", SignalStatus::NORMAL, 65.0};
|
||||
}
|
||||
|
||||
void SpinalCord::update(double deltaTime_s) {
|
||||
void SpinalCord::update(Patient& patient, double deltaTime_s) {
|
||||
// In a healthy state, status doesn't change.
|
||||
// Pathology models would alter these values.
|
||||
// For now, we just simulate minor fluctuations in a healthy velocity.
|
||||
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
#include "MedicalLib/Spleen.h"
|
||||
#include "MedicalLib/Patient.h"
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
@@ -18,7 +19,7 @@ Spleen::Spleen(int id) : Organ(id, "Spleen") {
|
||||
whitePulp = {1500.0, 500.0};
|
||||
}
|
||||
|
||||
void Spleen::update(double deltaTime_s) {
|
||||
void Spleen::update(Patient& patient, double deltaTime_s) {
|
||||
// In a real model, these values would change in response to infection or disease.
|
||||
// For now, we just simulate minor fluctuations around a healthy baseline.
|
||||
|
||||
|
||||
+9
-8
@@ -1,4 +1,6 @@
|
||||
#include "MedicalLib/Stomach.h"
|
||||
#include "MedicalLib/Patient.h"
|
||||
#include "MedicalLib/Intestines.h"
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
@@ -20,17 +22,11 @@ Stomach::Stomach(int id)
|
||||
gastricJuiceSecretionRate_ml_per_s(0.1),
|
||||
emptyingRate_ml_per_s(0.5) {}
|
||||
|
||||
void Stomach::update(double deltaTime_s) {
|
||||
void Stomach::update(Patient& patient, double deltaTime_s) {
|
||||
// --- State Machine Logic ---
|
||||
switch (currentState) {
|
||||
case GastricState::EMPTY:
|
||||
// For demo, simulate food arriving every 20 seconds
|
||||
static double timeUntilFood = 0.0;
|
||||
timeUntilFood += deltaTime_s;
|
||||
if (timeUntilFood > 20.0) {
|
||||
addSubstance(150.0); // Simulate arrival of a meal
|
||||
timeUntilFood = 0.0;
|
||||
}
|
||||
// In a real simulation, addSubstance would be called externally (e.g., from Esophagus)
|
||||
break;
|
||||
|
||||
case GastricState::FILLING:
|
||||
@@ -60,6 +56,11 @@ void Stomach::update(double deltaTime_s) {
|
||||
case GastricState::EMPTYING:
|
||||
// Empty chyme into intestines
|
||||
double amountToEmpty = emptyingRate_ml_per_s * deltaTime_s;
|
||||
|
||||
if (Intestines* intestines = getOrgan<Intestines>(patient)) {
|
||||
intestines->receiveChyme(amountToEmpty);
|
||||
}
|
||||
|
||||
currentVolume_mL -= amountToEmpty;
|
||||
|
||||
if (currentVolume_mL <= 0) {
|
||||
|
||||
Reference in New Issue
Block a user