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:
+69
-12
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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; }
|
||||
|
||||
Reference in New Issue
Block a user