diff --git a/src/Tarcog/src/IGU.cpp b/src/Tarcog/src/IGU.cpp index f9b9f342..6f493060 100644 --- a/src/Tarcog/src/IGU.cpp +++ b/src/Tarcog/src/IGU.cpp @@ -534,8 +534,22 @@ namespace Tarcog } if(std::dynamic_pointer_cast(t_Layer) != nullptr) { + auto gap = std::dynamic_pointer_cast(t_Layer); if(std::dynamic_pointer_cast(t_Layer->getPreviousLayer()) != nullptr) + { + auto newLayer = std::make_shared(gap); + replaceLayer(std::dynamic_pointer_cast(t_Layer), newLayer); + } + else if(gap->isVentilationForced() + && std::dynamic_pointer_cast(t_Layer->getPreviousLayer()) + != nullptr + && std::dynamic_pointer_cast(t_Layer->getPreviousLayer()) + == nullptr + && std::dynamic_pointer_cast(t_Layer->getNextLayer()) + != nullptr + && std::dynamic_pointer_cast(t_Layer->getNextLayer()) + == nullptr) { auto newLayer = std::make_shared( std::dynamic_pointer_cast(t_Layer)); diff --git a/src/Tarcog/src/IGUVentilatedGapLayer.cpp b/src/Tarcog/src/IGUVentilatedGapLayer.cpp index 0b9b7b1b..1b94889c 100644 --- a/src/Tarcog/src/IGUVentilatedGapLayer.cpp +++ b/src/Tarcog/src/IGUVentilatedGapLayer.cpp @@ -3,9 +3,13 @@ #include #include +#include "BaseShade.hpp" +#include "TarcogConstants.hpp" #include "IGUVentilatedGapLayer.hpp" #include "WCEGases.hpp" +#include "WCECommon.hpp" +using FenestrationCommon::Side; namespace Tarcog { @@ -155,10 +159,79 @@ namespace Tarcog CIGUGapLayer::calculateConvectionOrConductionFlow(); if(!isCalculated()) { + if(isVentilationForced() && m_NextLayer != nullptr && m_PreviousLayer != nullptr + && std::dynamic_pointer_cast(m_PreviousLayer) != nullptr + && std::dynamic_pointer_cast(m_PreviousLayer) == nullptr + && std::dynamic_pointer_cast(m_NextLayer) != nullptr + && std::dynamic_pointer_cast(m_NextLayer) == nullptr) + { + auto previousSolidLayer = + std::dynamic_pointer_cast(m_PreviousLayer); + auto nextSolidLayer = std::dynamic_pointer_cast(m_NextLayer); + calcSealedForcedVentilationGapTemperatures(previousSolidLayer, nextSolidLayer); + } ventilatedFlow(); } } + void CIGUVentilatedGapLayer::calcSealedForcedVentilationGapTemperatures( + std::shared_ptr t_PreviousLayer, + std::shared_ptr t_NextLayer) + { + // Inspired by `CIGUShadeLayer::calcEdgeShadeFlow` + double TgapOut = layerTemperature(); + double RelaxationParameter = IterationConstants::RELAXATION_PARAMETER_AIRFLOW; + bool converged = false; + size_t iterationStep = 0; + + double tempGap = layerTemperature(); + ForcedVentilation forcedVentilation = getForcedVentilation(); + setFlowSpeed(forcedVentilation.Speed); + // m_AirSpeed = forcedVentilation.Speed; + double tempPreviousLayer = t_PreviousLayer->getTemperature(Side::Back); + while(!converged) + { + double TavGap = averageTemperature(); + // TODO Calling `betaCoeff` results in an infinite recursion + // because it calls `calculateLayerHeatFlow`. I do not believe + // that the latter call is required because we set `m_AirSpeed` + // above. Are all other properties also set? What about + // `m_ConductiveConvectiveCoeff`? + // TODO If `beta` and `TavGap` do not change during the + // loop, then extract them. + double beta = exp(-m_Height / characteristicHeight()); + double alpha = 1 - beta; + + double TgapOutOld = TgapOut; + + TgapOut = alpha * TavGap + beta * tempPreviousLayer; + + setFlowTemperatures(tempPreviousLayer, TgapOut); + // m_inTemperature = tempPreviousLayer; + // m_outTemperature = TgapOut; + + tempGap = layerTemperature(); + + TgapOut = RelaxationParameter * tempGap + (1 - RelaxationParameter) * TgapOutOld; + + converged = std::abs(TgapOut - TgapOutOld) + < IterationConstants::CONVERGENCE_TOLERANCE_AIRFLOW; + + ++iterationStep; + if(iterationStep > IterationConstants::NUMBER_OF_STEPS) + { + RelaxationParameter -= IterationConstants::RELAXATION_PARAMETER_AIRFLOW_STEP; + iterationStep = 0; + if(RelaxationParameter == IterationConstants::RELAXATION_PARAMETER_AIRFLOW_MIN) + { + converged = true; + throw std::runtime_error("Airflow iterations fail to converge. " + "Maximum number of iteration steps reached."); + } + } + } + } + double CIGUVentilatedGapLayer::characteristicHeight() { const auto aProperties = m_Gas.getGasProperties(); diff --git a/src/Tarcog/src/IGUVentilatedGapLayer.hpp b/src/Tarcog/src/IGUVentilatedGapLayer.hpp index 0d5bd87a..6f539224 100644 --- a/src/Tarcog/src/IGUVentilatedGapLayer.hpp +++ b/src/Tarcog/src/IGUVentilatedGapLayer.hpp @@ -3,6 +3,7 @@ #include +#include "BaseShade.hpp" #include "WCEGases.hpp" #include "IGUGapLayer.hpp" @@ -41,6 +42,9 @@ namespace Tarcog double characteristicHeight(); double calcImpedance(double t_A) const; void ventilatedFlow(); + void calcSealedForcedVentilationGapTemperatures( + std::shared_ptr t_PreviousLayer, + std::shared_ptr t_NextLayer); std::shared_ptr m_Layer; Gases::CGas m_ReferenceGas; diff --git a/src/Tarcog/tst/units/GapLayerSealedForcedVentilation.unit.cpp b/src/Tarcog/tst/units/GapLayerSealedForcedVentilation.unit.cpp new file mode 100644 index 00000000..fdb5fc7f --- /dev/null +++ b/src/Tarcog/tst/units/GapLayerSealedForcedVentilation.unit.cpp @@ -0,0 +1,164 @@ +#include +#include + +#include "WCETarcog.hpp" + +class TestGapLayerSealedForcedVentilation : public testing::Test +{ +private: + std::shared_ptr m_TarcogSystem; + +protected: + void SetUp() override + { + ///////////////////////////////////////////////////////// + // Outdoor + ///////////////////////////////////////////////////////// + auto airTemperature = 255.15; // Kelvins + auto airSpeed = 5.5; // meters per second + auto tSky = 255.15; // Kelvins + auto solarRadiation = 0.0; + + auto Outdoor = Tarcog::ISO15099::Environments::outdoor( + airTemperature, airSpeed, solarRadiation, tSky, Tarcog::ISO15099::SkyModel::AllSpecified); + ASSERT_TRUE(Outdoor != nullptr); + Outdoor->setHCoeffModel(Tarcog::ISO15099::BoundaryConditionsCoeffModel::CalculateH); + + ///////////////////////////////////////////////////////// + /// Indoor + ///////////////////////////////////////////////////////// + + auto roomTemperature = 295.15; + + auto Indoor = Tarcog::ISO15099::Environments::indoor(roomTemperature); + ASSERT_TRUE(Indoor != nullptr); + + // IGU + auto solidLayerThickness = 0.005715; // [m] + auto solidLayerConductance = 1.0; + + auto solidLayer1 = + Tarcog::ISO15099::Layers::solid(solidLayerThickness, solidLayerConductance); + ASSERT_TRUE(solidLayer1 != nullptr); + + auto solidLayer2 = + Tarcog::ISO15099::Layers::solid(solidLayerThickness, solidLayerConductance); + ASSERT_TRUE(solidLayer2 != nullptr); + + auto gapThickness = 0.0127; + auto gapAirSpeed = 0.5; + Tarcog::ISO15099::ForcedVentilation forcedVentilation = {gapAirSpeed}; + auto gap = Tarcog::ISO15099::Layers::forcedVentilationGap(gapThickness, forcedVentilation); + ASSERT_TRUE(gap != nullptr); + + double windowWidth = 1; + double windowHeight = 1; + Tarcog::ISO15099::CIGU aIGU(windowWidth, windowHeight); + aIGU.addLayers({solidLayer1, gap, solidLayer2}); + + ///////////////////////////////////////////////////////// + /// System + ///////////////////////////////////////////////////////// + m_TarcogSystem = std::make_shared(aIGU, Indoor, Outdoor); + ASSERT_TRUE(m_TarcogSystem != nullptr); + + m_TarcogSystem->solve(); + } + +public: + std::shared_ptr GetSolidLayer1() const + { + auto solidLayer = m_TarcogSystem->getSolidLayers()[0]; + assert(std::dynamic_pointer_cast(solidLayer) != nullptr); + return std::dynamic_pointer_cast(solidLayer); + }; + + std::shared_ptr GetGap() const + { + auto gap = m_TarcogSystem->getGapLayers()[0]; + assert(std::dynamic_pointer_cast(gap) != nullptr); + return std::dynamic_pointer_cast(gap); + }; + + std::shared_ptr GetSolidLayer2() const + { + auto solidLayer = m_TarcogSystem->getSolidLayers()[1]; + assert(std::dynamic_pointer_cast(solidLayer) != nullptr); + return std::dynamic_pointer_cast(solidLayer); + }; +}; + +TEST_F(TestGapLayerSealedForcedVentilation, GainEnergy) +{ + SCOPED_TRACE("Begin Test: Test Ventilated Gap Layer - Gain Energy"); + + auto aLayer = GetGap(); + + // Airflow iterations are set to 1e-4 and it cannot exceed that precision + + ASSERT_TRUE(aLayer != nullptr); + auto gainEnergy = aLayer->getGainFlow(); + EXPECT_NEAR(-57.193291279467125, gainEnergy, 1e-4); +} + +TEST_F(TestGapLayerSealedForcedVentilation, Solid1Temperatures) +{ + SCOPED_TRACE("Begin Test: Test Ventilated Gap Layer - Solid 1 Temperatures"); + + auto aLayer = GetSolidLayer1(); + + // Airflow iterations are set to 1e-4 and it cannot exceed that precision + + ASSERT_TRUE(aLayer != nullptr); + auto frontTemperature = aLayer->getTemperature(FenestrationCommon::Side::Front); + auto backTemperature = aLayer->getTemperature(FenestrationCommon::Side::Back); + EXPECT_NEAR(257.88610911376719, frontTemperature, 1e-4); + EXPECT_NEAR(258.34294987245784, backTemperature, 1e-4); +} + +TEST_F(TestGapLayerSealedForcedVentilation, GapTemperatures) +{ + SCOPED_TRACE("Begin Test: Test Ventilated Gap Layer - Gap Temperatures"); + + auto aLayer = GetGap(); + + // Airflow iterations are set to 1e-4 and it cannot exceed that precision + + ASSERT_TRUE(aLayer != nullptr); + auto frontTemperature = aLayer->getTemperature(FenestrationCommon::Side::Front); + auto backTemperature = aLayer->getTemperature(FenestrationCommon::Side::Back); + auto layerTemperature = aLayer->layerTemperature(); + auto averageTemperature = aLayer->averageTemperature(); + EXPECT_NEAR(258.34294987245784, frontTemperature, 1e-4); + EXPECT_NEAR(276.01222466583204, backTemperature, 1e-4); + EXPECT_NEAR(262.42249308270669, layerTemperature, 1e-4); + EXPECT_NEAR(267.17758726914496, averageTemperature, 1e-4); +} + +TEST_F(TestGapLayerSealedForcedVentilation, Solid2Temperatures) +{ + SCOPED_TRACE("Begin Test: Test Ventilated Gap Layer - Solid 2 Temperatures"); + + auto aLayer = GetSolidLayer2(); + + // Airflow iterations are set to 1e-4 and it cannot exceed that precision + + ASSERT_TRUE(aLayer != nullptr); + auto frontTemperature = aLayer->getTemperature(FenestrationCommon::Side::Front); + auto backTemperature = aLayer->getTemperature(FenestrationCommon::Side::Back); + EXPECT_NEAR(276.01222466583204, frontTemperature, 1e-4); + EXPECT_NEAR(276.79592508330529, backTemperature, 1e-4); +} + +TEST_F(TestGapLayerSealedForcedVentilation, AirflowReferencePoint) +{ + SCOPED_TRACE("Begin Test: Test Ventilated Gap Layer - Airflow Reference Point"); + + auto aLayer = GetGap(); + + // Airflow iterations are set to 1e-4 and it cannot exceed that precision + + ASSERT_TRUE(aLayer != nullptr); + auto airflowReferencePoint = aLayer->getAirflowReferencePoint(0.5); + EXPECT_NEAR(6911.4449859804226, airflowReferencePoint, 1e-4); +} diff --git a/src/Tarcog/tst/units/GapLayerSealedForcedVentilationNarrow.unit.cpp b/src/Tarcog/tst/units/GapLayerSealedForcedVentilationNarrow.unit.cpp new file mode 100644 index 00000000..c2095601 --- /dev/null +++ b/src/Tarcog/tst/units/GapLayerSealedForcedVentilationNarrow.unit.cpp @@ -0,0 +1,164 @@ +#include +#include + +#include "WCETarcog.hpp" + +class TestGapLayerSealedForcedVentilationNarrow : public testing::Test +{ +private: + std::shared_ptr m_TarcogSystem; + +protected: + void SetUp() override + { + ///////////////////////////////////////////////////////// + // Outdoor + ///////////////////////////////////////////////////////// + auto airTemperature = 255.15; // Kelvins + auto airSpeed = 5.5; // meters per second + auto tSky = 255.15; // Kelvins + auto solarRadiation = 0.0; + + auto Outdoor = Tarcog::ISO15099::Environments::outdoor( + airTemperature, airSpeed, solarRadiation, tSky, Tarcog::ISO15099::SkyModel::AllSpecified); + ASSERT_TRUE(Outdoor != nullptr); + Outdoor->setHCoeffModel(Tarcog::ISO15099::BoundaryConditionsCoeffModel::CalculateH); + + ///////////////////////////////////////////////////////// + /// Indoor + ///////////////////////////////////////////////////////// + + auto roomTemperature = 295.15; + + auto Indoor = Tarcog::ISO15099::Environments::indoor(roomTemperature); + ASSERT_TRUE(Indoor != nullptr); + + // IGU + auto solidLayerThickness = 0.005715; // [m] + auto solidLayerConductance = 1.0; + + auto solidLayer1 = + Tarcog::ISO15099::Layers::solid(solidLayerThickness, solidLayerConductance); + ASSERT_TRUE(solidLayer1 != nullptr); + + auto solidLayer2 = + Tarcog::ISO15099::Layers::solid(solidLayerThickness, solidLayerConductance); + ASSERT_TRUE(solidLayer2 != nullptr); + + auto gapThickness = 0.00001; + auto gapAirSpeed = 0.5; + Tarcog::ISO15099::ForcedVentilation forcedVentilation = {gapAirSpeed}; + auto gap = Tarcog::ISO15099::Layers::forcedVentilationGap(gapThickness, forcedVentilation); + ASSERT_TRUE(gap != nullptr); + + double windowWidth = 1; + double windowHeight = 1; + Tarcog::ISO15099::CIGU aIGU(windowWidth, windowHeight); + aIGU.addLayers({solidLayer1, gap, solidLayer2}); + + ///////////////////////////////////////////////////////// + /// System + ///////////////////////////////////////////////////////// + m_TarcogSystem = std::make_shared(aIGU, Indoor, Outdoor); + ASSERT_TRUE(m_TarcogSystem != nullptr); + + m_TarcogSystem->solve(); + } + +public: + std::shared_ptr GetSolidLayer1() const + { + auto solidLayer = m_TarcogSystem->getSolidLayers()[0]; + assert(std::dynamic_pointer_cast(solidLayer) != nullptr); + return std::dynamic_pointer_cast(solidLayer); + }; + + std::shared_ptr GetGap() const + { + auto gap = m_TarcogSystem->getGapLayers()[0]; + assert(std::dynamic_pointer_cast(gap) != nullptr); + return std::dynamic_pointer_cast(gap); + }; + + std::shared_ptr GetSolidLayer2() const + { + auto solidLayer = m_TarcogSystem->getSolidLayers()[1]; + assert(std::dynamic_pointer_cast(solidLayer) != nullptr); + return std::dynamic_pointer_cast(solidLayer); + }; +}; + +TEST_F(TestGapLayerSealedForcedVentilationNarrow, GainEnergy) +{ + SCOPED_TRACE("Begin Test: Test Ventilated Gap Layer - Gain Energy"); + + auto aLayer = GetGap(); + + // Airflow iterations are set to 1e-4 and it cannot exceed that precision + + ASSERT_TRUE(aLayer != nullptr); + auto gainEnergy = aLayer->getGainFlow(); + EXPECT_NEAR(-0.00032377683741991229, gainEnergy, 1e-4); +} + +TEST_F(TestGapLayerSealedForcedVentilationNarrow, Solid1Temperatures) +{ + SCOPED_TRACE("Begin Test: Test Ventilated Gap Layer - Solid 1 Temperatures"); + + auto aLayer = GetSolidLayer1(); + + // Airflow iterations are set to 1e-4 and it cannot exceed that precision + + ASSERT_TRUE(aLayer != nullptr); + auto frontTemperature = aLayer->getTemperature(FenestrationCommon::Side::Front); + auto backTemperature = aLayer->getTemperature(FenestrationCommon::Side::Back); + EXPECT_NEAR(262.8455712342456, frontTemperature, 1e-4); + EXPECT_NEAR(264.13464915091032, backTemperature, 1e-4); +} + +TEST_F(TestGapLayerSealedForcedVentilationNarrow, GapTemperatures) +{ + SCOPED_TRACE("Begin Test: Test Ventilated Gap Layer - Gap Temperatures"); + + auto aLayer = GetGap(); + + // Airflow iterations are set to 1e-4 and it cannot exceed that precision + + ASSERT_TRUE(aLayer != nullptr); + auto frontTemperature = aLayer->getTemperature(FenestrationCommon::Side::Front); + auto backTemperature = aLayer->getTemperature(FenestrationCommon::Side::Back); + auto layerTemperature = aLayer->layerTemperature(); + auto averageTemperature = aLayer->averageTemperature(); + EXPECT_NEAR(264.13464915091032, frontTemperature, 1e-4); + EXPECT_NEAR(264.23102533430392, backTemperature, 1e-4); + EXPECT_NEAR(264.18283724260709, layerTemperature, 1e-4); + EXPECT_NEAR(264.18283724260709, averageTemperature, 1e-4); +} + +TEST_F(TestGapLayerSealedForcedVentilationNarrow, Solid2Temperatures) +{ + SCOPED_TRACE("Begin Test: Test Ventilated Gap Layer - Solid 2 Temperatures"); + + auto aLayer = GetSolidLayer2(); + + // Airflow iterations are set to 1e-4 and it cannot exceed that precision + + ASSERT_TRUE(aLayer != nullptr); + auto frontTemperature = aLayer->getTemperature(FenestrationCommon::Side::Front); + auto backTemperature = aLayer->getTemperature(FenestrationCommon::Side::Back); + EXPECT_NEAR(264.23102533430392, frontTemperature, 1e-4); + EXPECT_NEAR(265.52010325096921, backTemperature, 1e-4); +} + +TEST_F(TestGapLayerSealedForcedVentilationNarrow, AirflowReferencePoint) +{ + SCOPED_TRACE("Begin Test: Test Ventilated Gap Layer - Airflow Reference Point"); + + auto aLayer = GetGap(); + + // Airflow iterations are set to 1e-4 and it cannot exceed that precision + + ASSERT_TRUE(aLayer != nullptr); + auto airflowReferencePoint = aLayer->getAirflowReferencePoint(0.5); + EXPECT_NEAR(6911.5329001843065, airflowReferencePoint, 1e-4); +}