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:
+44
-6
@@ -8,31 +8,69 @@
|
|||||||
#include "MedicalLib/Patient.h"
|
#include "MedicalLib/Patient.h"
|
||||||
#include "MedicalLib/Organ.h"
|
#include "MedicalLib/Organ.h"
|
||||||
#include "MedicalLib/Heart.h"
|
#include "MedicalLib/Heart.h"
|
||||||
|
#include "MedicalLib/Stomach.h"
|
||||||
|
#include "MedicalLib/Lungs.h"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// Initialize a new patient with a 12-lead heart
|
// Initialize a new patient with a 12-lead heart
|
||||||
Patient patient = initializePatient(1, 12);
|
Patient patient = initializePatient(1, 12);
|
||||||
std::cout << "Patient created with ID: " << patient.patientId << std::endl;
|
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
|
// Simulate time passing and print a live summary
|
||||||
const double simulationTime_s = 10.0;
|
const double simulationTime_s = 60.0; // Run for a longer time to see effects
|
||||||
const double deltaTime_s = 0.05; // 20 Hz update rate for display
|
const double deltaTime_s = 0.1;
|
||||||
const int numSteps = static_cast<int>(simulationTime_s / deltaTime_s);
|
const int numSteps = static_cast<int>(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<Stomach>(patient);
|
||||||
|
if(stomach) {
|
||||||
|
stomach->addSubstance(300.0); // Simulate eating a meal
|
||||||
|
std::cout << "A 300mL meal has been consumed." << std::endl;
|
||||||
|
}
|
||||||
|
Lungs* lungs = getOrgan<Lungs>(patient);
|
||||||
|
|
||||||
|
|
||||||
|
std::cout << "\n--- Simulating " << simulationTime_s << " seconds... ---" << std::endl;
|
||||||
|
|
||||||
for (int i = 0; i < numSteps; ++i) {
|
for (int i = 0; i < numSteps; ++i) {
|
||||||
|
double currentTime = i * deltaTime_s;
|
||||||
// Clear console on systems that support ANSI escape codes
|
// Clear console on systems that support ANSI escape codes
|
||||||
#if defined(__linux__) || defined(__APPLE__)
|
#if defined(__linux__) || defined(__APPLE__)
|
||||||
std::cout << "\033[2J\033[1;1H";
|
std::cout << "\033[2J\033[1;1H";
|
||||||
#endif
|
#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);
|
updatePatient(patient, deltaTime_s);
|
||||||
|
|
||||||
std::cout << "Time: " << i * deltaTime_s << "s / " << simulationTime_s << "s\n" << std::endl;
|
std::cout << "Time: " << currentTime << "s / " << simulationTime_s << "s\n" << std::endl;
|
||||||
std::cout << getOrganSummary(patient, "Heart") << 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;
|
std::cout << "\n--- Simulation Complete. Final State: ---\n" << std::endl;
|
||||||
|
|||||||
@@ -25,9 +25,10 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates the bladder's state over a time interval.
|
* @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.
|
* @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.
|
* @brief Gets a string summary of the bladder's state.
|
||||||
|
|||||||
@@ -28,9 +28,10 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates the brain's state over a time interval.
|
* @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.
|
* @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.
|
* @brief Gets a string summary of the brain's vitals.
|
||||||
|
|||||||
@@ -34,9 +34,10 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates the esophagus state over a time interval.
|
* @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.
|
* @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.
|
* @brief Gets a string summary of the esophagus's state.
|
||||||
|
|||||||
@@ -24,9 +24,10 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates the gallbladder's state over a time interval.
|
* @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.
|
* @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.
|
* @brief Gets a string summary of the gallbladder's state.
|
||||||
|
|||||||
@@ -52,9 +52,10 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates the heart's state over time, simulating the cardiac cycle.
|
* @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.
|
* @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.
|
* @brief Gets a string summary of the heart's vitals, including EKG and mechanical data.
|
||||||
|
|||||||
@@ -28,9 +28,10 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates the intestines' state over a time interval.
|
* @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.
|
* @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.
|
* @brief Gets a string summary of the intestines' state.
|
||||||
|
|||||||
@@ -26,9 +26,10 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates the kidneys' state over a time interval.
|
* @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.
|
* @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.
|
* @brief Gets a string summary of the kidneys' state.
|
||||||
|
|||||||
@@ -26,9 +26,10 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates the liver's state over a time interval.
|
* @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.
|
* @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.
|
* @brief Gets a string summary of the liver's vitals.
|
||||||
|
|||||||
@@ -44,9 +44,10 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates the lungs' state over a time interval.
|
* @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.
|
* @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.
|
* @brief Gets a string summary of the lungs' vitals.
|
||||||
@@ -54,6 +55,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
std::string getSummary() const override;
|
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 ---
|
// --- Getters for Key Respiratory Vitals ---
|
||||||
|
|
||||||
/** @brief Gets the current respiration rate in breaths per minute. */
|
/** @brief Gets the current respiration rate in breaths per minute. */
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
// Forward-declare to avoid circular dependency
|
||||||
|
struct Patient;
|
||||||
|
|
||||||
// Define MEDICAL_LIB_EXPORT for exporting symbols from the DLL
|
// Define MEDICAL_LIB_EXPORT for exporting symbols from the DLL
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#if defined(MEDICAL_LIB_EXPORT)
|
#if defined(MEDICAL_LIB_EXPORT)
|
||||||
@@ -33,9 +36,10 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Pure virtual function to update the organ's state over time.
|
* @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.
|
* @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.
|
* @brief Pure virtual function to get a string summary of the organ's vitals.
|
||||||
|
|||||||
@@ -16,9 +16,10 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates the pancreas's state over a time interval.
|
* @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.
|
* @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.
|
* @brief Gets a string summary of the pancreas's state.
|
||||||
|
|||||||
@@ -7,11 +7,22 @@
|
|||||||
// Forward-declare the Organ class to avoid circular dependencies
|
// Forward-declare the Organ class to avoid circular dependencies
|
||||||
class Organ;
|
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.
|
* @brief Holds all the vital signs and other medical information for a patient.
|
||||||
*/
|
*/
|
||||||
struct Patient {
|
struct Patient {
|
||||||
int patientId;
|
int patientId;
|
||||||
|
Blood blood;
|
||||||
std::vector<std::unique_ptr<Organ>> organs;
|
std::vector<std::unique_ptr<Organ>> 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.
|
* @brief Gets a pointer to a specific organ by its type.
|
||||||
* @tparam T The type of the organ to get.
|
* @tparam T The type of the organ to get.
|
||||||
* @param patient The patient to get the organ from.
|
* @param patient The patient to get the organ from.
|
||||||
|
* @return A pointer to the organ if found, otherwise nullptr.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
T* getOrgan(Patient& patient) {
|
||||||
|
for (auto& organ : patient.organs) {
|
||||||
|
if (T* specificOrgan = dynamic_cast<T*>(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.
|
* @return A const pointer to the organ if found, otherwise nullptr.
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|||||||
@@ -35,9 +35,10 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates the spinal cord's state over a time interval.
|
* @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.
|
* @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.
|
* @brief Gets a string summary of the spinal cord's vitals.
|
||||||
|
|||||||
@@ -32,9 +32,10 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates the spleen's state over a time interval.
|
* @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.
|
* @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.
|
* @brief Gets a string summary of the spleen's state.
|
||||||
|
|||||||
@@ -35,9 +35,10 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Updates the stomach state over a time interval.
|
* @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.
|
* @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.
|
* @brief Gets a string summary of the stomach's state.
|
||||||
|
|||||||
+2
-8
@@ -1,4 +1,5 @@
|
|||||||
#include "MedicalLib/Bladder.h"
|
#include "MedicalLib/Bladder.h"
|
||||||
|
#include "MedicalLib/Patient.h"
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -11,14 +12,7 @@ Bladder::Bladder(int id)
|
|||||||
pressure_cmH2O(5.0),
|
pressure_cmH2O(5.0),
|
||||||
internalSphincterClosed(true) {}
|
internalSphincterClosed(true) {}
|
||||||
|
|
||||||
void Bladder::update(double deltaTime_s) {
|
void Bladder::update(Patient& patient, 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simple pressure model: pressure increases with volume
|
// Simple pressure model: pressure increases with volume
|
||||||
pressure_cmH2O = (currentVolume_mL / capacity_mL) * 60.0;
|
pressure_cmH2O = (currentVolume_mL / capacity_mL) * 60.0;
|
||||||
|
|
||||||
|
|||||||
+48
-8
@@ -1,4 +1,6 @@
|
|||||||
#include "MedicalLib/Brain.h"
|
#include "MedicalLib/Brain.h"
|
||||||
|
#include "MedicalLib/Patient.h" // For Blood struct
|
||||||
|
#include "MedicalLib/Heart.h" // For Heart data
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -29,13 +31,17 @@ Brain::Brain(int id)
|
|||||||
cerebellum = {"Cerebellum", 0.6, 60.0};
|
cerebellum = {"Cerebellum", 0.6, 60.0};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Brain::update(double deltaTime_s) {
|
void Brain::update(Patient& patient, double deltaTime_s) {
|
||||||
totalTime_s += deltaTime_s;
|
totalTime_s += deltaTime_s;
|
||||||
|
|
||||||
// In a real scenario, MAP would be provided by the circulatory system (Heart)
|
// Get Mean Arterial Pressure from the Heart
|
||||||
// For now, we'll just keep it stable with minor fluctuations.
|
if (const Heart* heart = getOrgan<Heart>(patient)) {
|
||||||
meanArterialPressure_mmHg += getFluctuation(0.1);
|
meanArterialPressure_mmHg = heart->getAorticPressure();
|
||||||
meanArterialPressure_mmHg = std::clamp(meanArterialPressure_mmHg, 85.0, 95.0);
|
} 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);
|
updateActivity(deltaTime_s);
|
||||||
updatePressures(meanArterialPressure_mmHg);
|
updatePressures(meanArterialPressure_mmHg);
|
||||||
@@ -45,6 +51,37 @@ void Brain::update(double deltaTime_s) {
|
|||||||
if (eegData.size() > eegHistorySize) {
|
if (eegData.size() > eegHistorySize) {
|
||||||
eegData.pop_back();
|
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) {
|
void Brain::updateActivity(double deltaTime_s) {
|
||||||
@@ -52,9 +89,12 @@ void Brain::updateActivity(double deltaTime_s) {
|
|||||||
frontalLobe.activityLevel += getFluctuation(0.005);
|
frontalLobe.activityLevel += getFluctuation(0.005);
|
||||||
frontalLobe.activityLevel = std::clamp(frontalLobe.activityLevel, 0.7, 0.9);
|
frontalLobe.activityLevel = std::clamp(frontalLobe.activityLevel, 0.7, 0.9);
|
||||||
|
|
||||||
// GCS is a clinical score, doesn't typically change second-to-second.
|
// GCS is a clinical score, doesn't typically change second-to-second,
|
||||||
// This is a placeholder for future, more complex pathology simulation.
|
// but it will be affected by severe hypoxia or hypercapnia.
|
||||||
gcsScore = 15;
|
// 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) {
|
void Brain::updatePressures(double meanArterialPressure) {
|
||||||
|
|||||||
+2
-1
@@ -1,4 +1,5 @@
|
|||||||
#include "MedicalLib/Esophagus.h"
|
#include "MedicalLib/Esophagus.h"
|
||||||
|
#include "MedicalLib/Patient.h"
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -9,7 +10,7 @@ Esophagus::Esophagus(int id)
|
|||||||
currentState(PeristalsisState::IDLE),
|
currentState(PeristalsisState::IDLE),
|
||||||
lowerEsophagealSphincterTone(20.0) {}
|
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
|
// Simulate a swallow every 15 seconds for demonstration
|
||||||
static double timeSinceLastSwallow = 0.0;
|
static double timeSinceLastSwallow = 0.0;
|
||||||
timeSinceLastSwallow += deltaTime_s;
|
timeSinceLastSwallow += deltaTime_s;
|
||||||
|
|||||||
+10
-5
@@ -1,4 +1,6 @@
|
|||||||
#include "MedicalLib/Gallbladder.h"
|
#include "MedicalLib/Gallbladder.h"
|
||||||
|
#include "MedicalLib/Patient.h"
|
||||||
|
#include "MedicalLib/Liver.h"
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -10,12 +12,15 @@ Gallbladder::Gallbladder(int id)
|
|||||||
storedBile_mL(30.0),
|
storedBile_mL(30.0),
|
||||||
bileConcentrationFactor(5.0) {}
|
bileConcentrationFactor(5.0) {}
|
||||||
|
|
||||||
void Gallbladder::update(double deltaTime_s) {
|
void Gallbladder::update(Patient& patient, double deltaTime_s) {
|
||||||
// A real model would be driven by liver output and CCK hormone for contraction.
|
// Get bile from the liver
|
||||||
// For now, simulate slow storage and concentration, with a periodic contraction.
|
if (const Liver* liver = getOrgan<Liver>(patient)) {
|
||||||
|
double bileProduced_mL = liver->getBileProductionRate() * deltaTime_s;
|
||||||
|
storeBile(bileProduced_mL);
|
||||||
|
}
|
||||||
|
|
||||||
// Simulate bile coming from the liver
|
// A real model would also be driven by CCK hormone for contraction.
|
||||||
storeBile(0.005 * deltaTime_s); // Slow constant trickle
|
// For now, simulate slow storage and concentration, with a periodic contraction.
|
||||||
|
|
||||||
switch (currentState) {
|
switch (currentState) {
|
||||||
case GallbladderState::STORING:
|
case GallbladderState::STORING:
|
||||||
|
|||||||
+13
-2
@@ -1,4 +1,5 @@
|
|||||||
#include "MedicalLib/Heart.h"
|
#include "MedicalLib/Heart.h"
|
||||||
|
#include "MedicalLib/Patient.h"
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#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 ---
|
// --- Electrical Simulation Update ---
|
||||||
totalTime_s += deltaTime_s;
|
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 += 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 cycleDuration_s = 60.0 / heartRate;
|
||||||
|
|
||||||
double oldCyclePosition = cardiacCyclePosition_s;
|
double oldCyclePosition = cardiacCyclePosition_s;
|
||||||
|
|||||||
+6
-9
@@ -1,4 +1,5 @@
|
|||||||
#include "MedicalLib/Intestines.h"
|
#include "MedicalLib/Intestines.h"
|
||||||
|
#include "MedicalLib/Patient.h"
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -23,20 +24,16 @@ Intestines::Intestines(int id)
|
|||||||
colon = {"Colon", 1.5, 0.5, 0.1, 1.0}; // High water absorption
|
colon = {"Colon", 1.5, 0.5, 0.1, 1.0}; // High water absorption
|
||||||
}
|
}
|
||||||
|
|
||||||
void Intestines::update(double deltaTime_s) {
|
void Intestines::update(Patient& patient, 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chymeVolume_mL > 0) {
|
if (chymeVolume_mL > 0) {
|
||||||
// Simplified absorption model: total absorption is an average of all segments
|
// Simplified absorption model: total absorption is an average of all segments
|
||||||
double totalNutrientAbsorption = (duodenum.nutrientAbsorptionRate + jejunum.nutrientAbsorptionRate + ileum.nutrientAbsorptionRate + colon.nutrientAbsorptionRate) / 4.0;
|
double totalNutrientAbsorption = (duodenum.nutrientAbsorptionRate + jejunum.nutrientAbsorptionRate + ileum.nutrientAbsorptionRate + colon.nutrientAbsorptionRate) / 4.0;
|
||||||
double totalWaterAbsorption = (duodenum.waterAbsorptionRate + jejunum.waterAbsorptionRate + ileum.waterAbsorptionRate + colon.waterAbsorptionRate) / 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
|
// Reduce chyme volume based on absorption
|
||||||
double absorbedVolume = (totalNutrientAbsorption * 0.01 + totalWaterAbsorption * 0.1) * deltaTime_s;
|
double absorbedVolume = (totalNutrientAbsorption * 0.01 + totalWaterAbsorption * 0.1) * deltaTime_s;
|
||||||
chymeVolume_mL -= absorbedVolume;
|
chymeVolume_mL -= absorbedVolume;
|
||||||
|
|||||||
+18
-4
@@ -1,4 +1,7 @@
|
|||||||
#include "MedicalLib/Kidneys.h"
|
#include "MedicalLib/Kidneys.h"
|
||||||
|
#include "MedicalLib/Patient.h"
|
||||||
|
#include "MedicalLib/Heart.h"
|
||||||
|
#include "MedicalLib/Bladder.h"
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#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
|
// Recalculate total capacity based on nephron health
|
||||||
totalFiltrationCapacity = 0.0;
|
totalFiltrationCapacity = 0.0;
|
||||||
for (const auto& nephron : nephrons) {
|
for (const auto& nephron : nephrons) {
|
||||||
@@ -38,14 +41,25 @@ void Kidneys::update(double deltaTime_s) {
|
|||||||
}
|
}
|
||||||
totalFiltrationCapacity /= nephrons.size();
|
totalFiltrationCapacity /= nephrons.size();
|
||||||
|
|
||||||
// GFR is dependent on overall health
|
// GFR is dependent on blood pressure from the heart
|
||||||
const double baseline_gfr = 125.0 * totalFiltrationCapacity;
|
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);
|
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 = gfr_mL_per_min / 60.0 * 0.01; // Simplified relationship
|
||||||
urineOutput_mL_per_s += getFluctuation(0.001);
|
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
|
// Simulate electrolyte balance
|
||||||
bloodSodium_mEq_per_L += getFluctuation(0.05);
|
bloodSodium_mEq_per_L += getFluctuation(0.05);
|
||||||
bloodPotassium_mEq_per_L += getFluctuation(0.01);
|
bloodPotassium_mEq_per_L += getFluctuation(0.01);
|
||||||
|
|||||||
+19
-1
@@ -1,4 +1,5 @@
|
|||||||
#include "MedicalLib/Liver.h"
|
#include "MedicalLib/Liver.h"
|
||||||
|
#include "MedicalLib/Patient.h" // For Blood struct
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#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)
|
// Recalculate total capacity based on lobule health (for future use)
|
||||||
totalMetabolicCapacity = 0.0;
|
totalMetabolicCapacity = 0.0;
|
||||||
for (const auto& lobule : lobules) {
|
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);
|
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);
|
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);
|
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 {
|
std::string Liver::getSummary() const {
|
||||||
|
|||||||
+32
-2
@@ -1,4 +1,5 @@
|
|||||||
#include "MedicalLib/Lungs.h"
|
#include "MedicalLib/Lungs.h"
|
||||||
|
#include "MedicalLib/Patient.h" // For Blood struct
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -37,7 +38,7 @@ Lungs::Lungs(int id)
|
|||||||
mainBronchus = {"Main Bronchus", 0.8};
|
mainBronchus = {"Main Bronchus", 0.8};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Lungs::update(double deltaTime_s) {
|
void Lungs::update(Patient& patient, double deltaTime_s) {
|
||||||
totalTime_s += deltaTime_s;
|
totalTime_s += deltaTime_s;
|
||||||
|
|
||||||
updateRespiratoryMechanics(deltaTime_s);
|
updateRespiratoryMechanics(deltaTime_s);
|
||||||
@@ -48,6 +49,24 @@ void Lungs::update(double deltaTime_s) {
|
|||||||
if (capnographyData.size() > capnographyHistorySize) {
|
if (capnographyData.size() > capnographyHistorySize) {
|
||||||
capnographyData.pop_back();
|
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) {
|
void Lungs::updateRespiratoryMechanics(double deltaTime_s) {
|
||||||
@@ -68,12 +87,14 @@ void Lungs::updateRespiratoryMechanics(double deltaTime_s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Pressure and Volume dynamics
|
// Pressure and Volume dynamics
|
||||||
|
double totalCompliance = rightUpperLobe.compliance + rightMiddleLobe.compliance + rightLowerLobe.compliance + leftUpperLobe.compliance + leftLowerLobe.compliance;
|
||||||
|
|
||||||
double flowRate_mL_s = 0;
|
double flowRate_mL_s = 0;
|
||||||
if (currentState == RespiratoryState::INSPIRATION) {
|
if (currentState == RespiratoryState::INSPIRATION) {
|
||||||
// Simple sine wave for pressure generation
|
// Simple sine wave for pressure generation
|
||||||
double pressure_wave = sin(M_PI * (cyclePosition_s / inspirationDuration));
|
double pressure_wave = sin(M_PI * (cyclePosition_s / inspirationDuration));
|
||||||
peakInspiratoryPressure_cmH2O = 15.0 * pressure_wave; // 15 cmH2O peak
|
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;
|
tidalVolume_mL += flowRate_mL_s * deltaTime_s;
|
||||||
} else { // EXPIRATION
|
} else { // EXPIRATION
|
||||||
peakInspiratoryPressure_cmH2O = 0;
|
peakInspiratoryPressure_cmH2O = 0;
|
||||||
@@ -138,6 +159,15 @@ std::string Lungs::getSummary() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- Getters Implementation ---
|
// --- 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::getRespirationRate() const { return respirationRate; }
|
||||||
double Lungs::getOxygenSaturation() const { return oxygenSaturation; }
|
double Lungs::getOxygenSaturation() const { return oxygenSaturation; }
|
||||||
double Lungs::getTidalVolume() const { return tidalVolume_mL; }
|
double Lungs::getTidalVolume() const { return tidalVolume_mL; }
|
||||||
|
|||||||
+25
-12
@@ -1,4 +1,5 @@
|
|||||||
#include "MedicalLib/Pancreas.h"
|
#include "MedicalLib/Pancreas.h"
|
||||||
|
#include "MedicalLib/Patient.h"
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -19,22 +20,34 @@ Pancreas::Pancreas(int id)
|
|||||||
amylaseSecretion_U_per_L(80.0),
|
amylaseSecretion_U_per_L(80.0),
|
||||||
lipaseSecretion_U_per_L(40.0) {}
|
lipaseSecretion_U_per_L(40.0) {}
|
||||||
|
|
||||||
void Pancreas::update(double deltaTime_s) {
|
void Pancreas::update(Patient& patient, double deltaTime_s) {
|
||||||
// In a real model, hormone secretion would be driven by blood glucose.
|
// Hormone secretion is driven by blood glucose.
|
||||||
// Enzyme secretion would be driven by food in the duodenum.
|
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.
|
// 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);
|
amylaseSecretion_U_per_L += getFluctuation(0.2);
|
||||||
lipaseSecretion_U_per_L += getFluctuation(0.2);
|
lipaseSecretion_U_per_L += getFluctuation(0.2);
|
||||||
|
|
||||||
// Clamp to healthy ranges
|
// Clamp to healthy/possible ranges
|
||||||
insulinSecretion_units_per_hr = std::clamp(insulinSecretion_units_per_hr, 0.5, 2.0);
|
insulinSecretion_units_per_hr = std::clamp(insulinSecretion_units_per_hr, 0.5, 10.0);
|
||||||
glucagonSecretion_ng_per_hr = std::clamp(glucagonSecretion_ng_per_hr, 40.0, 60.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);
|
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);
|
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.
|
* @param deltaTime_s The time elapsed in seconds.
|
||||||
*/
|
*/
|
||||||
void updatePatient(Patient& patient, double deltaTime_s) {
|
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) {
|
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/SpinalCord.h"
|
||||||
|
#include "MedicalLib/Patient.h"
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -21,7 +22,7 @@ SpinalCord::SpinalCord(int id)
|
|||||||
ascendingSensoryTract = {"Ascending Sensory Tract", SignalStatus::NORMAL, 65.0};
|
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.
|
// In a healthy state, status doesn't change.
|
||||||
// Pathology models would alter these values.
|
// Pathology models would alter these values.
|
||||||
// For now, we just simulate minor fluctuations in a healthy velocity.
|
// For now, we just simulate minor fluctuations in a healthy velocity.
|
||||||
|
|||||||
+2
-1
@@ -1,4 +1,5 @@
|
|||||||
#include "MedicalLib/Spleen.h"
|
#include "MedicalLib/Spleen.h"
|
||||||
|
#include "MedicalLib/Patient.h"
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -18,7 +19,7 @@ Spleen::Spleen(int id) : Organ(id, "Spleen") {
|
|||||||
whitePulp = {1500.0, 500.0};
|
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.
|
// 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.
|
// For now, we just simulate minor fluctuations around a healthy baseline.
|
||||||
|
|
||||||
|
|||||||
+9
-8
@@ -1,4 +1,6 @@
|
|||||||
#include "MedicalLib/Stomach.h"
|
#include "MedicalLib/Stomach.h"
|
||||||
|
#include "MedicalLib/Patient.h"
|
||||||
|
#include "MedicalLib/Intestines.h"
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -20,17 +22,11 @@ Stomach::Stomach(int id)
|
|||||||
gastricJuiceSecretionRate_ml_per_s(0.1),
|
gastricJuiceSecretionRate_ml_per_s(0.1),
|
||||||
emptyingRate_ml_per_s(0.5) {}
|
emptyingRate_ml_per_s(0.5) {}
|
||||||
|
|
||||||
void Stomach::update(double deltaTime_s) {
|
void Stomach::update(Patient& patient, double deltaTime_s) {
|
||||||
// --- State Machine Logic ---
|
// --- State Machine Logic ---
|
||||||
switch (currentState) {
|
switch (currentState) {
|
||||||
case GastricState::EMPTY:
|
case GastricState::EMPTY:
|
||||||
// For demo, simulate food arriving every 20 seconds
|
// In a real simulation, addSubstance would be called externally (e.g., from Esophagus)
|
||||||
static double timeUntilFood = 0.0;
|
|
||||||
timeUntilFood += deltaTime_s;
|
|
||||||
if (timeUntilFood > 20.0) {
|
|
||||||
addSubstance(150.0); // Simulate arrival of a meal
|
|
||||||
timeUntilFood = 0.0;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GastricState::FILLING:
|
case GastricState::FILLING:
|
||||||
@@ -60,6 +56,11 @@ void Stomach::update(double deltaTime_s) {
|
|||||||
case GastricState::EMPTYING:
|
case GastricState::EMPTYING:
|
||||||
// Empty chyme into intestines
|
// Empty chyme into intestines
|
||||||
double amountToEmpty = emptyingRate_ml_per_s * deltaTime_s;
|
double amountToEmpty = emptyingRate_ml_per_s * deltaTime_s;
|
||||||
|
|
||||||
|
if (Intestines* intestines = getOrgan<Intestines>(patient)) {
|
||||||
|
intestines->receiveChyme(amountToEmpty);
|
||||||
|
}
|
||||||
|
|
||||||
currentVolume_mL -= amountToEmpty;
|
currentVolume_mL -= amountToEmpty;
|
||||||
|
|
||||||
if (currentVolume_mL <= 0) {
|
if (currentVolume_mL <= 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user