feat: Add detailed simulation to remaining simple organs

This commit applies a detailed physiological model to all remaining simple organ classes, bringing them to a level of complexity consistent with the Heart, Lungs, and Brain.

Updates include:
- Esophagus: Simulates peristalsis and bolus movement.
- Stomach: Implements a gastric state machine for digestion.
- Intestines: Adds segments (duodenum, jejunum, etc.) and simulates absorption.
- Pancreas: Differentiates endocrine and exocrine functions.
- Gallbladder: Simulates storing, concentrating, and releasing bile.
- Kidneys: Models nephrons, GFR, and electrolyte balance.
- Bladder: Implements a micturition cycle with pressure dynamics.
- Spleen: Models red and white pulp for blood filtering and immunity.
This commit is contained in:
google-labs-jules[bot]
2025-08-20 07:11:44 +00:00
parent 278ef9fe8e
commit 7459435e25
20 changed files with 1022 additions and 183 deletions
+50 -7
View File
@@ -1,24 +1,67 @@
#pragma once
#include "Organ.h"
#include <string>
/**
* @brief Represents the Bladder.
* @brief Represents the state of the bladder muscles and sphincters.
*/
enum class MicturitionState {
FILLING,
FULL,
VOIDING
};
/**
* @brief Represents the Bladder, which stores urine.
*/
class MEDICAL_LIB_API Bladder : public Organ {
public:
/**
* @brief Constructor for the Bladder class.
* @param id The ID of the organ.
*/
Bladder(int id);
/**
* @brief Updates the bladder's state over a time interval.
* @param deltaTime_s The time elapsed in seconds.
*/
void update(double deltaTime_s) override;
/**
* @brief Gets a string summary of the bladder's state.
* @return A string containing the bladder's state.
*/
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.
/**
* @brief Adds urine from the kidneys.
* @param amount_ml The volume of urine to add.
*/
void addUrine(double amount_ml);
double getCurrentVolume() const;
double getCapacity() const;
// --- Getters for Bladder State ---
/** @brief Gets the current volume of urine in the bladder in mL. */
double getVolume() const;
/** @brief Gets the current pressure inside the bladder in cmH2O. */
double getPressure() const;
/** @brief Gets the current state of the micturition cycle. */
MicturitionState getCurrentState() const;
private:
double currentVolume; // in ml
double capacity; // in ml
// --- Helper to convert enum to string ---
std::string stateToString(MicturitionState state) const;
// --- Physiological Parameters ---
MicturitionState currentState;
double currentVolume_mL;
double pressure_cmH2O;
bool internalSphincterClosed;
const double capacity_mL = 500.0;
const double pressureThreshold_cmH2O = 40.0; // Pressure at which voiding reflex is strong
};
+57 -4
View File
@@ -1,19 +1,72 @@
#pragma once
#include "Organ.h"
#include <string>
#include <vector>
/**
* @brief Represents the Esophagus.
* @note This is a placeholder with minimal logic for now.
* @brief Represents the state of esophageal muscle contraction.
*/
enum class PeristalsisState {
IDLE,
CONTRACTING,
RELAXING
};
/**
* @brief Represents a small mass of chewed food.
*/
struct Bolus {
double volume_mL;
double position_cm; // Position from the top of the esophagus
};
/**
* @brief Represents the Esophagus with a more detailed physiological model.
*/
class MEDICAL_LIB_API Esophagus : public Organ {
public:
/**
* @brief Constructor for the Esophagus class.
* @param id The ID of the organ.
*/
Esophagus(int id);
/**
* @brief Updates the esophagus state over a time interval.
* @param deltaTime_s The time elapsed in seconds.
*/
void update(double deltaTime_s) override;
/**
* @brief Gets a string summary of the esophagus's state.
* @return A string containing the esophagus's state.
*/
std::string getSummary() const override;
double getMotility() const; // Peristalsis efficiency
/**
* @brief Initiates a swallow.
* @param bolusVolume_mL The volume of the bolus being swallowed.
*/
void initiateSwallow(double bolusVolume_mL);
// --- Getters for Esophageal State ---
/** @brief Gets the current state of peristalsis. */
PeristalsisState getCurrentState() const;
/** @brief Checks if a bolus is currently being swallowed. */
bool isSwallowing() const;
private:
double motility;
// --- Helper to convert enum to string ---
std::string stateToString(PeristalsisState state) const;
// --- Physiological Parameters ---
PeristalsisState currentState;
double lowerEsophagealSphincterTone; // Pressure in mmHg
// --- Simulation State ---
std::vector<Bolus> activeBoli;
const double length_cm = 25.0; // Average length of esophagus
};
+48 -3
View File
@@ -1,18 +1,63 @@
#pragma once
#include "Organ.h"
#include <string>
/**
* @brief Represents the Gallbladder.
* @brief Represents the contraction state of the gallbladder.
*/
enum class GallbladderState {
STORING,
CONTRACTING
};
/**
* @brief Represents the Gallbladder, which stores and concentrates bile.
*/
class MEDICAL_LIB_API Gallbladder : public Organ {
public:
/**
* @brief Constructor for the Gallbladder class.
* @param id The ID of the organ.
*/
Gallbladder(int id);
/**
* @brief Updates the gallbladder's state over a time interval.
* @param deltaTime_s The time elapsed in seconds.
*/
void update(double deltaTime_s) override;
/**
* @brief Gets a string summary of the gallbladder's state.
* @return A string containing the gallbladder's state.
*/
std::string getSummary() const override;
double getBileStored() const;
/**
* @brief Adds bile from the liver.
* @param volume_mL The volume of bile to add.
*/
void storeBile(double volume_mL);
// --- Getters for Gallbladder State ---
/** @brief Gets the current volume of stored bile in mL. */
double getStoredBileVolume() const;
/** @brief Gets the concentration factor of the stored bile. */
double getBileConcentration() const;
/** @brief Gets the current state of the gallbladder. */
GallbladderState getCurrentState() const;
private:
double bileStored; // in ml
// --- Helper to convert enum to string ---
std::string stateToString(GallbladderState state) const;
// --- Physiological Parameters ---
GallbladderState currentState;
double storedBile_mL;
double bileConcentrationFactor; // How concentrated the bile is (1x, 5x, etc.)
const double capacity_mL = 50.0;
};
+46 -5
View File
@@ -1,20 +1,61 @@
#pragma once
#include "Organ.h"
#include <string>
#include <vector>
/**
* @brief Represents the Intestines (Small and Large combined).
* @brief Represents a segment of the intestines.
*/
struct IntestinalSegment {
std::string name;
double length_m;
double motility; // Rate of chyme movement
double nutrientAbsorptionRate;
double waterAbsorptionRate;
};
/**
* @brief Represents the Intestines (Small and Large) with a more detailed model.
*/
class MEDICAL_LIB_API Intestines : public Organ {
public:
/**
* @brief Constructor for the Intestines class.
* @param id The ID of the organ.
*/
Intestines(int id);
/**
* @brief Updates the intestines' state over a time interval.
* @param deltaTime_s The time elapsed in seconds.
*/
void update(double deltaTime_s) override;
/**
* @brief Gets a string summary of the intestines' state.
* @return A string containing the intestines' state.
*/
std::string getSummary() const override;
double getNutrientAbsorptionRate() const;
double getWaterAbsorptionRate() const;
/**
* @brief Adds chyme from the stomach to the duodenum.
* @param volume_mL The volume of chyme.
*/
void receiveChyme(double volume_mL);
// --- Getters for Intestinal State ---
/** @brief Gets the total volume of chyme currently in the intestines. */
double getTotalChymeVolume() const;
private:
double nutrientAbsorptionRate; // in arbitrary units
double waterAbsorptionRate; // in ml/s
// --- Anatomical Components ---
IntestinalSegment duodenum;
IntestinalSegment jejunum;
IntestinalSegment ileum;
IntestinalSegment colon;
// --- Simulation State ---
double chymeVolume_mL; // Total volume in the whole system for now
};
+48 -5
View File
@@ -1,20 +1,63 @@
#pragma once
#include "Organ.h"
#include <string>
#include <vector>
/**
* @brief Represents the Kidneys.
* @brief Represents a functional unit of the kidney.
*/
struct Nephron {
std::string id;
double filtrationEfficiency; // 0.0 to 1.0
bool isDamaged;
};
/**
* @brief Represents the Kidneys, responsible for filtering blood and producing urine.
*/
class MEDICAL_LIB_API Kidneys : public Organ {
public:
/**
* @brief Constructor for the Kidneys class.
* @param id The ID of the organ.
*/
Kidneys(int id);
/**
* @brief Updates the kidneys' state over a time interval.
* @param deltaTime_s The time elapsed in seconds.
*/
void update(double deltaTime_s) override;
/**
* @brief Gets a string summary of the kidneys' state.
* @return A string containing the kidneys' state.
*/
std::string getSummary() const override;
double getFiltrationRate() const;
double getUrineProductionRate() const;
// --- Getters for Renal Function ---
/** @brief Gets the Glomerular Filtration Rate (GFR) in mL/min. */
double getGfr() const;
/** @brief Gets the rate of urine production in mL/s. */
double getUrineOutputRate() const;
/** @brief Gets the simulated blood sodium level in mEq/L. */
double getBloodSodium() const;
/** @brief Gets the simulated blood potassium level in mEq/L. */
double getBloodPotassium() const;
private:
double filtrationRate; // in ml/min
double urineProductionRate; // in ml/s
// --- Physiological Parameters ---
double gfr_mL_per_min;
double urineOutput_mL_per_s;
double bloodSodium_mEq_per_L;
double bloodPotassium_mEq_per_L;
// --- Anatomical Components ---
std::vector<Nephron> nephrons;
double totalFiltrationCapacity;
};
+39 -7
View File
@@ -1,9 +1,20 @@
#pragma once
#include "Organ.h"
#include <string>
#include <vector>
/**
* @brief Represents the Liver organ.
* @brief Represents a functional unit of the liver.
*/
struct HepaticLobule {
std::string id;
double metabolicActivity; // A factor from 0.0 to 1.0+
bool isDamaged;
};
/**
* @brief Represents the Liver organ with a more detailed physiological model.
*/
class MEDICAL_LIB_API Liver : public Organ {
public:
@@ -14,7 +25,7 @@ public:
Liver(int id);
/**
* @brief Updates the liver's state over time.
* @brief Updates the liver's state over a time interval.
* @param deltaTime_s The time elapsed in seconds.
*/
void update(double deltaTime_s) override;
@@ -25,11 +36,32 @@ public:
*/
std::string getSummary() const override;
// Specific getters for Liver properties
double getBileProductionRate() const; // in ml/s
double getGlucoseProductionRate() const; // in g/s
// --- Getters for Key Metabolic Vitals ---
/** @brief Gets the rate of bile production in mL/min. */
double getBileProductionRate() const;
/** @brief Gets the rate of glucose production (gluconeogenesis) in g/min. */
double getGlucoseProductionRate() const;
/** @brief Gets the Alanine Aminotransferase (ALT) level in U/L. */
double getAltLevel() const;
/** @brief Gets the Aspartate Aminotransferase (AST) level in U/L. */
double getAstLevel() const;
/** @brief Gets the total bilirubin level in mg/dL. */
double getBilirubinLevel() const;
private:
double bileProductionRate;
double glucoseProductionRate;
// --- Physiological Parameters ---
double bileProductionRate_ml_per_s;
double glucoseProductionRate_g_per_s;
double alt_U_per_L; ///< Alanine Aminotransferase
double ast_U_per_L; ///< Aspartate Aminotransferase
double bilirubin_mg_per_dL; ///< Total bilirubin
// --- Anatomical Components ---
std::vector<HepaticLobule> lobules;
double totalMetabolicCapacity;
};
+37 -4
View File
@@ -1,20 +1,53 @@
#pragma once
#include "Organ.h"
#include <string>
/**
* @brief Represents the Pancreas, with both endocrine and exocrine functions.
*/
class MEDICAL_LIB_API Pancreas : public Organ {
public:
/**
* @brief Constructor for the Pancreas class.
* @param id The ID of the organ.
*/
Pancreas(int id);
/**
* @brief Updates the pancreas's state over a time interval.
* @param deltaTime_s The time elapsed in seconds.
*/
void update(double deltaTime_s) override;
/**
* @brief Gets a string summary of the pancreas's state.
* @return A string containing the pancreas's state.
*/
std::string getSummary() const override;
double getInsulinProduction() const;
double getGlucagonProduction() const;
// --- Getters for Endocrine Functions (Hormones) ---
/** @brief Gets the current insulin secretion rate in units/hr. */
double getInsulinSecretion() const;
/** @brief Gets the current glucagon secretion rate in ng/hr. */
double getGlucagonSecretion() const;
// --- Getters for Exocrine Functions (Enzymes) ---
/** @brief Gets the current amylase secretion rate in U/L. */
double getAmylaseSecretion() const;
/** @brief Gets the current lipase secretion rate in U/L. */
double getLipaseSecretion() const;
private:
double insulinProduction; // in units/hr
double glucagonProduction; // in ng/hr
// --- Endocrine Parameters ---
double insulinSecretion_units_per_hr;
double glucagonSecretion_ng_per_hr;
// --- Exocrine Parameters ---
double amylaseSecretion_U_per_L;
double lipaseSecretion_U_per_L;
};
+54 -3
View File
@@ -1,18 +1,69 @@
#pragma once
#include "Organ.h"
#include <string>
#include <vector>
/**
* @brief Represents the Spinal Cord.
* @brief Represents the functional status of a neural pathway.
*/
enum class SignalStatus {
NORMAL,
IMPAIRED,
SEVERED
};
/**
* @brief Represents a major bundle of nerve fibers in the spinal cord.
*/
struct SpinalTract {
std::string name;
SignalStatus status;
double conductionVelocity_m_per_s;
};
/**
* @brief Represents the Spinal Cord with a more detailed physiological model.
*/
class MEDICAL_LIB_API SpinalCord : public Organ {
public:
/**
* @brief Constructor for the SpinalCord class.
* @param id The ID of the organ.
*/
SpinalCord(int id);
/**
* @brief Updates the spinal cord's state over a time interval.
* @param deltaTime_s The time elapsed in seconds.
*/
void update(double deltaTime_s) override;
/**
* @brief Gets a string summary of the spinal cord's vitals.
* @return A string containing the spinal cord's vital signs.
*/
std::string getSummary() const override;
double getSignalConductionVelocity() const; // in m/s
// --- Getters for Key Neurological Pathways ---
/** @brief Gets the status of the primary motor pathways. */
SignalStatus getMotorPathwayStatus() const;
/** @brief Gets the status of the primary sensory pathways. */
SignalStatus getSensoryPathwayStatus() const;
/** @brief Gets the status of a basic reflex arc. */
bool isReflexArcIntact() const;
private:
double signalConductionVelocity;
// --- Helper to convert enum to string ---
std::string statusToString(SignalStatus status) const;
// --- Anatomical Components ---
SpinalTract descendingMotorTract;
SpinalTract ascendingSensoryTract;
// --- Physiological Parameters ---
bool reflexArcIntact; // Simplified representation of a reflex (e.g., patellar)
};
+42 -5
View File
@@ -1,20 +1,57 @@
#pragma once
#include "Organ.h"
#include <string>
/**
* @brief Represents the Spleen.
* @brief Represents the red pulp, responsible for filtering blood.
*/
struct RedPulp {
double filtrationRate; // Arbitrary units
double rbcBreakdownRate; // Rate of old red blood cell removal
};
/**
* @brief Represents the white pulp, part of the immune system.
*/
struct WhitePulp {
double lymphocyteCount; // in millions
double macrophageCount; // in millions
};
/**
* @brief Represents the Spleen, involved in blood filtering and immunity.
*/
class MEDICAL_LIB_API Spleen : public Organ {
public:
/**
* @brief Constructor for the Spleen class.
* @param id The ID of the organ.
*/
Spleen(int id);
/**
* @brief Updates the spleen's state over a time interval.
* @param deltaTime_s The time elapsed in seconds.
*/
void update(double deltaTime_s) override;
/**
* @brief Gets a string summary of the spleen's state.
* @return A string containing the spleen's state.
*/
std::string getSummary() const override;
double getRedBloodCellCount() const;
double getWhiteBloodCellCount() const;
// --- Getters for Spleen Function ---
/** @brief Gets the rate of red blood cell breakdown. */
double getRbcBreakdownRate() const;
/** @brief Gets the total lymphocyte count in the white pulp. */
double getLymphocyteCount() const;
private:
double redBloodCellCount; // in millions/uL
double whiteBloodCellCount; // in thousands/uL
// --- Anatomical Components ---
RedPulp redPulp;
WhitePulp whitePulp;
};
+63 -5
View File
@@ -1,20 +1,78 @@
#pragma once
#include "Organ.h"
#include <string>
#include <vector>
/**
* @brief Represents the Stomach.
* @brief Represents the current digestive state of the stomach.
*/
enum class GastricState {
EMPTY,
FILLING,
DIGESTING,
EMPTYING
};
/**
* @brief Represents the mixture of partially digested food and gastric juices.
*/
struct Chyme {
double volume_mL;
double acidity_pH;
};
/**
* @brief Represents the Stomach with a more detailed physiological model.
*/
class MEDICAL_LIB_API Stomach : public Organ {
public:
/**
* @brief Constructor for the Stomach class.
* @param id The ID of the organ.
*/
Stomach(int id);
/**
* @brief Updates the stomach state over a time interval.
* @param deltaTime_s The time elapsed in seconds.
*/
void update(double deltaTime_s) override;
/**
* @brief Gets a string summary of the stomach's state.
* @return A string containing the stomach's state.
*/
std::string getSummary() const override;
double getPhLevel() const;
double getDigestionRate() const;
/**
* @brief Adds a substance (e.g., a bolus from the esophagus) to the stomach.
* @param volume_mL The volume of the substance.
*/
void addSubstance(double volume_mL);
// --- Getters for Gastric State ---
/** @brief Gets the current gastric state. */
GastricState getCurrentState() const;
/** @brief Gets the current volume of contents in the stomach in mL. */
double getVolume() const;
/** @brief Gets the current pH of the stomach contents. */
double getAcidity() const;
private:
double phLevel; // Acidity
double digestionRate; // in arbitrary units
// --- Helper to convert enum to string ---
std::string stateToString(GastricState state) const;
// --- Physiological Parameters ---
GastricState currentState;
double currentVolume_mL;
double currentPh;
double gastricJuiceSecretionRate_ml_per_s;
double emptyingRate_ml_per_s;
// --- Simulation State ---
const double capacity_mL = 1500.0;
};
+69 -12
View File
@@ -2,28 +2,85 @@
#include <random>
#include <algorithm>
#include <sstream>
#include <iomanip>
Bladder::Bladder(int id) : Organ(id, "Bladder"), currentVolume(50.0), capacity(500.0) {}
Bladder::Bladder(int id)
: Organ(id, "Bladder"),
currentState(MicturitionState::FILLING),
currentVolume_mL(50.0),
pressure_cmH2O(5.0),
internalSphincterClosed(true) {}
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);
// 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
pressure_cmH2O = (currentVolume_mL / capacity_mL) * 60.0;
// State machine
switch (currentState) {
case MicturitionState::FILLING:
if (currentVolume_mL > capacity_mL * 0.8 || pressure_cmH2O > pressureThreshold_cmH2O) {
currentState = MicturitionState::FULL;
}
break;
case MicturitionState::FULL:
// For demo, automatically start voiding after 10 seconds in FULL state
static double timeInFullState = 0.0;
timeInFullState += deltaTime_s;
if (timeInFullState > 10.0) {
currentState = MicturitionState::VOIDING;
internalSphincterClosed = false;
timeInFullState = 0.0;
}
break;
case MicturitionState::VOIDING:
double voidingRate_ml_per_s = 15.0;
currentVolume_mL -= voidingRate_ml_per_s * deltaTime_s;
if (currentVolume_mL <= 0) {
currentVolume_mL = 0;
currentState = MicturitionState::FILLING;
internalSphincterClosed = true;
}
break;
}
}
void Bladder::addUrine(double amount_ml) {
currentVolume += amount_ml;
currentVolume = std::clamp(currentVolume, 0.0, capacity);
if (currentState != MicturitionState::VOIDING) {
currentVolume_mL += amount_ml;
currentVolume_mL = std::clamp(currentVolume_mL, 0.0, capacity_mL);
}
}
std::string Bladder::stateToString(MicturitionState state) const {
switch (state) {
case MicturitionState::FILLING: return "Filling";
case MicturitionState::FULL: return "Full";
case MicturitionState::VOIDING: return "Voiding";
default: return "Unknown";
}
}
std::string Bladder::getSummary() const {
std::stringstream ss;
ss << "Type: " << organType << " (ID: " << organId << ")\n"
<< " Volume: " << currentVolume << " / " << capacity << " ml";
ss.precision(1);
ss << std::fixed;
ss << "--- Bladder Summary ---\n"
<< "State: " << stateToString(currentState) << "\n"
<< "Volume: " << getVolume() << " / " << capacity_mL << " mL\n"
<< "Pressure: " << getPressure() << " cmH2O\n";
return ss.str();
}
double Bladder::getCurrentVolume() const { return currentVolume; }
double Bladder::getCapacity() const { return capacity; }
// --- Getters Implementation ---
double Bladder::getVolume() const { return currentVolume_mL; }
double Bladder::getPressure() const { return pressure_cmH2O; }
MicturitionState Bladder::getCurrentState() const { return currentState; }
+58 -9
View File
@@ -2,25 +2,74 @@
#include <random>
#include <algorithm>
#include <sstream>
#include <iomanip>
Esophagus::Esophagus(int id) : Organ(id, "Esophagus"), motility(1.0) {}
Esophagus::Esophagus(int id)
: Organ(id, "Esophagus"),
currentState(PeristalsisState::IDLE),
lowerEsophagealSphincterTone(20.0) {}
void Esophagus::update(double deltaTime_s) {
// Placeholder, no real logic yet.
// Fluctuate motility slightly.
// Simulate a swallow every 15 seconds for demonstration
static double timeSinceLastSwallow = 0.0;
timeSinceLastSwallow += deltaTime_s;
if (timeSinceLastSwallow > 15.0) {
initiateSwallow(15.0); // Swallow a 15mL bolus
timeSinceLastSwallow = 0.0;
}
if (!activeBoli.empty()) {
currentState = PeristalsisState::CONTRACTING;
const double peristalsisSpeed_cm_per_s = 3.0;
for (auto& bolus : activeBoli) {
bolus.position_cm += peristalsisSpeed_cm_per_s * deltaTime_s;
}
// Remove boli that have passed into the stomach
activeBoli.erase(std::remove_if(activeBoli.begin(), activeBoli.end(),
[this](const Bolus& b) { return b.position_cm >= this->length_cm; }),
activeBoli.end());
if (activeBoli.empty()) {
currentState = PeristalsisState::IDLE;
}
} else {
currentState = PeristalsisState::IDLE;
}
// Fluctuate LES tone slightly
static std::random_device rd;
static std::mt19937 gen(rd());
std::normal_distribution<> d(0, 0.001);
std::normal_distribution<> d(0, 0.1);
lowerEsophagealSphincterTone += d(gen) * deltaTime_s;
lowerEsophagealSphincterTone = std::clamp(lowerEsophagealSphincterTone, 18.0, 25.0);
}
motility += d(gen) * deltaTime_s;
motility = std::clamp(motility, 0.95, 1.05);
void Esophagus::initiateSwallow(double bolusVolume_mL) {
activeBoli.push_back({bolusVolume_mL, 0.0});
}
std::string Esophagus::stateToString(PeristalsisState state) const {
switch (state) {
case PeristalsisState::IDLE: return "Idle";
case PeristalsisState::CONTRACTING: return "Contracting";
case PeristalsisState::RELAXING: return "Relaxing";
default: return "Unknown";
}
}
std::string Esophagus::getSummary() const {
std::stringstream ss;
ss << "Type: " << organType << " (ID: " << organId << ")\n"
<< " Motility: " << motility * 100 << "%";
ss << "--- Esophagus Summary ---\n"
<< "State: " << stateToString(currentState) << "\n"
<< "LES Tone: " << std::fixed << std::setprecision(1) << lowerEsophagealSphincterTone << " mmHg\n"
<< "Boluses in transit: " << activeBoli.size() << "\n";
if (!activeBoli.empty()) {
ss << " - Top bolus position: " << activeBoli.front().position_cm << " / " << length_cm << " cm\n";
}
return ss.str();
}
double Esophagus::getMotility() const { return motility; }
PeristalsisState Esophagus::getCurrentState() const { return currentState; }
bool Esophagus::isSwallowing() const { return !activeBoli.empty(); }
+63 -11
View File
@@ -2,25 +2,77 @@
#include <random>
#include <algorithm>
#include <sstream>
#include <iomanip>
Gallbladder::Gallbladder(int id) : Organ(id, "Gallbladder"), bileStored(30.0) {}
Gallbladder::Gallbladder(int id)
: Organ(id, "Gallbladder"),
currentState(GallbladderState::STORING),
storedBile_mL(30.0),
bileConcentrationFactor(5.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);
// 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.
bileStored += d(gen) * deltaTime_s;
bileStored = std::clamp(bileStored, 10.0, 50.0);
// Simulate bile coming from the liver
storeBile(0.005 * deltaTime_s); // Slow constant trickle
switch (currentState) {
case GallbladderState::STORING:
// Concentrate bile over time
bileConcentrationFactor += 0.05 * deltaTime_s;
bileConcentrationFactor = std::min(10.0, bileConcentrationFactor);
// For demo, contract every 40 seconds
static double timeSinceContraction = 0.0;
timeSinceContraction += deltaTime_s;
if (timeSinceContraction > 40.0) {
currentState = GallbladderState::CONTRACTING;
timeSinceContraction = 0.0;
}
break;
case GallbladderState::CONTRACTING:
// Release bile
double releasedBile = 2.0 * deltaTime_s;
storedBile_mL -= releasedBile;
if (storedBile_mL < 5.0) { // Stop contracting when near empty
storedBile_mL = std::max(0.0, storedBile_mL);
bileConcentrationFactor = 1.0; // Bile is fresh
currentState = GallbladderState::STORING;
}
break;
}
}
void Gallbladder::storeBile(double volume_mL) {
if (currentState == GallbladderState::STORING) {
storedBile_mL += volume_mL;
storedBile_mL = std::clamp(storedBile_mL, 0.0, capacity_mL);
}
}
std::string Gallbladder::stateToString(GallbladderState state) const {
switch (state) {
case GallbladderState::STORING: return "Storing/Concentrating";
case GallbladderState::CONTRACTING: return "Contracting (Releasing)";
default: return "Unknown";
}
}
std::string Gallbladder::getSummary() const {
std::stringstream ss;
ss << "Type: " << organType << " (ID: " << organId << ")\n"
<< " Bile Stored: " << bileStored << " ml";
ss.precision(1);
ss << std::fixed;
ss << "--- Gallbladder Summary ---\n"
<< "State: " << stateToString(currentState) << "\n"
<< "Volume: " << getStoredBileVolume() << " / " << capacity_mL << " mL\n"
<< "Concentration: " << getBileConcentration() << "x\n";
return ss.str();
}
double Gallbladder::getBileStored() const { return bileStored; }
// --- Getters Implementation ---
double Gallbladder::getStoredBileVolume() const { return storedBile_mL; }
double Gallbladder::getBileConcentration() const { return bileConcentrationFactor; }
GallbladderState Gallbladder::getCurrentState() const { return currentState; }
+46 -15
View File
@@ -2,6 +2,7 @@
#include <random>
#include <algorithm>
#include <sstream>
#include <iomanip>
// Helper function for random fluctuations
static double getFluctuation(double stddev) {
@@ -11,29 +12,59 @@ static double getFluctuation(double stddev) {
return d(gen);
}
Intestines::Intestines(int id) : Organ(id, "Intestines"), nutrientAbsorptionRate(1.0), waterAbsorptionRate(0.1) {}
Intestines::Intestines(int id)
: Organ(id, "Intestines"),
chymeVolume_mL(0.0) {
// Initialize segments with typical values
duodenum = {"Duodenum", 0.25, 1.0, 0.5, 0.1};
jejunum = {"Jejunum", 2.5, 1.0, 1.0, 0.3};
ileum = {"Ileum", 3.0, 1.0, 0.8, 0.5};
colon = {"Colon", 1.5, 0.5, 0.1, 1.0}; // High water absorption
}
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;
// 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;
}
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);
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;
nutrientAbsorptionRate = std::clamp(nutrientAbsorptionRate, 0.8, 1.2);
waterAbsorptionRate = std::clamp(waterAbsorptionRate, 0.08, 0.12);
// Reduce chyme volume based on absorption
double absorbedVolume = (totalNutrientAbsorption * 0.01 + totalWaterAbsorption * 0.1) * deltaTime_s;
chymeVolume_mL -= absorbedVolume;
chymeVolume_mL = std::max(0.0, chymeVolume_mL);
}
// Fluctuate motility slightly
duodenum.motility += getFluctuation(0.01);
duodenum.motility = std::clamp(duodenum.motility, 0.9, 1.1);
}
void Intestines::receiveChyme(double volume_mL) {
chymeVolume_mL += volume_mL;
}
std::string Intestines::getSummary() const {
std::stringstream ss;
ss << "Type: " << organType << " (ID: " << organId << ")\n"
<< " Nutrient Absorption: " << nutrientAbsorptionRate << "\n"
<< " Water Absorption: " << waterAbsorptionRate << " ml/s";
ss.precision(2);
ss << std::fixed;
ss << "--- Intestines Summary ---\n"
<< "Total Chyme Volume: " << getTotalChymeVolume() << " mL\n\n"
<< "--- Segments ---\n"
<< duodenum.name << ": Motility " << duodenum.motility << "\n"
<< jejunum.name << ": Nutrient Abs. " << jejunum.nutrientAbsorptionRate << "\n"
<< ileum.name << ": Water Abs. " << ileum.waterAbsorptionRate << "\n"
<< colon.name << ": Water Abs. " << colon.waterAbsorptionRate << "\n";
return ss.str();
}
double Intestines::getNutrientAbsorptionRate() const { return nutrientAbsorptionRate; }
double Intestines::getWaterAbsorptionRate() const { return waterAbsorptionRate; }
// --- Getters Implementation ---
double Intestines::getTotalChymeVolume() const { return chymeVolume_mL; }
+52 -15
View File
@@ -2,6 +2,8 @@
#include <random>
#include <algorithm>
#include <sstream>
#include <iomanip>
#include <numeric>
// Helper function for random fluctuations
static double getFluctuation(double stddev) {
@@ -11,29 +13,64 @@ static double getFluctuation(double stddev) {
return d(gen);
}
Kidneys::Kidneys(int id) : Organ(id, "Kidneys"), filtrationRate(125.0), urineProductionRate(0.02) {}
Kidneys::Kidneys(int id)
: Organ(id, "Kidneys"),
gfr_mL_per_min(125.0),
urineOutput_mL_per_s(0.02),
bloodSodium_mEq_per_L(140.0),
bloodPotassium_mEq_per_L(4.0),
totalFiltrationCapacity(1.0) {
// Create a simplified representation of nephrons
nephrons.resize(100); // 100 representative units
for (int i = 0; i < nephrons.size(); ++i) {
nephrons[i] = {"Nephron " + std::to_string(i), 1.0, false};
}
}
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;
// Recalculate total capacity based on nephron health
totalFiltrationCapacity = 0.0;
for (const auto& nephron : nephrons) {
if (!nephron.isDamaged) {
totalFiltrationCapacity += nephron.filtrationEfficiency;
}
}
totalFiltrationCapacity /= nephrons.size();
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);
// GFR is dependent on overall health
const double baseline_gfr = 125.0 * totalFiltrationCapacity;
gfr_mL_per_min += 0.1 * (baseline_gfr - gfr_mL_per_min) * deltaTime_s + getFluctuation(0.5);
filtrationRate = std::clamp(filtrationRate, 100.0, 150.0);
urineProductionRate = std::clamp(urineProductionRate, 0.01, 0.03);
// Urine output is related to GFR but also hydration status (not modeled yet)
urineOutput_mL_per_s = gfr_mL_per_min / 60.0 * 0.01; // Simplified relationship
urineOutput_mL_per_s += getFluctuation(0.001);
// Simulate electrolyte balance
bloodSodium_mEq_per_L += getFluctuation(0.05);
bloodPotassium_mEq_per_L += getFluctuation(0.01);
// Clamp to healthy ranges
gfr_mL_per_min = std::clamp(gfr_mL_per_min, 90.0, 150.0);
urineOutput_mL_per_s = std::clamp(urineOutput_mL_per_s, 0.01, 0.03);
bloodSodium_mEq_per_L = std::clamp(bloodSodium_mEq_per_L, 135.0, 145.0);
bloodPotassium_mEq_per_L = std::clamp(bloodPotassium_mEq_per_L, 3.5, 5.0);
}
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";
ss.precision(1);
ss << std::fixed;
ss << "--- Kidneys Summary ---\n"
<< "Glomerular Filtration Rate (GFR): " << getGfr() << " mL/min\n"
<< "Urine Output: " << getUrineOutputRate() * 3600 << " mL/hr\n"
<< "Blood Sodium: " << getBloodSodium() << " mEq/L\n"
<< "Blood Potassium: " << getBloodPotassium() << " mEq/L\n";
return ss.str();
}
double Kidneys::getFiltrationRate() const { return filtrationRate; }
double Kidneys::getUrineProductionRate() const { return urineProductionRate; }
// --- Getters Implementation ---
double Kidneys::getGfr() const { return gfr_mL_per_min; }
double Kidneys::getUrineOutputRate() const { return urineOutput_mL_per_s; }
double Kidneys::getBloodSodium() const { return bloodSodium_mEq_per_L; }
double Kidneys::getBloodPotassium() const { return bloodPotassium_mEq_per_L; }
+57 -18
View File
@@ -2,6 +2,7 @@
#include <random>
#include <algorithm>
#include <sstream>
#include <numeric>
// Helper function for random fluctuations
static double getFluctuation(double stddev) {
@@ -11,32 +12,70 @@ static double getFluctuation(double 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) {}
Liver::Liver(int id)
: Organ(id, "Liver"),
bileProductionRate_ml_per_s(0.0069),
glucoseProductionRate_g_per_s(0.001),
alt_U_per_L(25.0),
ast_U_per_L(25.0),
bilirubin_mg_per_dL(0.8),
totalMetabolicCapacity(1.0) {
// Create a simplified representation of lobules
lobules.resize(100); // 100 representative units
for (int i = 0; i < lobules.size(); ++i) {
lobules[i] = {"Lobule " + std::to_string(i), 1.0, false};
}
}
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;
// Recalculate total capacity based on lobule health (for future use)
totalMetabolicCapacity = 0.0;
for (const auto& lobule : lobules) {
if (!lobule.isDamaged) {
totalMetabolicCapacity += lobule.metabolicActivity;
}
}
totalMetabolicCapacity /= lobules.size();
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);
// Baseline production rates are modulated by liver health
const double baseline_bile_rate = 0.0069 * totalMetabolicCapacity;
const double baseline_glucose_rate = 0.001 * totalMetabolicCapacity;
bileProductionRate = std::clamp(bileProductionRate, 0.005, 0.009);
glucoseProductionRate = std::clamp(glucoseProductionRate, 0.0008, 0.0012);
// Update production rates with minor fluctuations
bileProductionRate_ml_per_s += 0.02 * (baseline_bile_rate - bileProductionRate_ml_per_s) * deltaTime_s + getFluctuation(0.0001);
glucoseProductionRate_g_per_s += 0.02 * (baseline_glucose_rate - glucoseProductionRate_g_per_s) * deltaTime_s + getFluctuation(0.00005);
// Update enzyme and bilirubin levels
// In a healthy state, they hover around a normal baseline
alt_U_per_L += getFluctuation(0.1);
ast_U_per_L += getFluctuation(0.1);
bilirubin_mg_per_dL += getFluctuation(0.01);
// Clamp to normal healthy ranges
bileProductionRate_ml_per_s = std::clamp(bileProductionRate_ml_per_s, 0.005, 0.009);
glucoseProductionRate_g_per_s = std::clamp(glucoseProductionRate_g_per_s, 0.0008, 0.0012);
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);
}
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";
ss.precision(3);
ss << std::fixed;
ss << "--- Liver Summary ---\n"
<< "Bile Production: " << getBileProductionRate() * 60.0 << " mL/min\n"
<< "Glucose Production: " << getGlucoseProductionRate() * 60.0 << " g/min\n"
<< "ALT Level: " << getAltLevel() << " U/L\n"
<< "AST Level: " << getAstLevel() << " U/L\n"
<< "Bilirubin: " << getBilirubinLevel() << " mg/dL\n";
return ss.str();
}
double Liver::getBileProductionRate() const { return bileProductionRate; }
double Liver::getGlucoseProductionRate() const { return glucoseProductionRate; }
// --- Getters Implementation ---
double Liver::getBileProductionRate() const { return bileProductionRate_ml_per_s; }
double Liver::getGlucoseProductionRate() const { return glucoseProductionRate_g_per_s; }
double Liver::getAltLevel() const { return alt_U_per_L; }
double Liver::getAstLevel() const { return ast_U_per_L; }
double Liver::getBilirubinLevel() const { return bilirubin_mg_per_dL; }
+36 -15
View File
@@ -2,6 +2,7 @@
#include <random>
#include <algorithm>
#include <sstream>
#include <iomanip>
// Helper function for random fluctuations
static double getFluctuation(double stddev) {
@@ -11,29 +12,49 @@ static double getFluctuation(double stddev) {
return d(gen);
}
Pancreas::Pancreas(int id) : Organ(id, "Pancreas"), insulinProduction(1.0), glucagonProduction(50.0) {}
Pancreas::Pancreas(int id)
: Organ(id, "Pancreas"),
insulinSecretion_units_per_hr(1.0),
glucagonSecretion_ng_per_hr(50.0),
amylaseSecretion_U_per_L(80.0),
lipaseSecretion_U_per_L(40.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;
// In a real model, hormone secretion would be driven by blood glucose.
// Enzyme secretion would be driven by food in the duodenum.
// For now, we just simulate minor fluctuations around a baseline.
insulinProduction += theta * (baseline_insulin - insulinProduction) * deltaTime_s + getFluctuation(insulin_stddev * deltaTime_s);
glucagonProduction += theta * (baseline_glucagon - glucagonProduction) * deltaTime_s + getFluctuation(glucagon_stddev * deltaTime_s);
// Endocrine fluctuations
insulinSecretion_units_per_hr += getFluctuation(0.05);
glucagonSecretion_ng_per_hr += getFluctuation(0.5);
insulinProduction = std::clamp(insulinProduction, 0.5, 2.0);
glucagonProduction = std::clamp(glucagonProduction, 40.0, 60.0);
// 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);
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);
}
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";
ss.precision(1);
ss << std::fixed;
ss << "--- Pancreas Summary ---\n"
<< "--- Endocrine Function ---\n"
<< "Insulin Secretion: " << getInsulinSecretion() << " units/hr\n"
<< "Glucagon Secretion: " << getGlucagonSecretion() << " ng/hr\n"
<< "--- Exocrine Function ---\n"
<< "Amylase Secretion: " << getAmylaseSecretion() << " U/L\n"
<< "Lipase Secretion: " << getLipaseSecretion() << " U/L\n";
return ss.str();
}
double Pancreas::getInsulinProduction() const { return insulinProduction; }
double Pancreas::getGlucagonProduction() const { return glucagonProduction; }
// --- Getters Implementation ---
double Pancreas::getInsulinSecretion() const { return insulinSecretion_units_per_hr; }
double Pancreas::getGlucagonSecretion() const { return glucagonSecretion_ng_per_hr; }
double Pancreas::getAmylaseSecretion() const { return amylaseSecretion_U_per_L; }
double Pancreas::getLipaseSecretion() const { return lipaseSecretion_U_per_L; }
+39 -9
View File
@@ -2,6 +2,7 @@
#include <random>
#include <algorithm>
#include <sstream>
#include <iomanip>
// Helper function for random fluctuations
static double getFluctuation(double stddev) {
@@ -11,23 +12,52 @@ static double getFluctuation(double stddev) {
return d(gen);
}
SpinalCord::SpinalCord(int id) : Organ(id, "SpinalCord"), signalConductionVelocity(70.0) {}
SpinalCord::SpinalCord(int id)
: Organ(id, "SpinalCord"),
reflexArcIntact(true) {
// Initialize major pathways
descendingMotorTract = {"Descending Motor Tract", SignalStatus::NORMAL, 75.0};
ascendingSensoryTract = {"Ascending Sensory Tract", SignalStatus::NORMAL, 65.0};
}
void SpinalCord::update(double deltaTime_s) {
const double baseline_velocity = 70.0;
const double theta = 0.01;
const double velocity_stddev = 0.1;
// 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.
descendingMotorTract.conductionVelocity_m_per_s += getFluctuation(0.1);
descendingMotorTract.conductionVelocity_m_per_s = std::clamp(descendingMotorTract.conductionVelocity_m_per_s, 70.0, 80.0);
signalConductionVelocity += theta * (baseline_velocity - signalConductionVelocity) * deltaTime_s + getFluctuation(velocity_stddev * deltaTime_s);
ascendingSensoryTract.conductionVelocity_m_per_s += getFluctuation(0.1);
ascendingSensoryTract.conductionVelocity_m_per_s = std::clamp(ascendingSensoryTract.conductionVelocity_m_per_s, 60.0, 70.0);
signalConductionVelocity = std::clamp(signalConductionVelocity, 60.0, 80.0);
// Reflex arc is a simple boolean for now.
reflexArcIntact = (descendingMotorTract.status == SignalStatus::NORMAL && ascendingSensoryTract.status == SignalStatus::NORMAL);
}
std::string SpinalCord::statusToString(SignalStatus status) const {
switch (status) {
case SignalStatus::NORMAL: return "Normal";
case SignalStatus::IMPAIRED: return "Impaired";
case SignalStatus::SEVERED: return "Severed";
default: return "Unknown";
}
}
std::string SpinalCord::getSummary() const {
std::stringstream ss;
ss << "Type: " << organType << " (ID: " << organId << ")\n"
<< " Signal Velocity: " << signalConductionVelocity << " m/s";
ss << "--- Spinal Cord Summary ---\n"
<< "Motor Pathway (" << descendingMotorTract.name << "): "
<< statusToString(descendingMotorTract.status) << " ("
<< std::fixed << std::setprecision(1) << descendingMotorTract.conductionVelocity_m_per_s << " m/s)\n"
<< "Sensory Pathway (" << ascendingSensoryTract.name << "): "
<< statusToString(ascendingSensoryTract.status) << " ("
<< std::fixed << std::setprecision(1) << ascendingSensoryTract.conductionVelocity_m_per_s << " m/s)\n"
<< "Reflex Arc Intact: " << (isReflexArcIntact() ? "Yes" : "No") << "\n";
return ss.str();
}
double SpinalCord::getSignalConductionVelocity() const { return signalConductionVelocity; }
// --- Getters Implementation ---
SignalStatus SpinalCord::getMotorPathwayStatus() const { return descendingMotorTract.status; }
SignalStatus SpinalCord::getSensoryPathwayStatus() const { return ascendingSensoryTract.status; }
bool SpinalCord::isReflexArcIntact() const { return reflexArcIntact; }
+32 -15
View File
@@ -2,6 +2,7 @@
#include <random>
#include <algorithm>
#include <sstream>
#include <iomanip>
// Helper function for random fluctuations
static double getFluctuation(double stddev) {
@@ -11,29 +12,45 @@ static double getFluctuation(double stddev) {
return d(gen);
}
Spleen::Spleen(int id) : Organ(id, "Spleen"), redBloodCellCount(4.5), whiteBloodCellCount(7.5) {}
Spleen::Spleen(int id) : Organ(id, "Spleen") {
// Initialize pulp components
redPulp = {1.0, 0.5};
whitePulp = {1500.0, 500.0};
}
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;
// 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.
redBloodCellCount += theta * (baseline_rbc - redBloodCellCount) * deltaTime_s + getFluctuation(rbc_stddev * deltaTime_s);
whiteBloodCellCount += theta * (baseline_wbc - whiteBloodCellCount) * deltaTime_s + getFluctuation(wbc_stddev * deltaTime_s);
// Red pulp fluctuations
redPulp.filtrationRate += getFluctuation(0.01);
redPulp.rbcBreakdownRate += getFluctuation(0.005);
redBloodCellCount = std::clamp(redBloodCellCount, 4.0, 5.0);
whiteBloodCellCount = std::clamp(whiteBloodCellCount, 5.0, 10.0);
// White pulp fluctuations
whitePulp.lymphocyteCount += getFluctuation(1.0);
whitePulp.macrophageCount += getFluctuation(0.5);
// Clamp to healthy ranges
redPulp.filtrationRate = std::clamp(redPulp.filtrationRate, 0.9, 1.1);
redPulp.rbcBreakdownRate = std::clamp(redPulp.rbcBreakdownRate, 0.45, 0.55);
whitePulp.lymphocyteCount = std::clamp(whitePulp.lymphocyteCount, 1400.0, 1600.0);
whitePulp.macrophageCount = std::clamp(whitePulp.macrophageCount, 450.0, 550.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";
ss.precision(1);
ss << std::fixed;
ss << "--- Spleen Summary ---\n"
<< "--- Red Pulp ---\n"
<< "Filtration Rate: " << redPulp.filtrationRate << "\n"
<< "RBC Breakdown Rate: " << getRbcBreakdownRate() << "\n"
<< "--- White Pulp ---\n"
<< "Lymphocyte Count: " << getLymphocyteCount() << " million\n"
<< "Macrophage Count: " << whitePulp.macrophageCount << " million\n";
return ss.str();
}
double Spleen::getRedBloodCellCount() const { return redBloodCellCount; }
double Spleen::getWhiteBloodCellCount() const { return whiteBloodCellCount; }
// --- Getters Implementation ---
double Spleen::getRbcBreakdownRate() const { return redPulp.rbcBreakdownRate; }
double Spleen::getLymphocyteCount() const { return whitePulp.lymphocyteCount; }
+86 -16
View File
@@ -2,6 +2,7 @@
#include <random>
#include <algorithm>
#include <sstream>
#include <iomanip>
// Helper function for random fluctuations
static double getFluctuation(double stddev) {
@@ -11,30 +12,99 @@ static double getFluctuation(double stddev) {
return d(gen);
}
Stomach::Stomach(int id) : Organ(id, "Stomach"), phLevel(2.0), digestionRate(1.0) {}
Stomach::Stomach(int id)
: Organ(id, "Stomach"),
currentState(GastricState::EMPTY),
currentVolume_mL(0.0),
currentPh(4.5), // pH of an empty stomach is higher
gastricJuiceSecretionRate_ml_per_s(0.1),
emptyingRate_ml_per_s(0.5) {}
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;
// --- 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;
}
break;
phLevel += theta * (baseline_ph - phLevel) * deltaTime_s + getFluctuation(ph_stddev * deltaTime_s);
digestionRate += theta * (baseline_digestion - digestionRate) * deltaTime_s + getFluctuation(digestion_stddev * deltaTime_s);
case GastricState::FILLING:
// Transition to DIGESTING after a short period
static double fillTime = 0.0;
fillTime += deltaTime_s;
if (fillTime > 2.0) {
currentState = GastricState::DIGESTING;
fillTime = 0.0;
}
break;
phLevel = std::clamp(phLevel, 1.5, 3.5);
digestionRate = std::clamp(digestionRate, 0.5, 1.5);
case GastricState::DIGESTING:
// Secrete acid, lowering pH
currentPh -= 0.5 * deltaTime_s;
currentPh = std::max(1.5, currentPh);
// After some time, start emptying
static double digestionTime = 0.0;
digestionTime += deltaTime_s;
if (digestionTime > 30.0) { // Digest for 30 seconds
currentState = GastricState::EMPTYING;
digestionTime = 0.0;
}
break;
case GastricState::EMPTYING:
// Empty chyme into intestines
double amountToEmpty = emptyingRate_ml_per_s * deltaTime_s;
currentVolume_mL -= amountToEmpty;
if (currentVolume_mL <= 0) {
currentVolume_mL = 0;
currentState = GastricState::EMPTY;
currentPh = 4.5; // pH returns to baseline
}
break;
}
// Secrete a baseline level of gastric juice, increasing during digestion
double currentSecretionRate = (currentState == GastricState::DIGESTING) ? 2.0 : 0.1;
currentVolume_mL += currentSecretionRate * deltaTime_s;
currentVolume_mL = std::clamp(currentVolume_mL, 0.0, capacity_mL);
}
void Stomach::addSubstance(double volume_mL) {
currentVolume_mL += volume_mL;
// Food buffers the acid initially
currentPh = std::min(4.0, currentPh + 0.5);
currentState = GastricState::FILLING;
}
std::string Stomach::stateToString(GastricState state) const {
switch (state) {
case GastricState::EMPTY: return "Empty";
case GastricState::FILLING: return "Filling";
case GastricState::DIGESTING: return "Digesting";
case GastricState::EMPTYING: return "Emptying";
default: return "Unknown";
}
}
std::string Stomach::getSummary() const {
std::stringstream ss;
ss << "Type: " << organType << " (ID: " << organId << ")\n"
<< " pH Level: " << phLevel << "\n"
<< " Digestion Rate: " << digestionRate;
ss.precision(1);
ss << std::fixed;
ss << "--- Stomach Summary ---\n"
<< "State: " << stateToString(currentState) << "\n"
<< "Volume: " << currentVolume_mL << " / " << capacity_mL << " mL\n"
<< "Acidity (pH): " << getAcidity() << "\n";
return ss.str();
}
double Stomach::getPhLevel() const { return phLevel; }
double Stomach::getDigestionRate() const { return digestionRate; }
// --- Getters Implementation ---
GastricState Stomach::getCurrentState() const { return currentState; }
double Stomach::getVolume() const { return currentVolume_mL; }
double Stomach::getAcidity() const { return currentPh; }