Respiratory.cpp 190 KB
Newer Older
Aaron Bray's avatar
Aaron Bray committed
1 2
/* Distributed under the Apache License, Version 2.0.
   See accompanying NOTICE file for details.*/
Aaron Bray's avatar
Aaron Bray committed
3 4

#include "stdafx.h"
5 6 7 8
#include "physiology/Respiratory.h"
#include "controller/Circuits.h"
#include "controller/Compartments.h"
#include "controller/Substances.h"
9 10
#include "PulseConfiguration.h"
// Conditions 
11
#include "engine/SEConditionManager.h"
12 13 14
#include "patient/conditions/SEChronicObstructivePulmonaryDisease.h"
#include "patient/conditions/SELobarPneumonia.h"
#include "patient/conditions/SEImpairedAlveolarExchange.h"
Anusha's avatar
Anusha committed
15
#include "patient/conditions/SEPulmonaryFibrosis.h"
16
#include "patient/conditions/SEPulmonaryShunt.h"
Aaron Bray's avatar
Aaron Bray committed
17
#include "patient/conditions/SEAcuteRespiratoryDistressSyndrome.h"
18
// Actions
19
#include "engine/SEActionManager.h"
20
#include "engine/SEOverrides.h"
21
#include "engine/SEPatientActionCollection.h"
Aaron Bray's avatar
Aaron Bray committed
22
#include "patient/actions/SEAcuteRespiratoryDistressSyndromeExacerbation.h"
23 24 25 26
#include "patient/actions/SEAirwayObstruction.h"
#include "patient/actions/SEAsthmaAttack.h"
#include "patient/actions/SEBronchoconstriction.h"
#include "patient/actions/SEChestOcclusiveDressing.h"
Aaron Bray's avatar
Aaron Bray committed
27
#include "patient/actions/SEChronicObstructivePulmonaryDiseaseExacerbation.h"
28 29 30
#include "patient/actions/SEConsciousRespiration.h"
#include "patient/actions/SEForcedExhale.h"
#include "patient/actions/SEForcedInhale.h"
31
#include "patient/actions/SEForcedPause.h"
32
#include "patient/actions/SEImpairedAlveolarExchangeExacerbation.h"
33
#include "patient/actions/SEUseInhaler.h"
34
#include "patient/actions/SEDyspnea.h"
35
#include "patient/actions/SEIntubation.h"
Aaron Bray's avatar
Aaron Bray committed
36
#include "patient/actions/SELobarPneumoniaExacerbation.h"
37 38
#include "patient/actions/SEMechanicalVentilation.h"
#include "patient/actions/SENeedleDecompression.h"
39
#include "patient/actions/SEPulmonaryShuntExacerbation.h"
40
#include "patient/actions/SERespiratoryFatigue.h"
41
#include "patient/actions/SESupplementalOxygen.h"
42 43 44 45 46 47 48 49 50
#include "patient/actions/SETensionPneumothorax.h"
// Assessments
#include "patient/assessments/SEPulmonaryFunctionTest.h"
// Dependent Systems
#include "system/physiology/SEBloodChemistrySystem.h"
#include "system/physiology/SEDrugSystem.h"
#include "system/physiology/SEEnergySystem.h"
// CDM
#include "patient/SEPatient.h"
51
#include "engine/SEEventManager.h"
52 53
#include "substance/SESubstance.h"
#include "substance/SESubstanceAerosolization.h"
54
#include "substance/SESubstanceConcentration.h"
55 56 57 58 59 60 61 62
#include "substance/SESubstanceFraction.h"
#include "substance/SESubstanceTransport.h"
#include "circuit/fluid/SEFluidCircuitCalculator.h"
#include "circuit/fluid/SEFluidCircuit.h"
#include "circuit/fluid/SEFluidCircuitNode.h"
#include "circuit/fluid/SEFluidCircuitPath.h"
#include "compartment/fluid/SEGasCompartmentGraph.h"
#include "compartment/fluid/SELiquidCompartmentGraph.h"
Aaron Bray's avatar
Aaron Bray committed
63 64
// Properties
#include "properties/SEScalar0To1.h"
65 66
#include "properties/SEScalarArea.h"
#include "properties/SEScalarFrequency.h"
Aaron Bray's avatar
Aaron Bray committed
67
#include "properties/SEScalarInversePressure.h"
68
#include "properties/SEScalarInverseVolume.h"
Aaron Bray's avatar
Aaron Bray committed
69 70 71
#include "properties/SEScalarLength.h"
#include "properties/SEScalarMass.h"
#include "properties/SEScalarMassPerVolume.h"
72 73 74
#include "properties/SEScalarNegative1To1.h"
#include "properties/SEScalarPower.h"
#include "properties/SEScalarPressure.h"
75
#include "properties/SEScalarPressurePerVolume.h"
76
#include "properties/SEScalarPressureTimePerVolume.h"
77 78 79
#include "properties/SEScalarTime.h"
#include "properties/SEScalarVolume.h"
#include "properties/SEScalarVolumePerTime.h"
80
#include "properties/SEScalarVolumePerPressure.h"
Aaron Bray's avatar
Aaron Bray committed
81
#include "properties/SEFunctionVolumeVsTime.h"
82
#include "properties/SERunningAverage.h"
83
// Utilitiy Classes
84
#include "utils/DataTrack.h"
85
#include "utils/GeneralMath.h"
86

Aaron Bray's avatar
Aaron Bray committed
87 88 89 90
#ifdef _MSC_VER 
#pragma warning( disable : 4305 4244 )  // Disable some warning messages
#endif

91 92 93 94
//Flag for data tracks
//Should be commented out, unless debugging
//#define DEBUG

Aaron Bray's avatar
Aaron Bray committed
95 96
//Flag for setting things constant to test
//Should be commented out, unless debugging/tuning
Jeff Webb's avatar
Jeff Webb committed
97
//#define TUNING
Aaron Bray's avatar
Aaron Bray committed
98

99
Respiratory::Respiratory(PulseData& data) : PulseRespiratorySystem(data)
Aaron Bray's avatar
Aaron Bray committed
100
{
101
  m_BloodPHRunningAverage = new SERunningAverage();
102
  m_MeanAirwayPressure_cmH2O = new SERunningAverage();
103 104
  m_ArterialO2RunningAverage_mmHg = new SERunningAverage();
  m_ArterialCO2RunningAverage_mmHg = new SERunningAverage();
105

106
  m_Calculator = new SEFluidCircuitCalculator(VolumePerPressureUnit::L_Per_cmH2O, VolumePerTimeUnit::L_Per_s, PressureTimeSquaredPerVolumeUnit::cmH2O_s2_Per_L, PressureUnit::cmH2O, VolumeUnit::L, PressureTimePerVolumeUnit::cmH2O_s_Per_L, GetLogger());
107 108
  m_GasTransporter = new SEGasTransporter(VolumePerTimeUnit::L_Per_s, VolumeUnit::L, VolumeUnit::L, GetLogger());
  m_AerosolTransporter = new SELiquidTransporter(VolumePerTimeUnit::mL_Per_s, VolumeUnit::mL, MassUnit::ug, MassPerVolumeUnit::ug_Per_mL, GetLogger());
Aaron Bray's avatar
Aaron Bray committed
109
  Clear();
Aaron Bray's avatar
Aaron Bray committed
110 111 112 113 114
}

Respiratory::~Respiratory()
{
  Clear();
115
  delete m_BloodPHRunningAverage;
116
  delete m_MeanAirwayPressure_cmH2O;
117 118 119 120 121 122
  delete m_ArterialO2RunningAverage_mmHg;
  delete m_ArterialCO2RunningAverage_mmHg;

  delete m_Calculator;
  delete m_GasTransporter;
  delete m_AerosolTransporter;
Aaron Bray's avatar
Aaron Bray committed
123 124 125 126 127 128 129 130
}

void Respiratory::Clear()
{
  SERespiratorySystem::Clear();
  m_PatientActions = nullptr;

  m_Environment = nullptr;
Aaron Bray's avatar
Aaron Bray committed
131
  m_AerosolAirway = nullptr;
Aaron Bray's avatar
Aaron Bray committed
132
  m_AerosolCarina = nullptr;
133 134
  m_AerosolLeftAnatomicDeadSpace = nullptr;
  m_AerosolLeftAlveolarDeadSpace = nullptr;
Aaron Bray's avatar
Aaron Bray committed
135
  m_AerosolLeftAlveoli = nullptr;
136 137
  m_AerosolRightAnatomicDeadSpace = nullptr;
  m_AerosolRightAlveolarDeadSpace = nullptr;
Aaron Bray's avatar
Aaron Bray committed
138 139 140 141 142 143 144
  m_AerosolRightAlveoli = nullptr;
  m_Lungs = nullptr;
  m_LeftLungExtravascular = nullptr;
  m_RightLungExtravascular = nullptr;
  m_Carina = nullptr;
  m_AortaO2 = nullptr;
  m_AortaCO2 = nullptr;
145 146
  m_MechanicalVentilationConnection = nullptr;
  m_MechanicalVentilationAerosolConnection = nullptr;
147
  m_PleuralCavity = nullptr;
Aaron Bray's avatar
Aaron Bray committed
148 149 150

  m_RespiratoryCircuit = nullptr;

Aaron Bray's avatar
Aaron Bray committed
151
  m_Airway = nullptr;
Aaron Bray's avatar
Aaron Bray committed
152
  m_LeftAlveoli = nullptr;
153 154
  m_LeftAnatomicDeadSpace = nullptr;
  m_LeftAlveolarDeadSpace = nullptr;
Aaron Bray's avatar
Aaron Bray committed
155 156 157
  m_LeftPleural = nullptr;
  m_RespiratoryMuscle = nullptr;
  m_RightAlveoli = nullptr;
158 159
  m_RightAnatomicDeadSpace = nullptr;
  m_RightAlveolarDeadSpace = nullptr;
Aaron Bray's avatar
Aaron Bray committed
160 161 162 163
  m_RightPleural = nullptr;

  m_CarinaToLeftAnatomicDeadSpace = nullptr;
  m_CarinaToRightAnatomicDeadSpace = nullptr;
164 165 166 167
  m_LeftAnatomicDeadSpaceToLeftAlveolarDeadSpace = nullptr;
  m_RightAnatomicDeadSpaceToRightAlveolarDeadSpace = nullptr;
  m_LeftAlveolarDeadSpaceToLeftAlveoli = nullptr;
  m_RightAlveolarDeadSpaceToRightAlveoli = nullptr;
Aaron Bray's avatar
Aaron Bray committed
168 169 170
  m_RightPleuralToRespiratoryMuscle = nullptr;
  m_LeftPleuralToRespiratoryMuscle = nullptr;
  m_DriverPressurePath = nullptr;
Aaron Bray's avatar
Aaron Bray committed
171 172
  m_AirwayToCarina = nullptr;
  m_AirwayToStomach = nullptr;
Aaron Bray's avatar
Aaron Bray committed
173 174 175 176 177 178 179 180 181 182
  m_EnvironmentToLeftChestLeak = nullptr;
  m_EnvironmentToRightChestLeak = nullptr;
  m_LeftAlveoliLeakToLeftPleural = nullptr;
  m_RightAlveoliLeakToRightPleural = nullptr;
  m_LeftPleuralToEnvironment = nullptr;
  m_RightPleuralToEnvironment = nullptr;
  m_RightAlveoliToRightPleuralConnection = nullptr;
  m_LeftAlveoliToLeftPleuralConnection = nullptr;
  m_RightPulmonaryCapillary = nullptr;
  m_LeftPulmonaryCapillary = nullptr;
183 184
  m_LeftPulmonaryArteriesToVeins = nullptr;
  m_RightPulmonaryArteriesToVeins = nullptr;
Aaron Bray's avatar
Aaron Bray committed
185
  m_ConnectionToAirway = nullptr;
Aaron Bray's avatar
Aaron Bray committed
186 187
  m_GroundToConnection = nullptr;

188
  m_BloodPHRunningAverage->Clear();
189
  m_MeanAirwayPressure_cmH2O->Clear();
190 191
  m_ArterialO2RunningAverage_mmHg->Clear();
  m_ArterialCO2RunningAverage_mmHg->Clear();
Aaron Bray's avatar
Aaron Bray committed
192 193 194 195 196
}

//--------------------------------------------------------------------------------------------------
/// \brief
/// Initializes system properties to valid homeostatic values.
197 198 199 200
///
/// \details
/// For stabilization only!
/// Called AFTER Setup when stabilizing a new patient
Aaron Bray's avatar
Aaron Bray committed
201 202 203
//--------------------------------------------------------------------------------------------------
void Respiratory::Initialize()
{
204
  PulseSystem::Initialize();
Aaron Bray's avatar
Aaron Bray committed
205 206

  //Vital signs
207
  m_NotBreathing = false;
Aaron Bray's avatar
Aaron Bray committed
208 209
  m_TopBreathTotalVolume_L = 0.0;
  m_TopBreathAlveoliVolume_L = 0.0;
210
  m_TopBreathPleuralVolume_L = 0.0;
Aaron Bray's avatar
Aaron Bray committed
211
  m_TopBreathPleuralPressure_cmH2O = 0.0;
212 213
  m_TopBreathAlveoliPressure_cmH2O = 0.0;
  m_TopBreathDriverPressure_cmH2O = 0.0;
Aaron Bray's avatar
Aaron Bray committed
214
  m_LastCardiacCycleBloodPH = 7.4;
215 216 217 218 219
  m_TopCarinaO2 = 0.2;
  m_TopBreathElapsedTime_min = 0.0;
  m_BottomBreathElapsedTime_min = 0.0;
  m_BottomBreathTotalVolume_L = 0.0;
  m_BottomBreathAlveoliVolume_L = m_BottomBreathTotalVolume_L;
220
  m_BottomBreathPleuralVolume_L = 0.0;
221
  m_BottomBreathPleuralPressure_cmH2O = 0.0;
222 223 224 225
  m_BottomBreathAlveoliPressure_cmH2O = 0.0;
  m_BottomBreathDriverPressure_cmH2O = 0.0;
  m_PeakAlveolarPressure_cmH2O = 0.0;
  m_MaximalAlveolarPressure_cmH2O = 0.0;
Aaron Bray's avatar
Aaron Bray committed
226 227 228

  //Driver
  m_ElapsedBreathingCycleTime_min = 0.0;
229
  m_TopBreathElapsedTime_min = 0.0;
230
  m_BreathingCycle = false;  
231
  m_VentilationFrequency_Per_min = m_data.GetCurrentPatient().GetRespirationRateBaseline(FrequencyUnit::Per_min);
232
  m_BreathingCycleTime_s = 60.0 / m_VentilationFrequency_Per_min + m_data.GetTimeStep_s(); //Make the engine start at the beginning of a breath
233
  m_DriverPressure_cmH2O = 0.0;
Aaron Bray's avatar
Aaron Bray committed
234 235
  m_VentilationToTidalVolumeSlope = 30.0;
  //The peak driver pressure is the pressure above the default pressure
236 237
  m_PeakInspiratoryPressure_cmH2O = 0.0;
  m_PeakExpiratoryPressure_cmH2O = 0.0;
238
  m_PreviousTargetAlveolarVentilation_L_Per_min = m_data.GetCurrentPatient().GetTidalVolumeBaseline(VolumeUnit::L) * m_VentilationFrequency_Per_min;
Aaron Bray's avatar
Aaron Bray committed
239 240
  m_AverageLocalTissueBronchodilationEffects = 0.0;

241
  m_IERatioScaleFactor = 1.0;
Aaron Bray's avatar
Aaron Bray committed
242

243 244 245
  m_leftAlveoliDecrease_L = 0;
  m_rightAlveoliDecrease_L = 0;

Aaron Bray's avatar
Aaron Bray committed
246
  //System data
247 248
  double TidalVolume_L = m_data.GetCurrentPatient().GetTidalVolumeBaseline(VolumeUnit::L);
  double RespirationRate_Per_min = m_data.GetCurrentPatient().GetRespirationRateBaseline(FrequencyUnit::Per_min);
Aaron Bray's avatar
Aaron Bray committed
249 250
  GetTidalVolume().SetValue(TidalVolume_L, VolumeUnit::L);
  GetRespirationRate().SetValue(RespirationRate_Per_min, FrequencyUnit::Per_min);
251
  GetInspiratoryExpiratoryRatio().SetValue(0.5);
Aaron Bray's avatar
Aaron Bray committed
252
  GetCarricoIndex().SetValue(452.0, PressureUnit::mmHg);
253 254 255 256 257
  GetFractionOfInsipredOxygen().SetValue(0.21);
  GetSaturationAndFractionOfInspiredOxygenRatio().SetValue(0.0);
  GetOxygenationIndex().SetValue(0.0);
  GetOxygenSaturationIndex().SetValue(0.0, PressureUnit::cmH2O);
  GetMeanAirwayPressure().SetValue(0.0, PressureUnit::cmH2O);
Aaron Bray's avatar
Aaron Bray committed
258

259
  double AnatomicDeadSpace_L = m_LeftAnatomicDeadSpace->GetVolumeBaseline(VolumeUnit::L) + m_RightAnatomicDeadSpace->GetVolumeBaseline(VolumeUnit::L);
260
  double AlveolarDeadSpace_L = m_LeftAlveolarDeadSpace->GetVolumeBaseline(VolumeUnit::L) + m_RightAlveolarDeadSpace->GetVolumeBaseline(VolumeUnit::L);
261 262
  GetAnatomicDeadSpace().SetValue(AnatomicDeadSpace_L, VolumeUnit::L);
  GetAlveolarDeadSpace().SetValue(AlveolarDeadSpace_L, VolumeUnit::L);
263
  GetPhysiologicDeadSpace().SetValue(AnatomicDeadSpace_L + AlveolarDeadSpace_L, VolumeUnit::L);
264 265

  GetTotalAlveolarVentilation().SetValue(RespirationRate_Per_min * TidalVolume_L, VolumePerTimeUnit::L_Per_min);
Aaron Bray's avatar
Aaron Bray committed
266
  GetTotalPulmonaryVentilation().SetValue(RespirationRate_Per_min * TidalVolume_L, VolumePerTimeUnit::L_Per_min);
267
  GetTotalDeadSpaceVentilation().SetValue(AnatomicDeadSpace_L * RespirationRate_Per_min, VolumePerTimeUnit::L_Per_min);
Aaron Bray's avatar
Aaron Bray committed
268
  GetSpecificVentilation().SetValue(0.21);
269

Aaron Bray's avatar
Aaron Bray committed
270 271
  GetEndTidalCarbonDioxideFraction().SetValue(0.0827);
  GetEndTidalCarbonDioxidePressure().SetValue(0.0, PressureUnit::mmHg);
272 273 274
  GetEndTidalOxygenFraction().SetValue(0.0);
  GetEndTidalOxygenPressure().SetValue(0.0, PressureUnit::mmHg);

275
  GetInspiratoryFlow().SetValue(0, VolumePerTimeUnit::L_Per_s);
276 277 278 279 280 281 282 283
  GetIntrapleuralPressure().SetValue(0.0, PressureUnit::cmH2O);
  GetTransrespiratoryPressure().SetValue(0.0, PressureUnit::cmH2O);
  GetTransairwayPressure().SetValue(0.0, PressureUnit::cmH2O);
  GetTranspulmonaryPressure().SetValue(0.0, PressureUnit::cmH2O);
  GetTransalveolarPressure().SetValue(0.0, PressureUnit::cmH2O);
  GetTransthoracicPressure().SetValue(0.0, PressureUnit::cmH2O);
  GetTransChestWallPressure().SetValue(0.0, PressureUnit::cmH2O);

284
  GetPulmonaryCompliance().SetValue(0.1, VolumePerPressureUnit::L_Per_cmH2O);
285
  GetLungCompliance().SetValue(0.1, VolumePerPressureUnit::L_Per_cmH2O);
286
  GetChestWallCompliance().SetValue(0.2, VolumePerPressureUnit::L_Per_cmH2O);
287
  GetPulmonaryElastance().SetValue(1.0 / 0.1, PressurePerVolumeUnit::cmH2O_Per_L);
Aaron Bray's avatar
Aaron Bray committed
288

289
  GetTotalRespiratoryModelCompliance().SetValue(0.1, VolumePerPressureUnit::L_Per_cmH2O);
Aaron Bray's avatar
Aaron Bray committed
290
  GetTotalRespiratoryModelResistance().SetValue(1.5, PressureTimePerVolumeUnit::cmH2O_s_Per_L);
291

292 293 294 295 296 297 298 299
  // Muscle Pressure Waveform
  m_InspiratoryRiseFraction = 0;
  m_InspiratoryHoldFraction = 0;
  m_InspiratoryReleaseFraction = 0;
  m_InspiratoryToExpiratoryPauseFraction = 0;
  m_ExpiratoryRiseFraction = 0;
  m_ExpiratoryHoldFraction = 0;
  m_ExpiratoryReleaseFraction = 0;
300

301 302 303 304
  // Disease State
  m_leftAlveoliDecrease_L = 0;
  m_rightAlveoliDecrease_L = 0;

305 306
  //Conscious Respiration
  m_ActiveConsciousRespirationCommand = false;
307

308 309 310 311
  //Overrides
  m_RespiratoryResistanceOverride_cmH2O_s_Per_L = -1.0;
  m_RespiratoryComplianceOverride_L_Per_cmH2O = -1.0;

312 313 314 315 316 317 318
  if (m_data.HasCardiovascular())
  {
    m_ArterialO2PartialPressure_mmHg = m_AortaO2->GetPartialPressure(PressureUnit::mmHg);
    m_ArterialCO2PartialPressure_mmHg = m_AortaCO2->GetPartialPressure(PressureUnit::mmHg);
  }

  //Get the substances to a good starting point
Aaron Bray's avatar
Aaron Bray committed
319 320 321 322 323 324 325
  TuneCircuit();
}

//--------------------------------------------------------------------------------------------------
/// \brief
/// Initializes parameters for Respiratory Class
///
326 327 328 329
/// \details
/// Called during both State loading and Patient Stabilization
/// Pull and setup up our data (can be from other systems)
/// Initialize will be called after this and can overwrite any of this data (only if stabilizing)
Aaron Bray's avatar
Aaron Bray committed
330 331 332 333 334
//--------------------------------------------------------------------------------------------------
void Respiratory::SetUp()
{
  //Patient
  m_PatientActions = &m_data.GetActions().GetPatientActions();
335 336
  //Driver
  m_MaxDriverPressure_cmH2O = -50.0;
Aaron Bray's avatar
Aaron Bray committed
337
  //Configuration parameters
338 339 340 341
  m_DefaultOpenResistance_cmH2O_s_Per_L = m_data.GetConfiguration().GetDefaultOpenFlowResistance(PressureTimePerVolumeUnit::cmH2O_s_Per_L);
  m_DefaultClosedResistance_cmH2O_s_Per_L = m_data.GetConfiguration().GetDefaultClosedFlowResistance(PressureTimePerVolumeUnit::cmH2O_s_Per_L);
  m_RespOpenResistance_cmH2O_s_Per_L = m_data.GetConfiguration().GetRespiratoryOpenResistance(PressureTimePerVolumeUnit::cmH2O_s_Per_L);
  m_RespClosedResistance_cmH2O_s_Per_L = m_data.GetConfiguration().GetRespiratoryClosedResistance(PressureTimePerVolumeUnit::cmH2O_s_Per_L);
Aaron Bray's avatar
Aaron Bray committed
342 343 344 345
  m_PeripheralControlGainConstant = m_data.GetConfiguration().GetPeripheralVentilatoryControllerGain();
  m_CentralControlGainConstant = m_data.GetConfiguration().GetCentralVentilatoryControllerGain();
  m_VentilationTidalVolumeIntercept = m_data.GetConfiguration().GetVentilationTidalVolumeIntercept(VolumeUnit::L);
  m_VentilatoryOcclusionPressure_cmH2O = m_data.GetConfiguration().GetVentilatoryOcclusionPressure(PressureUnit::cmH2O); //This increases the absolute max driver pressure
346 347
  m_MinimumAllowableTidalVolume_L = m_data.GetConfiguration().GetMinimumAllowableTidalVolume(VolumeUnit::L);
  m_MinimumAllowableInpiratoryAndExpiratoryPeriod_s = m_data.GetConfiguration().GetMinimumAllowableInpiratoryAndExpiratoryPeriod(TimeUnit::s);
Aaron Bray's avatar
Aaron Bray committed
348
  //Compartments
Aaron Bray's avatar
Aaron Bray committed
349
  m_Environment = m_data.GetCompartments().GetGasCompartment(pulse::EnvironmentCompartment::Ambient);
Aaron Bray's avatar
Aaron Bray committed
350
  m_AerosolAirway = m_data.GetCompartments().GetLiquidCompartment(pulse::PulmonaryCompartment::Airway);
Aaron Bray's avatar
Aaron Bray committed
351
  m_AerosolCarina = m_data.GetCompartments().GetLiquidCompartment(pulse::PulmonaryCompartment::Carina);
352 353
  m_AerosolLeftAnatomicDeadSpace = m_data.GetCompartments().GetLiquidCompartment(pulse::PulmonaryCompartment::LeftAnatomicDeadSpace);
  m_AerosolLeftAlveolarDeadSpace = m_data.GetCompartments().GetLiquidCompartment(pulse::PulmonaryCompartment::LeftAlveolarDeadSpace);
Aaron Bray's avatar
Aaron Bray committed
354
  m_AerosolLeftAlveoli = m_data.GetCompartments().GetLiquidCompartment(pulse::PulmonaryCompartment::LeftAlveoli);
355 356
  m_AerosolRightAnatomicDeadSpace = m_data.GetCompartments().GetLiquidCompartment(pulse::PulmonaryCompartment::RightAnatomicDeadSpace);
  m_AerosolRightAlveolarDeadSpace = m_data.GetCompartments().GetLiquidCompartment(pulse::PulmonaryCompartment::RightAlveolarDeadSpace);
Aaron Bray's avatar
Aaron Bray committed
357 358
  m_AerosolRightAlveoli = m_data.GetCompartments().GetLiquidCompartment(pulse::PulmonaryCompartment::RightAlveoli);
  m_Lungs = m_data.GetCompartments().GetGasCompartment(pulse::PulmonaryCompartment::Lungs);
359 360
  m_LeftLung = m_data.GetCompartments().GetGasCompartment(pulse::PulmonaryCompartment::LeftLung);
  m_RightLung = m_data.GetCompartments().GetGasCompartment(pulse::PulmonaryCompartment::RightLung);
361
  m_PleuralCavity = m_data.GetCompartments().GetGasCompartment(pulse::PulmonaryCompartment::PleuralCavity);
Aaron Bray's avatar
Aaron Bray committed
362 363 364
  m_LeftLungExtravascular = m_data.GetCompartments().GetLiquidCompartment(pulse::ExtravascularCompartment::LeftLungIntracellular);
  m_RightLungExtravascular = m_data.GetCompartments().GetLiquidCompartment(pulse::ExtravascularCompartment::RightLungIntracellular);
  m_Carina = m_data.GetCompartments().GetGasCompartment(pulse::PulmonaryCompartment::Carina);
Aaron Bray's avatar
Aaron Bray committed
365
  m_CarinaO2 = m_Carina->GetSubstanceQuantity(m_data.GetSubstances().GetO2());
Aaron Bray's avatar
Aaron Bray committed
366 367
  m_LeftAlveoliO2 = m_data.GetCompartments().GetGasCompartment(pulse::PulmonaryCompartment::LeftAlveoli)->GetSubstanceQuantity(m_data.GetSubstances().GetO2());
  m_RightAlveoliO2 = m_data.GetCompartments().GetGasCompartment(pulse::PulmonaryCompartment::RightAlveoli)->GetSubstanceQuantity(m_data.GetSubstances().GetO2());
Aaron Bray's avatar
Aaron Bray committed
368
  // Compartments we will process aerosol effects on
Aaron Bray's avatar
Aaron Bray committed
369
  m_AerosolEffects.clear();
Aaron Bray's avatar
Aaron Bray committed
370 371
  m_AerosolEffects.push_back(m_data.GetCompartments().GetLiquidCompartment(pulse::PulmonaryCompartment::Carina));
  m_AerosolEffects.push_back(m_data.GetCompartments().GetLiquidCompartment(pulse::PulmonaryCompartment::LeftAlveoli));
372 373
  m_AerosolEffects.push_back(m_data.GetCompartments().GetLiquidCompartment(pulse::PulmonaryCompartment::LeftAnatomicDeadSpace));
  m_AerosolEffects.push_back(m_data.GetCompartments().GetLiquidCompartment(pulse::PulmonaryCompartment::LeftAlveolarDeadSpace));
Aaron Bray's avatar
Aaron Bray committed
374
  m_AerosolEffects.push_back(m_data.GetCompartments().GetLiquidCompartment(pulse::PulmonaryCompartment::RightAlveoli));
375 376
  m_AerosolEffects.push_back(m_data.GetCompartments().GetLiquidCompartment(pulse::PulmonaryCompartment::RightAnatomicDeadSpace));
  m_AerosolEffects.push_back(m_data.GetCompartments().GetLiquidCompartment(pulse::PulmonaryCompartment::RightAlveolarDeadSpace));
Aaron Bray's avatar
Aaron Bray committed
377 378 379
  //Circuits
  m_RespiratoryCircuit = &m_data.GetCircuits().GetRespiratoryCircuit();
  //Nodes
Aaron Bray's avatar
Aaron Bray committed
380
  m_Airway = m_RespiratoryCircuit->GetNode(pulse::RespiratoryNode::Airway);
Aaron Bray's avatar
Aaron Bray committed
381
  m_LeftAlveoli = m_RespiratoryCircuit->GetNode(pulse::RespiratoryNode::LeftAlveoli);
382 383
  m_LeftAnatomicDeadSpace = m_RespiratoryCircuit->GetNode(pulse::RespiratoryNode::LeftAnatomicDeadSpace);
  m_LeftAlveolarDeadSpace = m_RespiratoryCircuit->GetNode(pulse::RespiratoryNode::LeftAlveolarDeadSpace);
Aaron Bray's avatar
Aaron Bray committed
384 385 386
  m_LeftPleural = m_RespiratoryCircuit->GetNode(pulse::RespiratoryNode::LeftPleural);
  m_RespiratoryMuscle = m_RespiratoryCircuit->GetNode(pulse::RespiratoryNode::RespiratoryMuscle);
  m_RightAlveoli = m_RespiratoryCircuit->GetNode(pulse::RespiratoryNode::RightAlveoli);
387 388
  m_RightAnatomicDeadSpace = m_RespiratoryCircuit->GetNode(pulse::RespiratoryNode::RightAnatomicDeadSpace);
  m_RightAlveolarDeadSpace = m_RespiratoryCircuit->GetNode(pulse::RespiratoryNode::RightAlveolarDeadSpace);
Aaron Bray's avatar
Aaron Bray committed
389 390 391
  m_RightPleural = m_RespiratoryCircuit->GetNode(pulse::RespiratoryNode::RightPleural);
  m_Ambient = m_RespiratoryCircuit->GetNode(pulse::EnvironmentNode::Ambient);
  m_Stomach = m_RespiratoryCircuit->GetNode(pulse::RespiratoryNode::Stomach);
Aaron Bray's avatar
Aaron Bray committed
392
  //Paths
Aaron Bray's avatar
Aaron Bray committed
393 394
  m_CarinaToLeftAnatomicDeadSpace = m_RespiratoryCircuit->GetPath(pulse::RespiratoryPath::CarinaToLeftAnatomicDeadSpace);
  m_CarinaToRightAnatomicDeadSpace = m_RespiratoryCircuit->GetPath(pulse::RespiratoryPath::CarinaToRightAnatomicDeadSpace);
395 396 397 398
  m_LeftAnatomicDeadSpaceToLeftAlveolarDeadSpace = m_RespiratoryCircuit->GetPath(pulse::RespiratoryPath::LeftAnatomicDeadSpaceToLeftAlveolarDeadSpace);
  m_RightAnatomicDeadSpaceToRightAlveolarDeadSpace = m_RespiratoryCircuit->GetPath(pulse::RespiratoryPath::RightAnatomicDeadSpaceToRightAlveolarDeadSpace);
  m_LeftAlveolarDeadSpaceToLeftAlveoli = m_RespiratoryCircuit->GetPath(pulse::RespiratoryPath::LeftAlveolarDeadSpaceToLeftAlveoli);
  m_RightAlveolarDeadSpaceToRightAlveoli = m_RespiratoryCircuit->GetPath(pulse::RespiratoryPath::RightAlveolarDeadSpaceToRightAlveoli);
Aaron Bray's avatar
Aaron Bray committed
399 400 401
  m_RightPleuralToRespiratoryMuscle = m_RespiratoryCircuit->GetPath(pulse::RespiratoryPath::RightPleuralToRespiratoryMuscle);
  m_LeftPleuralToRespiratoryMuscle = m_RespiratoryCircuit->GetPath(pulse::RespiratoryPath::LeftPleuralToRespiratoryMuscle);
  m_DriverPressurePath = m_RespiratoryCircuit->GetPath(pulse::RespiratoryPath::EnvironmentToRespiratoryMuscle);
Aaron Bray's avatar
Aaron Bray committed
402 403
  m_AirwayToCarina = m_RespiratoryCircuit->GetPath(pulse::RespiratoryPath::AirwayToCarina);
  m_AirwayToStomach = m_RespiratoryCircuit->GetPath(pulse::RespiratoryPath::AirwayToStomach);
Aaron Bray's avatar
Aaron Bray committed
404 405 406 407 408 409 410 411
  m_EnvironmentToLeftChestLeak = m_RespiratoryCircuit->GetPath(pulse::RespiratoryPath::EnvironmentToLeftChestLeak);
  m_EnvironmentToRightChestLeak = m_RespiratoryCircuit->GetPath(pulse::RespiratoryPath::EnvironmentToRightChestLeak);
  m_LeftAlveoliLeakToLeftPleural = m_RespiratoryCircuit->GetPath(pulse::RespiratoryPath::LeftAlveoliLeakToLeftPleural);
  m_RightAlveoliLeakToRightPleural = m_RespiratoryCircuit->GetPath(pulse::RespiratoryPath::RightAlveoliLeakToRightPleural);
  m_LeftPleuralToEnvironment = m_RespiratoryCircuit->GetPath(pulse::RespiratoryPath::LeftPleuralToEnvironment);
  m_RightPleuralToEnvironment = m_RespiratoryCircuit->GetPath(pulse::RespiratoryPath::RightPleuralToEnvironment);
  m_RightAlveoliToRightPleuralConnection = m_RespiratoryCircuit->GetPath(pulse::RespiratoryPath::RightAlveoliToRightPleuralConnection);
  m_LeftAlveoliToLeftPleuralConnection = m_RespiratoryCircuit->GetPath(pulse::RespiratoryPath::LeftAlveoliToLeftPleuralConnection);
Aaron Bray's avatar
Aaron Bray committed
412
  m_ConnectionToAirway = m_data.GetCircuits().GetRespiratoryAndMechanicalVentilationCircuit().GetPath(pulse::MechanicalVentilationPath::ConnectionToAirway);
413
  m_GroundToConnection = m_data.GetCircuits().GetRespiratoryAndMechanicalVentilationCircuit().GetPath(pulse::MechanicalVentilationPath::GroundToConnection);
Aaron Bray's avatar
Aaron Bray committed
414 415

  /// \todo figure out how to modify these resistances without getting the cv circuit - maybe add a parameter, like baroreceptors does
Jeff Webb's avatar
Jeff Webb committed
416
  //Venous Return
Aaron Bray's avatar
Aaron Bray committed
417 418
  m_RightPulmonaryCapillary = m_data.GetCircuits().GetCardiovascularCircuit().GetPath(pulse::CardiovascularPath::RightPulmonaryCapillariesToRightPulmonaryVeins);
  m_LeftPulmonaryCapillary = m_data.GetCircuits().GetCardiovascularCircuit().GetPath(pulse::CardiovascularPath::LeftPulmonaryCapillariesToLeftPulmonaryVeins);
419 420 421
  //Pulmonary Shunt
  m_LeftPulmonaryArteriesToVeins = m_data.GetCircuits().GetCardiovascularCircuit().GetPath(pulse::CardiovascularPath::LeftPulmonaryArteriesToLeftPulmonaryVeins);
  m_RightPulmonaryArteriesToVeins = m_data.GetCircuits().GetCardiovascularCircuit().GetPath(pulse::CardiovascularPath::RightPulmonaryArteriesToRightPulmonaryVeins);
422 423 424 425 426 427 428 429 430 431 432

  //Mechanical Ventilation Compartments
  m_MechanicalVentilationConnection = m_data.GetCompartments().GetGasCompartment(pulse::MechanicalVentilationCompartment::Connection);
  m_MechanicalVentilationAerosolConnection = m_data.GetCompartments().GetLiquidCompartment(pulse::MechanicalVentilationCompartment::Connection);

  if (m_data.HasCardiovascular())
  {
    SELiquidCompartment* Aorta = m_data.GetCompartments().GetLiquidCompartment(pulse::VascularCompartment::Aorta);
    m_AortaO2 = Aorta->GetSubstanceQuantity(m_data.GetSubstances().GetO2());
    m_AortaCO2 = Aorta->GetSubstanceQuantity(m_data.GetSubstances().GetCO2());
  }
Aaron Bray's avatar
Aaron Bray committed
433 434 435 436 437 438 439 440 441 442 443 444
}

//--------------------------------------------------------------------------------------------------
/// \brief
/// Respiratory system at steady state
///
/// \details
/// Initializes respiratory conditions if any are present.
///  <UL>
///   <LI>COPD</LI>
///   <LI>Lobar Pneumonia</LI>
///   <LI>ImpairedAlveolarExchange</LI>
Anusha's avatar
Anusha committed
445
///   <LI>Pulmonary Fibrosis< / LI>
Aaron Bray's avatar
Aaron Bray committed
446 447 448 449 450
///  </UL>
///
//--------------------------------------------------------------------------------------------------
void Respiratory::AtSteadyState()
{
451
  /// \todo figure out how to save an initial healthy/baseline patient definition and another current patient definition
452
  //Experimentally determined  
453
  double tidalVolumeBaseline_L = GetTidalVolume(VolumeUnit::L);
454
  //Calculated
455 456 457
  double totalLungCapacity_L = m_data.GetCurrentPatient().GetTotalLungCapacity(VolumeUnit::L);
  double functionalResidualCapacity_L = m_data.GetCurrentPatient().GetFunctionalResidualCapacity(VolumeUnit::L);
  double inspiratoryReserveVolume_L = totalLungCapacity_L - functionalResidualCapacity_L - tidalVolumeBaseline_L;
Aaron Bray's avatar
Aaron Bray committed
458

459
  std::string typeString;
Aaron Bray's avatar
Aaron Bray committed
460
  if (m_data.GetState() == EngineState::AtInitialStableState)
461
  {
462
    typeString = "Initial Stabilization Homeostasis: ";
463 464
    //At Resting State
    //Note: Respiratory conditions are applied each timestep to handle combined effects properly
465 466

    //Update healthy patient volumes
467 468 469 470
    //Tidal Volume is experimentatlly determined and is dependent on other patient settings
    //Inspiratory Reserve Volume is calcualted from Tidal Volume
    m_data.GetCurrentPatient().GetTidalVolumeBaseline().SetValue(tidalVolumeBaseline_L, VolumeUnit::L);
    m_data.GetCurrentPatient().GetInspiratoryReserveVolume().SetValue(inspiratoryReserveVolume_L, VolumeUnit::L);
Aaron Bray's avatar
Aaron Bray committed
471
  }
472 473 474 475 476 477 478 479 480 481
  else if (m_data.GetState() == EngineState::AtSecondaryStableState)
    typeString = "Secondary Stabilization Homeostasis: ";
  else if (m_data.GetState() == EngineState::Active)
    typeString = "Final Stabilization Homeostasis: ";

  std::stringstream ss;
  ss << typeString << "Patient tidal volume = " << tidalVolumeBaseline_L << " L.";
  Info(ss);
  ss << typeString << "Patient inspiratory reserve volume = " << inspiratoryReserveVolume_L << " L.";
  Info(ss);
Aaron Bray's avatar
Aaron Bray committed
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
}

//--------------------------------------------------------------------------------------------------
/// \brief
/// Respiratory system preprocess function
///
/// \details
/// Calculates the muscle pressure source that drives the respiratory system.
/// Updates airway resistance to account for changes arising from factors 
/// like drugs and respiratory insults and interventions. 
//// Updates the chest wall variable compliance. Handles all respiratory
/// insults and actions.
//--------------------------------------------------------------------------------------------------
void Respiratory::PreProcess()
{
497 498 499
  if (m_data.HasOverride())
  {
    // Look for any known overrides
Aaron Bray's avatar
Aaron Bray committed
500
    for (auto& o : m_data.GetOverrides())
501
    {
502 503
      if (o.name == "RespiratoryResistance")
      {
Aaron Bray's avatar
Aaron Bray committed
504 505 506 507
        if (std::isnan(o.value))
          m_RespiratoryResistanceOverride_cmH2O_s_Per_L = -1;
        else
          m_RespiratoryResistanceOverride_cmH2O_s_Per_L = Convert(o.value, PressureTimePerVolumeUnit::GetCompoundUnit(o.unit), PressureTimePerVolumeUnit::cmH2O_s_Per_L);
508 509
      }
      else if (o.name == "RespiratoryCompliance")
510
      {
Aaron Bray's avatar
Aaron Bray committed
511 512 513 514
        if (std::isnan(o.value))
          m_RespiratoryComplianceOverride_L_Per_cmH2O = -1;
        else
          m_RespiratoryComplianceOverride_L_Per_cmH2O = Convert(o.value, VolumePerPressureUnit::GetCompoundUnit(o.unit), VolumePerPressureUnit::L_Per_cmH2O);
515 516 517 518
      }
    }
  }

519 520 521
  CalculateWork();
  CalculateFatigue();

522
  UpdateChestWallCompliances();
Aaron Bray's avatar
Aaron Bray committed
523 524 525 526 527
  UpdateVolumes();
  UpdateResistances();
  UpdateAlveolarCompliances();
  UpdateInspiratoryExpiratoryRatio();
  UpdateDiffusion();
528 529 530 531 532
  if (m_data.HasCardiovascular())
  {
    UpdatePulmonaryCapillary();
    UpdatePulmonaryShunt();
  }
Aaron Bray's avatar
Aaron Bray committed
533

Aaron Bray's avatar
Aaron Bray committed
534
  ProcessAerosolSubstances();
535
  Pneumothorax();
Aaron Bray's avatar
Aaron Bray committed
536 537

  MechanicalVentilation();
538
  SupplementalOxygen();
Aaron Bray's avatar
Aaron Bray committed
539

540 541 542 543
  if (m_data.HasCardiovascular())
  {
    RespiratoryDriver();
  }
544 545 546 547

  //Do the overrides
  SetRespiratoryResistance();
  SetRespiratoryCompliance();
Aaron Bray's avatar
Aaron Bray committed
548 549 550 551 552 553 554 555 556 557 558 559 560 561
}

//--------------------------------------------------------------------------------------------------
/// \brief
/// Respiratory system process function
///
/// \details
/// Ensures the selection of the respiratory system with or without the anesthesia machine. 
///  Handles the integration of the anesthesia machine to the respiratory system when the anesthesia machine is turned on.
/// The integration of the anesthesia machine to the respiratory system is handled at run time by constructing a combined circuit of 
/// the respiratory and anesthesia machine.  
/// Handles lung volume changes during alveolar gas transfer. 
/// Calculates physiological parameters such as respiration rate, tidal volume and others that belonging to the respiratory system.
//--------------------------------------------------------------------------------------------------
562
void Respiratory::Process(bool solve_and_transport)
Aaron Bray's avatar
Aaron Bray committed
563
{
564 565 566 567 568 569 570
  if (solve_and_transport)
  {
    // Respiration circuit changes based on if Anesthesia Machine is on or off
    // When dynamic intercircuit connections work, we can stash off the respiration circuit in a member variable
    SEFluidCircuit& RespirationCircuit = m_data.GetCircuits().GetActiveRespiratoryCircuit();

    // Calc the circuits
571
    m_Calculator->Process(RespirationCircuit, m_data.GetTimeStep_s());
572 573 574 575 576 577

    //ModifyPleuralVolume();
    SEGasCompartmentGraph& RespirationGraph = m_data.GetCompartments().GetActiveRespiratoryGraph();
    SELiquidCompartmentGraph& AerosolGraph = m_data.GetCompartments().GetActiveAerosolGraph();

    // Transport substances
578
    m_GasTransporter->Transport(RespirationGraph, m_data.GetTimeStep_s());
Aaron Bray's avatar
Aaron Bray committed
579
    if (m_AerosolAirway->HasSubstanceQuantities())
580
      m_AerosolTransporter->Transport(AerosolGraph, m_data.GetTimeStep_s());
581 582 583 584

#ifdef DEBUG
    Debugging(RespirationCircuit);
#endif
585
  }
Aaron Bray's avatar
Aaron Bray committed
586 587
  //Update system data
  CalculateVitalSigns();
588

589 590 591 592
  ComputeExposedModelParameters();
}
void Respiratory::ComputeExposedModelParameters()
{
593 594 595 596 597 598 599 600 601
  double leftChestWallCompliance_L_Per_cmH2O = m_LeftPleuralToRespiratoryMuscle->GetNextCompliance(VolumePerPressureUnit::L_Per_cmH2O);
  double rightChestWallCompliance_L_Per_cmH2O = m_RightPleuralToRespiratoryMuscle->GetNextCompliance(VolumePerPressureUnit::L_Per_cmH2O);
  double leftLungCompliance_L_Per_cmH2O = m_LeftAlveoliToLeftPleuralConnection->GetNextCompliance(VolumePerPressureUnit::L_Per_cmH2O);
  double rightLungCompliance_L_Per_cmH2O = m_RightAlveoliToRightPleuralConnection->GetNextCompliance(VolumePerPressureUnit::L_Per_cmH2O);
  double leftSideCompliance_L_Per_cmH2O = 1.0 / (1.0 / leftChestWallCompliance_L_Per_cmH2O + 1.0 / leftLungCompliance_L_Per_cmH2O);
  double rightSideCompliance_L_Per_cmH2O = 1.0 / (1.0 / rightChestWallCompliance_L_Per_cmH2O + 1.0 / rightLungCompliance_L_Per_cmH2O);
  double totalCompliance_L_Per_cmH2O = leftSideCompliance_L_Per_cmH2O + rightSideCompliance_L_Per_cmH2O;
  GetTotalRespiratoryModelCompliance().SetValue(totalCompliance_L_Per_cmH2O, VolumePerPressureUnit::L_Per_cmH2O);

Aaron Bray's avatar
Aaron Bray committed
602
  double airwayResistance_cmH2O_s_Per_L = m_AirwayToCarina->GetNextResistance(PressureTimePerVolumeUnit::cmH2O_s_Per_L);
603 604 605 606 607 608 609 610
  double leftBronchiResistance_cmH2O_s_Per_L = m_CarinaToLeftAnatomicDeadSpace->GetNextResistance(PressureTimePerVolumeUnit::cmH2O_s_Per_L);
  double rightBronchiResistance_cmH2O_s_Per_L = m_CarinaToRightAnatomicDeadSpace->GetNextResistance(PressureTimePerVolumeUnit::cmH2O_s_Per_L);
  double leftAlveoliDuctResistance_cmH2O_s_Per_L = m_LeftAnatomicDeadSpaceToLeftAlveolarDeadSpace->GetNextResistance(PressureTimePerVolumeUnit::cmH2O_s_Per_L);
  double rightAlveoliDuctResistance_cmH2O_s_Per_L = m_RightAnatomicDeadSpaceToRightAlveolarDeadSpace->GetNextResistance(PressureTimePerVolumeUnit::cmH2O_s_Per_L);
  double leftSideResistance_cmH2O_s_Per_L = leftBronchiResistance_cmH2O_s_Per_L + leftAlveoliDuctResistance_cmH2O_s_Per_L;
  double rightSideResistance_cmH2O_s_Per_L = rightBronchiResistance_cmH2O_s_Per_L + rightAlveoliDuctResistance_cmH2O_s_Per_L;
  double totalDownstreamResistance_cmH2O_s_Per_L = 1.0 / (1.0 / leftSideResistance_cmH2O_s_Per_L + 1.0 / rightSideResistance_cmH2O_s_Per_L);
  double totalResistance_cmH2O_s_Per_L = airwayResistance_cmH2O_s_Per_L + totalDownstreamResistance_cmH2O_s_Per_L;
Aaron Bray's avatar
Aaron Bray committed
611 612

  GetTotalRespiratoryModelResistance().SetValue(totalResistance_cmH2O_s_Per_L, PressureTimePerVolumeUnit::cmH2O_s_Per_L);
Aaron Bray's avatar
Aaron Bray committed
613 614 615 616 617 618 619 620 621 622
}

//--------------------------------------------------------------------------------------------------
/// \brief
/// Respiratory system postprocess function
///
/// \details
/// Updates the current values of the gas volume fraction and gas volumes for the nodes in the respiratory circuit 
/// or the nodes in the combined (respiratory + anesthesia machine) circuit when the anesthesia machine is turned on.
//--------------------------------------------------------------------------------------------------
Aaron Bray's avatar
Aaron Bray committed
623
void Respiratory::PostProcess(bool solve_and_transport)
Aaron Bray's avatar
Aaron Bray committed
624
{
Aaron Bray's avatar
Aaron Bray committed
625 626 627 628 629 630 631
  if (solve_and_transport)
  {
    // Respiration circuit changes based on if Anesthesia Machine is on or off
    // When dynamic intercircuit connections work, we can stash off the respiration circuit in a member variable
    SEFluidCircuit& RespirationCircuit = m_data.GetCircuits().GetActiveRespiratoryCircuit();
    m_Calculator->PostProcess(RespirationCircuit);
  }
Aaron Bray's avatar
Aaron Bray committed
632 633 634 635 636 637 638
}

//--------------------------------------------------------------------------------------------------
/// \brief
/// Compute deposited mass, update localized PD effects 
///
/// \details
Aaron Bray's avatar
Aaron Bray committed
639 640
/// For each aerosol get the SIDE coefficient to determine deposited mass in each respiratory compartment.
/// Adjust the resistances between compartments as a function of deposited mass to reach validated data.
Aaron Bray's avatar
Aaron Bray committed
641 642 643 644 645 646
/// Liquid and solid aerosols are handeled here. 
//--------------------------------------------------------------------------------------------------
void Respiratory::ProcessAerosolSubstances()
{
  m_AverageLocalTissueBronchodilationEffects = 0.0; //No effect

Aaron Bray's avatar
Aaron Bray committed
647
  size_t numAerosols = m_AerosolAirway->GetSubstanceQuantities().size();
Aaron Bray's avatar
Aaron Bray committed
648 649 650 651 652 653
  if (numAerosols == 0)
    return;

  double inflammationCoefficient;

  // For this time step
Aaron Bray's avatar
Aaron Bray committed
654
  double airwayDepositied_ug = 0;
Aaron Bray's avatar
Aaron Bray committed
655 656 657 658 659 660 661
  double carinaDepositied_ug = 0;
  double leftDeadSpaceDepositied_ug = 0;
  double leftAlveoliDepositied_ug = 0;
  double rightDeadSpaceDepositied_ug = 0;
  double rightAlveoliDepositied_ug = 0;

  // Total amount deposited (including this time step)
Aaron Bray's avatar
Aaron Bray committed
662
  double airwayTotalDepositied_ug = 0;
Aaron Bray's avatar
Aaron Bray committed
663 664 665 666 667 668 669
  double carinaTotalDepositied_ug = 0;
  double leftDeadSpaceTotalDepositied_ug = 0;
  double leftAlveoliTotalDepositied_ug = 0;
  double rightDeadSpaceTotalDepositied_ug = 0;
  double rightAlveoliTotalDepositied_ug = 0;

  // Resistance Modifier Sum
Aaron Bray's avatar
Aaron Bray committed
670
  double airwayResistanceModifier=1;
Aaron Bray's avatar
Aaron Bray committed
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
  double carinaResistanceModifier=1;
  double leftDeadSpaceResistanceModifier=1;
  double leftAlveoliResistanceModifier=1;
  double rightDeadSpaceResistanceModifier=1;
  double rightAlveoliResistanceModifier=1;

  // Currently, There is no way to clear out depositied particulate out of the respiratory systems.
  // Maybe we could have it to cough or some other excretion related method... 
  
  SELiquidSubstanceQuantity* subQ;
  SELiquidSubstanceQuantity* tSubQ;
  const SizeIndependentDepositionEfficencyCoefficient* SIDECoeff;
  double combinedRightBronchodilationEffects = 0.0;
  double combinedLeftBronchodilationEffects = 0.0;
  for (size_t i=0; i<numAerosols; i++)
  {
    //initialize substance
Aaron Bray's avatar
Aaron Bray committed
688
    subQ = m_AerosolAirway->GetSubstanceQuantities()[i];
Aaron Bray's avatar
Aaron Bray committed
689 690 691
    //Adjust inflammation coefficient (scaled down):
    inflammationCoefficient = subQ->GetSubstance().GetAerosolization().GetInflammationCoefficient().GetValue();// Once for each subQ
    inflammationCoefficient *= 0.01;
Aaron Bray's avatar
Aaron Bray committed
692
    //Airway
Aaron Bray's avatar
Aaron Bray committed
693
    SIDECoeff = &m_data.GetSubstances().GetSizeIndependentDepositionEfficencyCoefficient(subQ->GetSubstance());// Once for each subQ
694
    airwayDepositied_ug = subQ->GetConcentration(MassPerVolumeUnit::ug_Per_mL)*m_AerosolAirway->GetInFlow(VolumePerTimeUnit::mL_Per_s)*m_data.GetTimeStep_s()*SIDECoeff->GetAirway();
Aaron Bray's avatar
Aaron Bray committed
695
    if (airwayDepositied_ug > subQ->GetMass(MassUnit::ug))
Aaron Bray's avatar
Aaron Bray committed
696
    {
Aaron Bray's avatar
Aaron Bray committed
697
      airwayDepositied_ug = subQ->GetMass(MassUnit::ug);
Aaron Bray's avatar
Aaron Bray committed
698 699 700
      subQ->GetMass().SetValue(0, MassUnit::ug);
    }
    else
Aaron Bray's avatar
Aaron Bray committed
701
      subQ->GetMass().IncrementValue(-airwayDepositied_ug, MassUnit::ug);
Aaron Bray's avatar
Aaron Bray committed
702
    subQ->Balance(BalanceLiquidBy::Mass);
Aaron Bray's avatar
Aaron Bray committed
703 704
    airwayTotalDepositied_ug = subQ->GetMassDeposited().IncrementValue(airwayDepositied_ug, MassUnit::ug);
    airwayResistanceModifier += airwayTotalDepositied_ug*inflammationCoefficient;
Aaron Bray's avatar
Aaron Bray committed
705 706
    //Carina
    subQ = m_AerosolCarina->GetSubstanceQuantities()[i];
707
    carinaDepositied_ug = subQ->GetConcentration(MassPerVolumeUnit::ug_Per_mL)*m_AerosolCarina->GetInFlow(VolumePerTimeUnit::mL_Per_s)*m_data.GetTimeStep_s()*SIDECoeff->GetCarina();
Aaron Bray's avatar
Aaron Bray committed
708 709 710 711 712 713 714 715 716 717 718
    if (carinaDepositied_ug > subQ->GetMass(MassUnit::ug))
    {
      carinaDepositied_ug = subQ->GetMass(MassUnit::ug);
      subQ->GetMass().SetValue(0, MassUnit::ug);
    }
    else
      subQ->GetMass().IncrementValue(-carinaDepositied_ug, MassUnit::ug);
    subQ->Balance(BalanceLiquidBy::Mass);
    carinaTotalDepositied_ug = subQ->GetMassDeposited().IncrementValue(carinaDepositied_ug, MassUnit::ug);
    carinaResistanceModifier += carinaTotalDepositied_ug*inflammationCoefficient;
    //Left DeadSpace
719
    subQ = m_AerosolLeftAnatomicDeadSpace->GetSubstanceQuantities()[i];
720
    leftDeadSpaceDepositied_ug = subQ->GetConcentration(MassPerVolumeUnit::ug_Per_mL)*m_AerosolLeftAnatomicDeadSpace->GetInFlow(VolumePerTimeUnit::mL_Per_s)*m_data.GetTimeStep_s()*SIDECoeff->GetDeadSpace();
Aaron Bray's avatar
Aaron Bray committed
721 722 723 724 725 726 727 728 729 730 731 732
    if (leftDeadSpaceDepositied_ug > subQ->GetMass(MassUnit::ug))
    {
      leftDeadSpaceDepositied_ug = subQ->GetMass(MassUnit::ug);
      subQ->GetMass().SetValue(0, MassUnit::ug);
    }
    else
      subQ->GetMass().IncrementValue(-leftDeadSpaceDepositied_ug, MassUnit::ug);
    subQ->Balance(BalanceLiquidBy::Mass);
    leftDeadSpaceTotalDepositied_ug = subQ->GetMassDeposited().IncrementValue(leftDeadSpaceDepositied_ug, MassUnit::ug);
    leftDeadSpaceResistanceModifier += leftDeadSpaceTotalDepositied_ug*inflammationCoefficient;
    //Left Alveoli
    subQ = m_AerosolLeftAlveoli->GetSubstanceQuantities()[i];
733
    leftAlveoliDepositied_ug = subQ->GetConcentration(MassPerVolumeUnit::ug_Per_mL)*m_AerosolLeftAlveoli->GetInFlow(VolumePerTimeUnit::mL_Per_s)*m_data.GetTimeStep_s()*SIDECoeff->GetAlveoli();
Aaron Bray's avatar
Aaron Bray committed
734 735 736 737 738 739 740 741 742 743 744
    if (leftAlveoliDepositied_ug > subQ->GetMass(MassUnit::ug))
    {
      leftAlveoliDepositied_ug = subQ->GetMass(MassUnit::ug);
      subQ->GetMass().SetValue(0, MassUnit::ug);
    }
    else
      subQ->GetMass().IncrementValue(-leftAlveoliDepositied_ug, MassUnit::ug);
    subQ->Balance(BalanceLiquidBy::Mass);
    leftAlveoliTotalDepositied_ug = subQ->GetMassDeposited().IncrementValue(leftAlveoliDepositied_ug, MassUnit::ug);
    leftAlveoliResistanceModifier += leftAlveoliTotalDepositied_ug*inflammationCoefficient;
    //Right DeadSpace
745
    subQ = m_AerosolRightAnatomicDeadSpace->GetSubstanceQuantities()[i];
746
    rightDeadSpaceDepositied_ug = subQ->GetConcentration(MassPerVolumeUnit::ug_Per_mL)*m_AerosolRightAnatomicDeadSpace->GetInFlow(VolumePerTimeUnit::mL_Per_s)*m_data.GetTimeStep_s()*SIDECoeff->GetDeadSpace();
Aaron Bray's avatar
Aaron Bray committed
747 748 749 750 751 752 753 754 755 756 757 758
    if (rightDeadSpaceDepositied_ug > subQ->GetMass(MassUnit::ug))
    {
      rightDeadSpaceDepositied_ug = subQ->GetMass(MassUnit::ug);
      subQ->GetMass().SetValue(0, MassUnit::ug);
    }
    else
      subQ->GetMass().IncrementValue(-rightDeadSpaceDepositied_ug, MassUnit::ug);
    subQ->Balance(BalanceLiquidBy::Mass);
    rightDeadSpaceTotalDepositied_ug = subQ->GetMassDeposited().IncrementValue(rightDeadSpaceDepositied_ug, MassUnit::ug);
    rightDeadSpaceResistanceModifier += rightDeadSpaceTotalDepositied_ug*inflammationCoefficient;
    //Right Alveoli
    subQ = m_AerosolRightAlveoli->GetSubstanceQuantities()[i];
759
    rightAlveoliDepositied_ug = subQ->GetConcentration(MassPerVolumeUnit::ug_Per_mL)*m_AerosolRightAlveoli->GetInFlow(VolumePerTimeUnit::mL_Per_s)*m_data.GetTimeStep_s()*SIDECoeff->GetAlveoli();
Aaron Bray's avatar
Aaron Bray committed
760 761 762 763 764 765 766 767 768 769 770 771 772
    if (rightAlveoliDepositied_ug > subQ->GetMass(MassUnit::ug))
    {
      rightAlveoliDepositied_ug = subQ->GetMass(MassUnit::ug);
      subQ->GetMass().SetValue(0, MassUnit::ug);
    }
    else
      subQ->GetMass().IncrementValue(-rightAlveoliDepositied_ug, MassUnit::ug);
    subQ->Balance(BalanceLiquidBy::Mass);
    rightAlveoliTotalDepositied_ug = subQ->GetMassDeposited().IncrementValue(rightAlveoliDepositied_ug, MassUnit::ug);
    rightAlveoliResistanceModifier += rightAlveoliTotalDepositied_ug*inflammationCoefficient;
    
    // Apply the BronchileModifier dilation effect
    // This is all just tuned to Albuterol - it'll work for other substances, and can be tuned using the other parameters (especially BronchioleModifier)
773
    if (subQ->GetSubstance().GetState() == eSubstance_State::Liquid)
Aaron Bray's avatar
Aaron Bray committed
774 775 776 777 778 779 780
    {
      // Sum the Bronchiole Effects
      // Must be positive
      double bronchioleModifier = subQ->GetSubstance().GetAerosolization().GetBronchioleModifier().GetValue();

      // Diffuse into Tissues
      // We only process mass deposited on the lungs (dead space and alveoli)
Aaron Bray's avatar
Aaron Bray committed
781
      // We do not currently do anything with the mass in the airway and carina
Aaron Bray's avatar
Aaron Bray committed
782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800
      // Could possibly let it go into the stomach somehow... 
      tSubQ = m_LeftLungExtravascular->GetSubstanceQuantity(subQ->GetSubstance());
      tSubQ->GetMass().IncrementValue(leftDeadSpaceDepositied_ug + leftAlveoliDepositied_ug, MassUnit::ug); tSubQ->Balance(BalanceLiquidBy::Mass);    
      combinedLeftBronchodilationEffects += bronchioleModifier * tSubQ->GetConcentration(MassPerVolumeUnit::ug_Per_mL);

      tSubQ = m_RightLungExtravascular->GetSubstanceQuantity(subQ->GetSubstance());
      tSubQ->GetMass().IncrementValue(rightDeadSpaceDepositied_ug + rightAlveoliDepositied_ug, MassUnit::ug); tSubQ->Balance(BalanceLiquidBy::Mass);
      combinedRightBronchodilationEffects += bronchioleModifier * tSubQ->GetConcentration(MassPerVolumeUnit::ug_Per_mL);
    }
  }

  //We're going to make the bronchodilation effects be based off of Albuterol.
  //Experimentally, 1mg of Albuterol given via a spacer device on an endotracheal tube caused a pulmonary resistance change of ~20% @cite mancebo1991effects.
  //The bronchi are ~30% of the total pulmonary resistance, so we'll make a dilation effect really strong with a normal dose.
  //This was tuned using a standard inhaler dose of 90ug
  m_AverageLocalTissueBronchodilationEffects = (combinedLeftBronchodilationEffects + combinedRightBronchodilationEffects) / 2.0;
  combinedLeftBronchodilationEffects = exp(-32894.0 * combinedLeftBronchodilationEffects);
  combinedRightBronchodilationEffects = exp(-32894.0 * combinedRightBronchodilationEffects);  

801
  // Change resistances due to deposition
Aaron Bray's avatar
Aaron Bray committed
802
  double dTracheaResistance = m_AirwayToCarina->GetNextResistance(PressureTimePerVolumeUnit::cmH2O_s_Per_L)*carinaResistanceModifier;
803 804
  double dLeftAlveoliResistance = m_LeftAnatomicDeadSpaceToLeftAlveolarDeadSpace->GetNextResistance(PressureTimePerVolumeUnit::cmH2O_s_Per_L)*leftAlveoliResistanceModifier;
  double dRightAlveoliResistance = m_RightAnatomicDeadSpaceToRightAlveolarDeadSpace->GetNextResistance(PressureTimePerVolumeUnit::cmH2O_s_Per_L)*rightAlveoliResistanceModifier;
Aaron Bray's avatar
Aaron Bray committed
805

806 807
  double dLeftBronchiResistance = m_CarinaToLeftAnatomicDeadSpace->GetNextResistance(PressureTimePerVolumeUnit::cmH2O_s_Per_L);
  double dRightBronchiResistance = m_CarinaToRightAnatomicDeadSpace->GetNextResistance(PressureTimePerVolumeUnit::cmH2O_s_Per_L);
Aaron Bray's avatar
Aaron Bray committed
808 809
  dLeftBronchiResistance *= leftDeadSpaceResistanceModifier * combinedLeftBronchodilationEffects;
  dRightBronchiResistance *= rightDeadSpaceResistanceModifier * combinedRightBronchodilationEffects;
810 811
  dLeftBronchiResistance = LIMIT(dLeftBronchiResistance, m_RespClosedResistance_cmH2O_s_Per_L, m_RespOpenResistance_cmH2O_s_Per_L);
  dRightBronchiResistance = LIMIT(dRightBronchiResistance, m_RespClosedResistance_cmH2O_s_Per_L, m_RespOpenResistance_cmH2O_s_Per_L);
Aaron Bray's avatar
Aaron Bray committed
812

Aaron Bray's avatar
Aaron Bray committed
813
  m_AirwayToCarina->GetNextResistance().SetValue(dTracheaResistance, PressureTimePerVolumeUnit::cmH2O_s_Per_L);
814 815
  m_CarinaToLeftAnatomicDeadSpace->GetNextResistance().SetValue(dLeftBronchiResistance, PressureTimePerVolumeUnit::cmH2O_s_Per_L);
  m_CarinaToRightAnatomicDeadSpace->GetNextResistance().SetValue(dRightBronchiResistance, PressureTimePerVolumeUnit::cmH2O_s_Per_L);
816 817
  m_LeftAnatomicDeadSpaceToLeftAlveolarDeadSpace->GetNextResistance().SetValue(dLeftAlveoliResistance, PressureTimePerVolumeUnit::cmH2O_s_Per_L);
  m_RightAnatomicDeadSpaceToRightAlveolarDeadSpace->GetNextResistance().SetValue(dRightAlveoliResistance, PressureTimePerVolumeUnit::cmH2O_s_Per_L);
Aaron Bray's avatar
Aaron Bray committed
818 819 820 821
}

//--------------------------------------------------------------------------------------------------
/// \brief
Aaron Bray's avatar
Aaron Bray committed
822
/// Modifies the pressure and/or flow at the airway
Aaron Bray's avatar
Aaron Bray committed
823 824 825
///
/// \details
/// Handles the mechanical ventilation action that adds a flow and pressure source to instantaneously
Aaron Bray's avatar
Aaron Bray committed
826
/// set the respiratory connection (airway) to user specified values.  
Aaron Bray's avatar
Aaron Bray committed
827 828 829 830 831
//--------------------------------------------------------------------------------------------------
void Respiratory::MechanicalVentilation()
{
  if (m_data.GetActions().GetPatientActions().HasMechanicalVentilation())
  {
832
    SEMechanicalVentilation& mv = m_data.GetActions().GetPatientActions().GetMechanicalVentilation();
Aaron Bray's avatar
Aaron Bray committed
833
    // You only get here if action is On
834
    m_data.SetAirwayMode(eAirwayMode::MechanicalVentilation);
835 836

    //Set the substance volume fractions ********************************************
837
    std::vector<SESubstanceFraction*> gasFractions = mv.GetGasFractions();
838 839

    //Reset the substance quantities at the connection
840
    for (SEGasSubstanceQuantity* subQ : m_MechanicalVentilationConnection->GetSubstanceQuantities())
841 842 843 844
      subQ->SetToZero();

    //If no gas fractions specified, assume ambient
    if (gasFractions.empty())
Aaron Bray's avatar
Aaron Bray committed
845
    {
846 847
      for (auto s : m_Environment->GetSubstanceQuantities())
      {
848
        m_MechanicalVentilationConnection->GetSubstanceQuantity(s->GetSubstance())->GetVolumeFraction().Set(s->GetVolumeFraction());
849
      }
Aaron Bray's avatar
Aaron Bray committed
850
    }
851
    else
Aaron Bray's avatar
Aaron Bray committed
852
    {
853 854 855
      //Has fractions defined
      for (auto f : gasFractions)
      {
856
        const SESubstance& sub = f->GetSubstance();
857 858 859 860 861 862 863
        double fraction = f->GetFractionAmount().GetValue();

        //Do this, just in case it's something new
        m_data.GetSubstances().AddActiveSubstance(sub);

        //Now set it on the connection compartment
        //It has a NaN volume, so this will keep the same volume fraction no matter what's going on around it
864
        m_MechanicalVentilationConnection->GetSubstanceQuantity(sub)->GetVolumeFraction().SetValue(fraction);
865 866 867 868
      }
    }

    //Set the aerosol concentrations ********************************************
869
    std::vector<SESubstanceConcentration*> liquidConcentrations = mv.GetAerosols();
Aaron Bray's avatar
Aaron Bray committed
870

871
    //Reset the substance quantities at the connection
872
    for (SELiquidSubstanceQuantity* subQ : m_MechanicalVentilationAerosolConnection->GetSubstanceQuantities())
873
      subQ->SetToZero();
Aaron Bray's avatar
Aaron Bray committed
874

875 876 877 878 879
    if (!liquidConcentrations.empty())
    {
      //Has fractions defined
      for (auto f : liquidConcentrations)
      {
880
        const SESubstance& sub = f->GetSubstance();
881 882 883 884 885 886 887
        SEScalarMassPerVolume concentration = f->GetConcentration();

        //Do this, just in case it's something new
        m_data.GetSubstances().AddActiveSubstance(sub);

        //Now set it on the connection compartment
        //It has a NaN volume, so this will keep the same volume fraction no matter what's going on around it
888
        m_MechanicalVentilationAerosolConnection->GetSubstanceQuantity(sub)->GetConcentration().Set(concentration);
889
      }
Aaron Bray's avatar
Aaron Bray committed
890 891
    }

892
    //Apply the instantaneous flow ********************************************
893
    if (mv.HasFlow())
Aaron Bray's avatar
Aaron Bray committed
894
    {
895
      m_ConnectionToAirway->GetNextFlowSource().Set(mv.GetFlow());
896
      //It may or may not be there
Aaron Bray's avatar
Aaron Bray committed
897
      if (!m_ConnectionToAirway->HasFlowSource())
898
      {
899
        m_data.GetCircuits().GetRespiratoryAndMechanicalVentilationCircuit().StateChange();
900
      }
Aaron Bray's avatar
Aaron Bray committed
901
    }
902
    else
Aaron Bray's avatar
Aaron Bray committed
903
    {
904
      //If there's no flow specified, we need to remove the flow source    
Aaron Bray's avatar
Aaron Bray committed
905
      if (m_ConnectionToAirway->HasNextFlowSource())
906
      {
Aaron Bray's avatar
Aaron Bray committed
907
        m_ConnectionToAirway->GetNextFlowSource().Invalidate();
908
        m_data.GetCircuits().GetRespiratoryAndMechanicalVentilationCircuit().StateChange();
909 910 911 912
      }
    }

    //Apply the instantaneous pressure ********************************************  
913
    if (mv.HasPressure())
914 915
    {
      //This is the pressure above ambient
916
      m_GroundToConnection->GetNextPressureSource().Set(mv.GetPressure());
917 918 919 920 921
    }
    else
    {
      //Pressure is same as ambient
      m_GroundToConnection->GetNextPressureSource().SetValue(0.0, PressureUnit::cmH2O);
Aaron Bray's avatar
Aaron Bray committed
922 923
    }
  }
924
  else if (m_data.GetAirwayMode() == eAirwayMode::MechanicalVentilation)
Aaron Bray's avatar
Aaron Bray committed
925 926
  {
    // Was just turned off
927
    m_data.SetAirwayMode(eAirwayMode::Free);
Aaron Bray's avatar
Aaron Bray committed
928
    if (m_ConnectionToAirway->HasNextFlowSource())
929
    {
Aaron Bray's avatar
Aaron Bray committed
930
      m_ConnectionToAirway->