diff --git a/CMakeLists.txt b/CMakeLists.txt index fdc4907..1154bee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,24 @@ cmake_minimum_required(VERSION 3.10) project(MedicalLib) # Add the library -add_library(MedicalLib SHARED src/MedicalLib.cpp src/Patient.cpp) +add_library(MedicalLib SHARED + src/MedicalLib.cpp + src/Patient.cpp + src/Organ.cpp + src/Heart.cpp + src/Lungs.cpp + src/Brain.cpp + src/Liver.cpp + src/Kidneys.cpp + src/Bladder.cpp + src/Stomach.cpp + src/Intestines.cpp + src/Gallbladder.cpp + src/Pancreas.cpp + src/Esophagus.cpp + src/Spleen.cpp + src/SpinalCord.cpp +) # Define MEDICAL_LIB_EXPORT, so that __declspec(dllexport) is used target_compile_definitions(MedicalLib PRIVATE MEDICAL_LIB_EXPORT) diff --git a/examples/main.cpp b/examples/main.cpp index 34c0ad0..92f6f6d 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -1,28 +1,51 @@ #include +#include #include "MedicalLib/MedicalLib.h" +#include "MedicalLib/Patient.h" +#include "MedicalLib/Organ.h" +#include "MedicalLib/Heart.h" +#include "MedicalLib/Lungs.h" +#include "MedicalLib/Brain.h" +#include "MedicalLib/Liver.h" +#include "MedicalLib/Kidneys.h" +#include "MedicalLib/Stomach.h" -void printPatientVitals(const Patient& patient) { - std::cout << "Patient ID: " << patient.patientId << std::endl; - std::cout << " Blood Pressure: " << patient.bloodPressureSystolic << "/" << patient.bloodPressureDiastolic << " mmHg" << std::endl; - std::cout << " Heart Rate: " << patient.heartRate << " bpm" << std::endl; - std::cout << " Respiration Rate: " << patient.respirationRate << " breaths/min" << std::endl; - std::cout << " Body Temperature: " << patient.bodyTemperature << " C" << std::endl; - std::cout << " Oxygen Saturation: " << patient.oxygenSaturation << " %" << std::endl; +void printPatientSummary(const Patient& patient) { + std::cout << "--- Patient Summary (ID: " << patient.patientId << ") ---" << std::endl; + for (const auto& organ_ptr : patient.organs) { + // Print the general summary for each organ + std::cout << organ_ptr->getSummary() << std::endl; + + // Example of accessing specialized properties using dynamic_cast + if (const Heart* heart = dynamic_cast(organ_ptr.get())) { + std::cout << " -> Specific: Patient Heart Rate is " << heart->getHeartRate() << " bpm." << std::endl; + } + if (const Lungs* lungs = dynamic_cast(organ_ptr.get())) { + std::cout << " -> Specific: Patient SpO2 is " << lungs->getOxygenSaturation() << "%." << std::endl; + } + if (const Kidneys* kidneys = dynamic_cast(organ_ptr.get())) { + std::cout << " -> Specific: Kidney Filtration Rate is " << kidneys->getFiltrationRate() << " ml/min." << std::endl; + } + if (const Stomach* stomach = dynamic_cast(organ_ptr.get())) { + std::cout << " -> Specific: Stomach pH is " << stomach->getPhLevel() << "." << std::endl; + } + } + std::cout << "------------------------------------" << std::endl; } int main() { // Initialize a new patient Patient patient = initializePatient(1); - std::cout << "Initial Vitals:" << std::endl; - printPatientVitals(patient); + std::cout << "Initial State:" << std::endl; + printPatientSummary(patient); // Simulate a time step double deltaTime_s = 1.0; updatePatient(patient, deltaTime_s); - std::cout << "\nVitals after " << deltaTime_s << " second(s):" << std::endl; - printPatientVitals(patient); + std::cout << "\nState after " << deltaTime_s << " second(s):" << std::endl; + printPatientSummary(patient); return 0; } diff --git a/include/MedicalLib/Bladder.h b/include/MedicalLib/Bladder.h new file mode 100644 index 0000000..9e1eacb --- /dev/null +++ b/include/MedicalLib/Bladder.h @@ -0,0 +1,24 @@ +#pragma once + +#include "Organ.h" + +/** + * @brief Represents the Bladder. + */ +class MEDICAL_LIB_API Bladder : public Organ { +public: + Bladder(int id); + void update(double deltaTime_s) override; + std::string getSummary() const override; + + // Note: A real model would get urine input from kidneys. + // For now, it will just fill at a constant rate. + void addUrine(double amount_ml); + + double getCurrentVolume() const; + double getCapacity() const; + +private: + double currentVolume; // in ml + double capacity; // in ml +}; diff --git a/include/MedicalLib/Brain.h b/include/MedicalLib/Brain.h new file mode 100644 index 0000000..d679893 --- /dev/null +++ b/include/MedicalLib/Brain.h @@ -0,0 +1,35 @@ +#pragma once + +#include "Organ.h" + +/** + * @brief Represents the Brain organ. + */ +class MEDICAL_LIB_API Brain : public Organ { +public: + /** + * @brief Constructor for the Brain class. + * @param id The ID of the organ. + */ + Brain(int id); + + /** + * @brief Updates the brain's state over time. + * @param deltaTime_s The time elapsed in seconds. + */ + void update(double deltaTime_s) override; + + /** + * @brief Gets a string summary of the brain's vitals. + * @return A string containing the brain's vital signs. + */ + std::string getSummary() const override; + + // Specific getters for Brain properties + double getConsciousnessLevel() const; // A simplified scale, e.g., 0.0 to 1.0 + double getCerebralBloodFlow() const; // in ml/100g/min + +private: + double consciousnessLevel; + double cerebralBloodFlow; +}; diff --git a/include/MedicalLib/Esophagus.h b/include/MedicalLib/Esophagus.h new file mode 100644 index 0000000..57eeb97 --- /dev/null +++ b/include/MedicalLib/Esophagus.h @@ -0,0 +1,19 @@ +#pragma once + +#include "Organ.h" + +/** + * @brief Represents the Esophagus. + * @note This is a placeholder with minimal logic for now. + */ +class MEDICAL_LIB_API Esophagus : public Organ { +public: + Esophagus(int id); + void update(double deltaTime_s) override; + std::string getSummary() const override; + + double getMotility() const; // Peristalsis efficiency + +private: + double motility; +}; diff --git a/include/MedicalLib/Gallbladder.h b/include/MedicalLib/Gallbladder.h new file mode 100644 index 0000000..8e4eef2 --- /dev/null +++ b/include/MedicalLib/Gallbladder.h @@ -0,0 +1,18 @@ +#pragma once + +#include "Organ.h" + +/** + * @brief Represents the Gallbladder. + */ +class MEDICAL_LIB_API Gallbladder : public Organ { +public: + Gallbladder(int id); + void update(double deltaTime_s) override; + std::string getSummary() const override; + + double getBileStored() const; + +private: + double bileStored; // in ml +}; diff --git a/include/MedicalLib/Heart.h b/include/MedicalLib/Heart.h new file mode 100644 index 0000000..e41708c --- /dev/null +++ b/include/MedicalLib/Heart.h @@ -0,0 +1,37 @@ +#pragma once + +#include "Organ.h" + +/** + * @brief Represents the Heart organ. + */ +class MEDICAL_LIB_API Heart : public Organ { +public: + /** + * @brief Constructor for the Heart class. + * @param id The ID of the organ. + */ + Heart(int id); + + /** + * @brief Updates the heart's state over time. + * @param deltaTime_s The time elapsed in seconds. + */ + void update(double deltaTime_s) override; + + /** + * @brief Gets a string summary of the heart's vitals. + * @return A string containing the heart's vital signs. + */ + std::string getSummary() const override; + + // Specific getters for Heart properties + double getHeartRate() const; + double getBloodPressureSystolic() const; + double getBloodPressureDiastolic() const; + +private: + double heartRate; + double bloodPressureSystolic; + double bloodPressureDiastolic; +}; diff --git a/include/MedicalLib/Intestines.h b/include/MedicalLib/Intestines.h new file mode 100644 index 0000000..0585017 --- /dev/null +++ b/include/MedicalLib/Intestines.h @@ -0,0 +1,20 @@ +#pragma once + +#include "Organ.h" + +/** + * @brief Represents the Intestines (Small and Large combined). + */ +class MEDICAL_LIB_API Intestines : public Organ { +public: + Intestines(int id); + void update(double deltaTime_s) override; + std::string getSummary() const override; + + double getNutrientAbsorptionRate() const; + double getWaterAbsorptionRate() const; + +private: + double nutrientAbsorptionRate; // in arbitrary units + double waterAbsorptionRate; // in ml/s +}; diff --git a/include/MedicalLib/Kidneys.h b/include/MedicalLib/Kidneys.h new file mode 100644 index 0000000..87c1adc --- /dev/null +++ b/include/MedicalLib/Kidneys.h @@ -0,0 +1,20 @@ +#pragma once + +#include "Organ.h" + +/** + * @brief Represents the Kidneys. + */ +class MEDICAL_LIB_API Kidneys : public Organ { +public: + Kidneys(int id); + void update(double deltaTime_s) override; + std::string getSummary() const override; + + double getFiltrationRate() const; + double getUrineProductionRate() const; + +private: + double filtrationRate; // in ml/min + double urineProductionRate; // in ml/s +}; diff --git a/include/MedicalLib/Liver.h b/include/MedicalLib/Liver.h new file mode 100644 index 0000000..1fa483c --- /dev/null +++ b/include/MedicalLib/Liver.h @@ -0,0 +1,35 @@ +#pragma once + +#include "Organ.h" + +/** + * @brief Represents the Liver organ. + */ +class MEDICAL_LIB_API Liver : public Organ { +public: + /** + * @brief Constructor for the Liver class. + * @param id The ID of the organ. + */ + Liver(int id); + + /** + * @brief Updates the liver's state over time. + * @param deltaTime_s The time elapsed in seconds. + */ + void update(double deltaTime_s) override; + + /** + * @brief Gets a string summary of the liver's vitals. + * @return A string containing the liver's vital signs. + */ + std::string getSummary() const override; + + // Specific getters for Liver properties + double getBileProductionRate() const; // in ml/s + double getGlucoseProductionRate() const; // in g/s + +private: + double bileProductionRate; + double glucoseProductionRate; +}; diff --git a/include/MedicalLib/Lungs.h b/include/MedicalLib/Lungs.h new file mode 100644 index 0000000..4693fd5 --- /dev/null +++ b/include/MedicalLib/Lungs.h @@ -0,0 +1,35 @@ +#pragma once + +#include "Organ.h" + +/** + * @brief Represents the Lungs organ. + */ +class MEDICAL_LIB_API Lungs : public Organ { +public: + /** + * @brief Constructor for the Lungs class. + * @param id The ID of the organ. + */ + Lungs(int id); + + /** + * @brief Updates the lungs' state over time. + * @param deltaTime_s The time elapsed in seconds. + */ + void update(double deltaTime_s) override; + + /** + * @brief Gets a string summary of the lungs' vitals. + * @return A string containing the lungs' vital signs. + */ + std::string getSummary() const override; + + // Specific getters for Lungs properties + double getRespirationRate() const; + double getOxygenSaturation() const; + +private: + double respirationRate; + double oxygenSaturation; +}; diff --git a/include/MedicalLib/Organ.h b/include/MedicalLib/Organ.h new file mode 100644 index 0000000..5edfeff --- /dev/null +++ b/include/MedicalLib/Organ.h @@ -0,0 +1,61 @@ +#pragma once + +#include +#include + +// Define MEDICAL_LIB_EXPORT for exporting symbols from the DLL +#if defined(_WIN32) + #if defined(MEDICAL_LIB_EXPORT) + #define MEDICAL_LIB_API __declspec(dllexport) + #else + #define MEDICAL_LIB_API __declspec(dllimport) + #endif +#else + #define MEDICAL_LIB_API +#endif + +/** + * @brief Abstract base class for all organ types. + */ +class MEDICAL_LIB_API Organ { +public: + /** + * @brief Constructor for the Organ class. + * @param id The ID of the organ. + * @param type The type of the organ as a string. + */ + Organ(int id, const std::string& type); + + /** + * @brief Virtual destructor. + */ + virtual ~Organ() = default; + + /** + * @brief Pure virtual function to update the organ's state over time. + * @param deltaTime_s The time elapsed in seconds. + */ + virtual void update(double deltaTime_s) = 0; + + /** + * @brief Pure virtual function to get a string summary of the organ's vitals. + * @return A string containing the organ's vital signs. + */ + virtual std::string getSummary() const = 0; + + /** + * @brief Gets the organ ID. + * @return The organ ID. + */ + int getId() const; + + /** + * @brief Gets the organ type. + * @return The organ type as a string. + */ + const std::string& getType() const; + +protected: + int organId; + std::string organType; +}; diff --git a/include/MedicalLib/Pancreas.h b/include/MedicalLib/Pancreas.h new file mode 100644 index 0000000..3216fc4 --- /dev/null +++ b/include/MedicalLib/Pancreas.h @@ -0,0 +1,20 @@ +#pragma once + +#include "Organ.h" + +/** + * @brief Represents the Pancreas, with both endocrine and exocrine functions. + */ +class MEDICAL_LIB_API Pancreas : public Organ { +public: + Pancreas(int id); + void update(double deltaTime_s) override; + std::string getSummary() const override; + + double getInsulinProduction() const; + double getGlucagonProduction() const; + +private: + double insulinProduction; // in units/hr + double glucagonProduction; // in ng/hr +}; diff --git a/include/MedicalLib/Patient.h b/include/MedicalLib/Patient.h index e86d3b0..11984cc 100644 --- a/include/MedicalLib/Patient.h +++ b/include/MedicalLib/Patient.h @@ -1,16 +1,17 @@ #pragma once +#include +#include + +// Forward-declare the Organ class to avoid circular dependencies +class Organ; + /** * @brief Holds all the vital signs and other medical information for a patient. */ struct Patient { int patientId; - double bloodPressureSystolic; - double bloodPressureDiastolic; - double heartRate; - double respirationRate; - double bodyTemperature; - double oxygenSaturation; + std::vector> organs; }; // Define MEDICAL_LIB_EXPORT for exporting symbols from the DLL diff --git a/include/MedicalLib/SpinalCord.h b/include/MedicalLib/SpinalCord.h new file mode 100644 index 0000000..774ab27 --- /dev/null +++ b/include/MedicalLib/SpinalCord.h @@ -0,0 +1,18 @@ +#pragma once + +#include "Organ.h" + +/** + * @brief Represents the Spinal Cord. + */ +class MEDICAL_LIB_API SpinalCord : public Organ { +public: + SpinalCord(int id); + void update(double deltaTime_s) override; + std::string getSummary() const override; + + double getSignalConductionVelocity() const; // in m/s + +private: + double signalConductionVelocity; +}; diff --git a/include/MedicalLib/Spleen.h b/include/MedicalLib/Spleen.h new file mode 100644 index 0000000..4841bba --- /dev/null +++ b/include/MedicalLib/Spleen.h @@ -0,0 +1,20 @@ +#pragma once + +#include "Organ.h" + +/** + * @brief Represents the Spleen. + */ +class MEDICAL_LIB_API Spleen : public Organ { +public: + Spleen(int id); + void update(double deltaTime_s) override; + std::string getSummary() const override; + + double getRedBloodCellCount() const; + double getWhiteBloodCellCount() const; + +private: + double redBloodCellCount; // in millions/uL + double whiteBloodCellCount; // in thousands/uL +}; diff --git a/include/MedicalLib/Stomach.h b/include/MedicalLib/Stomach.h new file mode 100644 index 0000000..14886e8 --- /dev/null +++ b/include/MedicalLib/Stomach.h @@ -0,0 +1,20 @@ +#pragma once + +#include "Organ.h" + +/** + * @brief Represents the Stomach. + */ +class MEDICAL_LIB_API Stomach : public Organ { +public: + Stomach(int id); + void update(double deltaTime_s) override; + std::string getSummary() const override; + + double getPhLevel() const; + double getDigestionRate() const; + +private: + double phLevel; // Acidity + double digestionRate; // in arbitrary units +}; diff --git a/src/Bladder.cpp b/src/Bladder.cpp new file mode 100644 index 0000000..3de5008 --- /dev/null +++ b/src/Bladder.cpp @@ -0,0 +1,29 @@ +#include "MedicalLib/Bladder.h" +#include +#include +#include + +Bladder::Bladder(int id) : Organ(id, "Bladder"), currentVolume(50.0), capacity(500.0) {} + +void Bladder::update(double deltaTime_s) { + // In a more complex model, this would be driven by kidney output. + // For now, simulate a constant fill rate. + const double fillRate_ml_per_s = 0.02; + currentVolume += fillRate_ml_per_s * deltaTime_s; + currentVolume = std::clamp(currentVolume, 0.0, capacity); +} + +void Bladder::addUrine(double amount_ml) { + currentVolume += amount_ml; + currentVolume = std::clamp(currentVolume, 0.0, capacity); +} + +std::string Bladder::getSummary() const { + std::stringstream ss; + ss << "Type: " << organType << " (ID: " << organId << ")\n" + << " Volume: " << currentVolume << " / " << capacity << " ml"; + return ss.str(); +} + +double Bladder::getCurrentVolume() const { return currentVolume; } +double Bladder::getCapacity() const { return capacity; } diff --git a/src/Brain.cpp b/src/Brain.cpp new file mode 100644 index 0000000..2d98dc0 --- /dev/null +++ b/src/Brain.cpp @@ -0,0 +1,39 @@ +#include "MedicalLib/Brain.h" +#include +#include +#include + +// Helper function for random fluctuations +static double getFluctuation(double stddev) { + static std::random_device rd; + static std::mt19937 gen(rd()); + std::normal_distribution<> d(0, stddev); + return d(gen); +} + +Brain::Brain(int id) : Organ(id, "Brain"), consciousnessLevel(1.0), cerebralBloodFlow(50.0) {} + +void Brain::update(double deltaTime_s) { + const double baseline_consciousness = 1.0; + const double baseline_cbf = 50.0; + const double theta = 0.05; // Slower reversion for brain metrics + const double consciousness_stddev = 0.001; + const double cbf_stddev = 0.5; + + consciousnessLevel += theta * (baseline_consciousness - consciousnessLevel) * deltaTime_s + getFluctuation(consciousness_stddev * deltaTime_s); + cerebralBloodFlow += theta * (baseline_cbf - cerebralBloodFlow) * deltaTime_s + getFluctuation(cbf_stddev * deltaTime_s); + + consciousnessLevel = std::clamp(consciousnessLevel, 0.0, 1.0); + cerebralBloodFlow = std::clamp(cerebralBloodFlow, 40.0, 60.0); +} + +std::string Brain::getSummary() const { + std::stringstream ss; + ss << "Type: " << organType << " (ID: " << organId << ")\n" + << " Consciousness Level: " << consciousnessLevel * 100 << "%\n" + << " Cerebral Blood Flow: " << cerebralBloodFlow << " ml/100g/min"; + return ss.str(); +} + +double Brain::getConsciousnessLevel() const { return consciousnessLevel; } +double Brain::getCerebralBloodFlow() const { return cerebralBloodFlow; } diff --git a/src/Esophagus.cpp b/src/Esophagus.cpp new file mode 100644 index 0000000..9fe8d5f --- /dev/null +++ b/src/Esophagus.cpp @@ -0,0 +1,26 @@ +#include "MedicalLib/Esophagus.h" +#include +#include +#include + +Esophagus::Esophagus(int id) : Organ(id, "Esophagus"), motility(1.0) {} + +void Esophagus::update(double deltaTime_s) { + // Placeholder, no real logic yet. + // Fluctuate motility slightly. + static std::random_device rd; + static std::mt19937 gen(rd()); + std::normal_distribution<> d(0, 0.001); + + motility += d(gen) * deltaTime_s; + motility = std::clamp(motility, 0.95, 1.05); +} + +std::string Esophagus::getSummary() const { + std::stringstream ss; + ss << "Type: " << organType << " (ID: " << organId << ")\n" + << " Motility: " << motility * 100 << "%"; + return ss.str(); +} + +double Esophagus::getMotility() const { return motility; } diff --git a/src/Gallbladder.cpp b/src/Gallbladder.cpp new file mode 100644 index 0000000..23dbcb6 --- /dev/null +++ b/src/Gallbladder.cpp @@ -0,0 +1,26 @@ +#include "MedicalLib/Gallbladder.h" +#include +#include +#include + +Gallbladder::Gallbladder(int id) : Organ(id, "Gallbladder"), bileStored(30.0) {} + +void Gallbladder::update(double deltaTime_s) { + // A real model would be affected by liver production and digestion. + // For now, it just sits there with a small fluctuation. + static std::random_device rd; + static std::mt19937 gen(rd()); + std::normal_distribution<> d(0, 0.01); + + bileStored += d(gen) * deltaTime_s; + bileStored = std::clamp(bileStored, 10.0, 50.0); +} + +std::string Gallbladder::getSummary() const { + std::stringstream ss; + ss << "Type: " << organType << " (ID: " << organId << ")\n" + << " Bile Stored: " << bileStored << " ml"; + return ss.str(); +} + +double Gallbladder::getBileStored() const { return bileStored; } diff --git a/src/Heart.cpp b/src/Heart.cpp new file mode 100644 index 0000000..3c8727d --- /dev/null +++ b/src/Heart.cpp @@ -0,0 +1,43 @@ +#include "MedicalLib/Heart.h" +#include +#include +#include + +// Helper function for random fluctuations +static double getFluctuation(double stddev) { + static std::random_device rd; + static std::mt19937 gen(rd()); + std::normal_distribution<> d(0, stddev); + return d(gen); +} + +Heart::Heart(int id) : Organ(id, "Heart"), heartRate(75.0), bloodPressureSystolic(120.0), bloodPressureDiastolic(80.0) {} + +void Heart::update(double deltaTime_s) { + const double baseline_hr = 75.0; + const double baseline_bp_systolic = 120.0; + const double baseline_bp_diastolic = 80.0; + const double theta = 0.1; // Mean reversion speed + const double hr_stddev = 0.1; + const double bp_stddev = 0.1; + + heartRate += theta * (baseline_hr - heartRate) * deltaTime_s + getFluctuation(hr_stddev * deltaTime_s); + bloodPressureSystolic += theta * (baseline_bp_systolic - bloodPressureSystolic) * deltaTime_s + getFluctuation(bp_stddev * deltaTime_s); + bloodPressureDiastolic += theta * (baseline_bp_diastolic - bloodPressureDiastolic) * deltaTime_s + getFluctuation(bp_stddev * deltaTime_s); + + heartRate = std::clamp(heartRate, 60.0, 100.0); + bloodPressureSystolic = std::clamp(bloodPressureSystolic, 90.0, 120.0); + bloodPressureDiastolic = std::clamp(bloodPressureDiastolic, 60.0, 80.0); +} + +std::string Heart::getSummary() const { + std::stringstream ss; + ss << "Type: " << organType << " (ID: " << organId << ")\n" + << " Heart Rate: " << heartRate << " bpm\n" + << " Blood Pressure: " << bloodPressureSystolic << "/" << bloodPressureDiastolic << " mmHg"; + return ss.str(); +} + +double Heart::getHeartRate() const { return heartRate; } +double Heart::getBloodPressureSystolic() const { return bloodPressureSystolic; } +double Heart::getBloodPressureDiastolic() const { return bloodPressureDiastolic; } diff --git a/src/Intestines.cpp b/src/Intestines.cpp new file mode 100644 index 0000000..1df2ae1 --- /dev/null +++ b/src/Intestines.cpp @@ -0,0 +1,39 @@ +#include "MedicalLib/Intestines.h" +#include +#include +#include + +// Helper function for random fluctuations +static double getFluctuation(double stddev) { + static std::random_device rd; + static std::mt19937 gen(rd()); + std::normal_distribution<> d(0, stddev); + return d(gen); +} + +Intestines::Intestines(int id) : Organ(id, "Intestines"), nutrientAbsorptionRate(1.0), waterAbsorptionRate(0.1) {} + +void Intestines::update(double deltaTime_s) { + const double baseline_nutrient_abs = 1.0; + const double baseline_water_abs = 0.1; + const double theta = 0.05; + const double nutrient_abs_stddev = 0.02; + const double water_abs_stddev = 0.005; + + nutrientAbsorptionRate += theta * (baseline_nutrient_abs - nutrientAbsorptionRate) * deltaTime_s + getFluctuation(nutrient_abs_stddev * deltaTime_s); + waterAbsorptionRate += theta * (baseline_water_abs - waterAbsorptionRate) * deltaTime_s + getFluctuation(water_abs_stddev * deltaTime_s); + + nutrientAbsorptionRate = std::clamp(nutrientAbsorptionRate, 0.8, 1.2); + waterAbsorptionRate = std::clamp(waterAbsorptionRate, 0.08, 0.12); +} + +std::string Intestines::getSummary() const { + std::stringstream ss; + ss << "Type: " << organType << " (ID: " << organId << ")\n" + << " Nutrient Absorption: " << nutrientAbsorptionRate << "\n" + << " Water Absorption: " << waterAbsorptionRate << " ml/s"; + return ss.str(); +} + +double Intestines::getNutrientAbsorptionRate() const { return nutrientAbsorptionRate; } +double Intestines::getWaterAbsorptionRate() const { return waterAbsorptionRate; } diff --git a/src/Kidneys.cpp b/src/Kidneys.cpp new file mode 100644 index 0000000..d08d3c9 --- /dev/null +++ b/src/Kidneys.cpp @@ -0,0 +1,39 @@ +#include "MedicalLib/Kidneys.h" +#include +#include +#include + +// Helper function for random fluctuations +static double getFluctuation(double stddev) { + static std::random_device rd; + static std::mt19937 gen(rd()); + std::normal_distribution<> d(0, stddev); + return d(gen); +} + +Kidneys::Kidneys(int id) : Organ(id, "Kidneys"), filtrationRate(125.0), urineProductionRate(0.02) {} + +void Kidneys::update(double deltaTime_s) { + const double baseline_filtration = 125.0; + const double baseline_urine_prod = 0.02; + const double theta = 0.03; + const double filtration_stddev = 1.0; + const double urine_prod_stddev = 0.001; + + filtrationRate += theta * (baseline_filtration - filtrationRate) * deltaTime_s + getFluctuation(filtration_stddev * deltaTime_s); + urineProductionRate += theta * (baseline_urine_prod - urineProductionRate) * deltaTime_s + getFluctuation(urine_prod_stddev * deltaTime_s); + + filtrationRate = std::clamp(filtrationRate, 100.0, 150.0); + urineProductionRate = std::clamp(urineProductionRate, 0.01, 0.03); +} + +std::string Kidneys::getSummary() const { + std::stringstream ss; + ss << "Type: " << organType << " (ID: " << organId << ")\n" + << " Filtration Rate: " << filtrationRate << " ml/min\n" + << " Urine Production: " << urineProductionRate << " ml/s"; + return ss.str(); +} + +double Kidneys::getFiltrationRate() const { return filtrationRate; } +double Kidneys::getUrineProductionRate() const { return urineProductionRate; } diff --git a/src/Liver.cpp b/src/Liver.cpp new file mode 100644 index 0000000..934ac74 --- /dev/null +++ b/src/Liver.cpp @@ -0,0 +1,42 @@ +#include "MedicalLib/Liver.h" +#include +#include +#include + +// Helper function for random fluctuations +static double getFluctuation(double stddev) { + static std::random_device rd; + static std::mt19937 gen(rd()); + std::normal_distribution<> d(0, stddev); + return d(gen); +} + +// Healthy baseline rates converted to per-second +// Bile: 400-800 ml/day -> ~0.0069 ml/s +// Glucose: ~90 g/day -> ~0.001 g/s +Liver::Liver(int id) : Organ(id, "Liver"), bileProductionRate(0.0069), glucoseProductionRate(0.001) {} + +void Liver::update(double deltaTime_s) { + const double baseline_bile_rate = 0.0069; + const double baseline_glucose_rate = 0.001; + const double theta = 0.02; // Slow reversion for metabolic rates + const double bile_stddev = 0.0001; + const double glucose_stddev = 0.00005; + + bileProductionRate += theta * (baseline_bile_rate - bileProductionRate) * deltaTime_s + getFluctuation(bile_stddev * deltaTime_s); + glucoseProductionRate += theta * (baseline_glucose_rate - glucoseProductionRate) * deltaTime_s + getFluctuation(glucose_stddev * deltaTime_s); + + bileProductionRate = std::clamp(bileProductionRate, 0.005, 0.009); + glucoseProductionRate = std::clamp(glucoseProductionRate, 0.0008, 0.0012); +} + +std::string Liver::getSummary() const { + std::stringstream ss; + ss << "Type: " << organType << " (ID: " << organId << ")\n" + << " Bile Production Rate: " << bileProductionRate * 60 << " ml/min\n" + << " Glucose Production Rate: " << glucoseProductionRate * 60 << " g/min"; + return ss.str(); +} + +double Liver::getBileProductionRate() const { return bileProductionRate; } +double Liver::getGlucoseProductionRate() const { return glucoseProductionRate; } diff --git a/src/Lungs.cpp b/src/Lungs.cpp new file mode 100644 index 0000000..1ba4046 --- /dev/null +++ b/src/Lungs.cpp @@ -0,0 +1,39 @@ +#include "MedicalLib/Lungs.h" +#include +#include +#include + +// Helper function for random fluctuations +static double getFluctuation(double stddev) { + static std::random_device rd; + static std::mt19937 gen(rd()); + std::normal_distribution<> d(0, stddev); + return d(gen); +} + +Lungs::Lungs(int id) : Organ(id, "Lungs"), respirationRate(16.0), oxygenSaturation(98.0) {} + +void Lungs::update(double deltaTime_s) { + const double baseline_rr = 16.0; + const double baseline_spo2 = 98.0; + const double theta = 0.1; // Mean reversion speed + const double rr_stddev = 0.05; + const double spo2_stddev = 0.02; + + respirationRate += theta * (baseline_rr - respirationRate) * deltaTime_s + getFluctuation(rr_stddev * deltaTime_s); + oxygenSaturation += theta * (baseline_spo2 - oxygenSaturation) * deltaTime_s + getFluctuation(spo2_stddev * deltaTime_s); + + respirationRate = std::clamp(respirationRate, 12.0, 20.0); + oxygenSaturation = std::clamp(oxygenSaturation, 96.0, 100.0); +} + +std::string Lungs::getSummary() const { + std::stringstream ss; + ss << "Type: " << organType << " (ID: " << organId << ")\n" + << " Respiration Rate: " << respirationRate << " breaths/min\n" + << " Oxygen Saturation: " << oxygenSaturation << " %"; + return ss.str(); +} + +double Lungs::getRespirationRate() const { return respirationRate; } +double Lungs::getOxygenSaturation() const { return oxygenSaturation; } diff --git a/src/Organ.cpp b/src/Organ.cpp new file mode 100644 index 0000000..bdad160 --- /dev/null +++ b/src/Organ.cpp @@ -0,0 +1,11 @@ +#include "MedicalLib/Organ.h" + +Organ::Organ(int id, const std::string& type) : organId(id), organType(type) {} + +int Organ::getId() const { + return organId; +} + +const std::string& Organ::getType() const { + return organType; +} diff --git a/src/Pancreas.cpp b/src/Pancreas.cpp new file mode 100644 index 0000000..cea1efe --- /dev/null +++ b/src/Pancreas.cpp @@ -0,0 +1,39 @@ +#include "MedicalLib/Pancreas.h" +#include +#include +#include + +// Helper function for random fluctuations +static double getFluctuation(double stddev) { + static std::random_device rd; + static std::mt19937 gen(rd()); + std::normal_distribution<> d(0, stddev); + return d(gen); +} + +Pancreas::Pancreas(int id) : Organ(id, "Pancreas"), insulinProduction(1.0), glucagonProduction(50.0) {} + +void Pancreas::update(double deltaTime_s) { + const double baseline_insulin = 1.0; + const double baseline_glucagon = 50.0; + const double theta = 0.05; + const double insulin_stddev = 0.01; + const double glucagon_stddev = 1.0; + + insulinProduction += theta * (baseline_insulin - insulinProduction) * deltaTime_s + getFluctuation(insulin_stddev * deltaTime_s); + glucagonProduction += theta * (baseline_glucagon - glucagonProduction) * deltaTime_s + getFluctuation(glucagon_stddev * deltaTime_s); + + insulinProduction = std::clamp(insulinProduction, 0.5, 2.0); + glucagonProduction = std::clamp(glucagonProduction, 40.0, 60.0); +} + +std::string Pancreas::getSummary() const { + std::stringstream ss; + ss << "Type: " << organType << " (ID: " << organId << ")\n" + << " Insulin Production: " << insulinProduction << " units/hr\n" + << " Glucagon Production: " << glucagonProduction << " ng/hr"; + return ss.str(); +} + +double Pancreas::getInsulinProduction() const { return insulinProduction; } +double Pancreas::getGlucagonProduction() const { return glucagonProduction; } diff --git a/src/Patient.cpp b/src/Patient.cpp index 427a3b0..5deb88b 100644 --- a/src/Patient.cpp +++ b/src/Patient.cpp @@ -1,74 +1,54 @@ #include "MedicalLib/Patient.h" -#include -#include // For std::clamp +#include "MedicalLib/Heart.h" +#include "MedicalLib/Lungs.h" +#include "MedicalLib/Brain.h" +#include "MedicalLib/Liver.h" +#include "MedicalLib/Kidneys.h" +#include "MedicalLib/Bladder.h" +#include "MedicalLib/Stomach.h" +#include "MedicalLib/Intestines.h" +#include "MedicalLib/Gallbladder.h" +#include "MedicalLib/Pancreas.h" +#include "MedicalLib/Esophagus.h" +#include "MedicalLib/Spleen.h" +#include "MedicalLib/SpinalCord.h" +#include /** - * @brief Helper function to generate random fluctuations from a normal distribution. - * @param stddev The standard deviation of the distribution. - * @return A random value. - */ -double getFluctuation(double stddev) { - static std::random_device rd; - static std::mt19937 gen(rd()); - std::normal_distribution<> d(0, stddev); - return d(gen); -} - -/** - * @brief Initializes a new patient with baseline vital signs. + * @brief Initializes a new patient with baseline vital signs and a standard set of organs. * @param patientId The ID for the new patient. * @return A Patient struct with default healthy values. */ Patient initializePatient(int patientId) { Patient patient; patient.patientId = patientId; - patient.bloodPressureSystolic = 120.0; - patient.bloodPressureDiastolic = 80.0; - patient.heartRate = 75.0; - patient.respirationRate = 16.0; - patient.bodyTemperature = 37.0; - patient.oxygenSaturation = 98.0; + + // Initialize default organs + patient.organs.push_back(std::make_unique(1)); + patient.organs.push_back(std::make_unique(2)); + patient.organs.push_back(std::make_unique(3)); + patient.organs.push_back(std::make_unique(4)); + patient.organs.push_back(std::make_unique(5)); + patient.organs.push_back(std::make_unique(6)); + patient.organs.push_back(std::make_unique(7)); + patient.organs.push_back(std::make_unique(8)); + patient.organs.push_back(std::make_unique(9)); + patient.organs.push_back(std::make_unique(10)); + patient.organs.push_back(std::make_unique(11)); + patient.organs.push_back(std::make_unique(12)); + patient.organs.push_back(std::make_unique(13)); + return patient; } /** - * @brief Updates the patient's vital signs based on the time elapsed. - * This function simulates minor, random fluctuations around a healthy baseline. + * @brief Updates the patient's state by updating the state of all their organs. * @param patient The patient to update. * @param deltaTime_s The time elapsed in seconds. */ void updatePatient(Patient& patient, double deltaTime_s) { - // Baseline healthy values - const double baseline_hr = 75.0; - const double baseline_bp_systolic = 120.0; - const double baseline_bp_diastolic = 80.0; - const double baseline_rr = 16.0; - const double baseline_temp = 37.0; - const double baseline_spo2 = 98.0; - - // Reversion speed (how quickly vitals return to baseline) - const double theta = 0.1; - - // Standard deviations for random fluctuations per second - const double hr_stddev = 0.1; - const double bp_stddev = 0.1; - const double rr_stddev = 0.05; - const double temp_stddev = 0.01; - const double spo2_stddev = 0.02; - - // Update vitals using a mean-reverting model - patient.heartRate += theta * (baseline_hr - patient.heartRate) * deltaTime_s + getFluctuation(hr_stddev * deltaTime_s); - patient.bloodPressureSystolic += theta * (baseline_bp_systolic - patient.bloodPressureSystolic) * deltaTime_s + getFluctuation(bp_stddev * deltaTime_s); - patient.bloodPressureDiastolic += theta * (baseline_bp_diastolic - patient.bloodPressureDiastolic) * deltaTime_s + getFluctuation(bp_stddev * deltaTime_s); - patient.respirationRate += theta * (baseline_rr - patient.respirationRate) * deltaTime_s + getFluctuation(rr_stddev * deltaTime_s); - patient.bodyTemperature += theta * (baseline_temp - patient.bodyTemperature) * deltaTime_s + getFluctuation(temp_stddev * deltaTime_s); - patient.oxygenSaturation += theta * (baseline_spo2 - patient.oxygenSaturation) * deltaTime_s + getFluctuation(spo2_stddev * deltaTime_s); - - // Clamp values to within healthy physiological ranges - patient.heartRate = std::clamp(patient.heartRate, 60.0, 100.0); - patient.bloodPressureSystolic = std::clamp(patient.bloodPressureSystolic, 90.0, 120.0); - patient.bloodPressureDiastolic = std::clamp(patient.bloodPressureDiastolic, 60.0, 80.0); - patient.respirationRate = std::clamp(patient.respirationRate, 12.0, 20.0); - patient.bodyTemperature = std::clamp(patient.bodyTemperature, 36.5, 37.3); - patient.oxygenSaturation = std::clamp(patient.oxygenSaturation, 96.0, 100.0); + // Update all organs + for (auto& organ : patient.organs) { + organ->update(deltaTime_s); + } } diff --git a/src/SpinalCord.cpp b/src/SpinalCord.cpp new file mode 100644 index 0000000..54f6eba --- /dev/null +++ b/src/SpinalCord.cpp @@ -0,0 +1,33 @@ +#include "MedicalLib/SpinalCord.h" +#include +#include +#include + +// Helper function for random fluctuations +static double getFluctuation(double stddev) { + static std::random_device rd; + static std::mt19937 gen(rd()); + std::normal_distribution<> d(0, stddev); + return d(gen); +} + +SpinalCord::SpinalCord(int id) : Organ(id, "SpinalCord"), signalConductionVelocity(70.0) {} + +void SpinalCord::update(double deltaTime_s) { + const double baseline_velocity = 70.0; + const double theta = 0.01; + const double velocity_stddev = 0.1; + + signalConductionVelocity += theta * (baseline_velocity - signalConductionVelocity) * deltaTime_s + getFluctuation(velocity_stddev * deltaTime_s); + + signalConductionVelocity = std::clamp(signalConductionVelocity, 60.0, 80.0); +} + +std::string SpinalCord::getSummary() const { + std::stringstream ss; + ss << "Type: " << organType << " (ID: " << organId << ")\n" + << " Signal Velocity: " << signalConductionVelocity << " m/s"; + return ss.str(); +} + +double SpinalCord::getSignalConductionVelocity() const { return signalConductionVelocity; } diff --git a/src/Spleen.cpp b/src/Spleen.cpp new file mode 100644 index 0000000..9d05db0 --- /dev/null +++ b/src/Spleen.cpp @@ -0,0 +1,39 @@ +#include "MedicalLib/Spleen.h" +#include +#include +#include + +// Helper function for random fluctuations +static double getFluctuation(double stddev) { + static std::random_device rd; + static std::mt19937 gen(rd()); + std::normal_distribution<> d(0, stddev); + return d(gen); +} + +Spleen::Spleen(int id) : Organ(id, "Spleen"), redBloodCellCount(4.5), whiteBloodCellCount(7.5) {} + +void Spleen::update(double deltaTime_s) { + const double baseline_rbc = 4.5; + const double baseline_wbc = 7.5; + const double theta = 0.02; + const double rbc_stddev = 0.01; + const double wbc_stddev = 0.05; + + redBloodCellCount += theta * (baseline_rbc - redBloodCellCount) * deltaTime_s + getFluctuation(rbc_stddev * deltaTime_s); + whiteBloodCellCount += theta * (baseline_wbc - whiteBloodCellCount) * deltaTime_s + getFluctuation(wbc_stddev * deltaTime_s); + + redBloodCellCount = std::clamp(redBloodCellCount, 4.0, 5.0); + whiteBloodCellCount = std::clamp(whiteBloodCellCount, 5.0, 10.0); +} + +std::string Spleen::getSummary() const { + std::stringstream ss; + ss << "Type: " << organType << " (ID: " << organId << ")\n" + << " RBC Count: " << redBloodCellCount << " million/uL\n" + << " WBC Count: " << whiteBloodCellCount << " thousand/uL"; + return ss.str(); +} + +double Spleen::getRedBloodCellCount() const { return redBloodCellCount; } +double Spleen::getWhiteBloodCellCount() const { return whiteBloodCellCount; } diff --git a/src/Stomach.cpp b/src/Stomach.cpp new file mode 100644 index 0000000..7651fb8 --- /dev/null +++ b/src/Stomach.cpp @@ -0,0 +1,40 @@ +#include "MedicalLib/Stomach.h" +#include +#include +#include + +// Helper function for random fluctuations +static double getFluctuation(double stddev) { + static std::random_device rd; + static std::mt19937 gen(rd()); + std::normal_distribution<> d(0, stddev); + return d(gen); +} + +Stomach::Stomach(int id) : Organ(id, "Stomach"), phLevel(2.0), digestionRate(1.0) {} + +void Stomach::update(double deltaTime_s) { + // For now, these values just fluctuate around a baseline. + const double baseline_ph = 2.0; + const double baseline_digestion = 1.0; + const double theta = 0.1; + const double ph_stddev = 0.05; + const double digestion_stddev = 0.02; + + phLevel += theta * (baseline_ph - phLevel) * deltaTime_s + getFluctuation(ph_stddev * deltaTime_s); + digestionRate += theta * (baseline_digestion - digestionRate) * deltaTime_s + getFluctuation(digestion_stddev * deltaTime_s); + + phLevel = std::clamp(phLevel, 1.5, 3.5); + digestionRate = std::clamp(digestionRate, 0.5, 1.5); +} + +std::string Stomach::getSummary() const { + std::stringstream ss; + ss << "Type: " << organType << " (ID: " << organId << ")\n" + << " pH Level: " << phLevel << "\n" + << " Digestion Rate: " << digestionRate; + return ss.str(); +} + +double Stomach::getPhLevel() const { return phLevel; } +double Stomach::getDigestionRate() const { return digestionRate; }