projects/biogears/src/engine/Systems/Tissue.cpp
void Tissue::AlveolarPartialPressureGradientDiffusion(SEGasCompartment& pulmonary, SELiquidCompartment& vascular, SESubstance& sub, double DiffusingCapacityO2_mL_Per_s_mmHg, double timestep_s)
{
  SEGasSubstanceQuantity* pSubQ = pulmonary.GetSubstanceQuantity(sub);
  SELiquidSubstanceQuantity* vSubQ = vascular.GetSubstanceQuantity(sub);
  if (pSubQ == nullptr || vSubQ == nullptr)
    throw CommonDataModelException("No Substance Quantity found for substance " + sub.GetName());

  double PressureGradient_mmHg = pSubQ->GetPartialPressure(PressureUnit::mmHg) - vSubQ->GetPartialPressure(PressureUnit::mmHg);

  double DiffusedVolume_mL = PressureGradient_mmHg * DiffusingCapacityO2_mL_Per_s_mmHg * sub.GetRelativeDiffusionCoefficient().GetValue() * timestep_s;

  //Get special diffused volume if sub is CO
  if (PressureGradient_mmHg > 0 && &sub == m_CO) // Wants to come into the blood
  {
    DiffusedVolume_mL = PressureGradient_mmHg * DiffusingCapacityO2_mL_Per_s_mmHg * sub.GetRelativeDiffusionCoefficient().GetValue() * (1 / (5.404e-05 * vascular.GetSubstanceQuantity(*m_O2)->GetPartialPressure(PressureUnit::mmHg) + 0.02885)) * timestep_s; //Modify the relative diffusion coefficient
  }
  double DiffusedMass_ug = DiffusedVolume_mL * sub.GetDensity(MassPerVolumeUnit::ug_Per_mL);

  //Check to make sure we're not moving more than exists
  if (DiffusedVolume_mL > 0) {
    //It's moving from pulmonary to vascular
    double pVolume_mL = pSubQ->GetVolume(VolumeUnit::mL);
    if (DiffusedVolume_mL > pVolume_mL) {
      //Move all we can
      DiffusedVolume_mL = pVolume_mL;
      DiffusedMass_ug = DiffusedVolume_mL * sub.GetDensity(MassPerVolumeUnit::ug_Per_mL);
    }
  } else {
    //It's moving from vascular to pulmonary
    double vMass_ug = vSubQ->GetMass(MassUnit::ug);
    if (-DiffusedMass_ug > vMass_ug) {
      //Move all we can
      DiffusedMass_ug = -vMass_ug;
      DiffusedVolume_mL = DiffusedMass_ug / sub.GetDensity(MassPerVolumeUnit::ug_Per_mL);
    }
  }

  pSubQ->GetVolume().IncrementValue(-DiffusedVolume_mL, VolumeUnit::mL);
  sub.GetAlveolarTransfer().IncrementValue(DiffusedVolume_mL / timestep_s, VolumePerTimeUnit::mL_Per_s);
  sub.GetDiffusingCapacity().IncrementValue(DiffusingCapacityO2_mL_Per_s_mmHg * sub.GetRelativeDiffusionCoefficient().GetValue(), VolumePerTimePressureUnit::mL_Per_s_mmHg);

  vSubQ->GetMass().IncrementValue(DiffusedMass_ug, MassUnit::ug);
  if (std::abs(vSubQ->GetMass(MassUnit::ug)) < ZERO_APPROX) {
    vSubQ->GetMass().SetValue(0.0, MassUnit::ug);
  }
  vSubQ->Balance(BalanceLiquidBy::Mass);
}
//--------------------------------------------------------------------------------------------------
/// \brief
/// Calculates the mass transfer due to a partial pressure gradient
///
/// \param  Source pulmonary compartment for the mass transfer.
/// \param  Target vascular compartment for the mass transfer.
/// \param  sub Substance being transferred.
/// \param  DiffusingCapacityO2_mL_Per_s_mmHg the current diffusion capacity of oxygen for this alveolar exchange region.
/// \param  timestep Time step of the engine.
///
/// \details
/// Calculates the mass transfer from a pulmonary compartment/fluid to a vascular compartment/fluid
/// based on the partial pressure gradient of the gas in the two compartments/fluids.
///
/// We cannot balance gas compartment substance quantities on a per substance basis like we can a liquid
/// When the gas substance volume changes, the compartment volume changes as well,
/// which would then change the volume fraction for ALL the substances in the compartment.
/// So it is up to the end user to call balance on the compartment when they are done updating substances on it.
/// It would be inefficient to balance the compartment in this method, as this diffusion could be in a loop over all
/// active substances, and we would be looping over all substance repeatedly.
/// The alveolar exchange of any gas is computed from diffusion capacities relative to oxygen.
//--------------------------------------------------------------------------------------------------
\brief
Calculates the mass transfer due to a partial pressure gradient

\param  Source pulmonary compartment for the mass transfer.
\param  Target vascular compartment for the mass transfer.
\param  sub Substance being transferred.
\param  DiffusingCapacityO2_mL_Per_s_mmHg the current diffusion capacity of oxygen for this alveolar exchange region.
\param  timestep Time step of the engine.

\details
Calculates the mass transfer from a pulmonary compartment/fluid to a vascular compartment/fluid
based on the partial pressure gradient of the gas in the two compartments/fluids.

We cannot balance gas compartment substance quantities on a per substance basis like we can a liquid
When the gas substance volume changes, the compartment volume changes as well,
which would then change the volume fraction for ALL the substances in the compartment.
So it is up to the end user to call balance on the compartment when they are done updating substances on it.
It would be inefficient to balance the compartment in this method, as this diffusion could be in a loop over all
active substances, and we would be looping over all substance repeatedly.
The alveolar exchange of any gas is computed from diffusion capacities relative to oxygen.
\ brief Calculates the mass transfer due to a partial pressure gradient \ param Source pulmonary compartment for the mass transfer . \ param Target vascular compartment for the mass transfer . \ param sub Substance being transferred . \ param DiffusingCapacityO2_mL_Per_s_mmHg the current diffusion capacity of oxygen for this alveolar exchange region . \ param timestep Time step of the engine . \ details Calculates the mass transfer from a pulmonary compartment / fluid to a vascular compartment / fluid based on the partial pressure gradient of the gas in the two compartments / fluids . We cannot balance gas compartment substance quantities on a per substance basis like we can a liquid When the gas substance volume changes the compartment volume changes as well which would then change the volume fraction for ALL the substances in the compartment . So it is up to the end user to call balance on the compartment when they are done updating substances on it . It would be inefficient to balance the compartment in this method as this diffusion could be in a loop over all active substances and we would be looping over all substance repeatedly . The alveolar exchange of any gas is computed from diffusion capacities relative to oxygen .
void Tissue::AlveolarPartialPressureGradientDiffusion(SEGasCompartment& pulmonary, SELiquidCompartment& vascular, SESubstance& sub, double DiffusingCapacityO2_mL_Per_s_mmHg, double timestep_s)
{
  SEGasSubstanceQuantity* pSubQ = pulmonary.GetSubstanceQuantity(sub);
  SELiquidSubstanceQuantity* vSubQ = vascular.GetSubstanceQuantity(sub);
  if (pSubQ == nullptr || vSubQ == nullptr)
    throw CommonDataModelException("No Substance Quantity found for substance " + sub.GetName());
  double PressureGradient_mmHg = pSubQ->GetPartialPressure(PressureUnit::mmHg) - vSubQ->GetPartialPressure(PressureUnit::mmHg);
  double DiffusedVolume_mL = PressureGradient_mmHg * DiffusingCapacityO2_mL_Per_s_mmHg * sub.GetRelativeDiffusionCoefficient().GetValue() * timestep_s;
  if (PressureGradient_mmHg > 0 && &sub == m_CO) 
  {
    DiffusedVolume_mL = PressureGradient_mmHg * DiffusingCapacityO2_mL_Per_s_mmHg * sub.GetRelativeDiffusionCoefficient().GetValue() * (1 / (5.404e-05 * vascular.GetSubstanceQuantity(*m_O2)->GetPartialPressure(PressureUnit::mmHg) + 0.02885)) * timestep_s; 
  }
  double DiffusedMass_ug = DiffusedVolume_mL * sub.GetDensity(MassPerVolumeUnit::ug_Per_mL);
  if (DiffusedVolume_mL > 0) {
    double pVolume_mL = pSubQ->GetVolume(VolumeUnit::mL);
    if (DiffusedVolume_mL > pVolume_mL) {
      DiffusedVolume_mL = pVolume_mL;
      DiffusedMass_ug = DiffusedVolume_mL * sub.GetDensity(MassPerVolumeUnit::ug_Per_mL);
    }
  } else {
    double vMass_ug = vSubQ->GetMass(MassUnit::ug);
    if (-DiffusedMass_ug > vMass_ug) {
      DiffusedMass_ug = -vMass_ug;
      DiffusedVolume_mL = DiffusedMass_ug / sub.GetDensity(MassPerVolumeUnit::ug_Per_mL);
    }
  }
  pSubQ->GetVolume().IncrementValue(-DiffusedVolume_mL, VolumeUnit::mL);
  sub.GetAlveolarTransfer().IncrementValue(DiffusedVolume_mL / timestep_s, VolumePerTimeUnit::mL_Per_s);
  sub.GetDiffusingCapacity().IncrementValue(DiffusingCapacityO2_mL_Per_s_mmHg * sub.GetRelativeDiffusionCoefficient().GetValue(), VolumePerTimePressureUnit::mL_Per_s_mmHg);
  vSubQ->GetMass().IncrementValue(DiffusedMass_ug, MassUnit::ug);
  if (std::abs(vSubQ->GetMass(MassUnit::ug)) < ZERO_APPROX) {
    vSubQ->GetMass().SetValue(0.0, MassUnit::ug);
  }
  vSubQ->Balance(BalanceLiquidBy::Mass);
}
void Tissue :: AlveolarPartialPressureGradientDiffusion ( SEGasCompartment & pulmonary , SELiquidCompartment & vascular , SESubstance & sub , double DiffusingCapacityO2_mL_Per_s_mmHg , double timestep_s ) { SEGasSubstanceQuantity * pSubQ = pulmonary . GetSubstanceQuantity ( sub ) ; SELiquidSubstanceQuantity * vSubQ = vascular . GetSubstanceQuantity ( sub ) ; if ( pSubQ == nullptr || vSubQ == nullptr ) throw CommonDataModelException ( " " + sub . GetName ( ) ) ; double PressureGradient_mmHg = pSubQ -> GetPartialPressure ( PressureUnit :: mmHg ) - vSubQ -> GetPartialPressure ( PressureUnit :: mmHg ) ; double DiffusedVolume_mL = PressureGradient_mmHg * DiffusingCapacityO2_mL_Per_s_mmHg * sub . GetRelativeDiffusionCoefficient ( ) . GetValue ( ) * timestep_s ; if ( PressureGradient_mmHg > 0 && & sub == m_CO ) { DiffusedVolume_mL = PressureGradient_mmHg * DiffusingCapacityO2_mL_Per_s_mmHg * sub . GetRelativeDiffusionCoefficient ( ) . GetValue ( ) * ( 1 / ( 5.404e-05 * vascular . GetSubstanceQuantity ( * m_O2 ) -> GetPartialPressure ( PressureUnit :: mmHg ) + 0.02885 ) ) * timestep_s ; } double DiffusedMass_ug = DiffusedVolume_mL * sub . GetDensity ( MassPerVolumeUnit :: ug_Per_mL ) ; if ( DiffusedVolume_mL > 0 ) { double pVolume_mL = pSubQ -> GetVolume ( VolumeUnit :: mL ) ; if ( DiffusedVolume_mL > pVolume_mL ) { DiffusedVolume_mL = pVolume_mL ; DiffusedMass_ug = DiffusedVolume_mL * sub . GetDensity ( MassPerVolumeUnit :: ug_Per_mL ) ; } } else { double vMass_ug = vSubQ -> GetMass ( MassUnit :: ug ) ; if ( - DiffusedMass_ug > vMass_ug ) { DiffusedMass_ug = - vMass_ug ; DiffusedVolume_mL = DiffusedMass_ug / sub . GetDensity ( MassPerVolumeUnit :: ug_Per_mL ) ; } } pSubQ -> GetVolume ( ) . IncrementValue ( - DiffusedVolume_mL , VolumeUnit :: mL ) ; sub . GetAlveolarTransfer ( ) . IncrementValue ( DiffusedVolume_mL / timestep_s , VolumePerTimeUnit :: mL_Per_s ) ; sub . GetDiffusingCapacity ( ) . IncrementValue ( DiffusingCapacityO2_mL_Per_s_mmHg * sub . GetRelativeDiffusionCoefficient ( ) . GetValue ( ) , VolumePerTimePressureUnit :: mL_Per_s_mmHg ) ; vSubQ -> GetMass ( ) . IncrementValue ( DiffusedMass_ug , MassUnit :: ug ) ; if ( std :: abs ( vSubQ -> GetMass ( MassUnit :: ug ) ) < ZERO_APPROX ) { vSubQ -> GetMass ( ) . SetValue ( 0.0 , MassUnit :: ug ) ; } vSubQ -> Balance ( BalanceLiquidBy :: Mass ) ; }
\brief
Calculates the mass transfer due to a partial pressure gradient
\ brief Calculates the mass transfer due to a partial pressure gradient
//Get special diffused volume if sub is CO // Wants to come into the blood //Modify the relative diffusion coefficient //Check to make sure we're not moving more than exists //It's moving from pulmonary to vascular //Move all we can //It's moving from vascular to pulmonary //Move all we can