@@ -80,7 +80,6 @@ void Energy::Clear()
8080 m_SkinChloride = nullptr ;
8181 m_SkinPotassium = nullptr ;
8282 m_coreNode = nullptr ;
83- m_skinNode = nullptr ;
8483 m_temperatureGroundToCorePath = nullptr ;
8584 m_skinExtravascularToSweatingGroundPath = nullptr ;
8685 m_InternalTemperatureCircuit = nullptr ;
@@ -104,7 +103,8 @@ void Energy::Initialize()
104103 // Initialization of other system variables
105104 // / \cite herman2008physics
106105 GetCoreTemperature ().SetValue (37.0 , TemperatureUnit::C);
107- GetSkinTemperature ().SetValue (33.0 , TemperatureUnit::C);
106+ GetSkinTemperatureTorso ().SetValue (33.0 , TemperatureUnit::C);
107+ GetSkinTemperatureHead ().SetValue (33.0 , TemperatureUnit::C);
108108 // / \cite phypers2006lactate
109109 GetLactateProductionRate ().SetValue (1.3 , AmountPerTimeUnit::mol_Per_day);
110110 // / \cite guyton2006medical
@@ -182,7 +182,9 @@ void Energy::SetUp()
182182 m_InternalTemperatureCircuit = &m_data.GetCircuits ().GetInternalTemperatureCircuit ();
183183 // Nodes
184184 m_coreNode = m_InternalTemperatureCircuit->GetNode (BGE::InternalTemperatureNode::InternalCore);
185- m_skinNode = m_InternalTemperatureCircuit->GetNode (BGE::InternalTemperatureNode::InternalTorsoSkin); // NOTE this is currently used for vitals and sweat rate. First pass will use torso being the largest of the skin nodes
185+ m_skinNodes.clear ();
186+ m_skinNodes.push_back (m_InternalTemperatureCircuit->GetNode (BGE::InternalTemperatureNode::InternalTorsoSkin));
187+ m_skinNodes.push_back (m_InternalTemperatureCircuit->GetNode (BGE::InternalTemperatureNode::InternalHeadSkin));
186188 // Paths
187189 m_temperatureGroundToCorePath = m_InternalTemperatureCircuit->GetPath (BGE::InternalTemperaturePath::GroundToInternalCore);
188190 m_skinExtravascularToSweatingGroundPath = m_data.GetCircuits ().GetActiveCardiovascularCircuit ().GetPath (BGE::TissuePath::SkinSweating);
@@ -401,13 +403,15 @@ void Energy::PostProcess()
401403void Energy::CalculateVitalSigns ()
402404{
403405 double coreTemperature_degC = m_coreNode->GetTemperature (TemperatureUnit::C);
404- double skinTemperature_degC = m_skinNode->GetTemperature (TemperatureUnit::C);
406+ double skinTemperatureTorso_degC = m_skinNodes[0 ]->GetTemperature (TemperatureUnit::C);
407+ double skinTemperatureHead_degC = m_skinNodes[1 ]->GetTemperature (TemperatureUnit::C);
405408 if (m_data.GetDrugs ().HasFeverChange () && GetCoreTemperature ().GetValue (TemperatureUnit::C) > 37.0 ) { // Modifier for current drugs should not be able to increase core temperature
406409 coreTemperature_degC += m_data.GetDrugs ().GetFeverChange ().GetValue (TemperatureUnit::C);
407410 LLIM (coreTemperature_degC, 36.5 ); // Tylenol will not lower your basal core temperature
408411 }
409412 GetCoreTemperature ().SetValue (coreTemperature_degC, TemperatureUnit::C);
410- GetSkinTemperature ().SetValue (skinTemperature_degC, TemperatureUnit::C);
413+ GetSkinTemperatureTorso ().SetValue (skinTemperatureTorso_degC, TemperatureUnit::C);
414+ GetSkinTemperatureHead ().SetValue (skinTemperatureHead_degC, TemperatureUnit::C);
411415 std::stringstream ss;
412416
413417 // Hypothermia check
@@ -581,48 +585,51 @@ void Energy::CalculateSweatRate()
581585 double dWaterVaporPressureInAmbientAir_mmHg = GeneralMath::AntoineEquation (dAirTemperature_C);
582586 double m_dWaterVaporPressureInAmbientAir_Pa = Convert (dWaterVaporPressureInAmbientAir_mmHg, PressureUnit::mmHg, PressureUnit::Pa);
583587 // double ambientAtmosphericPressure_Pa = m_data.GetEnvironment().GetConditions().GetAtmosphericPressure().GetValue(PressureUnit::Pa);
584- double maximumEvaporativeCapacity_W = 14.21 * (m_Patient->GetSkinSurfaceArea ().GetValue (AreaUnit::m2)) * effectiveClothingEvaporation_im_Per_clo * (133.322 * (std::pow (10 , (8.1076 - (1750.286 / (235.0 + (m_skinNode->GetTemperature (TemperatureUnit::C))))))) - ((m_dWaterVaporPressureInAmbientAir_Pa))); // Still needs effective clothing evaporation
585-
586588 double vaporizationEnergy_J_Per_kg = m_data.GetConfiguration ().GetVaporizationEnergy (EnergyPerMassUnit::J_Per_kg);
587589 double sweatSodiumConcentration_mM = 51.0 ; // / \cite shirreffs1997whole
588590 double sweatPotassiumConcentration_mM = 6.0 ; // / \cite shirreffs1997whole
589591 double sweatChlorideConcentration_mM = 48.0 ; // / \cite shirreffs1997whole
590- // static double totalSweatLost_mL = 0; --Used to figure out total sweat loss during exercise scenario during debugging
591-
592- double currentEvaporativeCapacity_W = sweatHeatTranferCoefficient_W_Per_K * (m_skinNode->GetTemperature (TemperatureUnit::K));
593- if (currentEvaporativeCapacity_W > maximumEvaporativeCapacity_W) {
592+ // static double totalSweatLost_mL = 0; --Used to figure out total sweat loss during exercise scenario during debugging
594593
595- sweatHeatTranferCoefficient_W_Per_K = maximumEvaporativeCapacity_W / (m_skinNode->GetTemperature (TemperatureUnit::K));
596- }
597-
598- // / \todo Convert to sweat density once specific gravity calculation is in
594+ double overallSweatRate_kg_Per_s = 0.0 ;
599595 SEScalarMassPerVolume sweatDensity;
600- GeneralMath::CalculateWaterDensity (m_skinNode->GetTemperature (), sweatDensity);
601- double dehydrationFraction = m_data.GetTissue ().GetDehydrationFraction ().GetValue ();
596+ for (SEThermalCircuitNode* skinNode : m_skinNodes) {
597+ double maximumEvaporativeCapacity_W = 14.21 * (m_Patient->GetSkinSurfaceArea ().GetValue (AreaUnit::m2)) * effectiveClothingEvaporation_im_Per_clo * (133.322 * (std::pow (10 , (8.1076 - (1750.286 / (235.0 + (skinNode->GetTemperature (TemperatureUnit::C))))))) - ((m_dWaterVaporPressureInAmbientAir_Pa))); // Still needs effective clothing evaporation
598+ double currentEvaporativeCapacity_W = sweatHeatTranferCoefficient_W_Per_K * (skinNode->GetTemperature (TemperatureUnit::K));
599+ if (currentEvaporativeCapacity_W > maximumEvaporativeCapacity_W) {
602600
603- // Calculate sweat rate (in kg/s) from core temperature feedback.
604- // The sweat rate heat transfer is determined from a control equation that attempts to keep the core temperature in line
605- // / \cite herman2008physics
606- // Sweat rate decreases as dehydration becomes more severe, with max reduction seen at 10% dehydration
607- double dehydrationScalingFactor = GeneralMath::LinearInterpolator (0 , .1 , 1 , 0 , dehydrationFraction);
608- BLIM (dehydrationScalingFactor, 0 , 1 );
609- double sweatRate_kg_Per_s = dehydrationScalingFactor * (0.25 * sweatHeatTranferCoefficient_W_Per_K / vaporizationEnergy_J_Per_kg) * (coreTemperature_degC - coreTemperatureHigh_degC);
601+ sweatHeatTranferCoefficient_W_Per_K = maximumEvaporativeCapacity_W / (skinNode->GetTemperature (TemperatureUnit::K));
602+ }
610603
611- // The Sweat Scaling Factor is caused by changes in the Hyperhidrosis patient parameter to invoke either hyperhidrosis or hypohidrosis
612- // / \cite shih1983autonomic
613- double sweatScalingFactor = 0.0 ;
614- if (m_Patient->HasHyperhidrosis ()) {
615- sweatScalingFactor = m_Patient->GetHyperhidrosis ().GetValue ();
616- sweatRate_kg_Per_s = (1 + sweatScalingFactor) * sweatRate_kg_Per_s;
604+ double dehydrationFraction = m_data.GetTissue ().GetDehydrationFraction ().GetValue ();
605+
606+ // Calculate sweat rate (in kg/s) from core temperature feedback.
607+ // The sweat rate heat transfer is determined from a control equation that attempts to keep the core temperature in line
608+ // / \cite herman2008physics
609+ // Sweat rate decreases as dehydration becomes more severe, with max reduction seen at 10% dehydration
610+ double dehydrationScalingFactor = GeneralMath::LinearInterpolator (0 , .1 , 1 , 0 , dehydrationFraction);
611+ BLIM (dehydrationScalingFactor, 0 , 1 );
612+ double sweatRate_kg_Per_s = dehydrationScalingFactor * (0.25 * sweatHeatTranferCoefficient_W_Per_K / vaporizationEnergy_J_Per_kg) * (coreTemperature_degC - coreTemperatureHigh_degC);
613+
614+ // The Sweat Scaling Factor is caused by changes in the Hyperhidrosis patient parameter to invoke either hyperhidrosis or hypohidrosis
615+ // / \cite shih1983autonomic
616+ double sweatScalingFactor = 0.0 ;
617+ if (m_Patient->HasHyperhidrosis ()) {
618+ sweatScalingFactor = m_Patient->GetHyperhidrosis ().GetValue ();
619+ sweatRate_kg_Per_s = (1 + sweatScalingFactor) * sweatRate_kg_Per_s;
620+ }
621+ overallSweatRate_kg_Per_s += sweatRate_kg_Per_s;
617622 }
623+ // / \todo Convert to sweat density once specific gravity calculation is in
624+ GeneralMath::CalculateWaterDensity (m_skinNodes[0 ]->GetTemperature (), sweatDensity); // using trunk as representation due to it having the largest surface area. This will likely be vectorized out later
618625
619626 double maxSweatRate_kg_Per_s = 12.5 * m_Patient->GetSkinSurfaceArea ().GetValue (AreaUnit::m2) / 60.0 / 1000.0 ; // 10 - 15 g/min/m2
620- BLIM (sweatRate_kg_Per_s , 0.0 , maxSweatRate_kg_Per_s);
627+ BLIM (overallSweatRate_kg_Per_s , 0.0 , maxSweatRate_kg_Per_s);
621628
622629 // Account for mass lost by subtracting from the current patient mass
623- double massLost_kg = sweatRate_kg_Per_s * m_dT_s;
630+ double massLost_kg = overallSweatRate_kg_Per_s * m_dT_s;
624631 m_Patient->GetWeight ().IncrementValue (-massLost_kg, MassUnit::kg);
625- GetSweatRate ().SetValue (sweatRate_kg_Per_s , MassPerTimeUnit::kg_Per_s);
632+ GetSweatRate ().SetValue (overallSweatRate_kg_Per_s , MassPerTimeUnit::kg_Per_s);
626633
627634 // Calculate mass of ions lost in sweat (sodium, potassium, and chloride): Converts kg sweat lost -> L sweat lost -> mmol ion lost -> mg ion lost
628635 double sodiumLost_mg = massLost_kg / sweatDensity.GetValue (MassPerVolumeUnit::kg_Per_L) * sweatSodiumConcentration_mM * m_data.GetSubstances ().GetSodium ().GetMolarMass (MassPerAmountUnit::mg_Per_mmol);
@@ -641,7 +648,7 @@ void Energy::CalculateSweatRate()
641648 m_SkinChloride->Balance (BalanceLiquidBy::Mass);
642649
643650 // Set the flow source on the extravascular circuit to begin removing the fluid that is excreted
644- double sweatRate_mL_Per_s = sweatRate_kg_Per_s / sweatDensity.GetValue (MassPerVolumeUnit::kg_Per_mL);
651+ double sweatRate_mL_Per_s = overallSweatRate_kg_Per_s / sweatDensity.GetValue (MassPerVolumeUnit::kg_Per_mL);
645652 m_skinExtravascularToSweatingGroundPath->GetNextFlowSource ().SetValue (sweatRate_mL_Per_s, VolumePerTimeUnit::mL_Per_s );
646653}
647654
@@ -778,8 +785,10 @@ void Energy::ProcessOverride()
778785 if (override ->HasLactateProductionRateOverride ()) {
779786 GetLactateProductionRate ().SetValue (override ->GetLactateProductionRateOverride (AmountPerTimeUnit::mol_Per_s), AmountPerTimeUnit::mol_Per_s);
780787 }
788+ // All skin nodes currently adjusted for a skin temperature override
781789 if (override ->HasSkinTemperatureOverride ()) {
782- GetSkinTemperature ().SetValue (override ->GetSkinTemperatureOverride (TemperatureUnit::C), TemperatureUnit::C);
790+ GetSkinTemperatureTorso ().SetValue (override ->GetSkinTemperatureOverride (TemperatureUnit::C), TemperatureUnit::C);
791+ GetSkinTemperatureHead ().SetValue (override ->GetSkinTemperatureOverride (TemperatureUnit::C), TemperatureUnit::C);
783792 }
784793 if (override ->HasSweatRateOverride ()) {
785794 GetSweatRate ().SetValue (override ->GetSweatRateOverride (MassPerTimeUnit::g_Per_s), MassPerTimeUnit::g_Per_s);
0 commit comments