Commit ba836676 authored by Jeff Webb's avatar Jeff Webb
Browse files

Intermediate check in for modifying hemorrhage to create a path/link from any vascular compartment.

parent 6fcc307e
......@@ -527,7 +527,6 @@ namespace pulse {
DEFINE_STATIC_STRING(SpleenToLiver);
// Hemorrhage and IV
DEFINE_STATIC_STRING(VenaCavaHemorrhage);
DEFINE_STATIC_STRING(VenaCavaIV);
// Vascular To Tissue Links
......
......@@ -539,7 +539,6 @@ DEFINE_STATIC_STRING_EX(GroundToConnection, MechanicalVentilatorGroundToConnecti
DEFINE_STATIC_STRING(SpleenToPortalVein);
// Vena Cava
DEFINE_STATIC_STRING(VenaCavaToGround);
DEFINE_STATIC_STRING(VenaCavaBleed);
DEFINE_STATIC_STRING(IVToVenaCava);
};
......
......@@ -1525,8 +1525,6 @@ void PulseController::SetupCardiovascular()
SEFluidCircuitPath& VenaCavaToGround = cCardiovascular.CreatePath(VenaCava, Ground, pulse::CardiovascularPath::VenaCavaToGround);
VenaCavaToGround.GetComplianceBaseline().SetValue(0.0, FlowComplianceUnit::mL_Per_mmHg);
SEFluidCircuitPath& VenaCavaBleed = cCardiovascular.CreatePath(VenaCava, Ground, pulse::CardiovascularPath::VenaCavaBleed);
VenaCavaBleed.GetFlowSourceBaseline().SetValue(0.0, VolumePerTimeUnit::mL_Per_s);
SEFluidCircuitPath& IVToVenaCava = cCardiovascular.CreatePath(Ground, VenaCava, pulse::CardiovascularPath::IVToVenaCava);
IVToVenaCava.GetFlowSourceBaseline().SetValue(0.0, VolumePerTimeUnit::mL_Per_s);
......@@ -1931,8 +1929,6 @@ void PulseController::SetupCardiovascular()
/////////////////////
// Bleeds and IV's //
SELiquidCompartmentLink& vVenaCavaHemorrhage = m_Compartments->CreateLiquidLink(vVenaCava, vGround, pulse::VascularLink::VenaCavaHemorrhage);
vVenaCavaHemorrhage.MapPath(VenaCavaBleed);
SELiquidCompartmentLink& vVenaCavaIV = m_Compartments->CreateLiquidLink(vGround, vVenaCava, pulse::VascularLink::VenaCavaIV);
vVenaCavaIV.MapPath(IVToVenaCava);
......@@ -2010,7 +2006,6 @@ void PulseController::SetupCardiovascular()
gCardiovascular.AddLink(vSplanchnicToLiver);
gCardiovascular.AddLink(vAortaToSpleen);
gCardiovascular.AddLink(vSpleenToLiver);
gCardiovascular.AddLink(vVenaCavaHemorrhage);
gCardiovascular.AddLink(vVenaCavaIV);
gCardiovascular.StateChange();
......
......@@ -127,7 +127,6 @@ void Cardiovascular::Clear()
m_pAortaToSplanchnic = nullptr;
m_pAortaToSpleen = nullptr;
m_pVenaCavaHemorrhage = nullptr;
m_pGndToPericardium = nullptr;
m_pPericardiumToGnd = nullptr;
m_pRightHeartToGnd = nullptr;
......@@ -256,7 +255,8 @@ void Cardiovascular::SetUp()
//Circuits
m_CirculatoryCircuit = &m_data.GetCircuits().GetActiveCardiovascularCircuit();
m_CirculatoryGraph = &m_data.GetCompartments().GetActiveCardiovascularGraph();
//Compartments
//Compartments
m_Groundcmpt = m_data.GetCompartments().GetLiquidCompartment(pulse::VascularCompartment::Ground);
m_Aorta = m_data.GetCompartments().GetLiquidCompartment(pulse::VascularCompartment::Aorta);
m_AortaCO2 = m_Aorta->GetSubstanceQuantity(m_data.GetSubstances().GetCO2());
m_Brain = m_data.GetCompartments().GetLiquidCompartment(pulse::VascularCompartment::Brain);
......@@ -273,6 +273,7 @@ void Cardiovascular::SetUp()
//Nodes
m_MainPulmonaryArteries = m_CirculatoryCircuit->GetNode(pulse::CardiovascularNode::MainPulmonaryArteries);
m_LeftHeart2 = m_CirculatoryCircuit->GetNode(pulse::CardiovascularNode::LeftHeart2);
m_Ground = m_CirculatoryCircuit->GetNode(pulse::CardiovascularNode::Ground);
//Paths
m_LeftPulmonaryArteriesToVeins = m_CirculatoryCircuit->GetPath(pulse::CardiovascularPath::LeftPulmonaryArteriesToLeftPulmonaryVeins);
m_LeftPulmonaryArteriesToCapillaries = m_CirculatoryCircuit->GetPath(pulse::CardiovascularPath::LeftPulmonaryArteriesToLeftPulmonaryCapillaries);
......@@ -298,7 +299,6 @@ void Cardiovascular::SetUp()
m_pBrainResistanceDownstream = m_CirculatoryCircuit->GetPath(pulse::CardiovascularPath::Brain1ToBrain2);
m_pBrainResistanceUpstream = m_CirculatoryCircuit->GetPath(pulse::CardiovascularPath::Aorta1ToBrain1);
m_pVenaCavaHemorrhage = m_CirculatoryCircuit->GetPath(pulse::CardiovascularPath::VenaCavaBleed);
m_pGndToPericardium = m_CirculatoryCircuit->GetPath(pulse::CardiovascularPath::GroundToPericardium1);
m_pPericardiumToGnd = m_CirculatoryCircuit->GetPath(pulse::CardiovascularPath::Pericardium1ToGround);
m_pRightHeartToGnd = m_CirculatoryCircuit->GetPath(pulse::CardiovascularPath::RightHeart3ToGround);
......@@ -935,23 +935,31 @@ void Cardiovascular::TraumaticBrainInjury()
/// The hemorrhage function simulates bleeding from a specified compartment
///
/// \details
/// The user may specify multiple bleeds across the anatomical compartments. The total loss rate is
/// calculated simply by summing the bleed rates from each of these compartments. This loss rate is specified
/// as a negative flow source in the vena cava. This allows for modeling venous blood loss by using only one
/// path for specifying the negative flow source. Modeling the effects of bleeding from the actual anatomical compartment
/// would require a separate bleeding path for each compartment.
/// The user may specify multiple bleeds across the anatomical compartments. The Model creates a
/// separate bleeding path for each anatomical compartment. Hemorrhage calls for a compartment that
/// already contains a hemorrhage will be overwritten with the new value.
//--------------------------------------------------------------------------------------------------
void Cardiovascular::Hemorrhage()
{
/// \todo Enforce limits and remove fatal errors.
//jbw - Ensure it's a vascular compartment
//jbw - Do vectors keep order when serialized?
//Set all hemorrhage flows to zero, so we know to remove the ones that aren't overwritten
for (unsigned int hIter = 0; hIter < m_hemorrhagePaths.size(); hIter++)
{
m_hemorrhagePaths.at(hIter)->GetNextFlowSource().SetValue(0.0, VolumePerTimeUnit::mL_Per_s);
}
SEHemorrhage* h;
double TotalLossRate_mL_Per_s = 0;
const std::map <std::string, SEHemorrhage*> & hems = m_data.GetActions().GetPatientActions().GetHemorrhages();
for (auto hem : hems)
{
h = hem.second;
double rate_mL_Per_s = h->GetRate().GetValue(VolumePerTimeUnit::mL_Per_s);
/// \error Fatal: Bleeding rate cannot exceed cardiac output
if (h->GetRate().GetValue(VolumePerTimeUnit::mL_Per_s) > GetCardiacOutput().GetValue(VolumePerTimeUnit::mL_Per_s))
if (rate_mL_Per_s > GetCardiacOutput().GetValue(VolumePerTimeUnit::mL_Per_s))
{
m_ss << "Cannot have bleeding rate greater than cardiac output. \n\tCurrent cardiac output is: " << GetCardiacOutput()
<< "\n\tAnd specified bleeding rate is: " << h->GetRate();
......@@ -959,20 +967,109 @@ void Cardiovascular::Hemorrhage()
return;
}
/// \error Fatal: Bleeding rate cannot be less than zero
if (h->GetRate().GetValue(VolumePerTimeUnit::mL_Per_s) < 0)
if (rate_mL_Per_s < 0)
{
m_ss << "Cannot specify bleeding less than 0";
Fatal(m_ss);
return;
}
TotalLossRate_mL_Per_s += h->GetRate().GetValue(VolumePerTimeUnit::mL_Per_s);
TotalLossRate_mL_Per_s += rate_mL_Per_s;
//Update the circuit to remove blood from the specified compartment
SELiquidCompartment* compartment = m_data.GetCompartments().GetLiquidCompartment(h->GetCompartment());
const std::vector<SEFluidCircuitNode*>& nodes = compartment->GetNodeMapping().GetNodes();
unsigned int nodesWithVolume = 0;
double totalVolume_mL = 0.0;
for (auto node : nodes)
{
if (node->HasNextVolume())
{
nodesWithVolume++;
totalVolume_mL += node->GetNextVolume(VolumeUnit::mL);
}
}
for (auto node : nodes)
{
//Weight the flow sink value by node volume
double thisNodeRate_mL_Per_s = 0.0;
if (nodesWithVolume == 0)
{
//No nodes have volume, so evenly distribute
thisNodeRate_mL_Per_s = rate_mL_Per_s / double(nodes.size());
}
else if (!node->HasNextVolume())
{
//Some nodes have volume, but not this one, so move on
continue;
}
else
{
//This node has volume
thisNodeRate_mL_Per_s = rate_mL_Per_s * node->GetNextVolume(VolumeUnit::mL) / totalVolume_mL;
}
//Check if we've already been hemorrhaging here
SEFluidCircuitPath* hemorrhagePath;
bool pathFound = false;
for (unsigned int hIter = 0; hIter < m_hemorrhagePaths.size(); hIter++)
{
hemorrhagePath = m_hemorrhagePaths.at(hIter);
if (&(hemorrhagePath->GetSourceNode()) == node)
{
pathFound = true;
break;
}
}
if (pathFound)
{
//Update the existing bleed path
hemorrhagePath->GetNextFlowSource().SetValue(thisNodeRate_mL_Per_s, VolumePerTimeUnit::mL_Per_s);
}
else
{
//Add bleed path for fluid mechanics
SEFluidCircuitPath& newHemorrhagePath = m_CirculatoryCircuit->CreatePath(*node, *m_Ground, node->GetName() + "Hemorrhage");
newHemorrhagePath.GetNextFlowSource().SetValue(thisNodeRate_mL_Per_s, VolumePerTimeUnit::mL_Per_s);
m_CirculatoryCircuit->StateChange();
//Add bleed link for transport
SELiquidCompartmentLink& newHemorrhageLink = m_data.GetCompartments().CreateLiquidLink(*compartment, *m_Groundcmpt, compartment->GetName() + "Hemorrhage");
newHemorrhageLink.MapPath(newHemorrhagePath);
m_CirculatoryGraph->AddLink(newHemorrhageLink);
m_CirculatoryGraph->StateChange();
//Add to local lists
m_hemorrhagePaths.push_back(&newHemorrhagePath);
m_hemorrhageLinks.push_back(&newHemorrhageLink);
}
}
}
//Remove hemorrhage elements that aren't being used
//Make sure to do this even if no hemorrhage action, since it's needed when removed
unsigned int hIter = 0;
while (hIter < m_hemorrhagePaths.size())
{
if (m_hemorrhagePaths.at(hIter)->GetNextFlowSource(VolumePerTimeUnit::mL_Per_s) == 0.0)
{
m_CirculatoryCircuit->RemovePath(*m_hemorrhagePaths.at(hIter));
m_hemorrhagePaths.erase(m_hemorrhagePaths.begin() + hIter);
m_CirculatoryCircuit->StateChange();
m_CirculatoryGraph->RemoveLink(*m_hemorrhageLinks.at(hIter));
m_hemorrhageLinks.erase(m_hemorrhageLinks.begin() + hIter);
m_CirculatoryGraph->StateChange();
continue;
}
hIter++;
}
if (TotalLossRate_mL_Per_s == 0)
return;
//Remove blood from the vena cava
m_pVenaCavaHemorrhage->GetNextFlowSource().SetValue(TotalLossRate_mL_Per_s, VolumePerTimeUnit::mL_Per_s);
//Update the patient's mass
double bloodDensity_kg_Per_mL = m_data.GetBloodChemistry().GetBloodDensity(MassPerVolumeUnit::kg_Per_mL);
double massLost_kg = TotalLossRate_mL_Per_s*bloodDensity_kg_Per_mL*m_dT_s;
double patientMass_kg = m_patient->GetWeight(MassUnit::kg);
......
......@@ -8,6 +8,7 @@ class SEPatient;
class SELiquidCompartment;
class SELiquidSubstanceQuantity;
class SELiquidCompartmentGraph;
class SELiquidCompartmentLink;
class SELiquidTransporter;
class SEFluidCircuit;
class SEFluidCircuitNode;
......@@ -101,6 +102,10 @@ protected:
double m_CompressionTime_s;
double m_CompressionRatio;
double m_CompressionPeriod_s;
//Hemorrhage
//jbw - add to serialization
std::vector<SEFluidCircuitPath*> m_hemorrhagePaths;
std::vector<SELiquidCompartmentLink*> m_hemorrhageLinks;
// Vitals and Averages
double m_CurrentCardiacCycleTime_s;
double m_CardiacCycleDiastolicVolume_mL; // Maximum left heart volume for the current cardiac cycle
......@@ -131,11 +136,12 @@ protected:
SEPatient* m_patient;
SEFluidCircuit* m_CirculatoryCircuit;
SEFluidCircuit* m_CirculatoryCircuit;
SELiquidCompartmentGraph* m_CirculatoryGraph;
SEFluidCircuitNode* m_MainPulmonaryArteries;
SEFluidCircuitNode* m_LeftHeart2;
SEFluidCircuitNode* m_Ground;
SEFluidCircuitPath* m_AortaCompliance;
SEFluidCircuitPath* m_AortaResistance;
......@@ -163,7 +169,6 @@ protected:
SEFluidCircuitPath* m_pAortaToSplanchnic;
SEFluidCircuitPath* m_pAortaToSpleen;
SEFluidCircuitPath* m_pVenaCavaHemorrhage;
SEFluidCircuitPath* m_pGndToPericardium;
SEFluidCircuitPath* m_pPericardiumToGnd;
SEFluidCircuitPath* m_pRightHeartToGnd;
......@@ -178,6 +183,7 @@ protected:
SEFluidCircuitPath* m_leftRenalArteryPath;
SEFluidCircuitPath* m_rightRenalArteryPath;
SELiquidCompartment* m_Groundcmpt; //jbw - Add?
SELiquidCompartment* m_Aorta;
SELiquidSubstanceQuantity* m_AortaCO2;
SELiquidCompartment* m_Brain;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment