diff --git a/examples/main.cpp b/examples/main.cpp index 8daed99..938c184 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -8,31 +8,69 @@ #include "MedicalLib/Patient.h" #include "MedicalLib/Organ.h" #include "MedicalLib/Heart.h" +#include "MedicalLib/Stomach.h" +#include "MedicalLib/Lungs.h" int main() { // Initialize a new patient with a 12-lead heart Patient patient = initializePatient(1, 12); std::cout << "Patient created with ID: " << patient.patientId << std::endl; + // Introduce a toxin load to the blood for the liver to clear + patient.blood.toxins_au = 100.0; + std::cout << "Initial toxin load of 100.0 a.u. introduced.\n" << std::endl; + // Simulate time passing and print a live summary - const double simulationTime_s = 10.0; - const double deltaTime_s = 0.05; // 20 Hz update rate for display + const double simulationTime_s = 60.0; // Run for a longer time to see effects + const double deltaTime_s = 0.1; const int numSteps = static_cast(simulationTime_s / deltaTime_s); - std::cout << "\n--- Simulating " << simulationTime_s << " seconds of heart activity... ---" << std::endl; + // Get pointers to organs we want to interact with + Stomach* stomach = getOrgan(patient); + if(stomach) { + stomach->addSubstance(300.0); // Simulate eating a meal + std::cout << "A 300mL meal has been consumed." << std::endl; + } + Lungs* lungs = getOrgan(patient); + + + std::cout << "\n--- Simulating " << simulationTime_s << " seconds... ---" << std::endl; for (int i = 0; i < numSteps; ++i) { + double currentTime = i * deltaTime_s; // Clear console on systems that support ANSI escape codes #if defined(__linux__) || defined(__APPLE__) std::cout << "\033[2J\033[1;1H"; #endif + // --- Event scripting --- + if (std::abs(currentTime - 20.0) < deltaTime_s/2.0) { + if (lungs) { + std::cout << "\n*** LUNG INJURY EVENT ***\n" << std::endl; + lungs->inflictDamage(0.8); // 80% damage + } + } + updatePatient(patient, deltaTime_s); - std::cout << "Time: " << i * deltaTime_s << "s / " << simulationTime_s << "s\n" << std::endl; - std::cout << getOrganSummary(patient, "Heart") << std::endl; + std::cout << "Time: " << currentTime << "s / " << simulationTime_s << "s\n" << std::endl; + std::cout << "--- Blood Chemistry ---\n" + << "SpO2: " << patient.blood.oxygenSaturation << " %\n" + << "PaCO2: " << patient.blood.co2PartialPressure_mmHg << " mmHg\n" + << "Glucose: " << patient.blood.glucose_mg_per_dL << " mg/dL\n" + << "Toxins: " << patient.blood.toxins_au << " a.u.\n\n"; - std::this_thread::sleep_for(std::chrono::milliseconds(50)); + std::cout << getOrganSummary(patient, "Heart") << std::endl; + std::cout << getOrganSummary(patient, "Lungs") << std::endl; + std::cout << getOrganSummary(patient, "Brain") << std::endl; + std::cout << getOrganSummary(patient, "Stomach") << std::endl; + std::cout << getOrganSummary(patient, "Intestines") << std::endl; + std::cout << getOrganSummary(patient, "Pancreas") << std::endl; + std::cout << getOrganSummary(patient, "Kidneys") << std::endl; + std::cout << getOrganSummary(patient, "Bladder") << std::endl; + + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); } std::cout << "\n--- Simulation Complete. Final State: ---\n" << std::endl; diff --git a/include/MedicalLib/Bladder.h b/include/MedicalLib/Bladder.h index 89ffd29..4e113e7 100644 --- a/include/MedicalLib/Bladder.h +++ b/include/MedicalLib/Bladder.h @@ -25,9 +25,10 @@ public: /** * @brief Updates the bladder's state over a time interval. + * @param patient A reference to the patient object. * @param deltaTime_s The time elapsed in seconds. */ - void update(double deltaTime_s) override; + void update(Patient& patient, double deltaTime_s) override; /** * @brief Gets a string summary of the bladder's state. diff --git a/include/MedicalLib/Brain.h b/include/MedicalLib/Brain.h index 1b9d548..9ae9271 100644 --- a/include/MedicalLib/Brain.h +++ b/include/MedicalLib/Brain.h @@ -28,9 +28,10 @@ public: /** * @brief Updates the brain's state over a time interval. + * @param patient A reference to the patient object. * @param deltaTime_s The time elapsed in seconds. */ - void update(double deltaTime_s) override; + void update(Patient& patient, double deltaTime_s) override; /** * @brief Gets a string summary of the brain's vitals. diff --git a/include/MedicalLib/Esophagus.h b/include/MedicalLib/Esophagus.h index 56181d1..665f0a7 100644 --- a/include/MedicalLib/Esophagus.h +++ b/include/MedicalLib/Esophagus.h @@ -34,9 +34,10 @@ public: /** * @brief Updates the esophagus state over a time interval. + * @param patient A reference to the patient object. * @param deltaTime_s The time elapsed in seconds. */ - void update(double deltaTime_s) override; + void update(Patient& patient, double deltaTime_s) override; /** * @brief Gets a string summary of the esophagus's state. diff --git a/include/MedicalLib/Gallbladder.h b/include/MedicalLib/Gallbladder.h index 2d0ab57..86a9e4f 100644 --- a/include/MedicalLib/Gallbladder.h +++ b/include/MedicalLib/Gallbladder.h @@ -24,9 +24,10 @@ public: /** * @brief Updates the gallbladder's state over a time interval. + * @param patient A reference to the patient object. * @param deltaTime_s The time elapsed in seconds. */ - void update(double deltaTime_s) override; + void update(Patient& patient, double deltaTime_s) override; /** * @brief Gets a string summary of the gallbladder's state. diff --git a/include/MedicalLib/Heart.h b/include/MedicalLib/Heart.h index 7a01094..d754c46 100644 --- a/include/MedicalLib/Heart.h +++ b/include/MedicalLib/Heart.h @@ -52,9 +52,10 @@ public: /** * @brief Updates the heart's state over time, simulating the cardiac cycle. + * @param patient A reference to the patient object. * @param deltaTime_s The time elapsed in seconds. */ - void update(double deltaTime_s) override; + void update(Patient& patient, double deltaTime_s) override; /** * @brief Gets a string summary of the heart's vitals, including EKG and mechanical data. diff --git a/include/MedicalLib/Intestines.h b/include/MedicalLib/Intestines.h index 2d773b2..a08b516 100644 --- a/include/MedicalLib/Intestines.h +++ b/include/MedicalLib/Intestines.h @@ -28,9 +28,10 @@ public: /** * @brief Updates the intestines' state over a time interval. + * @param patient A reference to the patient object. * @param deltaTime_s The time elapsed in seconds. */ - void update(double deltaTime_s) override; + void update(Patient& patient, double deltaTime_s) override; /** * @brief Gets a string summary of the intestines' state. diff --git a/include/MedicalLib/Kidneys.h b/include/MedicalLib/Kidneys.h index 238d679..07ccede 100644 --- a/include/MedicalLib/Kidneys.h +++ b/include/MedicalLib/Kidneys.h @@ -26,9 +26,10 @@ public: /** * @brief Updates the kidneys' state over a time interval. + * @param patient A reference to the patient object. * @param deltaTime_s The time elapsed in seconds. */ - void update(double deltaTime_s) override; + void update(Patient& patient, double deltaTime_s) override; /** * @brief Gets a string summary of the kidneys' state. diff --git a/include/MedicalLib/Liver.h b/include/MedicalLib/Liver.h index df6b165..1892b12 100644 --- a/include/MedicalLib/Liver.h +++ b/include/MedicalLib/Liver.h @@ -26,9 +26,10 @@ public: /** * @brief Updates the liver's state over a time interval. + * @param patient A reference to the patient object. * @param deltaTime_s The time elapsed in seconds. */ - void update(double deltaTime_s) override; + void update(Patient& patient, double deltaTime_s) override; /** * @brief Gets a string summary of the liver's vitals. diff --git a/include/MedicalLib/Lungs.h b/include/MedicalLib/Lungs.h index c56c501..76adf86 100644 --- a/include/MedicalLib/Lungs.h +++ b/include/MedicalLib/Lungs.h @@ -44,9 +44,10 @@ public: /** * @brief Updates the lungs' state over a time interval. + * @param patient A reference to the patient object. * @param deltaTime_s The time elapsed in seconds. */ - void update(double deltaTime_s) override; + void update(Patient& patient, double deltaTime_s) override; /** * @brief Gets a string summary of the lungs' vitals. @@ -54,6 +55,12 @@ public: */ std::string getSummary() const override; + /** + * @brief Inflicts damage on the lungs, reducing their compliance. + * @param damage The amount of damage to inflict (0-1). + */ + void inflictDamage(double damage); + // --- Getters for Key Respiratory Vitals --- /** @brief Gets the current respiration rate in breaths per minute. */ diff --git a/include/MedicalLib/Organ.h b/include/MedicalLib/Organ.h index 5edfeff..efcda22 100644 --- a/include/MedicalLib/Organ.h +++ b/include/MedicalLib/Organ.h @@ -3,6 +3,9 @@ #include #include +// Forward-declare to avoid circular dependency +struct Patient; + // Define MEDICAL_LIB_EXPORT for exporting symbols from the DLL #if defined(_WIN32) #if defined(MEDICAL_LIB_EXPORT) @@ -33,9 +36,10 @@ public: /** * @brief Pure virtual function to update the organ's state over time. + * @param patient A reference to the patient object for inter-organ communication. * @param deltaTime_s The time elapsed in seconds. */ - virtual void update(double deltaTime_s) = 0; + virtual void update(Patient& patient, double deltaTime_s) = 0; /** * @brief Pure virtual function to get a string summary of the organ's vitals. diff --git a/include/MedicalLib/Pancreas.h b/include/MedicalLib/Pancreas.h index 8d89a0e..5d8f9a6 100644 --- a/include/MedicalLib/Pancreas.h +++ b/include/MedicalLib/Pancreas.h @@ -16,9 +16,10 @@ public: /** * @brief Updates the pancreas's state over a time interval. + * @param patient A reference to the patient object. * @param deltaTime_s The time elapsed in seconds. */ - void update(double deltaTime_s) override; + void update(Patient& patient, double deltaTime_s) override; /** * @brief Gets a string summary of the pancreas's state. diff --git a/include/MedicalLib/Patient.h b/include/MedicalLib/Patient.h index 35ec249..68f837e 100644 --- a/include/MedicalLib/Patient.h +++ b/include/MedicalLib/Patient.h @@ -7,11 +7,22 @@ // Forward-declare the Organ class to avoid circular dependencies class Organ; +/** + * @brief Represents the composition of the patient's blood. + */ +struct Blood { + double oxygenSaturation = 98.0; // Normal SpO2 + double co2PartialPressure_mmHg = 40.0; // Normal PaCO2 + double glucose_mg_per_dL = 100.0; // Normal fasting glucose + double toxins_au = 0.0; // Arbitrary units, 0 is clean +}; + /** * @brief Holds all the vital signs and other medical information for a patient. */ struct Patient { int patientId; + Blood blood; std::vector> organs; }; @@ -67,6 +78,22 @@ MEDICAL_LIB_API std::string getPatientSummary(const Patient& patient); * @brief Gets a pointer to a specific organ by its type. * @tparam T The type of the organ to get. * @param patient The patient to get the organ from. + * @return A pointer to the organ if found, otherwise nullptr. + */ +template +T* getOrgan(Patient& patient) { + for (auto& organ : patient.organs) { + if (T* specificOrgan = dynamic_cast(organ.get())) { + return specificOrgan; + } + } + return nullptr; +} + +/** + * @brief Gets a const pointer to a specific organ by its type. + * @tparam T The type of the organ to get. + * @param patient The patient to get the organ from. * @return A const pointer to the organ if found, otherwise nullptr. */ template diff --git a/include/MedicalLib/SpinalCord.h b/include/MedicalLib/SpinalCord.h index 849aa3c..90200e3 100644 --- a/include/MedicalLib/SpinalCord.h +++ b/include/MedicalLib/SpinalCord.h @@ -35,9 +35,10 @@ public: /** * @brief Updates the spinal cord's state over a time interval. + * @param patient A reference to the patient object. * @param deltaTime_s The time elapsed in seconds. */ - void update(double deltaTime_s) override; + void update(Patient& patient, double deltaTime_s) override; /** * @brief Gets a string summary of the spinal cord's vitals. diff --git a/include/MedicalLib/Spleen.h b/include/MedicalLib/Spleen.h index 363f647..805f083 100644 --- a/include/MedicalLib/Spleen.h +++ b/include/MedicalLib/Spleen.h @@ -32,9 +32,10 @@ public: /** * @brief Updates the spleen's state over a time interval. + * @param patient A reference to the patient object. * @param deltaTime_s The time elapsed in seconds. */ - void update(double deltaTime_s) override; + void update(Patient& patient, double deltaTime_s) override; /** * @brief Gets a string summary of the spleen's state. diff --git a/include/MedicalLib/Stomach.h b/include/MedicalLib/Stomach.h index 7becea3..b6d9690 100644 --- a/include/MedicalLib/Stomach.h +++ b/include/MedicalLib/Stomach.h @@ -35,9 +35,10 @@ public: /** * @brief Updates the stomach state over a time interval. + * @param patient A reference to the patient object. * @param deltaTime_s The time elapsed in seconds. */ - void update(double deltaTime_s) override; + void update(Patient& patient, double deltaTime_s) override; /** * @brief Gets a string summary of the stomach's state. diff --git a/src/Bladder.cpp b/src/Bladder.cpp index d4606f0..f086eae 100644 --- a/src/Bladder.cpp +++ b/src/Bladder.cpp @@ -1,4 +1,5 @@ #include "MedicalLib/Bladder.h" +#include "MedicalLib/Patient.h" #include #include #include @@ -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; diff --git a/src/Brain.cpp b/src/Brain.cpp index 689efd6..a1c34e5 100644 --- a/src/Brain.cpp +++ b/src/Brain.cpp @@ -1,4 +1,6 @@ #include "MedicalLib/Brain.h" +#include "MedicalLib/Patient.h" // For Blood struct +#include "MedicalLib/Heart.h" // For Heart data #include #include #include @@ -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(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) { diff --git a/src/Esophagus.cpp b/src/Esophagus.cpp index 5a0775c..ba5c1a3 100644 --- a/src/Esophagus.cpp +++ b/src/Esophagus.cpp @@ -1,4 +1,5 @@ #include "MedicalLib/Esophagus.h" +#include "MedicalLib/Patient.h" #include #include #include @@ -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; diff --git a/src/Gallbladder.cpp b/src/Gallbladder.cpp index ecb7184..dc0d12c 100644 --- a/src/Gallbladder.cpp +++ b/src/Gallbladder.cpp @@ -1,4 +1,6 @@ #include "MedicalLib/Gallbladder.h" +#include "MedicalLib/Patient.h" +#include "MedicalLib/Liver.h" #include #include #include @@ -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(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: diff --git a/src/Heart.cpp b/src/Heart.cpp index a1ae97f..e214278 100644 --- a/src/Heart.cpp +++ b/src/Heart.cpp @@ -1,4 +1,5 @@ #include "MedicalLib/Heart.h" +#include "MedicalLib/Patient.h" #include #include #include @@ -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; diff --git a/src/Intestines.cpp b/src/Intestines.cpp index 040f318..75d9e24 100644 --- a/src/Intestines.cpp +++ b/src/Intestines.cpp @@ -1,4 +1,5 @@ #include "MedicalLib/Intestines.h" +#include "MedicalLib/Patient.h" #include #include #include @@ -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; diff --git a/src/Kidneys.cpp b/src/Kidneys.cpp index d29e6b8..b9376e6 100644 --- a/src/Kidneys.cpp +++ b/src/Kidneys.cpp @@ -1,4 +1,7 @@ #include "MedicalLib/Kidneys.h" +#include "MedicalLib/Patient.h" +#include "MedicalLib/Heart.h" +#include "MedicalLib/Bladder.h" #include #include #include @@ -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(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(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); diff --git a/src/Liver.cpp b/src/Liver.cpp index b83ae2a..7a1fdd2 100644 --- a/src/Liver.cpp +++ b/src/Liver.cpp @@ -1,4 +1,5 @@ #include "MedicalLib/Liver.h" +#include "MedicalLib/Patient.h" // For Blood struct #include #include #include @@ -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 { diff --git a/src/Lungs.cpp b/src/Lungs.cpp index ed82a2f..24730ba 100644 --- a/src/Lungs.cpp +++ b/src/Lungs.cpp @@ -1,4 +1,5 @@ #include "MedicalLib/Lungs.h" +#include "MedicalLib/Patient.h" // For Blood struct #include #include #include @@ -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; } diff --git a/src/Pancreas.cpp b/src/Pancreas.cpp index e5eb55d..fa531b9 100644 --- a/src/Pancreas.cpp +++ b/src/Pancreas.cpp @@ -1,4 +1,5 @@ #include "MedicalLib/Pancreas.h" +#include "MedicalLib/Patient.h" #include #include #include @@ -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); } diff --git a/src/Patient.cpp b/src/Patient.cpp index 42f7625..865645a 100644 --- a/src/Patient.cpp +++ b/src/Patient.cpp @@ -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); } } diff --git a/src/SpinalCord.cpp b/src/SpinalCord.cpp index 87486c1..462b286 100644 --- a/src/SpinalCord.cpp +++ b/src/SpinalCord.cpp @@ -1,4 +1,5 @@ #include "MedicalLib/SpinalCord.h" +#include "MedicalLib/Patient.h" #include #include #include @@ -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. diff --git a/src/Spleen.cpp b/src/Spleen.cpp index d985462..f9750dd 100644 --- a/src/Spleen.cpp +++ b/src/Spleen.cpp @@ -1,4 +1,5 @@ #include "MedicalLib/Spleen.h" +#include "MedicalLib/Patient.h" #include #include #include @@ -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. diff --git a/src/Stomach.cpp b/src/Stomach.cpp index b374916..50abbb2 100644 --- a/src/Stomach.cpp +++ b/src/Stomach.cpp @@ -1,4 +1,6 @@ #include "MedicalLib/Stomach.h" +#include "MedicalLib/Patient.h" +#include "MedicalLib/Intestines.h" #include #include #include @@ -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(patient)) { + intestines->receiveChyme(amountToEmpty); + } + currentVolume_mL -= amountToEmpty; if (currentVolume_mL <= 0) {