From 0b2affaee84d756ad3531241ed28ebfac25c398c Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Thu, 20 Jun 2024 01:08:22 +0200 Subject: [PATCH 1/4] Add a test for #10574 --- tst/EnergyPlus/unit/WaterThermalTanks.unit.cc | 262 ++++++++++++++++++ 1 file changed, 262 insertions(+) diff --git a/tst/EnergyPlus/unit/WaterThermalTanks.unit.cc b/tst/EnergyPlus/unit/WaterThermalTanks.unit.cc index ff99c1ca594..9b135c20092 100644 --- a/tst/EnergyPlus/unit/WaterThermalTanks.unit.cc +++ b/tst/EnergyPlus/unit/WaterThermalTanks.unit.cc @@ -56,16 +56,22 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include +#include +#include #include #include #include +#include +#include #include #include #include @@ -5427,3 +5433,259 @@ TEST_F(EnergyPlusFixture, setBackupElementCapacityTest) expectedAnswer = -456.0; EXPECT_NEAR(DSup.BackupElementCapacity, expectedAnswer, allowedTolerance); } + +TEST_F(EnergyPlusFixture, MixedTank_PVT_Per_VolumeSizing_PerSolarCollectorArea) +{ + + std::string const idf_objects = delimited_string({ + + "Schedule:Constant, Sch 80C, , 80.0;", + "Schedule:Constant, Sch 55C, , 55.0;", + "Schedule:Constant, Always 1, , 1.0;", + + "Zone,", + " Zone1, !- Name", + " 0 , !- Direction of Relative North {deg}", + " 0, !- X Origin {m}", + " 0, !- Y Origin {m}", + " 0, !- Z Origin {m}", + " 1, !- Type", + " 1, !- Multiplier", + " , !- Ceiling Height {m}", + " 300, !- Volume {m3}", + " 100, !- Floor Area {m2}", + " TARP, !- Zone Inside Convection Algorithm", + " , !- Zone Outside Convection Algorithm", + " Yes; !- Part of Total Floor Area", + + "BuildingSurface:Detailed," + " Zone1, !- Name", + " Floor, !- Surface Type", + " DummyConstruction, !- Construction Name", + " Zone1, !- Zone Name", + " , !- Space Name", + " Outdoors, !- Outside Boundary Condition", + " , !- Outside Boundary Condition Object", + " NoSun, !- Sun Exposure", + " NoWind, !- Wind Exposure", + " 0, !- View Factor to Ground", + " 4, !- Number of Vertices", + " 10.0, 0.0, 0.0, !- X,Y,Z 1 {m}", + " 0.0, 0.0, 0.0, !- X,Y,Z 2 {m}", + " 0.0, 10.0, 0.0, !- X,Y,Z 3 {m}", + " 10.0, 10.0, 0.0; !- X,Y,Z 4 {m}", + + "Construction," + " DummyConstruction, !- Name", + " DummyMaterial; !- Outside Layer", + + "Material," + " DummyMaterial, !- Name", + " MediumRough, !- Roughness", + " 0.4, !- Thickness {m}", + " 0.033, !- Conductivity {W/m-K}", + " 32, !- Density {kg/m3}", + " 1210, !- Specific Heat {J/kg-K}", + " 0.9, !- Thermal Absorptance", + " 0.7, !- Solar Absorptance", + " 0.7; !- Visible Absorptance", + + "WaterHeater:Mixed," + " Solar Loop Water Heater, !- Name", + " Autosize, !- Tank Volume {m3}", + " Sch 80C, !- Setpoint Temperature Schedule Name", + " 5.00, !- Deadband Temperature Difference {deltaC}", + " 100.00, !- Maximum Temperature Limit {C}", + " Cycle, !- Heater Control Type", + " 0.0, !- Heater Maximum Capacity {W}", + " 0.0, !- Heater Minimum Capacity {W}", + " , !- Heater Ignition Minimum Flow Rate {m3/s}", + " , !- Heater Ignition Delay {s}", + " Electricity, !- Heater Fuel Type", + " 0.8, !- Heater Thermal Efficiency", + " , !- Part Load Factor Curve Name", + " , !- Off Cycle Parasitic Fuel Consumption Rate {W}", + " , !- Off Cycle Parasitic Fuel Type", + " , !- Off Cycle Parasitic Heat Fraction to Tank", + " , !- On Cycle Parasitic Fuel Consumption Rate {W}", + " , !- On Cycle Parasitic Fuel Type", + " , !- On Cycle Parasitic Heat Fraction to Tank", + " Zone, !- Ambient Temperature Indicator", + " , !- Ambient Temperature Schedule Name", + " Zone1, !- Ambient Temperature Zone Name", + " , !- Ambient Temperature Outdoor Air Node Name", + " 0.0000, !- Off Cycle Loss Coefficient to Ambient Temperature {W/K}", + " 1.00, !- Off Cycle Loss Fraction to Zone", + " 0.0000, !- On Cycle Loss Coefficient to Ambient Temperature {W/K}", + " 1.00, !- On Cycle Loss Fraction to Zone", + " 0.01, !- Peak Use Flow Rate {m3/s}", + " Always 1, !- Use Flow Rate Fraction Schedule Name", + " , !- Cold Water Supply Temperature Schedule Name", + " , !- Use Side Inlet Node Name", + " , !- Use Side Outlet Node Name", + " 1.00, !- Use Side Effectiveness", + " Solar Loop Water Heater Heating Inlet Node, !- Source Side Inlet Node Name", + " Solar Loop Water Heater Heating Outlet Node, !- Source Side Outlet Node Name", + " 1.00, !- Source Side Effectiveness", + " 1.0, !- Use Side Design Flow Rate {m3/s}", + " 1.0, !- Source Side Design Flow Rate {m3/s}", + " 1.500000, !- Indirect Water Heating Recovery Time {hr}", + " IndirectHeatPrimarySetpoint, !- Source Side Flow Control Mode", + " Sch 55C; !- Indirect Alternate Setpoint Temperature Schedule Name", + + "WaterHeater:Sizing," + " Solar Loop Water Heater, !- WaterHeater Name", + " PerSolarCollectorArea, !- Design Mode", + " 0.600000, !- Time Storage Can Meet Peak Draw {hr}", + " 0.600000, !- Time for Tank Recovery {hr}", + " 1.000000, !- Nominal Tank Volume for Autosizing Plant Connections {m3}", + " 4, !- Number of Bedrooms", + " 2, !- Number of Bathrooms", + " 0.200000, !- Storage Capacity per Person {m3/person}", + " 0.200000, !- Recovery Capacity per Person {m3/hr-person}", + " 0.020000, !- Storage Capacity per Floor Area {m3/m2}", + " 0.020000, !- Recovery Capacity per Floor Area {m3/hr-m2}", + " 4, !- Number of Units", + " 0.200000, !- Storage Capacity per Unit {m3}", + " 0.200000, !- Recovery Capacity PerUnit {m3/hr}", + " 0.200, !- Storage Capacity per Collector Area {m3/m2}", + " 1.000; !- Height Aspect Ratio", + + "SolarCollector:FlatPlate:PhotovoltaicThermal," + " Collector 2 PVT, !- Name", + " Solar collector 3, !- Surface Name", + " 30percentPVThalfarea, !- Photovoltaic-Thermal Model Performance Name", + " Collector 2 PV, !- Photovoltaic Name", + " Water, !- Thermal Working Fluid Type", + " Solar Collector Water Inlet Node, !- Water Inlet Node Name", + " Solar Collector Water Outlet Node, !- Water Outlet Node Name", + " , !- Air Inlet Node Name", + " , !- Air Outlet Node Name", + " autosize; !- Design Flow Rate {m3/s}", + + "SolarCollectorPerformance:PhotovoltaicThermal:Simple," + " 30percentPVThalfarea, !- Name", + " 0.5, !- Fraction of Surface Area with Active Thermal Collector {dimensionless}", + " Fixed, !- Thermal Conversion Efficiency Input Mode Type", + " 0.3, !- Value for Thermal Conversion Efficiency if Fixed", + " , !- Thermal Conversion Efficiency Schedule Name", + " 0.84; !- Front Surface Emittance", + + "Generator:Photovoltaic," + " Collector 2 PV, !- Name", + " Solar collector 3, !- Surface Name", + " PhotovoltaicPerformance:Simple, !- Photovoltaic Performance Object Type", + " 15percentPV Constant Efficiency, !- Module Performance Name", + " PhotovoltaicThermalSolarCollector, !- Heat Transfer Integration Mode", + " 1, !- Number of Series Strings in Parallel {dimensionless}", + " 1; !- Number of Modules in Series {dimensionless}", + + "PhotovoltaicPerformance:Simple," + " 15percentPV Constant Efficiency, !- Name", + " 0.90, !- Fraction of Surface Area with Active Solar Cells {dimensionless}", + " Fixed, !- Conversion Efficiency Input Mode", + " 0.15; !- Value for Cell Efficiency if Fixed", + + "Shading:Building:Detailed,", + " Solar collector 3, !- Name", + " , !- Transmittance Schedule Name", + " 4, !- Number of Vertices", + " 0, 10, 6, !- X,Y,Z Vertex 1 {m}", + " 0, 0, 6, !- X,Y,Z Vertex 2 {m}", + " 1, 0, 6, !- X,Y,Z Vertex 3 {m}", + " 1, 10, 6; !- X,Y,Z Vertex 4 {m} ", + }); + + ASSERT_TRUE(process_idf(idf_objects)); + + bool ErrorsFound = false; + HeatBalanceManager::GetHeatBalanceInput(*state); // Gets materials, constructions, zones, surfaces, etc. + HeatBalanceSurfaceManager::AllocateSurfaceHeatBalArrays(*state); + HeatBalanceManager::AllocateHeatBalArrays(*state); + + SurfaceGeometry::GetSurfaceData(*state, ErrorsFound); + EXPECT_FALSE(ErrorsFound); + SolarShading::AllocateModuleArrays(*state); + + Photovoltaics::GetPVInput(*state); + PhotovoltaicThermalCollectors::GetPVTcollectorsInput(*state); + + EXPECT_EQ(1, state->dataPhotovoltaicThermalCollector->NumPVT); + auto &pvt = state->dataPhotovoltaicThermalCollector->PVT(1); + // 10 m^2 for the surface, 0.5 Fraction of Surface Area with Active Thermal Collector + EXPECT_EQ(10.0 * 0.5, pvt.AreaCol); + InternalHeatGains::GetInternalHeatGainsInput(*state); + has_err_output(true); + EXPECT_FALSE(WaterThermalTanks::GetWaterThermalTankInput(*state)); // This returns true if ErrorsFound + EXPECT_TRUE(compare_err_stream("")); + + EXPECT_EQ(4, state->dataLoopNodes->NumOfNodes); + + EXPECT_EQ(1, state->dataWaterThermalTanks->numWaterHeaterMixed); + EXPECT_EQ(1, state->dataWaterThermalTanks->numWaterHeaterSizing); + EXPECT_EQ(0, state->dataWaterThermalTanks->numWaterHeaterStratified); + EXPECT_EQ(0, state->dataWaterThermalTanks->numWaterHeaterDesuperheater); + auto &Tank = state->dataWaterThermalTanks->WaterThermalTank(1); + EXPECT_TRUE(Tank.VolumeWasAutoSized); + + // set up the plant loops + // first the load side + state->dataPlnt->TotNumLoops = 1; + state->dataPlnt->PlantLoop.allocate(1); + + auto &plantLoop = state->dataPlnt->PlantLoop(1); + auto &supplySide = plantLoop.LoopSide(DataPlant::LoopSideLocation::Supply); + supplySide.TotalBranches = 1; + supplySide.Branch.allocate(1); + supplySide.Branch(1).TotalComponents = 1; + supplySide.Branch(1).Comp.allocate(1); + auto &PlantSupplySideComp = supplySide.Branch(1).Comp(1); + PlantSupplySideComp.Type = DataPlant::PlantEquipmentType::WtrHeaterMixed; + PlantSupplySideComp.Name = Tank.Name; + PlantSupplySideComp.NodeNumIn = Tank.SourceInletNode; + PlantSupplySideComp.NodeNumOut = Tank.SourceOutletNode; + + auto &demandSide = plantLoop.LoopSide(DataPlant::LoopSideLocation::Demand); + demandSide.TotalBranches = 1; + demandSide.Branch.allocate(1); + demandSide.Branch(1).TotalComponents = 1; + demandSide.Branch(1).Comp.allocate(1); + auto &PlantDemandSideComp = demandSide.Branch(1).Comp(1); + PlantDemandSideComp.Type = DataPlant::PlantEquipmentType::PVTSolarCollectorFlatPlate; + PlantDemandSideComp.Name = pvt.Name; + PlantDemandSideComp.NodeNumIn = pvt.PlantInletNodeNum; + PlantDemandSideComp.NodeNumOut = pvt.PlantOutletNodeNum; + + state->dataGlobal->BeginEnvrnFlag = false; + + EXPECT_ENUM_EQ(DataPlant::LoopSideLocation::Invalid, pvt.WPlantLoc.loopSideNum); + EXPECT_EQ(0, pvt.WPlantLoc.loopNum); + // This is actually unused by PVTCollectorStruct::onInitLoopEquip but in case that changes, make it make sense + PlantLocation plantLocDemand = PlantLocation(1, DataPlant::LoopSideLocation::Demand, 1, 1); + pvt.onInitLoopEquip(*state, plantLocDemand); + EXPECT_ENUM_EQ(DataPlant::LoopSideLocation::Demand, pvt.WPlantLoc.loopSideNum); + EXPECT_EQ(1, pvt.WPlantLoc.loopNum); + + EXPECT_ENUM_EQ(DataPlant::LoopSideLocation::Invalid, Tank.SrcSidePlantLoc.loopSideNum); + EXPECT_EQ(0, Tank.SrcSidePlantLoc.loopNum); + PlantLocation plantLocSupply = PlantLocation(1, DataPlant::LoopSideLocation::Supply, 1, 1); + EXPECT_DOUBLE_EQ(0.00, Tank.Sizing.TotalSolarCollectorArea); + EXPECT_DOUBLE_EQ(DataSizing::AutoSize, Tank.Volume); + + has_eio_output(true); + + state->dataPlnt->PlantFirstSizesOkayToFinalize = true; + state->dataPlnt->PlantFinalSizesOkayToReport = true; + Tank.onInitLoopEquip(*state, plantLocSupply); + EXPECT_ENUM_EQ(DataPlant::LoopSideLocation::Supply, Tank.SrcSidePlantLoc.loopSideNum); + EXPECT_EQ(1, Tank.SrcSidePlantLoc.loopNum); + + // compare_eio_stream(delimited_string({ + // "Water Heater Information,WaterHeater:Mixed,SOLAR LOOP WATER HEATER,-99998.9999,0.0,0.000,0.0000", + // "! , Component Type, Component Name, Input Field Description, Value", + // " Component Sizing Information, WaterHeater:Mixed, SOLAR LOOP WATER HEATER, Tank Volume [m3], 1.00000", + // })); + EXPECT_DOUBLE_EQ(5.00, Tank.Sizing.TotalSolarCollectorArea); + EXPECT_DOUBLE_EQ(0.2, Tank.Sizing.TankCapacityPerCollectorArea); + EXPECT_DOUBLE_EQ(1.0, Tank.Volume); +} From ed631fc941d1ae63488d6a3b5489e5b8f5c99cfd Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Thu, 20 Jun 2024 01:26:26 +0200 Subject: [PATCH 2/4] Specifically test for the NaN ``` [ RUN ] EnergyPlusFixture.WH_Sizing /Users/julien/Software/Others/EnergyPlus2/tst/EnergyPlus/unit/WaterThermalTanks.unit.cc:5690: Failure Expected equality of these values: 5.00 Which is: 5 Tank.Sizing.TotalSolarCollectorArea Which is: 0 /Users/julien/Software/Others/EnergyPlus2/tst/EnergyPlus/unit/WaterThermalTanks.unit.cc:5692: Failure Expected equality of these values: 1.0 Which is: 1 Tank.Volume Which is: 0 /Users/julien/Software/Others/EnergyPlus2/tst/EnergyPlus/unit/WaterThermalTanks.unit.cc:5711: Failure Value of: std::isnan(Tank.AmbientZoneGain) Actual: true Expected: false /Users/julien/Software/Others/EnergyPlus2/tst/EnergyPlus/unit/WaterThermalTanks.unit.cc:5712: Failure Expected equality of these values: 0.0 Which is: 0 Tank.AmbientZoneGain Which is: nan ``` --- tst/EnergyPlus/unit/WaterThermalTanks.unit.cc | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tst/EnergyPlus/unit/WaterThermalTanks.unit.cc b/tst/EnergyPlus/unit/WaterThermalTanks.unit.cc index 9b135c20092..c22cfba24ce 100644 --- a/tst/EnergyPlus/unit/WaterThermalTanks.unit.cc +++ b/tst/EnergyPlus/unit/WaterThermalTanks.unit.cc @@ -78,6 +78,8 @@ #include #include +#include + using namespace EnergyPlus; using namespace OutputReportPredefined; @@ -5688,4 +5690,24 @@ TEST_F(EnergyPlusFixture, MixedTank_PVT_Per_VolumeSizing_PerSolarCollectorArea) EXPECT_DOUBLE_EQ(5.00, Tank.Sizing.TotalSolarCollectorArea); EXPECT_DOUBLE_EQ(0.2, Tank.Sizing.TankCapacityPerCollectorArea); EXPECT_DOUBLE_EQ(1.0, Tank.Volume); + + state->dataGlobal->HourOfDay = 0; + state->dataGlobal->TimeStep = 1; + state->dataGlobal->TimeStepZone = 1.0 / 60.0; // one-minute system time step + state->dataHVACGlobal->TimeStepSys = state->dataGlobal->TimeStepZone; + state->dataHVACGlobal->TimeStepSysSec = state->dataHVACGlobal->TimeStepSys * Constant::SecInHour; + Tank.SavedTankTemp = 60.0; + Tank.TankTemp = 60.0; + Tank.AmbientTempZone = 20.0; + Tank.AmbientTemp = 20.0; + Tank.UseInletTemp = 20.0; + Tank.SetPointTemp = 55.0; + Tank.SetPointTemp2 = Tank.SetPointTemp; + Tank.TimeElapsed = 0.0; + + Tank.SourceMassFlowRate = 0.0; + + Tank.CalcWaterThermalTankMixed(*state); + EXPECT_FALSE(std::isnan(Tank.AmbientZoneGain)); + EXPECT_DOUBLE_EQ(0.0, Tank.AmbientZoneGain); // Didn't define on/off cycle losses } From df5042fb91e1dd2592e365832fff2a0b38e8496d Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Thu, 20 Jun 2024 01:35:15 +0200 Subject: [PATCH 3/4] Fix #10574 - Deal with BIPVT for WaterHeater sizing and throw error if Total Collector area found is zero --- src/EnergyPlus/WaterThermalTanks.cc | 95 +++++++++++++++++++++++------ 1 file changed, 78 insertions(+), 17 deletions(-) diff --git a/src/EnergyPlus/WaterThermalTanks.cc b/src/EnergyPlus/WaterThermalTanks.cc index 730b4f5ddad..4f747999d2a 100644 --- a/src/EnergyPlus/WaterThermalTanks.cc +++ b/src/EnergyPlus/WaterThermalTanks.cc @@ -77,6 +77,7 @@ #include #include #include +#include #include #include #include @@ -11201,9 +11202,6 @@ void WaterThermalTankData::SizeTankForSupplySide(EnergyPlusData &state) static constexpr std::string_view RoutineName("SizeTankForSupplySide"); - Real64 Tstart = 14.44; - Real64 Tfinish = 57.22; - Real64 tmpTankVolume = this->Volume; Real64 tmpMaxCapacity = this->MaxCapacity; @@ -11221,8 +11219,11 @@ void WaterThermalTankData::SizeTankForSupplySide(EnergyPlusData &state) } if (this->MaxCapacityWasAutoSized) { if (this->Sizing.RecoveryTime > 0.0) { - Real64 rho; - Real64 Cp; + Real64 rho = 0.0; + Real64 Cp = 0.0; + constexpr Real64 Tstart = 14.44; + constexpr Real64 Tfinish = 57.22; + if (this->SrcSidePlantLoc.loopNum > 0) { rho = FluidProperties::GetDensityGlycol(state, state.dataPlnt->PlantLoop(this->SrcSidePlantLoc.loopNum).FluidName, @@ -11242,8 +11243,7 @@ void WaterThermalTankData::SizeTankForSupplySide(EnergyPlusData &state) (this->Sizing.RecoveryTime * Constant::SecInHour); // m3 | kg/m3 | J/Kg/K | K | seconds } else { ShowFatalError( - state, - format("SizeTankForSupplySide: Tank=\"{}\", requested sizing for max capacity but entered Recovery Time is zero.", this->Name)); + state, format("{}: Tank=\"{}\", requested sizing for max capacity but entered Recovery Time is zero.", RoutineName, this->Name)); } } @@ -11259,12 +11259,40 @@ void WaterThermalTankData::SizeTankForSupplySide(EnergyPlusData &state) } else if (this->Sizing.DesignMode == SizingMode::PerSolarColArea) { this->Sizing.TotalSolarCollectorArea = 0.0; + if (state.dataSolarCollectors->GetInputFlag) { + SolarCollectors::GetSolarCollectorInput(state); + state.dataSolarCollectors->GetInputFlag = false; + } + for (int CollectorNum = 1; CollectorNum <= state.dataSolarCollectors->NumOfCollectors; ++CollectorNum) { - this->Sizing.TotalSolarCollectorArea += state.dataSurface->Surface(state.dataSolarCollectors->Collector(CollectorNum).Surface).Area; + auto const &collector = state.dataSolarCollectors->Collector(CollectorNum); + this->Sizing.TotalSolarCollectorArea += state.dataSurface->Surface(collector.Surface).Area; + } + + if (state.dataPhotovoltaicThermalCollector->GetInputFlag) { + PhotovoltaicThermalCollectors::GetPVTcollectorsInput(state); + state.dataPhotovoltaicThermalCollector->GetInputFlag = false; } - if (this->VolumeWasAutoSized) tmpTankVolume = this->Sizing.TotalSolarCollectorArea * this->Sizing.TankCapacityPerCollectorArea; - if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 0.0; + for (int CollectorNum = 1; CollectorNum <= state.dataPhotovoltaicThermalCollector->NumPVT; ++CollectorNum) { + auto const &collector = state.dataPhotovoltaicThermalCollector->PVT(CollectorNum); + this->Sizing.TotalSolarCollectorArea += collector.AreaCol; + } + + if (this->VolumeWasAutoSized) { + if (this->Sizing.TotalSolarCollectorArea > 0) { + tmpTankVolume = this->Sizing.TotalSolarCollectorArea * this->Sizing.TankCapacityPerCollectorArea; + } else { + ShowFatalError(state, + format("{}: Tank=\"{}\", requested sizing for volume with PerSolarCollectorArea but total found " + "area of Collectors is zero.", + RoutineName, + this->Name)); + } + } + if (this->MaxCapacityWasAutoSized) { + tmpMaxCapacity = 0.0; + } if (this->VolumeWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) { this->Volume = tmpTankVolume; if (state.dataPlnt->PlantFinalSizesOkayToReport) { @@ -11285,7 +11313,9 @@ void WaterThermalTankData::SizeTankForSupplySide(EnergyPlusData &state) } } - if (this->MaxCapacityWasAutoSized) this->setBackupElementCapacity(state); + if (this->MaxCapacityWasAutoSized) { + this->setBackupElementCapacity(state); + } if ((this->VolumeWasAutoSized) && (this->WaterThermalTankType == DataPlant::PlantEquipmentType::WtrHeaterStratified) && state.dataPlnt->PlantFirstSizesOkayToFinalize) { // might set height @@ -11577,8 +11607,7 @@ void WaterThermalTankData::SizeStandAloneWaterHeater(EnergyPlusData &state) } else { ShowFatalError( state, - format("SizeStandAloneWaterHeater: Tank=\"{}\", requested sizing for max capacity but entered Recovery Time is zero.", - this->Name)); + format("{}: Tank=\"{}\", requested sizing for max capacity but entered Recovery Time is zero.", RoutineName, this->Name)); } this->MaxCapacity = tmpMaxCapacity; BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Maximum Heater Capacity [W]", this->MaxCapacity); @@ -11800,13 +11829,43 @@ void WaterThermalTankData::SizeStandAloneWaterHeater(EnergyPlusData &state) break; } case SizingMode::PerSolarColArea: { + this->Sizing.TotalSolarCollectorArea = 0.0; + if (state.dataSolarCollectors->GetInputFlag) { + SolarCollectors::GetSolarCollectorInput(state); + state.dataSolarCollectors->GetInputFlag = false; + } + for (int CollectorNum = 1; CollectorNum <= state.dataSolarCollectors->NumOfCollectors; ++CollectorNum) { - this->Sizing.TotalSolarCollectorArea += state.dataSurface->Surface(state.dataSolarCollectors->Collector(CollectorNum).Surface).Area; + auto const &collector = state.dataSolarCollectors->Collector(CollectorNum); + this->Sizing.TotalSolarCollectorArea += state.dataSurface->Surface(collector.Surface).Area; + } + + if (state.dataPhotovoltaicThermalCollector->GetInputFlag) { + PhotovoltaicThermalCollectors::GetPVTcollectorsInput(state); + state.dataPhotovoltaicThermalCollector->GetInputFlag = false; + } + + for (int CollectorNum = 1; CollectorNum <= state.dataPhotovoltaicThermalCollector->NumPVT; ++CollectorNum) { + auto const &collector = state.dataPhotovoltaicThermalCollector->PVT(CollectorNum); + this->Sizing.TotalSolarCollectorArea += collector.AreaCol; + } + + if (this->VolumeWasAutoSized) { + if (this->Sizing.TotalSolarCollectorArea > 0) { + tmpTankVolume = this->Sizing.TotalSolarCollectorArea * this->Sizing.TankCapacityPerCollectorArea; + } else { + ShowFatalError(state, + format("{}: Tank=\"{}\", requested sizing for volume with PerSolarCollectorArea but total found " + "area of Collectors is zero.", + RoutineName, + this->Name)); + } + } + if (this->MaxCapacityWasAutoSized) { + tmpMaxCapacity = 0.0; } - if (this->VolumeWasAutoSized) tmpTankVolume = this->Sizing.TotalSolarCollectorArea * this->Sizing.TankCapacityPerCollectorArea; - if (this->MaxCapacityWasAutoSized) tmpMaxCapacity = 0.0; if (this->VolumeWasAutoSized) { this->Volume = tmpTankVolume; BaseSizer::reportSizerOutput(state, this->Type, this->Name, "Tank Volume [m3]", this->Volume); @@ -11818,7 +11877,9 @@ void WaterThermalTankData::SizeStandAloneWaterHeater(EnergyPlusData &state) break; } default: - if (this->MaxCapacityWasAutoSized) this->setBackupElementCapacity(state); + if (this->MaxCapacityWasAutoSized) { + this->setBackupElementCapacity(state); + } break; } } From 4ee8bcb4e80adb7f6d7a84c9e61eb08af59f40d8 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Thu, 20 Jun 2024 01:50:17 +0200 Subject: [PATCH 4/4] The CollectorData and PVTCollectorStruct use a factory, so we don't need to check if we need to trigger the getinput for them --- src/EnergyPlus/WaterThermalTanks.cc | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/EnergyPlus/WaterThermalTanks.cc b/src/EnergyPlus/WaterThermalTanks.cc index 4f747999d2a..060fc2d59dc 100644 --- a/src/EnergyPlus/WaterThermalTanks.cc +++ b/src/EnergyPlus/WaterThermalTanks.cc @@ -11259,21 +11259,12 @@ void WaterThermalTankData::SizeTankForSupplySide(EnergyPlusData &state) } else if (this->Sizing.DesignMode == SizingMode::PerSolarColArea) { this->Sizing.TotalSolarCollectorArea = 0.0; - if (state.dataSolarCollectors->GetInputFlag) { - SolarCollectors::GetSolarCollectorInput(state); - state.dataSolarCollectors->GetInputFlag = false; - } for (int CollectorNum = 1; CollectorNum <= state.dataSolarCollectors->NumOfCollectors; ++CollectorNum) { auto const &collector = state.dataSolarCollectors->Collector(CollectorNum); this->Sizing.TotalSolarCollectorArea += state.dataSurface->Surface(collector.Surface).Area; } - if (state.dataPhotovoltaicThermalCollector->GetInputFlag) { - PhotovoltaicThermalCollectors::GetPVTcollectorsInput(state); - state.dataPhotovoltaicThermalCollector->GetInputFlag = false; - } - for (int CollectorNum = 1; CollectorNum <= state.dataPhotovoltaicThermalCollector->NumPVT; ++CollectorNum) { auto const &collector = state.dataPhotovoltaicThermalCollector->PVT(CollectorNum); this->Sizing.TotalSolarCollectorArea += collector.AreaCol; @@ -11831,21 +11822,12 @@ void WaterThermalTankData::SizeStandAloneWaterHeater(EnergyPlusData &state) case SizingMode::PerSolarColArea: { this->Sizing.TotalSolarCollectorArea = 0.0; - if (state.dataSolarCollectors->GetInputFlag) { - SolarCollectors::GetSolarCollectorInput(state); - state.dataSolarCollectors->GetInputFlag = false; - } for (int CollectorNum = 1; CollectorNum <= state.dataSolarCollectors->NumOfCollectors; ++CollectorNum) { auto const &collector = state.dataSolarCollectors->Collector(CollectorNum); this->Sizing.TotalSolarCollectorArea += state.dataSurface->Surface(collector.Surface).Area; } - if (state.dataPhotovoltaicThermalCollector->GetInputFlag) { - PhotovoltaicThermalCollectors::GetPVTcollectorsInput(state); - state.dataPhotovoltaicThermalCollector->GetInputFlag = false; - } - for (int CollectorNum = 1; CollectorNum <= state.dataPhotovoltaicThermalCollector->NumPVT; ++CollectorNum) { auto const &collector = state.dataPhotovoltaicThermalCollector->PVT(CollectorNum); this->Sizing.TotalSolarCollectorArea += collector.AreaCol;