From 52aede933b5b9ba92ae74f0cbb22cc1d7b03abdd Mon Sep 17 00:00:00 2001 From: Aaron Bray Date: Mon, 14 Jun 2021 22:42:01 -0400 Subject: [PATCH] Add volume to SESubstanceInfusion --- src/cpp/cdm/io/protobuf/PBPatientActions.cpp | 4 ++ .../patient/actions/SESubstanceInfusion.cpp | 31 ++++++++++++++- .../cdm/patient/actions/SESubstanceInfusion.h | 5 +++ src/cpp/cpm/physiology/Drugs.cpp | 39 ++++++++++++++----- src/cpp/cpm/physiology/Drugs.h | 5 ++- src/csharp/pulse/cdm/io/PBPatientActions.cs | 4 ++ .../patient/actions/SESubstanceInfusion.cs | 15 +++++++ .../patient/actions/SESubstanceInfusion.java | 26 +++++++++++++ src/python/pulse/cdm/io/patient_actions.py | 2 + src/python/pulse/cdm/patient_actions.py | 29 ++++++++++---- .../pulse/cdm/bind/PatientActions.proto | 3 +- 11 files changed, 142 insertions(+), 21 deletions(-) diff --git a/src/cpp/cdm/io/protobuf/PBPatientActions.cpp b/src/cpp/cdm/io/protobuf/PBPatientActions.cpp index 0973bf8a..f25966e2 100644 --- a/src/cpp/cdm/io/protobuf/PBPatientActions.cpp +++ b/src/cpp/cdm/io/protobuf/PBPatientActions.cpp @@ -1189,6 +1189,8 @@ void PBPatientAction::Serialize(const CDM_BIND::SubstanceInfusionData& src, SESu PBProperty::Load(src.rate(), dst.GetRate()); if (src.has_concentration()) PBProperty::Load(src.concentration(), dst.GetConcentration()); + if (src.has_volume()) + PBProperty::Load(src.volume(), dst.GetVolume()); } CDM_BIND::SubstanceInfusionData* PBPatientAction::Unload(const SESubstanceInfusion& src) { @@ -1204,6 +1206,8 @@ void PBPatientAction::Serialize(const SESubstanceInfusion& src, CDM_BIND::Substa dst.set_allocated_rate(PBProperty::Unload(*src.m_Rate)); if (src.HasConcentration()) dst.set_allocated_concentration(PBProperty::Unload(*src.m_Concentration)); + if (src.HasVolume()) + dst.set_allocated_volume(PBProperty::Unload(*src.m_Volume)); } void PBPatientAction::Copy(const SESubstanceInfusion& src, SESubstanceInfusion& dst) { diff --git a/src/cpp/cdm/patient/actions/SESubstanceInfusion.cpp b/src/cpp/cdm/patient/actions/SESubstanceInfusion.cpp index 389d68e5..14a13cbc 100644 --- a/src/cpp/cdm/patient/actions/SESubstanceInfusion.cpp +++ b/src/cpp/cdm/patient/actions/SESubstanceInfusion.cpp @@ -13,12 +13,14 @@ SESubstanceInfusion::SESubstanceInfusion(const SESubstance& substance, Logger* l { m_Rate=nullptr; m_Concentration=nullptr; + m_Volume=nullptr; } SESubstanceInfusion::~SESubstanceInfusion() { SAFE_DELETE(m_Rate); SAFE_DELETE(m_Concentration); + SAFE_DELETE(m_Volume); } void SESubstanceInfusion::Clear() @@ -26,6 +28,7 @@ void SESubstanceInfusion::Clear() SEPatientAction::Clear(); INVALIDATE_PROPERTY(m_Rate); INVALIDATE_PROPERTY(m_Concentration); + INVALIDATE_PROPERTY(m_Volume); } void SESubstanceInfusion::Copy(const SESubstanceInfusion& src, bool preserveState) @@ -44,7 +47,13 @@ bool SESubstanceInfusion::IsActive() const { if (!SEPatientAction::IsActive()) return false; - return !m_Rate->IsZero() && !m_Concentration->IsZero(); + if (m_Rate->IsZero()) + return false; + if (m_Concentration->IsZero()) + return false; + if (HasVolume() && m_Volume->IsZero()) + return false; + return true; } void SESubstanceInfusion::Deactivate() { @@ -58,6 +67,8 @@ const SEScalar* SESubstanceInfusion::GetScalar(const std::string& name) return &GetRate(); if (name.compare("Concentration") == 0) return &GetConcentration(); + if (name.compare("Volume") == 0) + return &GetVolume(); return nullptr; } @@ -95,6 +106,23 @@ double SESubstanceInfusion::GetConcentration(const MassPerVolumeUnit& unit) cons return m_Concentration->GetValue(unit); } +bool SESubstanceInfusion::HasVolume() const +{ + return m_Volume == nullptr ? false : m_Volume->IsValid(); +} +SEScalarVolume& SESubstanceInfusion::GetVolume() +{ + if (m_Volume == nullptr) + m_Volume = new SEScalarVolume(); + return *m_Volume; +} +double SESubstanceInfusion::GetVolume(const VolumeUnit& unit) const +{ + if (m_Volume == nullptr) + return SEScalar::dNaN(); + return m_Volume->GetValue(unit); +} + SESubstance& SESubstanceInfusion::GetSubstance() { return const_cast(m_Substance); @@ -111,6 +139,7 @@ void SESubstanceInfusion::ToString(std::ostream &str) const str<<"\n\tComment: "< finished; for (auto infusion : infusions) { if (!infusion->IsActive()) continue; + if (!infusion->HasVolume()) + infusion->GetVolume().SetValue(1000, VolumeUnit::mL); + concentration_ug_Per_mL = infusion->GetConcentration().GetValue(MassPerVolumeUnit::ug_Per_mL); rate_mL_Per_s = infusion->GetRate().GetValue(VolumePerTimeUnit::mL_Per_s); + infusion->GetVolume().IncrementValue(-rate_mL_Per_s * m_data.GetTimeStep_s(), VolumeUnit::mL); + if (infusion->GetVolume().IsZero() || infusion->GetVolume().IsNegative()) + { /// \todo correct the mass based on what we have left in the bag + finished.push_back(&infusion->GetSubstance()); + continue; + } + massIncrement_ug = rate_mL_Per_s*concentration_ug_Per_mL*m_data.GetTimeStep_s(); subQ = m_venaCavaVascular->GetSubstanceQuantity(infusion->GetSubstance()); subQ->GetMass().IncrementValue(massIncrement_ug, MassUnit::ug); @@ -288,8 +301,11 @@ void Drugs::AdministerSubstanceInfusion() } /// \todo Need to add fluid amount to fluid system - - /// \todo Support state, and how would a user remove this action? + } + for (const SESubstance* sub : finished) + { + Info("Completed infusion of " + sub->GetName()); + m_data.GetActions().GetPatientActions().RemoveSubstanceInfusion(*sub); } } @@ -320,10 +336,11 @@ void Drugs::AdministerSubstanceCompoundInfusion() for(auto infusion : infusions) { + compound = &infusion->GetSubstanceCompound(); + if (!infusion->IsActive()) continue; - compound = &infusion->GetSubstanceCompound(); rate_mL_Per_s = infusion->GetRate().GetValue(VolumePerTimeUnit::mL_Per_s); totalRate_mL_Per_s += rate_mL_Per_s; /// \todo Enforce limits and remove the fatal error @@ -333,33 +350,35 @@ void Drugs::AdministerSubstanceCompoundInfusion() m_ss<<"Cannot specify an Infusion rate greater than 285 mL/min. Current administration rate is: "<< infusion->GetRate(); Fatal(m_ss); return; - } + } infusion->GetBagVolume().IncrementValue(-rate_mL_Per_s*m_data.GetTimeStep_s(), VolumeUnit::mL); - double total_mL = infusion->GetBagVolume().GetValue(VolumeUnit::mL); - if (total_mL <= 0) + if (infusion->GetBagVolume().IsZero() || infusion->GetBagVolume().IsNegative()) { /// \todo correct the mass based on what we have left in the bag emptyBags.push_back(compound); continue; } - + for (const SESubstanceConcentration* component : compound->GetComponents()) { subQ = m_venaCavaVascular->GetSubstanceQuantity(component->GetSubstance()); massIncrement_ug = rate_mL_Per_s*component->GetConcentration(MassPerVolumeUnit::ug_Per_mL)*m_data.GetTimeStep_s(); subQ->GetMass().IncrementValue(massIncrement_ug, MassUnit::ug); subQ->Balance(BalanceLiquidBy::Mass); - } + } - if (compound->GetName().compare("Saline") == 0) + if (compound == m_Saline) densityFluid_kg_Per_mL = m_data.GetConfiguration().GetWaterDensity(MassPerVolumeUnit::kg_Per_mL); - else if (compound->GetName().compare("Blood") == 0) + else if (compound == m_Blood) densityFluid_kg_Per_mL = m_data.GetBloodChemistry().GetBloodDensity(MassPerVolumeUnit::kg_Per_mL); patientMass_kg -= rate_mL_Per_s*densityFluid_kg_Per_mL*m_data.GetTimeStep_s(); } for (const SESubstanceCompound* c : emptyBags) + { + Info("Completed infusion of " + c->GetName()); m_data.GetActions().GetPatientActions().RemoveSubstanceCompoundInfusion(*c); + } m_data.GetCurrentPatient().GetWeight().SetValue(patientMass_kg, MassUnit::kg); m_IVToVenaCava->GetNextFlowSource().SetValue(totalRate_mL_Per_s, VolumePerTimeUnit::mL_Per_s); diff --git a/src/cpp/cpm/physiology/Drugs.h b/src/cpp/cpm/physiology/Drugs.h index 0db2fcf7..8826f586 100644 --- a/src/cpp/cpm/physiology/Drugs.h +++ b/src/cpp/cpm/physiology/Drugs.h @@ -7,6 +7,7 @@ class SEFluidCircuitPath; class SELiquidCompartment; class SETissueCompartment; +class SESubstanceCompound; /** * @brief @@ -48,7 +49,9 @@ protected: void CalculatePlasmaSubstanceConcentration(); void CalculateDrugEffects(); - // Stateless member variable (Set in SetUp()) + // Stateless member variable (Set in SetUp) + SESubstanceCompound* m_Saline; + SESubstanceCompound* m_Blood; SELiquidCompartment* m_aortaVascular; SELiquidCompartment* m_venaCavaVascular; SELiquidCompartment* m_muscleIntracellular; diff --git a/src/csharp/pulse/cdm/io/PBPatientActions.cs b/src/csharp/pulse/cdm/io/PBPatientActions.cs index 2f115467..82c669c9 100644 --- a/src/csharp/pulse/cdm/io/PBPatientActions.cs +++ b/src/csharp/pulse/cdm/io/PBPatientActions.cs @@ -1304,6 +1304,8 @@ namespace Pulse.CDM PBProperty.Load(src.Concentration, dst.GetConcentration()); if (src.Rate != null) PBProperty.Load(src.Rate, dst.GetRate()); + if (src.Volume != null) + PBProperty.Load(src.Volume, dst.GetVolume()); } public static pulse.cdm.bind.SubstanceInfusionData Unload(SESubstanceInfusion src) { @@ -1320,6 +1322,8 @@ namespace Pulse.CDM dst.Concentration = PBProperty.Unload(src.GetConcentration()); if (src.HasRate()) dst.Rate = PBProperty.Unload(src.GetRate()); + if (src.HasVolume()) + dst.Volume = PBProperty.Unload(src.GetVolume()); } #endregion diff --git a/src/csharp/pulse/cdm/patient/actions/SESubstanceInfusion.cs b/src/csharp/pulse/cdm/patient/actions/SESubstanceInfusion.cs index e12a622f..0c6f57eb 100644 --- a/src/csharp/pulse/cdm/patient/actions/SESubstanceInfusion.cs +++ b/src/csharp/pulse/cdm/patient/actions/SESubstanceInfusion.cs @@ -7,12 +7,14 @@ namespace Pulse.CDM { protected SEScalarMassPerVolume concentration; protected SEScalarVolumePerTime rate; + protected SEScalarVolume volume; protected string substance; public SESubstanceInfusion() { this.rate = null; this.concentration = null; + this.volume = null; this.substance = null; } @@ -24,6 +26,8 @@ namespace Pulse.CDM rate.Invalidate(); if (concentration != null) concentration.Invalidate(); + if (volume != null) + volume.Invalidate(); } public override bool IsValid() @@ -53,6 +57,17 @@ namespace Pulse.CDM return rate; } + public bool HasVolume() + { + return volume == null ? false : volume.IsValid(); + } + public SEScalarVolume GetVolume() + { + if (volume == null) + volume = new SEScalarVolume(); + return volume; + } + public bool HasSubstance() { return !string.IsNullOrEmpty(substance); } public string GetSubstance() { diff --git a/src/java/com/kitware/pulse/cdm/patient/actions/SESubstanceInfusion.java b/src/java/com/kitware/pulse/cdm/patient/actions/SESubstanceInfusion.java index 6ee0b12d..750f905a 100644 --- a/src/java/com/kitware/pulse/cdm/patient/actions/SESubstanceInfusion.java +++ b/src/java/com/kitware/pulse/cdm/patient/actions/SESubstanceInfusion.java @@ -5,6 +5,7 @@ package com.kitware.pulse.cdm.patient.actions; import com.kitware.pulse.cdm.bind.PatientActions.SubstanceInfusionData; import com.kitware.pulse.cdm.properties.SEScalarMassPerVolume; +import com.kitware.pulse.cdm.properties.SEScalarVolume; import com.kitware.pulse.cdm.properties.SEScalarVolumePerTime; public class SESubstanceInfusion extends SEPatientAction @@ -13,12 +14,14 @@ public class SESubstanceInfusion extends SEPatientAction private static final long serialVersionUID = 8029916816858227270L; protected SEScalarMassPerVolume concentration; protected SEScalarVolumePerTime rate; + protected SEScalarVolume volume; protected String substance; public SESubstanceInfusion() { this.rate = null; this.concentration = null; + this.volume = null; this.substance = ""; } @@ -38,6 +41,11 @@ public class SESubstanceInfusion extends SEPatientAction getConcentration().set(other.concentration); else if (concentration != null) concentration.invalidate(); + + if (other.volume != null) + getVolume().set(other.volume); + else if (volume != null) + volume.invalidate(); } @Override @@ -48,6 +56,8 @@ public class SESubstanceInfusion extends SEPatientAction rate.invalidate(); if (concentration != null) concentration.invalidate(); + if (volume != null) + volume.invalidate(); } @Override @@ -64,6 +74,8 @@ public class SESubstanceInfusion extends SEPatientAction SEScalarVolumePerTime.load(src.getRate(),dst.getRate()); if(src.hasConcentration()) SEScalarMassPerVolume.load(src.getConcentration(),dst.getConcentration()); + if(src.hasVolume()) + SEScalarVolume.load(src.getVolume(),dst.getVolume()); } public static SubstanceInfusionData unload(SESubstanceInfusion src) @@ -80,6 +92,8 @@ public class SESubstanceInfusion extends SEPatientAction dst.setRate(SEScalarVolumePerTime.unload(src.rate)); if (src.hasConcentration()) dst.setConcentration(SEScalarMassPerVolume.unload(src.concentration)); + if (src.hasVolume()) + dst.setVolume(SEScalarVolume.unload(src.volume)); dst.setSubstance(src.substance); } @@ -105,6 +119,17 @@ public class SESubstanceInfusion extends SEPatientAction return rate; } + public boolean hasVolume() + { + return volume == null ? false : volume.isValid(); + } + public SEScalarVolume getVolume() + { + if (volume == null) + volume = new SEScalarVolume(); + return volume; + } + public boolean hasSubstance() { return substance != null; } public void setSubstance(String name) { @@ -122,6 +147,7 @@ public class SESubstanceInfusion extends SEPatientAction return "Substance Infusion" + "\n\tRate: " + getRate() + "\n\tConcentration: " + getConcentration() + + "\n\tVolume: " + getVolume() + "\n\tSubstance: " + getSubstance(); else return "Action not specified properly"; diff --git a/src/python/pulse/cdm/io/patient_actions.py b/src/python/pulse/cdm/io/patient_actions.py index 9b53a7c9..96e04f50 100644 --- a/src/python/pulse/cdm/io/patient_actions.py +++ b/src/python/pulse/cdm/io/patient_actions.py @@ -409,6 +409,8 @@ def serialize_substance_infusion_to_bind(src:SESubstanceInfusion, dst: Substance serialize_scalar_mass_per_volume_to_bind(src.get_concentration(), dst.Concentration) if src.has_rate(): serialize_scalar_volume_per_time_to_bind(src.get_rate(), dst.Rate) + if src.has_volume(): + serialize_scalar_volume_to_bind(src.get_volume(), dst.Volume) if src.has_substance(): dst.Substance = src.get_substance() diff --git a/src/python/pulse/cdm/patient_actions.py b/src/python/pulse/cdm/patient_actions.py index 597becb1..d404793e 100644 --- a/src/python/pulse/cdm/patient_actions.py +++ b/src/python/pulse/cdm/patient_actions.py @@ -1119,12 +1119,13 @@ class SESubstanceCompoundInfusion(SEPatientAction): " Rate: {}").format(self._bag_volume, self._compound, self._rate) class SESubstanceInfusion(SEPatientAction): - __slots__ = ["_concentration", "_rate", "_substance"] + __slots__ = ["_concentration", "_rate", "_volume", "_substance"] def __init__(self): super().__init__() self._concentration = None self._rate = None + self._volume = None self._substance = None def clear(self): @@ -1133,17 +1134,13 @@ class SESubstanceInfusion(SEPatientAction): self._concentration = None if self._rate is not None: self._rate = None + if self._volume is not None: + self._volume = None if self._substance is not None: self._substance = None def is_valid(self): return self.has_rate() and self.has_substance() and self.has_concentration() - def has_rate(self): - return self._rate is not None - def get_rate(self): - if self._rate is None: - self._rate = SEScalarVolumePerTime() - return self._rate def has_substance(self): return self._substance is not None @@ -1158,11 +1155,27 @@ class SESubstanceInfusion(SEPatientAction): if self._concentration is None: self._concentration = SEScalarMassPerVolume() return self._concentration + + def has_rate(self): + return self._rate is not None + def get_rate(self): + if self._rate is None: + self._rate = SEScalarVolumePerTime() + return self._rate + + def has_volume(self): + return self._volume is not None + def get_volume(self): + if self._volume is None: + self._volume = SEScalarVolume() + return self._volume + def __repr__(self): return ("Substance Infusion\n" " Concentration: {}\n" " Substance: {}\n" - " Rate: {}").format(self._concentration, self._substance, self._rate) + " Rate: {}\n" + " Volume: {}").format(self._concentration, self._substance, self._rate, self._volume) class eDevice(Enum): NullDevice = 0 diff --git a/src/schema/pulse/cdm/bind/PatientActions.proto b/src/schema/pulse/cdm/bind/PatientActions.proto index 17169551..37127e73 100644 --- a/src/schema/pulse/cdm/bind/PatientActions.proto +++ b/src/schema/pulse/cdm/bind/PatientActions.proto @@ -353,7 +353,7 @@ message SubstanceCompoundInfusionData { PatientActionData PatientAction = 1; string SubstanceCompound = 2;/**<<@brief */ - ScalarVolumeData BagVolume = 3;/**<<@brief @ref SubstanceCompoundTable */ + ScalarVolumeData BagVolume = 3;/**<<@brief Amount of substance in bag */ ScalarVolumePerTimeData Rate = 4;/**<<@brief Flow rate of the infusion into the body. */ } @@ -364,6 +364,7 @@ message SubstanceInfusionData string Substance = 2;/**<<@brief @ref SubstanceTable */ ScalarMassPerVolumeData Concentration = 3;/**<<@brief Concentration of the dose to administer. */ ScalarVolumePerTimeData Rate = 4;/**<<@brief Flow rate of the infusion into the body. */ + ScalarVolumeData Volume = 5;/**<<@brief Amount of substance to infuse */ } /** @brief Extra Oxygen provided to the patient. */ -- GitLab